diff --git a/.travis.yml b/.travis.yml index 5b3a0fea7b25c3da405ad07e4027a7b6600d3e22..d05ad88b9dfd990875ba289079889e535998cc48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: cpp dist: trusty -sudo: required notifications: email: false diff --git a/src/Algorithms/AlgorithmAnnotationResample.cxx b/src/Algorithms/AlgorithmAnnotationResample.cxx new file mode 100644 index 0000000000000000000000000000000000000000..745eb464359a04b5d22ee4215a684ad5abd429e1 --- /dev/null +++ b/src/Algorithms/AlgorithmAnnotationResample.cxx @@ -0,0 +1,396 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretAssert.h" +#include "CaretLogger.h" + +#include "AlgorithmAnnotationResample.h" +#include "AlgorithmException.h" +#include "Annotation.h" +#include "AnnotationCoordinate.h" +#include "AnnotationFile.h" +#include "AnnotationGroup.h" +#include "AnnotationOneDimensionalShape.h" +#include "AnnotationTwoDimensionalShape.h" +#include "DataFileException.h" +#include "SurfaceFile.h" + +using namespace caret; + +/** + * \class caret::AlgorithmAnnotationResample + * \brief RESAMPLE AN ANNOTATION FILE TO DIFFERENT MESHES + */ + +/** + * @return Command line switch + */ +AString +AlgorithmAnnotationResample::getCommandSwitch() +{ + return "-annotation-resample"; +} + +/** + * @return Short description of algorithm + */ +AString +AlgorithmAnnotationResample::getShortDescription() +{ + return "RESAMPLE AN ANNOTATION FILE TO DIFFERENT MESHES"; +} + +/** + * @return Parameters for algorithm + */ +OperationParameters* +AlgorithmAnnotationResample::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + + ret->addAnnotationParameter(1, "annotation-in", "the annotation file to resample"); + + /* + * We need to preserve 'annotation groups' that may be created by the user. + * By modifying the annotation file that was read, any user created + * groups are preserved. In addition, we are only modifying annotations + * in 'surface space'; all others are preserved without modification. + * So, we get a string for the output filename instead of an output annotation file + */ + ret->addStringParameter(2, "annotation-out", "name of resampled annotation file"); + + ParameterComponent* surfacePairOpt = ret->createRepeatableParameter(3, + "-surface-pair", + "pair of surfaces for resampling surface annotations for one structure"); + surfacePairOpt->addSurfaceParameter(1, "source-surface", "the midthickness surface of the current mesh the annotations use"); + surfacePairOpt->addSurfaceParameter(2, "target-surface", "the midthickness surface of the mesh the annotations should be transferred to"); + + + AString helpText = ("Resample an annotation file from the source mesh to the target mesh.\n\n" + "Only annotations in surface space are modified, no changes are made to " + "annotations in other spaces. " + "The -surface-pair option may be repeated for additional " + "structures used by surface space annotations." + "\n\n" + "Note: -source-surface and -target-surface options are deprecated " + "and will be removed."); + + ret->setHelpText(helpText); + + return ret; +} + +/** + * Use Parameters and perform algorithm + * @param myParams + * Parameters for algorithm + * @param myProgObj + * The progress object + * @throws + * AlgorithmException if errors + */ +void +AlgorithmAnnotationResample::useParameters(OperationParameters* myParams, + ProgressObject* myProgObj) +{ + AnnotationFile* annotIn = myParams->getAnnotation(1); + + AString outputFileName = myParams->getString(2); + + std::vector sourceSurfaces; + std::vector targetSurfaces; + for (auto instance : *(myParams->getRepeatableParameterInstances(3))) { + sourceSurfaces.push_back(instance->getSurface(1)); + targetSurfaces.push_back(instance->getSurface(2)); + } + + /* + * Constructs and executes the algorithm + */ + AlgorithmAnnotationResample(myProgObj, + annotIn, + outputFileName, + sourceSurfaces, + targetSurfaces); + +} + +/** + * Constructor + * + * Calling the constructor will execute the algorithm + * + * @param myProgObj + * Parameters for algorithm + */ +AlgorithmAnnotationResample::AlgorithmAnnotationResample(ProgressObject* myProgObj, + AnnotationFile* annotationFile, + const AString& annotationFileName, + const std::vector& sourceSurfaces, + const std::vector& targetSurfaces) + : AbstractAlgorithm(myProgObj) +{ + /* + * Sets the algorithm up to use the progress object, and will + * finish the progress object automatically when the algorithm terminates + */ + LevelProgress myProgress(myProgObj); + + if (annotationFileName.isEmpty()) { + throw AlgorithmException("Output annotation file name is empty."); + } + + setupSurfaces(sourceSurfaces, + targetSurfaces); + + + std::vector allAnnotations; + annotationFile->getAllAnnotations(allAnnotations); + + for (auto ann : allAnnotations) { + CaretAssert(ann); + if (ann->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE) { + resampleAnnotation(ann); + } + } + + try { + const AString outputFileName(DataFileTypeEnum::addFileExtensionIfMissing(annotationFileName, + DataFileTypeEnum::ANNOTATION)); + annotationFile->writeFile(outputFileName); + } + catch (const DataFileException& dfe) { + throw AlgorithmException(dfe); + } +} + +/** + * Resample the given annotation + * + * @param ann + * The annotation + */ +void +AlgorithmAnnotationResample::resampleAnnotation(Annotation* ann) +{ + CaretAssert(ann); + CaretAssert(ann->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE); + + AnnotationOneDimensionalShape* oneDimAnn = ann->castToOneDimensionalShape(); + AnnotationTwoDimensionalShape* twoDimAnn = ann->castToTwoDimensionalShape(); + + std::vector coordinates; + if (oneDimAnn != NULL) { + coordinates.push_back(oneDimAnn->getStartCoordinate()); + coordinates.push_back(oneDimAnn->getEndCoordinate()); + } + else if (twoDimAnn != NULL) { + coordinates.push_back(twoDimAnn->getCoordinate()); + } + else { + const AString msg("Annotation is neither one- nor two-dimensional " + + ann->toString()); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return; + } + + for (auto coord : coordinates) { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t numberOfVertices(-1); + int32_t vertexIndex(-1); + coord->getSurfaceSpace(structure, numberOfVertices, vertexIndex); + + if (numberOfVertices < 0) { + throw AlgorithmException("Annotation in surface space has invalid number of vertices=" + + AString::number(numberOfVertices) + + " for " + + ann->toString()); + } + if (vertexIndex < 0) { + throw AlgorithmException("Annotation in surface space has invalid vertex index=" + + AString::number(vertexIndex) + + " for " + + ann->toString()); + } + if (vertexIndex > numberOfVertices) { + throw AlgorithmException("Annotation has invalid vertex index=" + + AString::number(vertexIndex) + + " but number of vertices=" + + AString::number(numberOfVertices) + + " for " + + ann->toString()); + } + + const auto stsIter = m_surfaces.find(structure); + if (stsIter != m_surfaces.end()) { + SourceTargetSurface* sts = stsIter->second; + CaretAssert(sts); + CaretAssert(sts->m_source); + CaretAssert(sts->m_target); + + if (numberOfVertices != sts->m_source->getNumberOfNodes()) { + throw AlgorithmException("Source surface with structure " + + StructureEnum::toName(structure) + + " contains " + + AString::number(sts->m_source->getNumberOfNodes()) + + " vertices but annotation requires surface with " + + AString::number(numberOfVertices) + + " for " + + ann->toString()); + } + float xyz[3]; + sts->m_source->getCoordinate(vertexIndex, + xyz); + + const int32_t targetVertexIndex = sts->m_target->closestNode(xyz); + if (targetVertexIndex >= 0) { + coord->setSurfaceSpace(structure, + sts->m_target->getNumberOfNodes(), + targetVertexIndex); + } + else { + throw AlgorithmException("Unable to find closest vertex in target surface for " + + ann->toString()); + } + } + else { + throw AlgorithmException("There are no surfaces for annotation with structure " + + StructureEnum::toName(structure) + + " for " + + ann->toString()); + } + } +} + +/** + * Setup the surfaces and validate them + * + * @param sourceSurfaces + * The source surfaces + * @param targetSurfaces + * The target surfaces + */ +void +AlgorithmAnnotationResample::setupSurfaces(const std::vector& sourceSurfaces, + const std::vector& targetSurfaces) +{ + if (sourceSurfaces.empty()) { + throw AlgorithmException("There are no source surfaces"); + } + if (targetSurfaces.empty()) { + throw AlgorithmException("There are no target surfaces"); + } + + /* + * Verify each source surface uses a unique structure + */ + for (const auto surf : sourceSurfaces) { + const StructureEnum::Enum structure = surf->getStructure(); + const auto iter = m_surfaces.find(structure); + if (iter == m_surfaces.end()) { + m_surfaces.insert(std::make_pair(structure, + new SourceTargetSurface(surf))); + } + else { + throw AlgorithmException("Source surfaces have same structure: " + + iter->second->m_source->getFileName() + + " and " + + surf->getFileName()); + } + } + + /* + * Verify target surfaces use unique structure and + * there is a source surface using the same structure + */ + for (const auto surf : targetSurfaces) { + const StructureEnum::Enum structure = surf->getStructure(); + auto iter = m_surfaces.find(structure); + if (iter == m_surfaces.end()) { + throw AlgorithmException("Target surface " + + surf->getFileName() + + " uses structure " + + StructureEnum::toName(structure) + + " but there is no source surface with the structure."); + } + else { + SourceTargetSurface* sts = iter->second; + CaretAssert(sts); + if (sts->m_target == NULL) { + sts->m_target = surf; + } + else { + throw AlgorithmException("Target surfaces have same structure: " + + sts->m_target->getFileName() + + " and " + + surf->getFileName()); + } + } + } + + /* + * Verify no missing target surfaces + */ + for (auto iter : m_surfaces) { + SourceTargetSurface* sts = iter.second; + CaretAssert(sts); + CaretAssert(sts->m_source); + if (sts->m_target == NULL) { + throw AlgorithmException("There is no target surface with structure " + + StructureEnum::toName(iter.first) + + " for source surface " + + sts->m_source->getFileName()); + } + } + + for (auto iter : m_surfaces) { + CaretAssert(iter.second); + CaretAssert(iter.second->m_source); + CaretAssert(iter.second->m_target); + } +} + +/** + * @return Algorithm internal weight + */ +float +AlgorithmAnnotationResample::getAlgorithmInternalWeight() +{ + /* + * override this if needed, if the progress bar isn't smooth + */ + return 1.0f; +} + +/** + * @return Algorithm sub-algorithm weight + */ +float +AlgorithmAnnotationResample::getSubAlgorithmWeight() +{ + /* + * If you use a subalgorithm + */ + //return AlgorithmInsertNameHere::getAlgorithmWeight() + return 0.0f; +} + diff --git a/src/Algorithms/AlgorithmAnnotationResample.h b/src/Algorithms/AlgorithmAnnotationResample.h new file mode 100644 index 0000000000000000000000000000000000000000..e1d46d443862711be80bdb833f88924641607deb --- /dev/null +++ b/src/Algorithms/AlgorithmAnnotationResample.h @@ -0,0 +1,82 @@ +#ifndef __ALGORITHM_ANNOTATION_RESAMPLE_H__ +#define __ALGORITHM_ANNOTATION_RESAMPLE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "AbstractAlgorithm.h" + +namespace caret { + + class Annotation; + + class AlgorithmAnnotationResample : public AbstractAlgorithm { + + private: + AlgorithmAnnotationResample(); + + protected: + static float getSubAlgorithmWeight(); + + static float getAlgorithmInternalWeight(); + + public: + AlgorithmAnnotationResample(ProgressObject* myProgObj, + AnnotationFile* annotationFile, + const AString& annotationFileName, + const std::vector& sourceSurfaces, + const std::vector& targetSurfaces); + + static OperationParameters* getParameters(); + + static void useParameters(OperationParameters* myParams, + ProgressObject* myProgObj); + + static AString getCommandSwitch(); + + static AString getShortDescription(); + + private: + class SourceTargetSurface { + public: + SourceTargetSurface(const SurfaceFile* source) + : m_source(source), + m_target(NULL) { } + + const SurfaceFile* m_source; + const SurfaceFile* m_target; + }; + + std::map m_surfaces; + + void setupSurfaces(const std::vector& sourceSurfaces, + const std::vector& targetSurfaces); + + void resampleAnnotation(Annotation* ann); + }; + + typedef TemplateAutoOperation AutoAlgorithmAnnotationResample; + +} // namespace + +#endif //__ALGORITHM_ANNOTATION_RESAMPLE_H__ + diff --git a/src/Algorithms/AlgorithmCiftiAverageROICorrelation.cxx b/src/Algorithms/AlgorithmCiftiAverageROICorrelation.cxx index d737a21f35be2eb3cff69efeed5a7ab4cbd3d76e..a19afed9ea7d590487908dcbe3d579d13de81e2f 100644 --- a/src/Algorithms/AlgorithmCiftiAverageROICorrelation.cxx +++ b/src/Algorithms/AlgorithmCiftiAverageROICorrelation.cxx @@ -80,7 +80,7 @@ OperationParameters* AlgorithmCiftiAverageROICorrelation::getParameters() ciftiOpt->addCiftiParameter(1, "cifti-in", "a cifti file to average across"); ret->setHelpText( - AString("Averages rows for each map of the ROI(s), takes the correlation of each ROI average to the rest of the rows in the same file, then averages the results across all files. ") + + AString("Averages rows for each map of the ROI(s), takes the correlation of each ROI average to the rest of the rows in the same file, applies the fisher small z transform, then averages the results across all files. ") + "ROIs are always treated as weighting functions, including negative values. " + "For efficiency, ensure that everything that is not intended to be used is zero in the ROI map. " + "If -cifti-roi is specified, -left-roi, -right-roi, -cerebellum-roi, and -vol-roi must not be specified. " + diff --git a/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx b/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx index ec0401d7fc346ffa776f06d7e4bcf8892a8a4a24..261fc72cdb1543a52a38995ffb4222dabc42de33 100644 --- a/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx +++ b/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx @@ -32,6 +32,8 @@ #include "Vector3D.h" #include "VolumeFile.h" #include "dot_wrapper.h" + +#include #include using namespace caret; @@ -90,6 +92,11 @@ OperationParameters* AlgorithmCiftiCorrelationGradient::getParameters() OptionalParameter* memLimitOpt = ret->createOptionalParameter(11, "-mem-limit", "restrict memory usage"); memLimitOpt->addDoubleParameter(1, "limit-GB", "memory limit in gigabytes"); + OptionalParameter* secondCorrOpt = ret->createOptionalParameter(14, "-double-correlation", "do two correlations before taking the gradient"); + secondCorrOpt->createOptionalParameter(1, "-fisher-z-first", "after the FIRST correlation, apply fisher small z transform (ie, artanh)"); + secondCorrOpt->createOptionalParameter(2, "-no-demean-first", "instead of correlation for the FIRST operation, do dot product of rows, then normalize by diagonal"); + secondCorrOpt->createOptionalParameter(3, "-covariance-first", "instead of correlation for the FIRST operation, compute covariance"); + ret->setHelpText( AString("For each structure, compute the correlation of the rows in the structure, and take the gradients of ") + "the resulting rows, then average them. " + @@ -179,27 +186,39 @@ void AlgorithmCiftiCorrelationGradient::useParameters(OperationParameters* myPar } } bool covariance = myParams->getOptionalParameter(13)->m_present; + bool doubleCorr = false, firstFisher = false, firstNoDemean = false, firstCovar = false; + OptionalParameter* doubleCorrOpt = myParams->getOptionalParameter(14); + if (doubleCorrOpt->m_present) + { + doubleCorr = true; + firstFisher = doubleCorrOpt->getOptionalParameter(1)->m_present; + firstNoDemean = doubleCorrOpt->getOptionalParameter(2)->m_present; + firstCovar = doubleCorrOpt->getOptionalParameter(3)->m_present; + } AlgorithmCiftiCorrelationGradient(myProgObj, myCifti, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, myLeftAreas, myRightAreas, myCerebAreas, - surfKern, volKern, undoFisherInput, applyFisher, surfaceExclude, volumeExclude, covariance, memLimitGB); + surfKern, volKern, undoFisherInput, applyFisher, surfaceExclude, volumeExclude, covariance, memLimitGB, + doubleCorr, firstFisher, firstNoDemean, firstCovar); } -AlgorithmCiftiCorrelationGradient::AlgorithmCiftiCorrelationGradient(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, +AlgorithmCiftiCorrelationGradient::AlgorithmCiftiCorrelationGradient(ProgressObject* myProgObj, CiftiFile* myCifti, CiftiFile* myCiftiOut, SurfaceFile* myLeftSurf, SurfaceFile* myRightSurf, SurfaceFile* myCerebSurf, const MetricFile* myLeftAreas, const MetricFile* myRightAreas, const MetricFile* myCerebAreas, const float& surfKern, const float& volKern, const bool& undoFisherInput, const bool& applyFisher, const float& surfaceExclude, const float& volumeExclude, const bool& covariance, - const float& memLimitGB) : AbstractAlgorithm(myProgObj) + const float& memLimitGB, + const bool doubleCorr, const bool firstFisher, const bool firstNoDemean, const bool firstCovar) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); - init(myCifti, undoFisherInput, applyFisher, covariance); - const CiftiXMLOld& myXML = myCifti->getCiftiXMLOld(); - CiftiXMLOld myNewXML = myXML; - myNewXML.resetDirectionToScalars(CiftiXMLOld::ALONG_ROW, 1); - myNewXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 0, "gradient"); + init(myCifti, memLimitGB, undoFisherInput, applyFisher, covariance, doubleCorr, firstFisher, firstNoDemean, firstCovar); + const CiftiXML& myXML = myCifti->getCiftiXML(); + CiftiXML myNewXML = myXML; + CiftiScalarsMap newMap(1); + newMap.setMapName(0, "gradient"); + myNewXML.setMap(CiftiXML::ALONG_ROW, newMap); myCiftiOut->setCiftiXML(myNewXML); - vector surfaceList, volumeList; - myXML.getStructureListsForColumns(surfaceList, volumeList); + const CiftiBrainModelsMap& spaceMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); + vector surfaceList = spaceMap.getSurfaceStructureList(), volumeList = spaceMap.getVolumeStructureList(); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces SurfaceFile* mySurf = NULL; @@ -279,6 +298,156 @@ AlgorithmCiftiCorrelationGradient::AlgorithmCiftiCorrelationGradient(ProgressObj myCiftiOut->setColumn(m_outColumn.data(), 0); } +namespace +{ + + //expects rows to already be demeaned, if demeaning is to be done + float correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2, const int64_t length, const bool covariance, const bool fisherz) + { + double r; + if (row1 == row2 && !covariance) + { + r = 1.0;//short circuit for same row - works because one row is always in the cache range + } else { + double accum = dsdot(row1, row2, length);//these have already had the row means subtracted out + if (covariance) + { + r = accum / length; + } else { + r = accum / (rrs1 * rrs2); + } + } + if (!covariance) + { + if (fisherz) + { + if (r > 0.999999) r = 0.999999;//prevent inf + if (r < -0.999999) r = -0.999999;//prevent -inf + r = 0.5 * log((1 + r) / (1 - r)); + } else { + if (r > 1.0) r = 1.0;//don't output anything silly + if (r < -1.0) r = -1.0; + } + } + return r; + } + + void adjustRow(float* rowOut, int64_t length, AlgorithmCiftiCorrelationGradient::RowInfo& rowInfo, const bool undoFisher, const bool covariance, const bool noDemean) + { + if (undoFisher) + { + for (int64_t i = 0; i < length; ++i) + { + double temp = exp(2 * rowOut[i]); + rowOut[i] = (float)((temp - 1)/(temp + 1)); + } + } + if (!rowInfo.m_haveCalculated) + { + double accum = 0.0; + float mean = 0.0f; + if (!noDemean) + { + for (int64_t i = 0; i < length; ++i) + { + accum += rowOut[i]; + } + mean = accum / length; + } + rowInfo.m_mean = mean;//note: mean is intentionally 0 when noDemean is true + if (!covariance)//rrs not used in covariance + { + accum = 0.0; + for (int i = 0; i < length; ++i) + { + float tempf = rowOut[i] - mean; + accum += tempf * tempf; + if (!noDemean)//do one less pass over the data the first time the mean is computed + { + rowOut[i] = tempf; + } + } + rowInfo.m_rootResidSqr = sqrt(accum); + } else { + rowInfo.m_rootResidSqr = 0.0f; + } + rowInfo.m_haveCalculated = true; + } else { + if (!noDemean) + { + float mean = rowInfo.m_mean; + for (int64_t i = 0; i < length; ++i) + { + rowOut[i] -= mean; + } + } + } + } + + struct FirstCorrPlan + { + bool m_cacheFullInput; + int64_t m_chunkSize; + }; + + bool firstCorrWarned = false; + + FirstCorrPlan firstCorrMemoryPlan(const int64_t totalRows, const int64_t cacheRowLength, const float memLimitGB, const bool inputIsMemory, const int64_t inputRowLength, const int64_t /*mapSize*/) + { + FirstCorrPlan ret; + ret.m_cacheFullInput = true; + ret.m_chunkSize = totalRows; + if (memLimitGB < 0.0f) + { + return ret; + } + int64_t inputRowBytes = sizeof(float) * inputRowLength; + int64_t mem_limit_bytes = int64_t(memLimitGB * 1024 * 1024 * 1024); + int64_t full_input_cache_bytes = inputRowBytes * cacheRowLength;//cache is a part of a square dconn, sized by the column length of the input + int64_t cache_bytes = sizeof(float) * totalRows * cacheRowLength; + int64_t input_memory_bytes = 0; + if (inputIsMemory) + { + input_memory_bytes = full_input_cache_bytes; + } + int64_t in_use_bytes = cache_bytes + input_memory_bytes;//the metric/volume file used to store the second correlation before gradient isn't allocated until after cacheRows() + int64_t available_bytes = mem_limit_bytes - in_use_bytes; + if (available_bytes <= 0) + { + //the user may have specified 0, just use minimum memory... + if (!inputIsMemory && !firstCorrWarned) + { + CaretLogWarning("double correlation specified with extremely low memory limit, this may take a long time and do a lot of IO"); + firstCorrWarned = true; + } + ret.m_chunkSize = 1; + ret.m_cacheFullInput = false; + return ret; + } + if (full_input_cache_bytes > available_bytes) + { + ret.m_cacheFullInput = false; + int64_t maxChunkSize = available_bytes / inputRowBytes; + if (maxChunkSize < 1) maxChunkSize = 1; + int64_t numPasses = (totalRows - 1) / maxChunkSize + 1;//compute number of passes to find the minimum chunk size to do that number of passes + ret.m_chunkSize = (totalRows - 1) / numPasses + 1;//technically, unequal chunks is slightly less computation and same total IO, but equal chunks makes IO more consistent + if (ret.m_chunkSize < 1) + { + if (!inputIsMemory && !firstCorrWarned) + { + CaretLogWarning("double correlation specified with extremely low memory limit, this may take a long time and do a lot of IO"); + firstCorrWarned = true; + } + ret.m_chunkSize = 1; + return ret; + } + } + //default is to cache full input + //unlike ordinary correlation, the memory for storing the in-progress output has already been dictated to us, so there is no advantage to chunking any smaller than the input cache + return ret; + } +} + void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::Enum& myStructure, const float& surfKern, const float& memLimitGB, SurfaceFile* mySurf, const MetricFile* myAreas) { const CiftiXMLOld& myXML = m_inputCifti->getCiftiXMLOld(); @@ -287,10 +456,10 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E int mapSize = (int)myMap.size(); vector accum(mapSize, 0.0); int numCacheRows = mapSize; - bool cacheFullInput = true; + bool cacheFullInput = true;//numRowsForMem() sets this if (memLimitGB >= 0.0f) { - numCacheRows = numRowsForMem(memLimitGB, m_numCols * sizeof(float), (mySurf->getNumberOfNodes() * (sizeof(float) * 8 + 1)) / 8, mapSize, cacheFullInput); + numCacheRows = numRowsForMem(m_numCols * sizeof(float), (mySurf->getNumberOfNodes() * (sizeof(float) * 8 + 1)) / 8, mapSize, cacheFullInput); } if (numCacheRows > mapSize) { @@ -311,7 +480,7 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E MetricFile myRoi; myRoi.setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), 1); myRoi.initializeColumn(0); - vector rowsToCache; + vector rowsToCache; for (int i = 0; i < mapSize; ++i) { myRoi.setValue(myMap[i].m_surfaceNode, 0, 1.0f); @@ -322,7 +491,7 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E } if (cacheFullInput) { - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } CaretPointer mySmooth; if (surfKern > 0.0f) @@ -340,40 +509,51 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E { rowsToCache.push_back(myMap[i].m_ciftiIndex); } - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } int curRow = 0;//because we can't trust the order threads hit the critical section MetricFile computeMetric; computeMetric.setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), endpos - startpos); -#pragma omp CARET_PARFOR schedule(dynamic) - for (int i = 0; i < mapSize; ++i) +#pragma omp CARET_PAR { - float movingRrs; - const float* movingRow; - int myrow; -#pragma omp critical - {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway - myrow = curRow;//so, manually force it to read sequentially - ++curRow; - movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs); - } - for (int j = startpos; j < endpos; ++j) + vector scratchRow1(m_numCols), scratchRow2(m_numCols); +#pragma omp CARET_FOR schedule(dynamic) + for (int i = 0; i < mapSize; ++i) { - if (myrow >= startpos && myrow < endpos) + float movingRrs; + const float* movingRow = NULL; + int myrow; +#pragma omp critical + {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway + myrow = curRow;//so, manually force it to read sequentially + ++curRow; + if (!m_doubleCorr) + {//when not doing double corr, we want to read single rows in order on disk + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + } + if (m_doubleCorr) + {//when doing double corr, let the threads compute correlations in parallel + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + for (int j = startpos; j < endpos; ++j) { - if (j >= myrow) + if (myrow >= startpos && myrow < endpos) { + if (j >= myrow) + { + float cacheRrs; + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); + computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); + computeMetric.setValue(myMap[j].m_surfaceNode, myrow - startpos, result); + } + } else { float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); - computeMetric.setValue(myMap[j].m_surfaceNode, myrow - startpos, result); } - } else { - float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); - computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); } } } @@ -419,7 +599,7 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E bool cacheFullInput = true; if (memLimitGB >= 0.0f) { - numCacheRows = numRowsForMem(memLimitGB, m_numCols * sizeof(float), (mySurf->getNumberOfNodes() * (sizeof(float) * 8 + 1)) / 8, mapSize, cacheFullInput); + numCacheRows = numRowsForMem(m_numCols * sizeof(float), (mySurf->getNumberOfNodes() * (sizeof(float) * 8 + 1)) / 8, mapSize, cacheFullInput); } if (numCacheRows > mapSize) { @@ -444,7 +624,7 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E vector > roiLookup(numCacheRows);//this gets bit compressed vector origRoi(mySurf->getNumberOfNodes()); vector > excludeNodes(numCacheRows); - vector rowsToCache; + vector rowsToCache; for (int i = 0; i < mapSize; ++i) { myRoi.setValue(myMap[i].m_surfaceNode, 0, 1.0f); @@ -455,7 +635,7 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E } if (cacheFullInput) { - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } CaretPointer mySmooth; if (surfKern > 0.0f) @@ -473,7 +653,7 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E { rowsToCache.push_back(myMap[i].m_ciftiIndex); } - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } int numSurfNodes = mySurf->getNumberOfNodes(); #pragma omp CARET_PAR @@ -501,37 +681,48 @@ void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::E int curRow = 0;//because we can't trust the order threads hit the critical section MetricFile computeMetric; computeMetric.setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), endpos - startpos); -#pragma omp CARET_PARFOR schedule(dynamic) - for (int i = 0; i < mapSize; ++i) +#pragma omp CARET_PAR { - float movingRrs; - const float* movingRow; - int myrow; -#pragma omp critical - {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway - myrow = curRow;//so, manually force it to read sequentially - ++curRow; - movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs); - } - for (int j = startpos; j < endpos; ++j) + vector scratchRow1(m_numCols), scratchRow2(m_numCols); +#pragma omp CARET_FOR schedule(dynamic) + for (int i = 0; i < mapSize; ++i) { - if (roiLookup[j - startpos][myMap[myrow].m_surfaceNode]) + float movingRrs; + const float* movingRow = NULL; + int myrow; +#pragma omp critical + {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway + myrow = curRow;//so, manually force it to read sequentially + ++curRow; + if (!m_doubleCorr) + {//when not doing double corr, we want to read single rows in order on disk + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + } + if (m_doubleCorr) + {//when doing double corr, let the threads compute correlations in parallel + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + for (int j = startpos; j < endpos; ++j) { - if (myrow >= startpos && myrow < endpos) + if (roiLookup[j - startpos][myMap[myrow].m_surfaceNode]) { - if (j >= myrow) + if (myrow >= startpos && myrow < endpos) { + if (j >= myrow) + { + float cacheRrs; + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); + computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); + computeMetric.setValue(myMap[j].m_surfaceNode, myrow - startpos, result); + } + } else { float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); - computeMetric.setValue(myMap[j].m_surfaceNode, myrow - startpos, result); } - } else { - float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); - computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); } } } @@ -622,7 +813,7 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En } if (memLimitGB >= 0.0f) { - numCacheRows = numRowsForMem(memLimitGB, m_numCols * sizeof(float), newdims[0] * newdims[1] * newdims[2] * sizeof(float), mapSize, cacheFullInput); + numCacheRows = numRowsForMem(m_numCols * sizeof(float), newdims[0] * newdims[1] * newdims[2] * sizeof(float), mapSize, cacheFullInput); } if (numCacheRows > mapSize) { @@ -640,7 +831,7 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En myXML.getVolumeDimsAndSForm(ciftiDims, ciftiSform); VolumeFile volRoi(newdims, ciftiSform); volRoi.setValueAllVoxels(0.0f); - vector rowsToCache; + vector rowsToCache; for (int i = 0; i < mapSize; ++i) { volRoi.setValue(1.0f, myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]); @@ -651,7 +842,7 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En } if (cacheFullInput) { - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } for (int startpos = 0; startpos < mapSize; startpos += numCacheRows) { @@ -664,41 +855,52 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En { rowsToCache.push_back(myMap[i].m_ciftiIndex); } - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } int curRow = 0;//because we can't trust the order threads hit the critical section vector computeDims = newdims; computeDims.push_back(endpos - startpos); VolumeFile computeVol(computeDims, ciftiSform); -#pragma omp CARET_PARFOR schedule(dynamic) - for (int i = 0; i < mapSize; ++i) +#pragma omp CARET_PAR { - float movingRrs; - const float* movingRow; - int myrow; -#pragma omp critical - {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway - myrow = curRow;//so, manually force it to read sequentially - ++curRow; - movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs); - } - for (int j = startpos; j < endpos; ++j) + vector scratchRow1(m_numCols), scratchRow2(m_numCols); +#pragma omp CARET_FOR schedule(dynamic) + for (int i = 0; i < mapSize; ++i) { - if (myrow >= startpos && myrow < endpos) + float movingRrs; + const float* movingRow = NULL; + int myrow; +#pragma omp critical + {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway + myrow = curRow;//so, manually force it to read sequentially + ++curRow; + if (!m_doubleCorr) + {//when not doing double corr, we want to read single rows in order on disk + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + } + if (m_doubleCorr) + {//when doing double corr, let the threads compute correlations in parallel + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + for (int j = startpos; j < endpos; ++j) { - if (j >= myrow) + if (myrow >= startpos && myrow < endpos) { + if (j >= myrow) + { + float cacheRrs; + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); + computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); + computeVol.setValue(result, myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2], myrow - startpos); + } + } else { float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); - computeVol.setValue(result, myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2], myrow - startpos); } - } else { - float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); - computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); } } } @@ -760,7 +962,7 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En } if (memLimitGB >= 0.0f) { - numCacheRows = numRowsForMem(memLimitGB, m_numCols * sizeof(float), newdims[0] * newdims[1] * newdims[2] * sizeof(float), mapSize, cacheFullInput); + numCacheRows = numRowsForMem(m_numCols * sizeof(float), newdims[0] * newdims[1] * newdims[2] * sizeof(float), mapSize, cacheFullInput); } if (numCacheRows > mapSize) { @@ -778,7 +980,7 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En myXML.getVolumeDimsAndSForm(ciftiDims, ciftiSform); VolumeFile volRoi(newdims, ciftiSform); volRoi.setValueAllVoxels(0.0f); - vector rowsToCache; + vector rowsToCache; for (int i = 0; i < mapSize; ++i) { volRoi.setValue(1.0f, myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]); @@ -789,7 +991,7 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En } if (cacheFullInput) { - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } for (int startpos = 0; startpos < mapSize; startpos += numCacheRows) { @@ -802,47 +1004,58 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En { rowsToCache.push_back(myMap[i].m_ciftiIndex); } - cacheRows(rowsToCache); + cacheRows(rowsToCache, mapSize); } int curRow = 0;//because we can't trust the order threads hit the critical section vector computeDims = newdims; computeDims.push_back(endpos - startpos); VolumeFile computeVol(computeDims, ciftiSform); -#pragma omp CARET_PARFOR schedule(dynamic) - for (int i = 0; i < mapSize; ++i) +#pragma omp CARET_PAR { - float movingRrs; - const float* movingRow; - int myrow; -#pragma omp critical - {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway - myrow = curRow;//so, manually force it to read sequentially - ++curRow; - movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs); - } - Vector3D movingLoc; - volRoi.indexToSpace(myMap[myrow].m_ijk, movingLoc);//NOTE: this is outside the cropped volume, but matches the real location in the full volume, because we didn't fix the center - for (int j = startpos; j < endpos; ++j) + vector scratchRow1(m_numCols), scratchRow2(m_numCols); +#pragma omp CARET_FOR schedule(dynamic) + for (int i = 0; i < mapSize; ++i) { - Vector3D seedLoc; - volRoi.indexToSpace(myMap[j].m_ijk, seedLoc);//ditto - if ((movingLoc - seedLoc).length() > volExclude)//don't correlate if closer than the exclude range + float movingRrs; + const float* movingRow = NULL; + int myrow; +#pragma omp critical + {//CiftiFile does use mutexes now (in NiftiIO), but sequential IO is better + myrow = curRow;//so, manually force it to read sequentially + ++curRow; + if (!m_doubleCorr) + {//when not doing double corr, we want to read single rows in order on disk + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + } + if (m_doubleCorr) + {//when doing double corr, let the threads compute correlations in parallel + movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); + } + Vector3D movingLoc; + volRoi.indexToSpace(myMap[myrow].m_ijk, movingLoc);//NOTE: this is outside the cropped volume, but matches the real location in the full volume, because we didn't fix the center + for (int j = startpos; j < endpos; ++j) { - if (myrow >= startpos && myrow < endpos) + Vector3D seedLoc; + volRoi.indexToSpace(myMap[j].m_ijk, seedLoc);//ditto + if ((movingLoc - seedLoc).length() > volExclude)//don't correlate if closer than the exclude range { - if (j >= myrow) + if (myrow >= startpos && myrow < endpos) { + if (j >= myrow) + { + float cacheRrs; + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); + computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); + computeVol.setValue(result, myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2], myrow - startpos); + } + } else { float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); + const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); + float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); - computeVol.setValue(result, myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2], myrow - startpos); } - } else { - float cacheRrs; - const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, true); - float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs); - computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); } } } @@ -888,38 +1101,8 @@ void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::En } } -float AlgorithmCiftiCorrelationGradient::correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2) -{ - double r; - if (row1 == row2 && !m_covariance) - { - r = 1.0;//short circuit for same row - } else { - double accum = dsdot(row1, row2, m_numCols);//these have already had the row means subtracted out - if (m_covariance) - { - r = accum / m_numCols; - } else { - r = accum / (rrs1 * rrs2); - } - } - if (!m_covariance) - { - if (m_applyFisher) - { - if (r > 0.999999) r = 0.999999;//prevent inf - if (r < -0.999999) r = -0.999999;//prevent -inf - r = 0.5 * log((1 + r) / (1 - r)); - } else { - if (r > 1.0) r = 1.0;//don't output anything silly - if (r < -1.0) r = -1.0; - } - } - return r; -} - -void AlgorithmCiftiCorrelationGradient::init(const CiftiFile* input, const bool& undoFisherInput, const bool& applyFisher, - const bool& covariance) +void AlgorithmCiftiCorrelationGradient::init(CiftiFile* input, const float& memLimitGB, const bool& undoFisherInput, const bool& applyFisher, + const bool& covariance, const bool doubleCorr, const bool firstFisher, const bool firstNoDemean, const bool firstCovar) { if (input->getCiftiXML().getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("input cifti file must have brain models mapping along column"); if (covariance) @@ -930,62 +1113,151 @@ void AlgorithmCiftiCorrelationGradient::init(const CiftiFile* input, const bool& m_applyFisher = applyFisher; m_covariance = covariance; m_inputCifti = input; - m_rowInfo.resize(m_inputCifti->getNumberOfRows()); - m_cacheUsed = 0; - m_numCols = m_inputCifti->getNumberOfColumns(); - m_outColumn.resize(m_inputCifti->getNumberOfRows()); + int64_t colLength = m_inputCifti->getNumberOfRows();//this is correct even for double correlation + m_doubleCorr = doubleCorr; + if (doubleCorr) + { + if (firstCovar && firstFisher) throw AlgorithmException("cannot apply fisher z transformation to first covariance"); + m_numCols = colLength;//virtual intermediate file is square and symmetric, because there is no -roi-override option + m_rowLengthFirst = m_inputCifti->getNumberOfColumns(); + m_firstFisher = firstFisher; + m_firstNoDemean = firstNoDemean; + m_firstCovar = firstCovar; + m_firstCorrInfo.resize(colLength); + } else { + m_numCols = m_inputCifti->getNumberOfColumns(); + m_rowLengthFirst = 0;//trick to get the memory computations to work out + } + m_memLimitGB = memLimitGB; + m_rowInfo.resize(colLength); + m_outColumn.resize(colLength); } -void AlgorithmCiftiCorrelationGradient::cacheRows(const vector& ciftiIndices) +void AlgorithmCiftiCorrelationGradient::cacheRows(const vector& ciftiIndices, const int64_t mapSize) { clearCache();//clear first, to be sure we never keep a cache around too long - int curIndex = 0, numIndices = (int)ciftiIndices.size();//manually in-order - m_rowCache.reserve(m_cacheUsed + numIndices);//so that pointers to members don't change -#pragma omp CARET_PAR + int64_t numIndices = (int64_t)ciftiIndices.size(); + m_rowCache.resize(numIndices, CacheRow(m_numCols)); + if (m_doubleCorr) { - int myIndex; - float* myPtr; -#pragma omp CARET_FOR schedule(dynamic) - for (int i = 0; i < numIndices; ++i) + for (int64_t i = 0; i < numIndices; ++i)//prepopulate intermediate output lookups, they will be useful to reuse symmetric correlations { - myPtr = NULL; -#pragma omp critical + m_rowCache[i].m_ciftiIndex = ciftiIndices[i]; + m_rowInfo[ciftiIndices[i]].m_cacheIndex = i; + } + vector > preparedInput; + FirstCorrPlan plan = firstCorrMemoryPlan(numIndices, m_numCols, m_memLimitGB, m_inputCifti->isInMemory(), m_rowLengthFirst, mapSize); + if (plan.m_cacheFullInput)//we could cache full input while still chunking computation, but there is no reason to for first corr... + { + preparedInput.resize(m_numCols, vector(m_rowLengthFirst)); + for (int64_t i = 0; i < m_numCols; ++i) { - myIndex = curIndex; - ++curIndex; - CaretAssertVectorIndex(m_rowInfo, ciftiIndices[myIndex]); - if (m_rowInfo[ciftiIndices[myIndex]].m_cacheIndex == -1) + m_inputCifti->getRow(preparedInput[i].data(), i); + adjustRow(preparedInput[i].data(), m_rowLengthFirst, m_firstCorrInfo[i], false, m_firstCovar, m_firstNoDemean);//also calculates rrs, needed for -no-demean-first in correlation mode + m_firstCorrInfo[i].m_cacheIndex = i; + } + } else { + preparedInput.resize(plan.m_chunkSize, vector(m_rowLengthFirst)); + } + vector scratchRow(m_rowLengthFirst); + for (int64_t chunkStart = 0; chunkStart < m_numCols; chunkStart += plan.m_chunkSize)//cache chunks are along the complete dimension + { + int64_t chunkEnd = min(m_numCols, chunkStart + plan.m_chunkSize); + if (!(plan.m_cacheFullInput)) + { + for (int64_t i = chunkStart; i < chunkEnd; ++i) { - if (m_cacheUsed >= (int)m_rowCache.size()) + m_inputCifti->getRow(preparedInput[i - chunkStart].data(), i); + adjustRow(preparedInput[i - chunkStart].data(), m_rowLengthFirst, m_firstCorrInfo[i], false, m_firstCovar, m_firstNoDemean); + m_firstCorrInfo[i].m_cacheIndex = i - chunkStart; + } + } + int64_t curIndex = 0;//force manual in-order +#pragma omp CARET_PARFOR schedule(dynamic) + for (int64_t i = 0; i < numIndices; ++i)//myIndex loops through the ciftiIndices array + { + float* movingData = NULL; + int64_t movingRow = -1, myIndex = -1; + bool doAdjust = false; +#pragma omp critical + { + myIndex = curIndex; + ++curIndex; + movingRow = ciftiIndices[myIndex]; + if (m_firstCorrInfo[movingRow].m_cacheIndex != -1) { - m_rowCache.push_back(CacheRow()); - m_rowCache[m_cacheUsed].m_row.resize(m_numCols); + movingData = preparedInput[m_firstCorrInfo[movingRow].m_cacheIndex].data(); + } else { + doAdjust = true; + movingData = scratchRow.data(); + m_inputCifti->getRow(movingData, movingRow); } - m_rowCache[m_cacheUsed].m_ciftiIndex = ciftiIndices[myIndex]; - myPtr = m_rowCache[m_cacheUsed].m_row.data(); - m_inputCifti->getRow(myPtr, ciftiIndices[myIndex]); - m_rowInfo[ciftiIndices[myIndex]].m_cacheIndex = m_cacheUsed; - ++m_cacheUsed; } - }//end critical, now compute while the next thread reads - if (myPtr != NULL) + if (doAdjust) + { + adjustRow(movingData, m_rowLengthFirst, m_firstCorrInfo[movingRow], false, m_firstCovar, m_firstNoDemean); + } + float movingRrs = m_firstCorrInfo[movingRow].m_rootResidSqr;//do not move this up, for some rows it is not computed until adjustRow + for (int64_t j = chunkStart; j < chunkEnd; ++j)//j loops through the complete dimension, in chunks + { + float* cacheData = preparedInput[j - chunkStart].data(); + float cacheRrs = m_firstCorrInfo[j].m_rootResidSqr; + if (m_rowInfo[j].m_cacheIndex == -1 || ciftiIndices[m_rowInfo[j].m_cacheIndex] >= movingRow)//if a symmetric output element exists in the rows to cache, don't do the correlation of the lower one + { + float corrval = correlate(movingData, movingRrs, cacheData, cacheRrs, m_rowLengthFirst, m_firstCovar, m_firstFisher); + m_rowCache[myIndex].m_row[j] = corrval; + if (m_rowInfo[j].m_cacheIndex != -1)//fill the symmetric part if it exists + { + m_rowCache[m_rowInfo[j].m_cacheIndex].m_row[movingRow] = corrval; + } + } + } + } + if (!(plan.m_cacheFullInput)) { - adjustRow(myPtr, ciftiIndices[myIndex]); + for (int64_t i = chunkStart; i < chunkEnd; ++i) + { + m_firstCorrInfo[i].m_cacheIndex = -1; + } } } +#pragma omp CARET_PARFOR schedule(dynamic) + for (int64_t i = 0; i < numIndices; ++i) + { + adjustRow(m_rowCache[i].m_row.data(), m_numCols, m_rowInfo[ciftiIndices[i]], m_undoFisherInput, m_covariance, false); + } + } else { + int64_t curIndex = 0; +#pragma omp CARET_PARFOR schedule(dynamic) + for (int64_t i = 0; i < numIndices; ++i) + { + float* myPtr = NULL; + int64_t myIndex = -1; +#pragma omp critical + {//manually in-order reading + myIndex = curIndex; + ++curIndex; + CaretAssertVectorIndex(m_rowInfo, ciftiIndices[myIndex]); + myPtr = m_rowCache[myIndex].m_row.data(); + m_inputCifti->getRow(myPtr, ciftiIndices[myIndex]); + m_rowCache[myIndex].m_ciftiIndex = ciftiIndices[myIndex]; + m_rowInfo[ciftiIndices[myIndex]].m_cacheIndex = myIndex; + }//end critical, now demean while the next thread reads + adjustRow(myPtr, m_numCols, m_rowInfo[ciftiIndices[myIndex]], m_undoFisherInput, m_covariance, false); + } } } void AlgorithmCiftiCorrelationGradient::clearCache() { - for (int i = 0; i < m_cacheUsed; ++i) + for (int64_t i = 0; i < int64_t(m_rowCache.size()); ++i) { m_rowInfo[m_rowCache[i].m_ciftiIndex].m_cacheIndex = -1; } - m_cacheUsed = 0; + m_rowCache.clear(); } -const float* AlgorithmCiftiCorrelationGradient::getRow(const int& ciftiIndex, float& rootResidSqr, const bool& mustBeCached) +const float* AlgorithmCiftiCorrelationGradient::getRow(const int& ciftiIndex, float& rootResidSqr, float* scratchStorage) { float* ret; CaretAssertVectorIndex(m_rowInfo, ciftiIndex); @@ -993,91 +1265,52 @@ const float* AlgorithmCiftiCorrelationGradient::getRow(const int& ciftiIndex, fl { ret = m_rowCache[m_rowInfo[ciftiIndex].m_cacheIndex].m_row.data(); } else { - CaretAssert(!mustBeCached); - if (mustBeCached)//largely so it doesn't give warning about unused when compiled in release - { - throw AlgorithmException("something very bad happened, notify the developers"); - } - ret = getTempRow(); - m_inputCifti->getRow(ret, ciftiIndex); - adjustRow(ret, ciftiIndex); - } - rootResidSqr = m_rowInfo[ciftiIndex].m_rootResidSqr; - return ret; -} - -void AlgorithmCiftiCorrelationGradient::adjustRow(float* rowOut, const int& ciftiIndex) -{ - if (m_undoFisherInput) - { - for (int i = 0; i < m_numCols; ++i) - { - double temp = exp(2 * rowOut[i]); - rowOut[i] = (float)((temp - 1)/(temp + 1)); - } - } - if (!m_rowInfo[ciftiIndex].m_haveCalculated) - { - double accum = 0.0;//double, for numerical stability - for (int i = 0; i < m_numCols; ++i)//two pass, for numerical stability - { - accum += rowOut[i]; - } - float mean = accum / m_numCols; - float rootResidSqr = 0.0f;//not used in covariance - if (!m_covariance) - { - accum = 0.0; - for (int i = 0; i < m_numCols; ++i) + ret = scratchStorage; + if (m_doubleCorr) + {//will only happen with a memory limit that prevents caching entire row range - may need a closer look + vector fixedRow(m_rowLengthFirst), movingRow(m_rowLengthFirst); + m_inputCifti->getRow(fixedRow.data(), ciftiIndex); + adjustRow(fixedRow.data(), m_rowLengthFirst, m_firstCorrInfo[ciftiIndex], false, m_firstCovar, m_firstNoDemean); + for (int64_t i = 0; i < m_numCols; ++i)//TODO: convert input to in-memory when possible { - float tempf = rowOut[i] - mean; - accum += tempf * tempf; + float* movingData = movingRow.data(); + if (i == ciftiIndex) + {//correlate has logic to give the right answer without doing the corr when the pointers are the same + movingData = fixedRow.data(); + } else { + m_inputCifti->getRow(movingRow.data(), i); + adjustRow(movingRow.data(), m_rowLengthFirst, m_firstCorrInfo[i], false, m_firstCovar, m_firstNoDemean); + } + ret[i] = correlate(fixedRow.data(), m_firstCorrInfo[ciftiIndex].m_rootResidSqr, movingData, m_firstCorrInfo[i].m_rootResidSqr, m_rowLengthFirst, m_firstCovar, m_firstFisher); } - rootResidSqr = sqrt(accum); + } else { + m_inputCifti->getRow(ret, ciftiIndex); } - m_rowInfo[ciftiIndex].m_mean = mean; - m_rowInfo[ciftiIndex].m_rootResidSqr = rootResidSqr; - m_rowInfo[ciftiIndex].m_haveCalculated = true; - } - float mean = m_rowInfo[ciftiIndex].m_mean; - for (int i = 0; i < m_numCols; ++i) - { - rowOut[i] -= mean; + adjustRow(ret, m_numCols, m_rowInfo[ciftiIndex], m_undoFisherInput, m_covariance, false); } + rootResidSqr = m_rowInfo[ciftiIndex].m_rootResidSqr; + return ret; } -float* AlgorithmCiftiCorrelationGradient::getTempRow() -{ -#ifdef CARET_OMP - int oldsize = (int)m_tempRows.size(); - int threadNum = omp_get_thread_num(); - if (threadNum >= oldsize) +int AlgorithmCiftiCorrelationGradient::numRowsForMem(const int64_t& inrowBytes, const int64_t& outrowBytes, const int& numRows, bool& cacheFullInputOut) +{//double corr might benefit from some reworking + if (m_memLimitGB < 0.0f) { - m_tempRows.resize(threadNum + 1); - for (int i = oldsize; i <= threadNum; ++i) - { - m_tempRows[i] = CaretArray(m_numCols); - } + cacheFullInputOut = true; + return numRows; } - return m_tempRows[threadNum].getArray(); -#else - if (m_tempRows.size() == 0) + int64_t targetBytes = (int64_t)(m_memLimitGB * 1024 * 1024 * 1024); + int64_t inputFileSize = sizeof(float) * m_inputCifti->getNumberOfColumns() * m_inputCifti->getNumberOfRows(); + bool inputIsMemory = m_inputCifti->isInMemory();//TODO: if in memory, we don't really need to cache input rows as much... + if (inputIsMemory) { - m_tempRows.resize(1); - m_tempRows[0] = CaretArray(m_numCols); + targetBytes -= inputFileSize;//count in-memory input against the total too } - return m_tempRows[0].getArray(); -#endif -} - -int AlgorithmCiftiCorrelationGradient::numRowsForMem(const float& memLimitGB, const int64_t& inrowBytes, const int64_t& outrowBytes, const int& numRows, bool& cacheFullInput) -{ - int64_t targetBytes = (int64_t)(memLimitGB * 1024 * 1024 * 1024); - if (m_inputCifti->isInMemory()) targetBytes -= numRows * inrowBytes;//count in-memory input against the total too targetBytes -= numRows * sizeof(RowInfo) + 2 * outrowBytes;//storage for mean, stdev, and info about caching, output structures if (targetBytes < 1) { - cacheFullInput = false;//the most memory conservation possible, though it will take a LOT of time and do a LOT of IO + if (!inputIsMemory) CaretLogWarning("extremely low memory limit used, this may take a long time and do a lot of IO"); + cacheFullInputOut = false;//the most memory conservation possible return 1; } if (inrowBytes * numRows < targetBytes)//if we can cache the full input, compute the number of passes needed and compare @@ -1102,19 +1335,36 @@ int AlgorithmCiftiCorrelationGradient::numRowsForMem(const float& memLimitGB, co fullPasses = numPassesPartial - 1; int64_t partialCorrSkip = (fullPasses * numRowsPartial * (numRowsPartial - 1) + (numRows - fullPasses * numRowsPartial) * (numRows - fullPasses * numRowsPartial - 1)) / 2; int ret; - if (partialCorrSkip > fullCorrSkip * 1.05f)//prefer full caching slightly - include a bias factor in options? + if (!m_doubleCorr && partialCorrSkip > fullCorrSkip * 1.05f)//prefer full caching slightly - always cache full if possible when doing double corr, recomputation is much more expensive than rereading {//assume IO and row adjustment (unfisher, subtract mean) won't be the limiting factor, since IO should be balanced during correlation due to evenly sized passes when not fully cached - cacheFullInput = false; + cacheFullInputOut = false; ret = numRowsPartial; } else { - cacheFullInput = true; + cacheFullInputOut = true; ret = numRowsFull; } if (ret < 1) ret = 1;//sanitize, just in case if (ret > numRows) ret = numRows; return ret; } else {//if we can't cache the whole thing, split passes evenly - cacheFullInput = false; + if (m_doubleCorr) + { + if (!inputIsMemory) + {//getting a correlation row outside of the cached range will cause a huge IO increase, so convert input to memory if at all possible + if (inputFileSize < targetBytes - (inrowBytes + outrowBytes) * sqrt(numRows))//TODO: consider edge cases + { + m_inputCifti->convertToInMemory(); + inputIsMemory = true; + } else { + if (!firstCorrWarned) + { + CaretLogWarning("double correlation specified with low memory limit, this may take an extremely long time and do a lot of IO"); + firstCorrWarned = true; + } + } + } + } + cacheFullInputOut = false; int64_t div = max((int64_t)1, (outrowBytes + inrowBytes) * numRows); #ifdef CARET_OMP targetBytes -= inrowBytes * omp_get_max_threads(); diff --git a/src/Algorithms/AlgorithmCiftiCorrelationGradient.h b/src/Algorithms/AlgorithmCiftiCorrelationGradient.h index 25b90dd123bf7fbfafa0efecdc40f6f30e6adae1..be7a80ef7565cbb003b24d173bba2c549fa7e997 100644 --- a/src/Algorithms/AlgorithmCiftiCorrelationGradient.h +++ b/src/Algorithms/AlgorithmCiftiCorrelationGradient.h @@ -22,7 +22,6 @@ /*LICENSE_END*/ #include "AbstractAlgorithm.h" -#include "CaretPointer.h" #include "StructureEnum.h" namespace caret { @@ -30,11 +29,7 @@ namespace caret { class AlgorithmCiftiCorrelationGradient : public AbstractAlgorithm { AlgorithmCiftiCorrelationGradient(); - struct CacheRow - { - int m_ciftiIndex; - std::vector m_row; - }; + public: struct RowInfo { bool m_haveCalculated; @@ -46,22 +41,32 @@ namespace caret { m_cacheIndex = -1; } }; + private: + struct CacheRow + { + int m_ciftiIndex; + std::vector m_row; + CacheRow(int64_t rowLength) + { + m_ciftiIndex = -1; + m_row.resize(rowLength); + } + }; std::vector m_rowCache; - std::vector m_rowInfo; - std::vector > m_tempRows;//reuse return values in getRow instead of reallocating + std::vector m_rowInfo, m_firstCorrInfo; std::vector m_outColumn; - int m_cacheUsed;//reuse cache entries instead of reallocating them - int m_numCols; + int64_t m_numCols; bool m_undoFisherInput, m_applyFisher, m_covariance; - const CiftiFile* m_inputCifti;//so that accesses work through the cache functions - void cacheRows(const std::vector& ciftiIndices);//grabs the rows and does whatever it needs to, using as much IO bandwidth and CPU resources as available/needed + CiftiFile* m_inputCifti; + int64_t m_rowLengthFirst;//for -double-correlation + bool m_doubleCorr, m_firstCovar, m_firstNoDemean, m_firstFisher; + float m_memLimitGB; + void cacheRows(const std::vector& ciftiIndices, const int64_t mapSize);//grabs the rows and does whatever it needs to, using as much IO bandwidth and CPU resources as available/needed void clearCache(); - const float* getRow(const int& ciftiIndex, float& rootResidSqr, const bool& mustBeCached = false); - void adjustRow(float* rowOut, const int& ciftiIndex);//does the reverse fisher transform, computes stuff, subtracts mean - float* getTempRow(); - float correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2); - void init(const CiftiFile* input, const bool& undoFisherInput, const bool& applyFisher, const bool& covariance); - int numRowsForMem(const float& memLimitGB, const int64_t& inrowBytes, const int64_t& outrowBytes, const int& numRows, bool& cacheFullInput); + const float* getRow(const int& ciftiIndex, float& rootResidSqr, float* scratchStorage); + void init(CiftiFile* input, const float& memLimitGB, const bool& undoFisherInput, const bool& applyFisher, const bool& covariance, + const bool doubleCorr, const bool firstFisher, const bool firstNoDemean, const bool firstCovar); + int numRowsForMem(const int64_t& inrowBytes, const int64_t& outrowBytes, const int& numRows, bool& cacheFullInput); //void processSurfaceComponentLocal(StructureEnum::Enum& myStructure, const float& surfKern, const float& memLimitGB, SurfaceFile* mySurf); void processSurfaceComponent(StructureEnum::Enum& myStructure, const float& surfKern, const float& memLimitGB, SurfaceFile* mySurf, const MetricFile* myAreas); void processSurfaceComponent(StructureEnum::Enum& myStructure, const float& surfKern, const float& surfExclude, const float& memLimitGB, SurfaceFile* mySurf, const MetricFile* myAreas); @@ -72,13 +77,14 @@ namespace caret { static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: - AlgorithmCiftiCorrelationGradient(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, + AlgorithmCiftiCorrelationGradient(ProgressObject* myProgObj, CiftiFile* myCifti, CiftiFile* myCiftiOut, SurfaceFile* myLeftSurf = NULL, SurfaceFile* myRightSurf = NULL, SurfaceFile* myCerebSurf = NULL, const MetricFile* myLeftAreas = NULL, const MetricFile* myRightAreas = NULL, const MetricFile* myCerebAreas = NULL, const float& surfKern = -1.0f, const float& volKern = -1.0f, const bool& undoFisherInput = false, const bool& applyFisher = false, const float& surfaceExclude = -1.0f, const float& volumeExclude = -1.0f, const bool& covariance = false, - const float& memLimitGB = -1.0f); + const float& memLimitGB = -1.0f, + const bool doubleCorr = false, const bool firstFisher = false, const bool firstNoDemean = false, const bool firstCovar = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmCiftiCreateDenseScalar.cxx b/src/Algorithms/AlgorithmCiftiCreateDenseScalar.cxx index 44ae4aedf01cc2eb25722379b9d1b5fcd7b15ea4..da037df2ce505ef2b5cf076d89341826fbf5ea24 100644 --- a/src/Algorithms/AlgorithmCiftiCreateDenseScalar.cxx +++ b/src/Algorithms/AlgorithmCiftiCreateDenseScalar.cxx @@ -63,7 +63,7 @@ OperationParameters* AlgorithmCiftiCreateDenseScalar::getParameters() OptionalParameter* leftRoiOpt = leftMetricOpt->createOptionalParameter(2, "-roi-left", "roi of vertices to use from left surface"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); - OptionalParameter* rightMetricOpt = ret->createOptionalParameter(4, "-right-metric", "metric for left surface"); + OptionalParameter* rightMetricOpt = ret->createOptionalParameter(4, "-right-metric", "metric for right surface"); rightMetricOpt->addMetricParameter(1, "metric", "the metric file"); OptionalParameter* rightRoiOpt = rightMetricOpt->createOptionalParameter(2, "-roi-right", "roi of vertices to use from right surface"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); diff --git a/src/Algorithms/AlgorithmCiftiDilate.cxx b/src/Algorithms/AlgorithmCiftiDilate.cxx index 55e360542b117661a099bec0bac0a7904300dbbe..b90be480f96ee20729ddf5137180441f3d703c73 100644 --- a/src/Algorithms/AlgorithmCiftiDilate.cxx +++ b/src/Algorithms/AlgorithmCiftiDilate.cxx @@ -80,6 +80,8 @@ OperationParameters* AlgorithmCiftiDilate::getParameters() ret->createOptionalParameter(11, "-merged-volume", "treat volume components as if they were a single component"); + ret->createOptionalParameter(12, "-legacy-mode", "use the math from v1.3.2 and earlier for weighted dilation"); + ret->setHelpText( AString("For all data values designated as bad, if they neighbor a good value or are within the specified distance of a good value in the same kind of model, ") + "replace the value with a distance weighted average of nearby good values, otherwise set the value to zero. " + @@ -149,13 +151,14 @@ void AlgorithmCiftiDilate::useParameters(OperationParameters* myParams, Progress } bool nearest = myParams->getOptionalParameter(10)->m_present; bool mergedVolume = myParams->getOptionalParameter(11)->m_present; - AlgorithmCiftiDilate(myProgObj, myCifti, myDir, surfDist, volDist, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, myLeftAreas, myRightAreas, myCerebAreas, myRoi, nearest, mergedVolume); + bool legacyMode = myParams->getOptionalParameter(12)->m_present; + AlgorithmCiftiDilate(myProgObj, myCifti, myDir, surfDist, volDist, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, myLeftAreas, myRightAreas, myCerebAreas, myRoi, nearest, mergedVolume, legacyMode); } AlgorithmCiftiDilate::AlgorithmCiftiDilate(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const float& surfDist, const float& volDist, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const SurfaceFile* myRightSurf, const SurfaceFile* myCerebSurf, const MetricFile* myLeftAreas, const MetricFile* myRightAreas, const MetricFile* myCerebAreas, - const CiftiFile* myBadRoi, const bool& nearest, const bool& mergedVolume) : AbstractAlgorithm(myProgObj) + const CiftiFile* myBadRoi, const bool& nearest, const bool& mergedVolume, const bool legacyMode) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CiftiXMLOld myXML = myCifti->getCiftiXMLOld(); @@ -166,6 +169,12 @@ AlgorithmCiftiDilate::AlgorithmCiftiDilate(ProgressObject* myProgObj, const Cift { throw AlgorithmException("specified direction does not contain brainordinates"); } + float volExponent = 7.0f, surfExponent = 6.0f; + if (legacyMode) + { + volExponent = 2.0f; + surfExponent = 2.0f; + } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; @@ -245,7 +254,7 @@ AlgorithmCiftiDilate::AlgorithmCiftiDilate(ProgressObject* myProgObj, const Cift AlgorithmMetricDilate::Method myMethod = AlgorithmMetricDilate::WEIGHTED; if (nearest) myMethod = AlgorithmMetricDilate::NEAREST; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &dataRoiMetric); - AlgorithmMetricDilate(NULL, &myMetric, mySurf, surfDist, &myMetricOut, badRoiPtr, &dataRoiMetric, -1, myMethod, 2.0f, myCorrAreas); + AlgorithmMetricDilate(NULL, &myMetric, mySurf, surfDist, &myMetricOut, badRoiPtr, &dataRoiMetric, -1, myMethod, surfExponent, myCorrAreas, legacyMode); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myMetricOut); } } @@ -253,8 +262,9 @@ AlgorithmCiftiDilate::AlgorithmCiftiDilate(ProgressObject* myProgObj, const Cift { if (myXML.hasVolumeData(myDir)) { - VolumeFile myVol, roiVol, myVolOut; - VolumeFile* roiPtr = NULL; + VolumeFile myVol, roiVol, myVolOut, dataRoi, junkVol; + VolumeFile* roiPtr = NULL, *dataRoiPtr = &dataRoi; + if (legacyMode) dataRoiPtr = NULL; int64_t offset[3]; AlgorithmVolumeDilate::Method myMethod = AlgorithmVolumeDilate::WEIGHTED; if (nearest) @@ -266,8 +276,8 @@ AlgorithmCiftiDilate::AlgorithmCiftiDilate(ProgressObject* myProgObj, const Cift AlgorithmCiftiSeparate(NULL, myBadRoi, CiftiXMLOld::ALONG_COLUMN, &roiVol, offset, NULL, true); roiPtr = &roiVol; } - AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, offset, NULL, true); - AlgorithmVolumeDilate(NULL, &myVol, volDist, myMethod, &myVolOut, roiPtr); + AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, offset, &dataRoi, true); + AlgorithmVolumeDilate(NULL, &myVol, volDist, myMethod, &myVolOut, roiPtr, dataRoiPtr, -1, volExponent, legacyMode); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, &myVolOut, true); } } else { diff --git a/src/Algorithms/AlgorithmCiftiDilate.h b/src/Algorithms/AlgorithmCiftiDilate.h index ecd21fd6bbc79d1fa90e0be46e92a8329146cd19..2414c63ad341a2cf863c73fad3c6bf129a23947b 100644 --- a/src/Algorithms/AlgorithmCiftiDilate.h +++ b/src/Algorithms/AlgorithmCiftiDilate.h @@ -35,7 +35,7 @@ namespace caret { AlgorithmCiftiDilate(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const float& surfDist, const float& volDist, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf = NULL, const SurfaceFile* myRightSurf = NULL, const SurfaceFile* myCerebSurf = NULL, const MetricFile* myLeftAreas = NULL, const MetricFile* myRightAreas = NULL, const MetricFile* myCerebAreas = NULL, - const CiftiFile* myRoi = NULL, const bool& nearest = false, const bool& mergedVolume = false); + const CiftiFile* myRoi = NULL, const bool& nearest = false, const bool& mergedVolume = false, const bool legacyMode = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmCiftiFindClusters.cxx b/src/Algorithms/AlgorithmCiftiFindClusters.cxx index d06844ca34f12a24a21be436da6472dda91d06ff..6ffb49c52da7a30a5bff96edcedcbe14518c8862 100644 --- a/src/Algorithms/AlgorithmCiftiFindClusters.cxx +++ b/src/Algorithms/AlgorithmCiftiFindClusters.cxx @@ -90,6 +90,7 @@ OperationParameters* AlgorithmCiftiFindClusters::getParameters() ret->setHelpText( AString("Outputs a cifti file with nonzero integers for all brainordinates within a large enough cluster, and zeros elsewhere. ") + "The integers denote cluster membership (by default, first cluster found will use value 1, second cluster 2, etc). " + + "Cluster values are not reused across maps of the output, but instead keep counting up. " + "The input cifti file must have a brain models mapping on the chosen dimension, columns for .dtseries, and either for .dconn. " + "The ROI should have a brain models mapping along columns, exactly matching the mapping of the chosen direction in the input file. " + "Data outside the ROI is ignored." diff --git a/src/Algorithms/AlgorithmCiftiLabelModifyKeys.cxx b/src/Algorithms/AlgorithmCiftiLabelModifyKeys.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1729cb7b86907c5e390c8f427c333dc9a8ddf161 --- /dev/null +++ b/src/Algorithms/AlgorithmCiftiLabelModifyKeys.cxx @@ -0,0 +1,221 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AlgorithmCiftiLabelModifyKeys.h" +#include "AlgorithmException.h" + +#include "CiftiFile.h" +#include "FileInformation.h" +#include "GiftiLabel.h" + +#include +#include +#include + +using namespace caret; +using namespace std; + +AString AlgorithmCiftiLabelModifyKeys::getCommandSwitch() +{ + return "-cifti-label-modify-keys"; +} + +AString AlgorithmCiftiLabelModifyKeys::getShortDescription() +{ + return "CHANGE KEY VALUES IN A DLABEL FILE"; +} + +OperationParameters* AlgorithmCiftiLabelModifyKeys::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + ret->addCiftiParameter(1, "cifti-in", "the input dlabel file"); + ret->addStringParameter(2, "remap-file", "text file with old and new key values"); + ret->addCiftiOutputParameter(3, "cifti-out", "the output dlabel file"); + + OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "select a single column to use"); + columnOpt->addStringParameter(1, "column", "the column number or name"); + + ret->setHelpText( + AString(" should have lines of the form 'oldkey newkey', like so:\n\n") + + "3 5\n5 8\n8 2\n\n" + + "This would change the current label with key '3' to use the key '5' instead, 5 would use 8, and 8 would use 2. " + + "Any collision in key values results in the label that was not specified in the remap file getting remapped to an otherwise unused key. " + + "Remapping more than one key to the same new key, or the same key to more than one new key, results in an error. " + + "This will not change the appearance of the file when displayed, as it will change the key values in the data at the same time." + ); + return ret; +} + +void AlgorithmCiftiLabelModifyKeys::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) +{ + CiftiFile* ciftiIn = myParams->getCifti(1); + AString remapName = myParams->getString(2); + CiftiFile* ciftiOut = myParams->getOutputCifti(3); + int column = -1; + OptionalParameter* columnOpt = myParams->getOptionalParameter(4); + if (columnOpt->m_present) + { + column = ciftiIn->getCiftiXML().getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(columnOpt->getString(1)); + if (column < 0) throw AlgorithmException("invalid column specified"); + } + FileInformation textFileInfo(remapName); + if (!textFileInfo.exists()) + { + throw AlgorithmException("label list file doesn't exist"); + } + fstream remapFile(remapName.toLocal8Bit().constData(), fstream::in); + if (!remapFile.good()) + { + throw AlgorithmException("error reading label list file"); + } + map remap; + int32_t oldkey, newkey; + while (remapFile >> oldkey >> newkey) + { + if (remap.find(oldkey) != remap.end()) throw AlgorithmException("remapping tried to duplicate label " + AString::number(oldkey)); + remap[oldkey] = newkey; + } + AlgorithmCiftiLabelModifyKeys(myProgObj, ciftiIn, remap, ciftiOut, column); +} + +AlgorithmCiftiLabelModifyKeys::AlgorithmCiftiLabelModifyKeys(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const map remap, CiftiFile* ciftiOut, const int column) : AbstractAlgorithm(myProgObj) +{ + LevelProgress myProgress(myProgObj); + const CiftiXML& xmlIn = ciftiIn->getCiftiXML(); + if (xmlIn.getNumberOfDimensions() != 2) throw AlgorithmException("cifti label modify keys only supports 2D cifti"); + if (xmlIn.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) throw AlgorithmException("input cifti file does not have labels mapping along row"); + const CiftiLabelsMap& oldmap = xmlIn.getLabelsMap(CiftiXML::ALONG_ROW); + int64_t numRows = ciftiIn->getNumberOfRows(); + int64_t startCol = 0, endCol = ciftiIn->getNumberOfColumns(); + if (column > -1) + { + startCol = column; + endCol = column + 1; + } + CiftiLabelsMap newmap; + newmap.setLength(endCol - startCol); + vector> valChanges(endCol - startCol); + for (int64_t i = startCol; i < endCol; ++i) + { + newmap.setMapName(i - startCol, oldmap.getMapName(i)); + const GiftiLabelTable* oldTable = oldmap.getMapLabelTable(i); + int32_t oldUnlabeled = oldTable->getUnassignedLabelKey();//because GiftiLabelTable is quirky, we need to check if the unlabeled value ends up as something other than 0 + GiftiLabelTable newTable;//careful, label 0 is created by the constructor + bool setZero = false;//because of this, we need to track if we overwrote it, so that we can pretend it isn't there + for (map::const_iterator iter = remap.begin(); iter != remap.end(); ++iter) + { + const GiftiLabel* oldLabel = oldTable->getLabel(iter->first); + if (oldLabel == NULL) throw AlgorithmException("label key " + AString::number(iter->first) + " does not exist in the input file"); + GiftiLabel newLabel(*oldLabel); + newLabel.setKey(iter->second); + if (iter->first == oldUnlabeled) + { + if (iter->second != 0)//if it isn't the default unlabeled value, then we have to do something + { + if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + newTable.deleteLabel(0);//delete the default, since we don't know what overwrites it, if anything + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) + } else {//otherwise, just error checking + if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + setZero = true;//we do have to track that zero now contains something that can't be overwritten + } + } else { + if (iter->second == 0)//if it remaps to the default unlabeled key, we have to check it differently + { + if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + setZero = true; + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, so it will overwrite the existing default 0 key + } else {//finally, the simple case + if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) + } + } + } + set keys = oldTable->getKeys(), collisions; + for (set::const_iterator iter = keys.begin(); iter != keys.end(); ++iter) + { + if (remap.find(*iter) == remap.end())//skip if it was remapped + { + if (*iter == 0)//again with the special default 0 key + { + if (setZero)//check for collision + { + collisions.insert(*iter); + } else { + setZero = true; + if (*iter != oldUnlabeled)//if its merely the unassigned label already, we can just keep the existing default + { + newTable.insertLabel(oldTable->getLabel(*iter)); + } + } + } else { + if (newTable.getLabel(*iter) == NULL) + { + newTable.insertLabel(oldTable->getLabel(*iter)); + } else {//collision + collisions.insert(*iter); + } + } + } + } + map& valueChanges = valChanges[i - startCol]; + valueChanges = remap;//start with the specified changes, then add the collision changes + for (set::const_iterator iter = collisions.begin(); iter != collisions.end(); ++iter) + {//now deal with collisions + int32_t newKey = newTable.generateUnusedKey(); + GiftiLabel newLabel(*(oldTable->getLabel(*iter))); + newLabel.setKey(newKey); + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) + valueChanges[*iter] = newKey; + } + *(newmap.getMapLabelTable(i - startCol)) = newTable; + } + CiftiXML xmlOut = xmlIn; + xmlOut.setMap(CiftiXML::ALONG_ROW, newmap); + ciftiOut->setCiftiXML(xmlOut); + vector scratchRow(ciftiIn->getNumberOfColumns()), outRow(endCol - startCol); + for (int i = 0; i < numRows; ++i) + { + ciftiIn->getRow(scratchRow.data(), i); + for (int j = startCol; j < endCol; ++j) + { + int32_t oldkey = floor(scratchRow[j] + 0.5f); + auto iter = valChanges[j - startCol].find(oldkey); + if (iter == valChanges[j - startCol].end()) + { + outRow[j - startCol] = oldkey; + } else { + outRow[j - startCol] = iter->second; + } + } + ciftiOut->setRow(outRow.data(), i); + } +} + +float AlgorithmCiftiLabelModifyKeys::getAlgorithmInternalWeight() +{ + return 1.0f;//override this if needed, if the progress bar isn't smooth +} + +float AlgorithmCiftiLabelModifyKeys::getSubAlgorithmWeight() +{ + //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm + return 0.0f; +} diff --git a/src/Algorithms/AlgorithmCiftiLabelModifyKeys.h b/src/Algorithms/AlgorithmCiftiLabelModifyKeys.h new file mode 100644 index 0000000000000000000000000000000000000000..96b70737fb5e3b2a61a641ddabeeaf0283089684 --- /dev/null +++ b/src/Algorithms/AlgorithmCiftiLabelModifyKeys.h @@ -0,0 +1,48 @@ +#ifndef __ALGORITHM_CIFTI_LABEL_MODIFY_KEYS_H__ +#define __ALGORITHM_CIFTI_LABEL_MODIFY_KEYS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AbstractAlgorithm.h" + +#include + +namespace caret { + + class AlgorithmCiftiLabelModifyKeys : public AbstractAlgorithm + { + AlgorithmCiftiLabelModifyKeys(); + protected: + static float getSubAlgorithmWeight(); + static float getAlgorithmInternalWeight(); + public: + AlgorithmCiftiLabelModifyKeys(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const std::map remap, CiftiFile* ciftiOut, const int column = -1); + static OperationParameters* getParameters(); + static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); + static AString getCommandSwitch(); + static AString getShortDescription(); + }; + + typedef TemplateAutoOperation AutoAlgorithmCiftiLabelModifyKeys; + +} + +#endif //__ALGORITHM_CIFTI_LABEL_MODIFY_KEYS_H__ diff --git a/src/Algorithms/AlgorithmCiftiParcellate.cxx b/src/Algorithms/AlgorithmCiftiParcellate.cxx index 66c2eedfe73fcb98b1ab69d5cd4d5c050c004295..82b2bfdb818fc9a9222ba00ddddd11d37d56276f 100644 --- a/src/Algorithms/AlgorithmCiftiParcellate.cxx +++ b/src/Algorithms/AlgorithmCiftiParcellate.cxx @@ -82,21 +82,24 @@ OperationParameters* AlgorithmCiftiParcellate::getParameters() ret->createOptionalParameter(9, "-only-numeric", "exclude non-numeric values"); - OptionalParameter* emptyOpt = ret->createOptionalParameter(10, "-include-empty", "create parcels for labels that have no vertices or voxels"); - OptionalParameter* emptyValOpt = emptyOpt->createOptionalParameter(1, "-fill-value", "specify value to use in empty parcels (default 0)"); + OptionalParameter* emptyValOpt = ret->createOptionalParameter(11, "-fill-value", "specify value to use in empty parcels (default 0)"); emptyValOpt->addDoubleParameter(1, "value", "the value to fill empty parcels with"); - OptionalParameter* emptyRoiOpt = emptyOpt->createOptionalParameter(2, "-nonempty-mask-out", "output a matching pscalar file that has 0s in empty parcels, and 1s elsewhere"); + OptionalParameter* emptyRoiOpt = ret->createOptionalParameter(12, "-nonempty-mask-out", "output a matching pscalar file that has 0s in empty parcels, and 1s elsewhere"); emptyRoiOpt->addCiftiOutputParameter(1, "mask-out", "the output mask file"); + ret->createOptionalParameter(13, "-legacy-mode", "use the old behavior, parcels are defined by the intersection between labels and valid data, and empty parcels are discarded"); + + ret->createOptionalParameter(10, "-include-empty", "deprecated: now the default behavior"); + ret->setHelpText( - AString("Each non-empty label (other than the unlabeled key) in the cifti label file will be treated as a parcel, and all rows or columns within the parcel are averaged together to form the output ") + - "row or column. " + - "If -include-empty is specified, empty labels will be treated as parcels with no elements, and filled with a constant value. " + + AString("Each label (other than the unlabeled key) in the cifti label file will be treated as a parcel, and all rows or columns of data within the parcel ") + + "are averaged together to form the parcel's output row or column. " + + "If -legacy-mode is specified, parcels will be defined as the overlap between a label and the data, with no errors for missing data vertices or voxels, and empty parcels discarded. " + CiftiXML::directionFromStringExplanation() + " " + "For dtseries or dscalar, use COLUMN. " + "If you are parcellating a dconn in both directions, parcellating by ROW first will use much less memory.\n\n" + "The parameter to the -method option must be one of the following:\n\n" + ReductionOperation::getHelpInfo() + - "\nThe -*-weights options are mutually exclusive and may only be used with MEAN, SUM, STDEV, SAMPSTDEV, VARIANCE, MEDIAN, or MODE." + "\nThe -*-weights options are mutually exclusive and may only be used with MEAN (default), SUM, STDEV, SAMPSTDEV, VARIANCE, MEDIAN, or MODE (default for label data)." ); return ret; } @@ -138,23 +141,20 @@ void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, Prog excludeHigh = (float)excludeOpt->getDouble(2); if (!(excludeLow > 0.0f && excludeHigh > 0.0f)) throw AlgorithmException("exclusion sigmas must be positive"); } - OptionalParameter* emptyOpt = myParams->getOptionalParameter(10); - bool includeEmpty = emptyOpt->m_present; + /*OptionalParameter* emptyOpt = */myParams->getOptionalParameter(10);//deprecated, but we need to "get" it to avoid a debug warning of an ignored option float emptyFillValue = 0.0f; + OptionalParameter* emptyValOpt = myParams->getOptionalParameter(11); + if (emptyValOpt->m_present) + { + emptyFillValue = emptyValOpt->getDouble(1); + } CiftiFile* emptyMaskOut = NULL; - if (includeEmpty) + OptionalParameter* emptyRoiOpt = myParams->getOptionalParameter(12); + if (emptyRoiOpt->m_present) { - OptionalParameter* emptyValOpt = emptyOpt->getOptionalParameter(1); - if (emptyValOpt->m_present) - { - emptyFillValue = emptyValOpt->getDouble(1); - } - OptionalParameter* emptyRoiOpt = emptyOpt->getOptionalParameter(2); - if (emptyRoiOpt->m_present) - { - emptyMaskOut = emptyRoiOpt->getOutputCifti(1); - } + emptyMaskOut = emptyRoiOpt->getOutputCifti(1); } + bool legacyMode = myParams->getOptionalParameter(13)->m_present; OptionalParameter* spatialWeightOpt = myParams->getOptionalParameter(5); OptionalParameter* ciftiWeightOpt = myParams->getOptionalParameter(6); if (spatialWeightOpt->m_present && ciftiWeightOpt->m_present) @@ -221,7 +221,7 @@ void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, Prog AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, leftWeights, rightWeights, cerebWeights, method, excludeLow, excludeHigh, onlyNumeric, - includeEmpty, emptyFillValue, emptyMaskOut); + legacyMode, emptyFillValue, emptyMaskOut); return; } if (ciftiWeightOpt->m_present) @@ -229,17 +229,17 @@ void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, Prog AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, ciftiWeightOpt->getCifti(1), method, excludeLow, excludeHigh, onlyNumeric, - includeEmpty, emptyFillValue, emptyMaskOut); + legacyMode, emptyFillValue, emptyMaskOut); return; } AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, method, excludeLow, excludeHigh, onlyNumeric, - includeEmpty, emptyFillValue, emptyMaskOut); + legacyMode, emptyFillValue, emptyMaskOut); } AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, - const bool& includeEmpty, const float& emptyFillVal, CiftiFile* emptyMaskOut) : AbstractAlgorithm(myProgObj) + const bool& legacyMode, const float& emptyFillVal, CiftiFile* emptyMaskOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); @@ -268,7 +268,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co } vector indexToParcel; CiftiXML myOutXML = myInputXML; - CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, includeEmpty); + CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, legacyMode); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { @@ -677,7 +677,7 @@ namespace AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const MetricFile* leftWeights, const MetricFile* rightWeights, const MetricFile* cerebWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, - const bool& includeEmpty, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) + const bool& legacyMode, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); @@ -735,7 +735,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co } vector indexToParcel; CiftiXML myOutXML = myInputXML; - CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, includeEmpty); + CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, legacyMode); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { @@ -778,7 +778,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const CiftiFile* ciftiWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, - const bool& includeEmpty, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) + const bool& legacyMode, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); @@ -803,20 +803,32 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co } const CiftiBrainModelsMap& inputDense = myInputXML.getBrainModelsMap(direction); const CiftiBrainModelsMap& labelDense = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); - if (!weightsXML.getMap(CiftiXML::ALONG_COLUMN)->approximateMatch(inputDense)) + const CiftiBrainModelsMap& weightsDense = weightsXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); + vector surfModels = labelDense.getSurfaceStructureList(); + for (int i = 0; i < int(surfModels.size()); ++i) { - throw AlgorithmException("cifti weight file does not match brain models mapping of input file"); + if (weightsDense.hasSurfaceData(surfModels[i])) + { + if (labelDense.getSurfaceNumberOfNodes(surfModels[i]) != weightsDense.getSurfaceNumberOfNodes(surfModels[i])) + { + throw AlgorithmException("cifti weight file has wrong number of vertices for surface structure " + StructureEnum::toName(surfModels[i])); + } + } } - if (inputDense.hasVolumeData()) + if (labelDense.hasVolumeData()) {//don't check volume space if direction doesn't have volume data - if (labelDense.hasVolumeData() && !inputDense.getVolumeSpace().matches(labelDense.getVolumeSpace())) + if (inputDense.hasVolumeData() && !labelDense.getVolumeSpace().matches(inputDense.getVolumeSpace())) { - throw AlgorithmException("input cifti files must have the same volume space"); + throw AlgorithmException("input cifti file has a different volume space"); + } + if (weightsDense.hasVolumeData() && !labelDense.getVolumeSpace().matches(weightsDense.getVolumeSpace())) + { + throw AlgorithmException("cifti weight file has a different volume space"); } } vector indexToParcel; CiftiXML myOutXML = myInputXML; - CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, includeEmpty); + CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, legacyMode); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { @@ -832,13 +844,28 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co int parcel = indexToParcel[j]; if (parcel != -1) { - parcelWeights[parcel].push_back(weightCol[j]);//we already tested that the dense mappings matched + int weightIndex = -1; + CiftiBrainModelsMap::IndexInfo myInfo = inputDense.getInfoForIndex(j); + switch (myInfo.m_type) + { + case CiftiBrainModelsMap::SURFACE: + weightIndex = weightsDense.getIndexForNode(myInfo.m_surfaceNode, myInfo.m_structure); + break; + case CiftiBrainModelsMap::VOXELS: + weightIndex = weightsDense.getIndexForVoxel(myInfo.m_ijk); + break; + } + if (weightIndex < 0) + { + throw AlgorithmException("cifti weights file does not contain all necessary vertices and voxels"); + } + parcelWeights[parcel].push_back(weightCol[weightIndex]); } } doWeightedParcellation(myCiftiIn, direction, myCiftiOut, indexToParcel, parcelWeights, method, excludeLow, excludeHigh, onlyNumeric, emptyFillVal, emptyMaskOut); } -CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, vector& indexToParcelOut, const bool& includeEmpty) +CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, vector& indexToParcelOut, const bool& legacyMode) { const CiftiXML& myLabelXML = myCiftiLabel->getCiftiXML(); if (myLabelXML.getNumberOfDimensions() != 2 || @@ -850,11 +877,11 @@ CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myC const CiftiLabelsMap& myLabelsMap = myLabelXML.getLabelsMap(CiftiXML::ALONG_ROW); const CiftiBrainModelsMap& labelDenseMap = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); CiftiParcelsMap ret; - if (toParcellate.hasVolumeData() && labelDenseMap.hasVolumeData()) - { + if (labelDenseMap.hasVolumeData() && toParcellate.hasVolumeData()) + {//if only one has voxel data, don't error until we know it is used if(!toParcellate.getVolumeSpace().matches(labelDenseMap.getVolumeSpace())) { - throw AlgorithmException("AlgorithmCiftiParcellate::parcellateMapping requires matching volume space between dlabel and dense mapping to parcellate"); + throw AlgorithmException("data file to parcellate has a different voxel space than the dlabel file"); } ret.setVolumeSpace(toParcellate.getVolumeSpace()); } @@ -864,9 +891,8 @@ CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myC myCiftiLabel->getColumn(labelData.data(), 0); indexToParcelOut.clear(); indexToParcelOut.resize(toParcellate.getLength(), -1); - vector surfList = toParcellate.getSurfaceStructureList(); - if (includeEmpty) - {//if we include empty, then the dlabel file by itself determines the entire parcel map, ignoring the data map + if (!legacyMode) + {//by default, the parcel definitions are based only on the dlabel file const vector labelSurfList = labelDenseMap.getSurfaceStructureList(); const set allLabelKeys = myLabelTable->getKeys(); map keyToParcel; @@ -885,11 +911,11 @@ CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myC for (int i = 0; i < (int)labelSurfList.size(); ++i) { StructureEnum::Enum myStruct = labelSurfList[i]; - if (labelDenseMap.hasSurfaceData(myStruct) && toParcellate.hasSurfaceData(myStruct)) - {//if they don't match in vertex count but one is empty, don't error? + if (toParcellate.hasSurfaceData(myStruct)) + {//if a surface is missing from the data, don't error until we know it is used by the parcellation if (labelDenseMap.getSurfaceNumberOfNodes(myStruct) != toParcellate.getSurfaceNumberOfNodes(myStruct)) - { - throw AlgorithmException("mismatch in number of surface vertices between input and dlabel for structure " + StructureEnum::toName(myStruct)); + {//if both have a surface, it must match + throw AlgorithmException("mismatch in number of surface vertices between data and dlabel for structure " + StructureEnum::toName(myStruct)); } } ret.addSurface(labelDenseMap.getSurfaceNumberOfNodes(myStruct), myStruct); @@ -903,10 +929,12 @@ CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myC int32_t whichParcel = found->second; parcelList[whichParcel].m_surfaceNodes[myStruct].insert(labelSurfMap[j].m_surfaceNode); int64_t dataIndex = toParcellate.getIndexForNode(labelSurfMap[j].m_surfaceNode, myStruct); - if (dataIndex != -1) + if (dataIndex < 0) { - indexToParcelOut[dataIndex] = whichParcel; + throw AlgorithmException("data file is missing vertex " + AString::number(labelSurfMap[j].m_surfaceNode) + " in structure " + + StructureEnum::toName(myStruct) + ", which is used by label '" + parcelList[whichParcel].m_name + "'"); } + indexToParcelOut[dataIndex] = whichParcel; } } } @@ -920,23 +948,26 @@ CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myC int32_t whichParcel = found->second; parcelList[whichParcel].m_voxelIndices.insert(labelVolMap[i].m_ijk); int64_t dataIndex = toParcellate.getIndexForVoxel(labelVolMap[i].m_ijk); - if (dataIndex != -1) + if (dataIndex < 0) { - indexToParcelOut[dataIndex] = whichParcel; + throw AlgorithmException("data file is missing voxel (" + AString::fromNumbers(labelVolMap[i].m_ijk, 3, ", ") + "), which is used by label '" + + parcelList[whichParcel].m_name + "'"); } + indexToParcelOut[dataIndex] = whichParcel; } } for (int i = 0; i < (int)parcelList.size(); ++i) { ret.addParcel(parcelList[i]); } - } else { + } else {//legacy mode: parcels are defined by overlap between labels and the data ROI, any parcels that don't overlap any data are discarded + vector surfList = toParcellate.getSurfaceStructureList(); map > usedKeys;//the keys from the label table that actually overlap with data in the input file for (int i = 0; i < (int)surfList.size(); ++i) { StructureEnum::Enum myStruct = surfList[i]; - if (labelDenseMap.hasSurfaceData(myStruct) && toParcellate.hasSurfaceData(myStruct)) - { + if (labelDenseMap.hasSurfaceData(myStruct)) + {//if a surface is missing from the label file, don't error if (labelDenseMap.getSurfaceNumberOfNodes(myStruct) != toParcellate.getSurfaceNumberOfNodes(myStruct)) { throw AlgorithmException("mismatch in number of surface vertices between input and dlabel for structure " + StructureEnum::toName(myStruct)); diff --git a/src/Algorithms/AlgorithmCiftiParcellate.h b/src/Algorithms/AlgorithmCiftiParcellate.h index 5d2771ae6c3a0d075758452c21fbafeb26279224..17d8e8740d0f0a407b9edeb550c4c0375ab5d01a 100644 --- a/src/Algorithms/AlgorithmCiftiParcellate.h +++ b/src/Algorithms/AlgorithmCiftiParcellate.h @@ -39,17 +39,17 @@ namespace caret { AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const ReductionEnum::Enum& method = ReductionEnum::MEAN, const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, - const bool& includeEmpty = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); + const bool& legacyMode = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const MetricFile* leftWeights, const MetricFile* rightWeights = NULL, const MetricFile* cerebWeights = NULL, const ReductionEnum::Enum& method = ReductionEnum::MEAN, const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, - const bool& includeEmpty = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); + const bool& legacyMode = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const CiftiFile* ciftiWeights, const ReductionEnum::Enum& method = ReductionEnum::MEAN, const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, - const bool& includeEmpty = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); - static CiftiParcelsMap parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, std::vector& indexToParcelOut, const bool& includeEmpty = false); + const bool& legacyMode = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); + static CiftiParcelsMap parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, std::vector& indexToParcelOut, const bool& legacyMode = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmCiftiReduce.cxx b/src/Algorithms/AlgorithmCiftiReduce.cxx index e80e07a6966710893f5479f4067678840c169163..fa7ac7a9be3007cb45bbc6469e89e663103727ef 100644 --- a/src/Algorithms/AlgorithmCiftiReduce.cxx +++ b/src/Algorithms/AlgorithmCiftiReduce.cxx @@ -108,6 +108,10 @@ AlgorithmCiftiReduce::AlgorithmCiftiReduce(ProgressObject* myProgObj, const Cift vector inDims = inputXML.getDimensions(); if (direction == CiftiXML::ALONG_ROW) { + if (inDims[0] == 1) + { + CaretLogWarning("-cifti-reduce is being used for a length=1 reduction on file '" + ciftiIn->getFileName() + "'"); + } vector scratchInRow(inDims[0]); for (MultiDimIterator iter(vector(inDims.begin() + 1, inDims.end())); !iter.atEnd(); ++iter) {// + 1 to exclude row dimension, because getRow/setRow @@ -122,6 +126,10 @@ AlgorithmCiftiReduce::AlgorithmCiftiReduce(ProgressObject* myProgObj, const Cift ciftiOut->setRow(&result, *iter);//if reducing along row, length of output row is 1 } } else { + if (inDims[direction] == 1) + { + CaretLogWarning("-cifti-reduce is being used for a length=1 reduction on file '" + ciftiIn->getFileName() + "'"); + } vector > scratchInRows(inDims[direction], vector(inDims[0])); vector outRow(inDims[0]), reduceScratch(inDims[direction]);//reduction isn't along row, so out rows will be same length as in rows vector otherDims = inDims; diff --git a/src/Algorithms/AlgorithmCiftiResample.cxx b/src/Algorithms/AlgorithmCiftiResample.cxx index 410ff77c724c38564856f20acbc8122d8683b661..04a0322a0e2b99aad8de7e490879ae0052c72645 100644 --- a/src/Algorithms/AlgorithmCiftiResample.cxx +++ b/src/Algorithms/AlgorithmCiftiResample.cxx @@ -75,60 +75,62 @@ OperationParameters* AlgorithmCiftiResample::getParameters() ret->createOptionalParameter(8, "-surface-largest", "use largest weight instead of weighted average or popularity when doing surface resampling"); OptionalParameter* volDilateOpt = ret->createOptionalParameter(9, "-volume-predilate", "dilate the volume components before resampling"); - volDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); - volDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); - OptionalParameter* volDilateWeightedOpt = volDilateOpt->createOptionalParameter(3, "-weighted", "use weighted dilation (default)"); - OptionalParameter* volDilateExpOpt = volDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); - volDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 2)"); + volDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); + volDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); + OptionalParameter* volDilateWeightedOpt = volDilateOpt->createOptionalParameter(3, "-weighted", "use weighted dilation (default)"); + OptionalParameter* volDilateExpOpt = volDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); + volDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 7)"); + volDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* surfDilateOpt = ret->createOptionalParameter(10, "-surface-postdilate", "dilate the surface components after resampling"); - surfDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); - surfDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); - surfDilateOpt->createOptionalParameter(3, "-linear", "use linear dilation"); - OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->createOptionalParameter(4, "-weighted", "use weighted dilation (default for non-label data)"); - OptionalParameter* surfDilateExpOpt = surfDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); - surfDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 2)"); + surfDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); + surfDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); + surfDilateOpt->createOptionalParameter(3, "-linear", "use linear dilation"); + OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->createOptionalParameter(4, "-weighted", "use weighted dilation (default for non-label data)"); + OptionalParameter* surfDilateExpOpt = surfDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); + surfDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 6)"); + surfDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* affineOpt = ret->createOptionalParameter(11, "-affine", "use an affine transformation on the volume components"); - affineOpt->addStringParameter(1, "affine-file", "the affine file to use"); - OptionalParameter* flirtOpt = affineOpt->createOptionalParameter(2, "-flirt", "MUST be used if affine is a flirt affine"); - flirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the affine"); - flirtOpt->addStringParameter(2, "target-volume", "the target volume used when generating the affine"); + affineOpt->addStringParameter(1, "affine-file", "the affine file to use"); + OptionalParameter* flirtOpt = affineOpt->createOptionalParameter(2, "-flirt", "MUST be used if affine is a flirt affine"); + flirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the affine"); + flirtOpt->addStringParameter(2, "target-volume", "the target volume used when generating the affine"); OptionalParameter* warpfieldOpt = ret->createOptionalParameter(12, "-warpfield", "use a warpfield on the volume components"); - warpfieldOpt->addStringParameter(1, "warpfield", "the warpfield to use"); - OptionalParameter* fnirtOpt = warpfieldOpt->createOptionalParameter(2, "-fnirt", "MUST be used if using a fnirt warpfield"); - fnirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the warpfield"); + warpfieldOpt->addStringParameter(1, "warpfield", "the warpfield to use"); + OptionalParameter* fnirtOpt = warpfieldOpt->createOptionalParameter(2, "-fnirt", "MUST be used if using a fnirt warpfield"); + fnirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the warpfield"); OptionalParameter* leftSpheresOpt = ret->createOptionalParameter(13, "-left-spheres", "specify spheres for left surface resampling"); - leftSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current left surface"); - leftSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new left mesh that is in register with the current sphere"); - OptionalParameter* leftAreaSurfsOpt = leftSpheresOpt->createOptionalParameter(3, "-left-area-surfs", "specify left surfaces to do vertex area correction based on"); - leftAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant left anatomical surface with current mesh"); - leftAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant left anatomical surface with new mesh"); - OptionalParameter* leftAreaMetricsOpt = leftSpheresOpt->createOptionalParameter(4, "-left-area-metrics", "specify left vertex area metrics to do area correction based on"); - leftAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); - leftAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); + leftSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current left surface"); + leftSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new left mesh that is in register with the current sphere"); + OptionalParameter* leftAreaSurfsOpt = leftSpheresOpt->createOptionalParameter(3, "-left-area-surfs", "specify left surfaces to do vertex area correction based on"); + leftAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant left anatomical surface with current mesh"); + leftAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant left anatomical surface with new mesh"); + OptionalParameter* leftAreaMetricsOpt = leftSpheresOpt->createOptionalParameter(4, "-left-area-metrics", "specify left vertex area metrics to do area correction based on"); + leftAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); + leftAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); OptionalParameter* rightSpheresOpt = ret->createOptionalParameter(14, "-right-spheres", "specify spheres for right surface resampling"); - rightSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current right surface"); - rightSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new right mesh that is in register with the current sphere"); - OptionalParameter* rightAreaSurfsOpt = rightSpheresOpt->createOptionalParameter(3, "-right-area-surfs", "specify right surfaces to do vertex area correction based on"); - rightAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant right anatomical surface with current mesh"); - rightAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant right anatomical surface with new mesh"); - OptionalParameter* rightAreaMetricsOpt = rightSpheresOpt->createOptionalParameter(4, "-right-area-metrics", "specify right vertex area metrics to do area correction based on"); - rightAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); - rightAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); + rightSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current right surface"); + rightSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new right mesh that is in register with the current sphere"); + OptionalParameter* rightAreaSurfsOpt = rightSpheresOpt->createOptionalParameter(3, "-right-area-surfs", "specify right surfaces to do vertex area correction based on"); + rightAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant right anatomical surface with current mesh"); + rightAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant right anatomical surface with new mesh"); + OptionalParameter* rightAreaMetricsOpt = rightSpheresOpt->createOptionalParameter(4, "-right-area-metrics", "specify right vertex area metrics to do area correction based on"); + rightAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); + rightAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); OptionalParameter* cerebSpheresOpt = ret->createOptionalParameter(15, "-cerebellum-spheres", "specify spheres for cerebellum surface resampling"); - cerebSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current cerebellum surface"); - cerebSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new cerebellum mesh that is in register with the current sphere"); - OptionalParameter* cerebAreaSurfsOpt = cerebSpheresOpt->createOptionalParameter(3, "-cerebellum-area-surfs", "specify cerebellum surfaces to do vertex area correction based on"); - cerebAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant cerebellum anatomical surface with current mesh"); - cerebAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant cerebellum anatomical surface with new mesh"); - OptionalParameter* cerebAreaMetricsOpt = cerebSpheresOpt->createOptionalParameter(4, "-cerebellum-area-metrics", "specify cerebellum vertex area metrics to do area correction based on"); - cerebAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); - cerebAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); + cerebSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current cerebellum surface"); + cerebSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new cerebellum mesh that is in register with the current sphere"); + OptionalParameter* cerebAreaSurfsOpt = cerebSpheresOpt->createOptionalParameter(3, "-cerebellum-area-surfs", "specify cerebellum surfaces to do vertex area correction based on"); + cerebAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant cerebellum anatomical surface with current mesh"); + cerebAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant cerebellum anatomical surface with new mesh"); + OptionalParameter* cerebAreaMetricsOpt = cerebSpheresOpt->createOptionalParameter(4, "-cerebellum-area-metrics", "specify cerebellum vertex area metrics to do area correction based on"); + cerebAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); + cerebAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); AString myHelpText = AString("Resample cifti data to a different brainordinate space. Use COLUMN for the direction to resample dscalar, dlabel, or dtseries. ") + @@ -216,9 +218,10 @@ void AlgorithmCiftiResample::useParameters(OperationParameters* myParams, Progre } } AlgorithmVolumeDilate::Method volDilateMethod = AlgorithmVolumeDilate::WEIGHTED; - float volDilateExponent = 2.0f; - AlgorithmMetricDilate::Method surfDilateMethod = AlgorithmMetricDilate::WEIGHTED;//label dilate doesn't support multiple methods - what to do there, share the enum between them? - float surfDilateExponent = 2.0f;//label dilate currently only supports nearest, so in order to accept a default in the algorithm, it currently ignores this on label data, no warning + float volDilateExponent = 7.0f; + AlgorithmMetricDilate::Method surfDilateMethod = AlgorithmMetricDilate::WEIGHTED;//label dilate doesn't support multiple methods + float surfDilateExponent = 6.0f;//label dilate currently only supports nearest, so in order to accept a default in the algorithm, it currently ignores this on label data, no warning + bool surfLegacyCutoff = false, volLegacyCutoff = false; OptionalParameter* volDilateOpt = myParams->getOptionalParameter(9);//but it does check the options on the command line for sanity if (volDilateOpt->m_present) { @@ -241,6 +244,7 @@ void AlgorithmCiftiResample::useParameters(OperationParameters* myParams, Progre { volDilateExponent = (float)volDilateExpOpt->getDouble(1); } + volLegacyCutoff = volDilateWeightedOpt->getOptionalParameter(2)->m_present; } } OptionalParameter* surfDilateOpt = myParams->getOptionalParameter(10); @@ -274,6 +278,7 @@ void AlgorithmCiftiResample::useParameters(OperationParameters* myParams, Progre surfDilateExponent = (float)surfDilateExpOpt->getDouble(1); } } + surfLegacyCutoff = surfDilateWeightedOpt->getOptionalParameter(2)->m_present; } OptionalParameter* affineOpt = myParams->getOptionalParameter(11); OptionalParameter* warpfieldOpt = myParams->getOptionalParameter(12); @@ -408,13 +413,13 @@ void AlgorithmCiftiResample::useParameters(OperationParameters* myParams, Progre curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, - volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent); + volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } else {//rely on AffineFile() being the identity transform for if neither option is specified AlgorithmCiftiResample(myProgObj, myCiftiIn, direction, myTemplate, templateDir, mySurfMethod, myVolMethod, myCiftiOut, surfLargest, voldilatemm, surfdilatemm, myAffine.getMatrix(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, - volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent); + volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } } @@ -505,19 +510,19 @@ namespace const SurfaceFile* curSphere, *newSphere; MetricFile tempMetric1, tempMetric2, surfDilateRoi; LabelFile tempLabel1, tempLabel2; - CaretPointer tempVol1, tempVol2, tempVol3, volDilateRoi; + CaretPointer inputVol, tempVol2, tempVol3, volDilateRoi; vector inSurfMap, outSurfMap; vector inVolMap, outVolMap; vector floatScratch1, floatScratch2; vector intScratch1, intScratch2; - vector inOffset; - int64_t refDims[3], refOffset[3]; + int64_t refDims[3], refOffset[3], inOffset[3]; vector > refSform; bool copyMode; + vector edgeVoxelList, outsideRoiVoxels, insideResampledRoiVoxels; }; void setupRowResampling(map& surfCache, map& volCache, const CiftiFile* myCiftiIn, CiftiFile* myCiftiOut, - const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const float& voldilatemm, + const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const float& voldilatemm, const FloatMatrix* affine, const VolumeFile* warpfield, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas) @@ -604,38 +609,136 @@ namespace myCache.outVolMap = outModels.getVolumeStructureMap(volList[i]); vector > sform; vector inDims(3); - myCache.inOffset.resize(3); myCache.floatScratch1.resize(inDims[0] * inDims[1] * inDims[2]); - AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiIn, CiftiXML::ALONG_ROW, volList[i], inDims.data(), sform, myCache.inOffset.data()); + AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiIn, CiftiXML::ALONG_ROW, volList[i], inDims.data(), sform, myCache.inOffset); AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiOut, CiftiXML::ALONG_ROW, volList[i], myCache.refDims, myCache.refSform, myCache.refOffset); if (labelMode) { - myCache.tempVol1.grabNew(new VolumeFile(inDims, sform, 1, SubvolumeAttributes::LABEL)); + myCache.inputVol.grabNew(new VolumeFile(inDims, sform, 1, SubvolumeAttributes::LABEL)); } else { - myCache.tempVol1.grabNew(new VolumeFile(inDims, sform)); - myCache.tempVol1->setValueAllVoxels(0.0f); + myCache.inputVol.grabNew(new VolumeFile(inDims, sform)); + myCache.inputVol->setValueAllVoxels(0.0f); } - myCache.tempVol2.grabNew(new VolumeFile(inDims, sform));//temporarily use to make the dilation roi, if needed + myCache.tempVol2.grabNew(new VolumeFile(inDims, sform));//make the dilation roi, to figure out edge voxels and in case we do dilation + myCache.tempVol2->setValueAllVoxels(0.0f); + for (int64_t j = 0; j < (int64_t)myCache.inVolMap.size(); ++j) + { + myCache.tempVol2->setValue(1.0f, myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], + myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], + myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); + } + int neighbors[] = { 0, 0, -1, + 0, -1, 0, + -1, 0, 0, + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }; + VolumeFile resampledRoi; if (voldilatemm > 0.0f) { - myCache.volPadding = VolumePaddingHelper::padMM(myCache.tempVol1, voldilatemm); + VolumeFile ROIinvTemp(inDims, sform); + ROIinvTemp.setValueAllVoxels(1.0f);//make the ordinary ROI so that we can dilate it + for (int64_t j = 0; j < (int64_t)myCache.inVolMap.size(); ++j) + { + ROIinvTemp.setValue(0.0f, myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], + myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], + myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); + } + myCache.volPadding = VolumePaddingHelper::padMM(myCache.inputVol, voldilatemm); myCache.volDilateRoi.grabNew(new VolumeFile()); - myCache.tempVol3.grabNew(new VolumeFile()); - myCache.tempVol2->setValueAllVoxels(1.0f); - for (int j = 0; j < (int)myCache.inVolMap.size(); ++j) + myCache.volPadding.doPadding(&ROIinvTemp, myCache.volDilateRoi, 1.0f);//this is the correct final volDilateRoi, we don't need the unpadded form anymore + ROIinvTemp.clear(); + myCache.tempVol3.grabNew(new VolumeFile());//this is only used in processing when dilating + myCache.volPadding.doPadding(myCache.tempVol2, myCache.tempVol3); + AlgorithmVolumeDilate(NULL, myCache.tempVol3, voldilatemm, AlgorithmVolumeDilate::NEAREST, myCache.tempVol2, myCache.volDilateRoi); + vector paddedDims = myCache.tempVol2->getDimensions(); + for (int64_t k = 0; k < paddedDims[2]; ++k) + { + for (int64_t j = 0; j < paddedDims[1]; ++j) + { + for (int64_t i = 0; i < paddedDims[0]; ++i) + { + if (myCache.tempVol2->getValue(i, j, k) > 0.0f) + { + for (int n = 0; n < 6; ++n) + { + VoxelIJK thisVoxel = VoxelIJK(i + neighbors[j * 3 + 0], + j + neighbors[j * 3 + 1], + k + neighbors[j * 3 + 2]); + if (myCache.tempVol2->indexValid(thisVoxel.m_ijk) && + myCache.tempVol2->getValue(thisVoxel.m_ijk) == 0.0f)//trick: if it is merely touching an FOV edge, cubic won't cause ringing there, so ignore that voxel + { + myCache.edgeVoxelList.push_back(VoxelIJK(i, j, k)); + break; + } + } + } else { + myCache.outsideRoiVoxels.push_back(VoxelIJK(i, j, k)); + } + } + } + } + if (warpfield != NULL) + { + AlgorithmVolumeWarpfieldResample(NULL, myCache.tempVol2, warpfield, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); + } else { + AlgorithmVolumeAffineResample(NULL, myCache.tempVol2, *affine, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); + } + } else { + for (int64_t k = 0; k < inDims[2]; ++k)//we have to loop through all voxels anyway to find the ones outside the ROI { - myCache.tempVol2->setValue(0.0f, myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], - myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], - myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); + for (int64_t j = 0; j < inDims[1]; ++j) + { + for (int64_t i = 0; i < inDims[0]; ++i) + { + if (myCache.tempVol2->getValue(i, j, k) > 0.0f) + { + for (int k = 0; k < 6; ++k) + { + VoxelIJK thisVoxel = VoxelIJK(myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0] + neighbors[k * 3 + 0], + myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1] + neighbors[k * 3 + 1], + myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2] + neighbors[k * 3 + 2]); + if (myCache.tempVol2->indexValid(thisVoxel.m_ijk) && + myCache.tempVol2->getValue(thisVoxel.m_ijk) == 0.0f) + { + myCache.edgeVoxelList.push_back(VoxelIJK(myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], + myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], + myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2])); + break; + } + } + } else { + myCache.outsideRoiVoxels.push_back(VoxelIJK(i, j, k)); + } + } + } + } + if (warpfield != NULL) + { + AlgorithmVolumeWarpfieldResample(NULL, myCache.tempVol2, warpfield, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); + } else { + AlgorithmVolumeAffineResample(NULL, myCache.tempVol2, *affine, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); + } + } + for (int64_t k = 0; k < myCache.refDims[2]; ++k) + { + for (int64_t j = 0; j < myCache.refDims[1]; ++j) + { + for (int64_t i = 0; i < myCache.refDims[0]; ++i) + { + if (resampledRoi.getValue(i, j, k) > 0.5f) + { + myCache.insideResampledRoiVoxels.push_back(VoxelIJK(i, j, k)); + } + } } - myCache.volPadding.doPadding(myCache.tempVol2, myCache.volDilateRoi, 1.0f); } } } void processRowSurface(ResampleCache& myCache, const vector& inRow, vector& outRow, const CiftiXML& myInputXML, const float& surfdilatemm, const bool& surfLargest, const int& unassignedLabelKey, const int64_t& row, - const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent) + const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool surfLegacyCutoff) { bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); int inMapSize = (int)myCache.inSurfMap.size(), outMapSize = (int)myCache.outSurfMap.size(); @@ -691,7 +794,7 @@ namespace MetricFile* toUse = &(myCache.tempMetric1); if (surfdilatemm > 0.0f) { - AlgorithmMetricDilate(NULL, toUse, myCache.newSphere, surfdilatemm, &(myCache.tempMetric2), &(myCache.surfDilateRoi), NULL, 0, surfDilateMethod, surfDilateExponent); + AlgorithmMetricDilate(NULL, toUse, myCache.newSphere, surfdilatemm, &(myCache.tempMetric2), &(myCache.surfDilateRoi), NULL, 0, surfDilateMethod, surfDilateExponent, NULL, surfLegacyCutoff); toUse = &(myCache.tempMetric2); } const float* outData = toUse->getValuePointerForColumn(0); @@ -702,6 +805,70 @@ namespace } } } + + void processRowVolume(ResampleCache& myCache, const vector& inRow, vector& outRow, const CiftiXML& myInputXML, + const float& voldilatemm, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const int& unassignedLabelKey, + const VolumeFile* warpfield, const FloatMatrix* affine, const VolumeFile::InterpType& myVolMethod, const bool volLegacyCutoff) + { + bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); + bool doEdgeAdjust = (myVolMethod == VolumeFile::VolumeFile::CUBIC);//if they ask for cubic on label data, let strange things happen (there will be warnings from resample) + if (labelMode)//gets initialized to 0 when not using labels + { + myCache.inputVol->setValueAllVoxels(unassignedLabelKey); + } + int inMapSize = (int)myCache.inVolMap.size(), outMapSize = (int)myCache.outVolMap.size(); + for (int j = 0; j < inMapSize; ++j) + { + myCache.inputVol->setValue(inRow[myCache.inVolMap[j].m_ciftiIndex], myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], + myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], + myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); + } + VolumeFile* toResample = myCache.inputVol; + if (voldilatemm > 0.0f) + {//inputVol is kept at original dimensions, don't overwrite it + myCache.volPadding.doPadding(myCache.inputVol, myCache.tempVol2); + AlgorithmVolumeDilate(NULL, myCache.tempVol2, voldilatemm, volDilateMethod, myCache.tempVol3, myCache.volDilateRoi, NULL, -1, volDilateExponent, volLegacyCutoff); + toResample = myCache.tempVol3; + } + if (doEdgeAdjust) + { + double edgeSum = 0.0;//calculate the average edge value so we can use it to reduce interpolation edge effects (particularly cubic) + for (int64_t j = 0; j < (int64_t)myCache.edgeVoxelList.size(); ++j) + { + edgeSum += toResample->getValue(myCache.edgeVoxelList[j]); + } + float edgeAverage = 0.0f; + if (!myCache.edgeVoxelList.empty()) + { + edgeAverage = edgeSum / myCache.edgeVoxelList.size(); + } + for (int j = 0; j < int(myCache.outsideRoiVoxels.size()); ++j) + { + toResample->setValue(edgeAverage, myCache.outsideRoiVoxels[j]); + } + }//toResample is never 2, so we can use 2 + if (warpfield != NULL) + { + AlgorithmVolumeWarpfieldResample(NULL, toResample, warpfield, myCache.refDims, myCache.refSform, myVolMethod, myCache.tempVol2); + } else { + AlgorithmVolumeAffineResample(NULL, toResample, *affine, myCache.refDims, myCache.refSform, myVolMethod, myCache.tempVol2); + } + if (doEdgeAdjust) + { + vector tempFrame(myCache.refDims[0] * myCache.refDims[1] * myCache.refDims[2], 0.0f);//for consistency with COLUMN, copy out only the selected voxels + for (int j = 0; j < int(myCache.insideResampledRoiVoxels.size()); ++j) + { + tempFrame[myCache.tempVol2->getIndex(myCache.insideResampledRoiVoxels[j])] = myCache.tempVol2->getValue(myCache.insideResampledRoiVoxels[j]); + } + myCache.tempVol2->setFrame(tempFrame.data()); + } + for (int j = 0; j < outMapSize; ++j) + { + outRow[myCache.outVolMap[j].m_ciftiIndex] = myCache.tempVol2->getValue(myCache.outVolMap[j].m_ijk[0] - myCache.refOffset[0], + myCache.outVolMap[j].m_ijk[1] - myCache.refOffset[1], + myCache.outVolMap[j].m_ijk[2] - myCache.refOffset[2]); + } + } } AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, @@ -712,7 +879,8 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, - const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent) : AbstractAlgorithm(myProgObj) + const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, + const bool volLegacyCutoff, const bool surfLegacyCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); pair myError = checkForErrors(myCiftiIn, direction, myTemplate, templateDir, mySurfMethod, @@ -723,7 +891,6 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); CiftiXML myOutXML = myInputXML; myOutXML.setMap(direction, *(myTemplate->getCiftiXML().getMap(templateDir))); - bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); const CiftiBrainModelsMap& outModels = myOutXML.getBrainModelsMap(direction); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); myCiftiOut->setCiftiXML(myOutXML); @@ -757,17 +924,18 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const throw AlgorithmException("unsupported surface structure: " + StructureEnum::toGuiName(surfList[i])); break; } - processSurfaceComponent(myCiftiIn, direction, surfList[i], mySurfMethod, myCiftiOut, surfLargest, surfdilatemm, curSphere, newSphere, curAreas, newAreas, surfDilateMethod, surfDilateExponent); + processSurfaceComponent(myCiftiIn, direction, surfList[i], mySurfMethod, myCiftiOut, surfLargest, surfdilatemm, curSphere, newSphere, curAreas, newAreas, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < (int)volList.size(); ++i) { - processVolumeWarpfield(myCiftiIn, direction, volList[i], myVolMethod, myCiftiOut, voldilatemm, warpfield, volDilateMethod, volDilateExponent); + processVolume(myCiftiIn, direction, volList[i], myVolMethod, myCiftiOut, voldilatemm, warpfield, NULL, volDilateMethod, volDilateExponent, volLegacyCutoff); } } else {//avoid cifti separate/replace with ALONG_ROW + bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); int numSurfStructs = (int)surfList.size(), numVolStructs = (int)volList.size(); vector unassignedLabelKey; - if (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS) + if (labelMode) { const CiftiLabelsMap& myLabelMap = myInputXML.getLabelsMap(CiftiXML::ALONG_COLUMN); unassignedLabelKey.resize(myLabelMap.getLength()); @@ -777,7 +945,7 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const } } map surfCache, volCache;//could make them different types, but whatever - two variables in case of structure overlap in surface and volume, as some members may get used by both - setupRowResampling(surfCache, volCache, myCiftiIn, myCiftiOut, mySurfMethod, voldilatemm, + setupRowResampling(surfCache, volCache, myCiftiIn, myCiftiOut, mySurfMethod, voldilatemm, NULL, warpfield, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); @@ -790,38 +958,13 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const { map::iterator iter = surfCache.find(surfList[i]); CaretAssert(iter != surfCache.end()); - processRowSurface(iter->second, inRow, outRow, myInputXML, surfdilatemm, surfLargest, unassignedLabelKey[row], row, surfDilateMethod, surfDilateExponent); + processRowSurface(iter->second, inRow, outRow, myInputXML, surfdilatemm, surfLargest, unassignedLabelKey[row], row, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < numVolStructs; ++i) { map::iterator iter = volCache.find(volList[i]); CaretAssert(iter != volCache.end()); - ResampleCache& myCache = iter->second; - if (labelMode)//gets initialized to 0 when not using labels - { - myCache.tempVol1->setValueAllVoxels(unassignedLabelKey[row]); - } - int inMapSize = (int)myCache.inVolMap.size(), outMapSize = (int)myCache.outVolMap.size(); - for (int j = 0; j < inMapSize; ++j) - { - myCache.tempVol1->setValue(inRow[myCache.inVolMap[j].m_ciftiIndex], myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], - myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], - myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); - } - const VolumeFile* toResample = myCache.tempVol1; - if (voldilatemm > 0.0f) - { - myCache.volPadding.doPadding(myCache.tempVol1, myCache.tempVol2); - AlgorithmVolumeDilate(NULL, myCache.tempVol2, voldilatemm, volDilateMethod, myCache.tempVol3, myCache.volDilateRoi, NULL, -1, volDilateExponent); - toResample = myCache.tempVol3; - } - AlgorithmVolumeWarpfieldResample(NULL, toResample, warpfield, myCache.refDims, myCache.refSform, myVolMethod, myCache.tempVol2); - for (int j = 0; j < outMapSize; ++j) - { - outRow[myCache.outVolMap[j].m_ciftiIndex] = myCache.tempVol2->getValue(myCache.outVolMap[j].m_ijk[0] - myCache.refOffset[0], - myCache.outVolMap[j].m_ijk[1] - myCache.refOffset[1], - myCache.outVolMap[j].m_ijk[2] - myCache.refOffset[2]); - } + processRowVolume(iter->second, inRow, outRow, myInputXML, voldilatemm, volDilateMethod, volDilateExponent, unassignedLabelKey[row], warpfield, NULL, myVolMethod, volLegacyCutoff); } myCiftiOut->setRow(outRow.data(), row); } @@ -836,7 +979,8 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, - const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent) : AbstractAlgorithm(myProgObj) + const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, + const bool volLegacyCutoff, const bool surfLegacyCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); pair myError = checkForErrors(myCiftiIn, direction, myTemplate, templateDir, mySurfMethod, @@ -880,17 +1024,18 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const throw AlgorithmException("unsupported surface structure: " + StructureEnum::toGuiName(surfList[i])); break; } - processSurfaceComponent(myCiftiIn, direction, surfList[i], mySurfMethod, myCiftiOut, surfLargest, surfdilatemm, curSphere, newSphere, curAreas, newAreas, surfDilateMethod, surfDilateExponent); + processSurfaceComponent(myCiftiIn, direction, surfList[i], mySurfMethod, myCiftiOut, surfLargest, surfdilatemm, curSphere, newSphere, curAreas, newAreas, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < (int)volList.size(); ++i) { - processVolumeAffine(myCiftiIn, direction, volList[i], myVolMethod, myCiftiOut, voldilatemm, affine, volDilateMethod, volDilateExponent); + processVolume(myCiftiIn, direction, volList[i], myVolMethod, myCiftiOut, voldilatemm, NULL, &affine, volDilateMethod, volDilateExponent, volLegacyCutoff); } } else {//avoid cifti separate/replace with ALONG_ROW + bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); int numSurfStructs = (int)surfList.size(), numVolStructs = (int)volList.size(); vector unassignedLabelKey; - if (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS) + if (labelMode) { const CiftiLabelsMap& myLabelMap = myInputXML.getLabelsMap(CiftiXML::ALONG_COLUMN); unassignedLabelKey.resize(myLabelMap.getLength()); @@ -900,7 +1045,7 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const } } map surfCache, volCache;//could make them different types, but whatever - two variables in case of structure overlap in surface and volume, as some members may get used by both - setupRowResampling(surfCache, volCache, myCiftiIn, myCiftiOut, mySurfMethod, voldilatemm, + setupRowResampling(surfCache, volCache, myCiftiIn, myCiftiOut, mySurfMethod, voldilatemm, &affine, NULL, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); @@ -913,34 +1058,13 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const { map::iterator iter = surfCache.find(surfList[i]); CaretAssert(iter != surfCache.end()); - processRowSurface(iter->second, inRow, outRow, myInputXML, surfdilatemm, surfLargest, unassignedLabelKey[row], row, surfDilateMethod, surfDilateExponent); + processRowSurface(iter->second, inRow, outRow, myInputXML, surfdilatemm, surfLargest, unassignedLabelKey[row], row, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < numVolStructs; ++i) { map::iterator iter = volCache.find(volList[i]); CaretAssert(iter != volCache.end()); - ResampleCache& myCache = iter->second; - int inMapSize = (int)myCache.inVolMap.size(), outMapSize = (int)myCache.outVolMap.size(); - for (int j = 0; j < inMapSize; ++j) - { - myCache.tempVol1->setValue(inRow[myCache.inVolMap[j].m_ciftiIndex], myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], - myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], - myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); - } - const VolumeFile* toResample = myCache.tempVol1; - if (voldilatemm > 0.0f) - { - myCache.volPadding.doPadding(myCache.tempVol1, myCache.tempVol2); - AlgorithmVolumeDilate(NULL, myCache.tempVol2, voldilatemm, volDilateMethod, myCache.tempVol3, myCache.volDilateRoi, NULL, -1, volDilateExponent); - toResample = myCache.tempVol3; - } - AlgorithmVolumeAffineResample(NULL, toResample, affine, myCache.refDims, myCache.refSform, myVolMethod, myCache.tempVol2); - for (int j = 0; j < outMapSize; ++j) - { - outRow[myCache.outVolMap[j].m_ciftiIndex] = myCache.tempVol2->getValue(myCache.outVolMap[j].m_ijk[0] - myCache.refOffset[0], - myCache.outVolMap[j].m_ijk[1] - myCache.refOffset[1], - myCache.outVolMap[j].m_ijk[2] - myCache.refOffset[2]); - } + processRowVolume(iter->second, inRow, outRow, myInputXML, voldilatemm, volDilateMethod, volDilateExponent, unassignedLabelKey[row], NULL, &affine, myVolMethod, volLegacyCutoff); } myCiftiOut->setRow(outRow.data(), row); } @@ -950,7 +1074,7 @@ AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const void AlgorithmCiftiResample::processSurfaceComponent(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& surfdilatemm, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const MetricFile* curAreas, const MetricFile* newAreas, - const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent) + const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool surfLegacyCutoff) { const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); if (myInputXML.getMappingType(1 - direction) == CiftiMappingType::LABELS) @@ -997,7 +1121,7 @@ void AlgorithmCiftiResample::processSurfaceComponent(const CiftiFile* myCiftiIn, float tempf = (resampleROI.getValue(j, 0) > 0.0f) ? 0.0f : 1.0f;//make an inverse ROI invertResampleROI.setValue(j, 0, tempf); } - AlgorithmMetricDilate(NULL, &newMetric, newSphere, surfdilatemm, &newDilate, &invertResampleROI, NULL, -1, surfDilateMethod, surfDilateExponent);//we could get the data roi from the template cifti and use it here + AlgorithmMetricDilate(NULL, &newMetric, newSphere, surfdilatemm, &newDilate, &invertResampleROI, NULL, -1, surfDilateMethod, surfDilateExponent, NULL, surfLegacyCutoff);//we could get the data roi from the template cifti and use it here newMetric.clear(); newUse = &newDilate; } @@ -1008,83 +1132,158 @@ void AlgorithmCiftiResample::processSurfaceComponent(const CiftiFile* myCiftiIn, } } -void AlgorithmCiftiResample::processVolumeWarpfield(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, - CiftiFile* myCiftiOut, const float& voldilatemm, const VolumeFile* warpfield, - const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent) +void AlgorithmCiftiResample::processVolume(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, + CiftiFile* myCiftiOut, const float& voldilatemm, const VolumeFile* warpfield, const FloatMatrix* affine, + const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const bool volLegacyCutoff) { - VolumeFile origData, origROI, origDilate, *origProcess; + VolumeFile origData, origDilate, origROI, ROIDilate, *origProcess, *ROIProcess; origProcess = &origData; + ROIProcess = &origROI; int64_t offset[3]; + const int neighbors[] = { 0, 0, -1, + 0, -1, 0, + -1, 0, 0, + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }; + const bool doEdgeAdjust = (myVolMethod == VolumeFile::CUBIC);//if someone asks for cubic resampling of label data, allow strange things to happen (there will be a warning from resample) + vector edgeVoxelList; AlgorithmCiftiSeparate(NULL, myCiftiIn, direction, myStruct, &origData, offset, &origROI, true); + vector origDims = origData.getDimensions(); if (voldilatemm > 0.0f) { - VolumeFile invertROI; - invertROI.reinitialize(origROI.getOriginalDimensions(), origROI.getSform()); - vector dims; - origROI.getDimensions(dims); - int64_t frameSize = dims[0] * dims[1] * dims[2]; - const float* roiFrame = origROI.getFrame(); - vector invertFrame(frameSize); - for (int64_t j = 0; j < frameSize; ++j) + vector spatialDims = origDims;//make the bad voxel roi by inverting + spatialDims.resize(3); + int64_t framesize = origDims[0] * origDims[1] * origDims[2]; + vector scratchframe(framesize); + const float* roiframe = origROI.getFrame(); + for (int64_t i = 0; i < framesize; ++i) { - invertFrame[j] = (roiFrame[j] > 0.0f) ? 0.0f : 1.0f; + scratchframe[i] = (roiframe[i] > 0.0f ? 0.0f : 1.0f); } - invertROI.setFrame(invertFrame.data()); + VolumeFile origPad, invertROI, invertROIPad; + invertROI.reinitialize(spatialDims, origData.getSform()); + invertROI.setFrame(scratchframe.data()); VolumePaddingHelper mypadding = VolumePaddingHelper::padMM(&origData, voldilatemm); - VolumeFile origPad, invertROIPad; mypadding.doPadding(&origData, &origPad); - origData.clear();//delete data we no longer need to keep memory use down + origData.clear();//free data copies we no longer need mypadding.doPadding(&invertROI, &invertROIPad, 1.0f);//pad with ones since this is an inverted ROI - AlgorithmVolumeDilate(NULL, &origPad, voldilatemm, volDilateMethod, &origDilate, &invertROIPad, NULL, -1, volDilateExponent); + AlgorithmVolumeDilate(NULL, &origPad, voldilatemm, volDilateMethod, &origDilate, &invertROIPad, NULL, -1, volDilateExponent, volLegacyCutoff); origPad.clear();//ditto origProcess = &origDilate; + if (doEdgeAdjust) + {//we need to use the dilated ROI + VolumeFile ROIPad; + mypadding.doPadding(&origROI, &ROIPad); + AlgorithmVolumeDilate(NULL, &ROIPad, voldilatemm, AlgorithmVolumeDilate::NEAREST, &ROIDilate, &invertROIPad); + ROIProcess = &ROIDilate; + vector paddedDims = ROIPad.getDimensions(); + for (int64_t k = 0; k < paddedDims[2]; ++k) + { + for (int64_t j = 0; j < paddedDims[1]; ++j) + { + for (int64_t i = 0; i < paddedDims[0]; ++i) + { + if (ROIDilate.getValue(i, j, k) > 0.0f) + { + for (int n = 0; n < 6; ++n) + { + VoxelIJK thisVoxel = VoxelIJK(i + neighbors[j * 3 + 0], + j + neighbors[j * 3 + 1], + k + neighbors[j * 3 + 2]); + if (ROIDilate.indexValid(thisVoxel.m_ijk) && + ROIDilate.getValue(thisVoxel.m_ijk) == 0.0f)//trick: if it is merely touching an FOV edge, cubic won't cause ringing there, so ignore that voxel + { + edgeVoxelList.push_back(VoxelIJK(i, j, k)); + break; + } + } + } + } + } + } + } + } else {//if we don't dilate, we can use cifti to find the used voxels + if (doEdgeAdjust) + { + vector myMap = myCiftiIn->getCiftiXML().getBrainModelsMap(direction).getVolumeStructureMap(myStruct); + for (int64_t i = 0; i < (int64_t)myMap.size(); ++i) + { + for (int j = 0; j < 6; ++j) + { + VoxelIJK thisVoxel = VoxelIJK(myMap[i].m_ijk[0] - offset[0] + neighbors[j * 3 + 0], + myMap[i].m_ijk[1] - offset[1] + neighbors[j * 3 + 1], + myMap[i].m_ijk[2] - offset[2] + neighbors[j * 3 + 2]); + if (origROI.indexValid(thisVoxel.m_ijk) && + origROI.getValue(thisVoxel.m_ijk) == 0.0f)//trick: if it is merely touching an FOV edge, cubic won't cause ringing there, so ignore that voxel + { + edgeVoxelList.push_back(VoxelIJK(myMap[i].m_ijk[0] - offset[0], + myMap[i].m_ijk[1] - offset[1], + myMap[i].m_ijk[2] - offset[2])); + break; + } + } + } + } + } + if (doEdgeAdjust) + { + vector currentDims = origProcess->getDimensions(); + int64_t framesize = currentDims[0] * currentDims[1] * currentDims[2]; + vector scratchframe(framesize); + const float* ROIFrame = ROIProcess->getFrame(); + for (int64_t b = 0; b < origDims[3]; ++b) + {//input is cifti, no RGB or complex types + double edgesum = 0.0; + for (int64_t i = 0; i < (int64_t)edgeVoxelList.size(); ++i) + { + edgesum += origProcess->getValue(edgeVoxelList[i].m_ijk, b); + } + float edgeMean = edgesum / edgeVoxelList.size(); + const float* dataFrame = origProcess->getFrame(b); + for (int64_t i = 0; i < framesize; ++i) + { + scratchframe[i] = (ROIFrame[i] > 0.0f ? dataFrame[i] : edgeMean);//trick: set the background to the edge mean so we don't need to readjust data values after resampling + } + origProcess->setFrame(scratchframe.data(), b); + } } VolumeFile newVolume; int64_t refdims[3], refoffset[3]; vector > refsform; AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiOut, direction, myStruct, refdims, refsform, refoffset); - AlgorithmVolumeWarpfieldResample(NULL, origProcess, warpfield, refdims, refsform, myVolMethod, &newVolume); - origProcess->clear();//ditto - AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, direction, myStruct, &newVolume, true); -} - -void AlgorithmCiftiResample::processVolumeAffine(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, - CiftiFile* myCiftiOut, const float& voldilatemm, const FloatMatrix& affine, - const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent) -{ - VolumeFile origData, origROI, origDilate, *origProcess; - origProcess = &origData; - int64_t offset[3]; - AlgorithmCiftiSeparate(NULL, myCiftiIn, direction, myStruct, &origData, offset, &origROI, true); - if (voldilatemm > 0.0f) + if (warpfield != NULL) { - VolumeFile invertROI; - invertROI.reinitialize(origROI.getOriginalDimensions(), origROI.getSform()); - vector dims; - origROI.getDimensions(dims); - int64_t frameSize = dims[0] * dims[1] * dims[2]; - const float* roiFrame = origROI.getFrame(); - vector invertFrame(frameSize); - for (int64_t j = 0; j < frameSize; ++j) + AlgorithmVolumeWarpfieldResample(NULL, origProcess, warpfield, refdims, refsform, myVolMethod, &newVolume); + } else { + AlgorithmVolumeAffineResample(NULL, origProcess, *affine, refdims, refsform, myVolMethod, &newVolume); + } + origProcess->clear(); + if (doEdgeAdjust) + {//to make it obvious when the dilation didn't cover the output ROI, mask the result with the (dilated) input ROI + VolumeFile newROI;//trilinear masked at 0.5 should give somewhat better downsampling behavior than enclosing + if (warpfield != NULL) { - invertFrame[j] = (roiFrame[j] > 0.0f) ? 0.0f : 1.0f; + AlgorithmVolumeWarpfieldResample(NULL, ROIProcess, warpfield, refdims, refsform, VolumeFile::TRILINEAR, &newROI); + } else { + AlgorithmVolumeAffineResample(NULL, ROIProcess, *affine, refdims, refsform, VolumeFile::TRILINEAR, &newROI); + } + const float* roiFrame = newROI.getFrame(); + int64_t framesize = refdims[0] * refdims[1] * refdims[2]; + vector scratchframe(framesize, 0.0f); + for (int64_t b = 0; b < origDims[3]; ++b) + { + const float* dataFrame = newVolume.getFrame(b); + for (int64_t i = 0; i < framesize; ++i) + { + if (roiFrame[i] > 0.5f) + { + scratchframe[i] = dataFrame[i]; + } + } + newVolume.setFrame(scratchframe.data(), b); } - invertROI.setFrame(invertFrame.data()); - VolumePaddingHelper mypadding = VolumePaddingHelper::padMM(&origData, voldilatemm); - VolumeFile origPad, invertROIPad; - mypadding.doPadding(&origData, &origPad); - origData.clear();//delete data we no longer need to keep memory use down - mypadding.doPadding(&invertROI, &invertROIPad, 1.0f);//pad with ones since this is an inverted ROI - AlgorithmVolumeDilate(NULL, &origPad, voldilatemm, volDilateMethod, &origDilate, &invertROIPad, NULL, -1, volDilateExponent); - origPad.clear();//ditto - origProcess = &origDilate; } - VolumeFile newVolume; - int64_t refdims[3], refoffset[3]; - vector > refsform; - AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiOut, direction, myStruct, refdims, refsform, refoffset); - AlgorithmVolumeAffineResample(NULL, origProcess, affine, refdims, refsform, myVolMethod, &newVolume); - origProcess->clear();//ditto AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, direction, myStruct, &newVolume, true); } diff --git a/src/Algorithms/AlgorithmCiftiResample.h b/src/Algorithms/AlgorithmCiftiResample.h index a08d379b3d5ff0839338152b44380b24dfa9aaf2..7b2aaeded3adff14b3fed4375849abd646403e5b 100644 --- a/src/Algorithms/AlgorithmCiftiResample.h +++ b/src/Algorithms/AlgorithmCiftiResample.h @@ -38,13 +38,11 @@ namespace caret { AlgorithmCiftiResample(); void processSurfaceComponent(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& surfdilatemm, const SurfaceFile* curSphere, const SurfaceFile* newSphere, - const MetricFile* curAreas, const MetricFile* newAreas, const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent); - void processVolumeWarpfield(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, - CiftiFile* myCiftiOut, const float& voldilatemm, const VolumeFile* warpfield, - const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent); - void processVolumeAffine(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, - CiftiFile* myCiftiOut, const float& voldilatemm, const FloatMatrix& affine, - const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent); + const MetricFile* curAreas, const MetricFile* newAreas, + const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool surfLegacyCutoff); + void processVolume(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, + CiftiFile* myCiftiOut, const float& voldilatemm, const VolumeFile* warpfield, const FloatMatrix* affine, + const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const bool volLegacyCutoff); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); @@ -63,8 +61,9 @@ namespace caret { const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, - const AlgorithmVolumeDilate::Method& volDilateMethod = AlgorithmVolumeDilate::WEIGHTED, const float& volDilateExponent = 2.0f, - const AlgorithmMetricDilate::Method& surfDilateMethod = AlgorithmMetricDilate::WEIGHTED, const float& surfDilateExponent = 2.0f); + const AlgorithmVolumeDilate::Method& volDilateMethod = AlgorithmVolumeDilate::WEIGHTED, const float& volDilateExponent = 7.0f, + const AlgorithmMetricDilate::Method& surfDilateMethod = AlgorithmMetricDilate::WEIGHTED, const float& surfDilateExponent = 6.0f, + const bool volLegacyCutoff = false, const bool surfLegacyCutoff = false); AlgorithmCiftiResample(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const VolumeFile::InterpType& myVolMethod, CiftiFile* myCiftiOut, @@ -73,8 +72,9 @@ namespace caret { const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, - const AlgorithmVolumeDilate::Method& volDilateMethod = AlgorithmVolumeDilate::WEIGHTED, const float& volDilateExponent = 2.0f, - const AlgorithmMetricDilate::Method& surfDilateMethod = AlgorithmMetricDilate::WEIGHTED, const float& surfDilateExponent = 2.0f); + const AlgorithmVolumeDilate::Method& volDilateMethod = AlgorithmVolumeDilate::WEIGHTED, const float& volDilateExponent = 7.0f, + const AlgorithmMetricDilate::Method& surfDilateMethod = AlgorithmMetricDilate::WEIGHTED, const float& surfDilateExponent = 6.0f, + const bool volLegacyCutoff = false, const bool surfLegacyCutoff = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); diff --git a/src/Algorithms/AlgorithmCiftiSeparate.cxx b/src/Algorithms/AlgorithmCiftiSeparate.cxx index d346768d5db34f8f9ab1672c046819d19d943ff0..886c7c2cb72857129b1b76fa9686d61030800a5e 100644 --- a/src/Algorithms/AlgorithmCiftiSeparate.cxx +++ b/src/Algorithms/AlgorithmCiftiSeparate.cxx @@ -118,7 +118,7 @@ void AlgorithmCiftiSeparate::useParameters(OperationParameters* myParams, Progre StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { - throw AlgorithmException("unrecognized structure type"); + throw AlgorithmException("unrecognized structure type: '" + structName + "'"); } LabelFile* labelOut = labelInstances[i]->getOutputLabel(2); MetricFile* roiOut = NULL; @@ -138,7 +138,7 @@ void AlgorithmCiftiSeparate::useParameters(OperationParameters* myParams, Progre StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { - throw AlgorithmException("unrecognized structure type"); + throw AlgorithmException("unrecognized structure type: '" + structName + "'"); } MetricFile* metricOut = metricInstances[i]->getOutputMetric(2); MetricFile* roiOut = NULL; @@ -158,7 +158,7 @@ void AlgorithmCiftiSeparate::useParameters(OperationParameters* myParams, Progre StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { - throw AlgorithmException("unrecognized structure type"); + throw AlgorithmException("unrecognized structure type: '" + structName + "'"); } VolumeFile* volOut = volumeInstances[i]->getOutputVolume(2); VolumeFile* roiOut = NULL; @@ -257,7 +257,7 @@ AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const metricOut->setNumberOfNodesAndColumns(numNodes, colSize); metricOut->setStructure(myStruct); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); - for (int j = 0; j < rowSize; ++j) + for (int j = 0; j < colSize; ++j) { metricOut->setMapName(j, myNamesMap.getIndexName(j)); } @@ -365,7 +365,7 @@ AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const labelOut->setNumberOfNodesAndColumns(numNodes, colSize); labelOut->setStructure(myStruct); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); - for (int j = 0; j < rowSize; ++j) + for (int j = 0; j < colSize; ++j) { labelOut->setMapName(j, myNamesMap.getIndexName(j)); } @@ -496,7 +496,7 @@ AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const volOut->reinitialize(newdims, mySform); volOut->setValueAllVoxels(0.0f); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); - for (int j = 0; j < rowSize; ++j) + for (int j = 0; j < colSize; ++j) { volOut->setMapName(j, myNamesMap.getIndexName(j)); } @@ -614,7 +614,7 @@ AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const volOut->reinitialize(newdims, mySform); volOut->setValueAllVoxels(0.0f); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); - for (int j = 0; j < rowSize; ++j) + for (int j = 0; j < colSize; ++j) { volOut->setMapName(j, myNamesMap.getIndexName(j)); } diff --git a/src/Algorithms/AlgorithmCreateSignedDistanceVolume.cxx b/src/Algorithms/AlgorithmCreateSignedDistanceVolume.cxx index bb2af567996ea51c41a12fdb69d83326a3b69f4b..65b6e62b911f23cf3d413ffe2aa03c9d6375bd1d 100644 --- a/src/Algorithms/AlgorithmCreateSignedDistanceVolume.cxx +++ b/src/Algorithms/AlgorithmCreateSignedDistanceVolume.cxx @@ -24,6 +24,7 @@ #include "CaretOMP.h" #include "CaretHeap.h" #include "MathFunctions.h" +#include "NiftiIO.h" #include "SurfaceFile.h" #include @@ -88,10 +89,11 @@ void AlgorithmCreateSignedDistanceVolume::useParameters(OperationParameters* myP vector > volSpace; vector volDims; { - VolumeFile myRefSpace; - myRefSpace.readFile(myRefName); - volSpace = myRefSpace.getSform(); - myRefSpace.getDimensions(volDims); + NiftiIO refSpaceIO; + refSpaceIO.openRead(myRefName); + volDims = refSpaceIO.getDimensions(); + if (volDims.size() < 3) volDims.resize(3, 1); + volSpace = refSpaceIO.getHeader().getSForm(); } volDims.resize(3); VolumeFile* myVolOut = myParams->getOutputVolume(3); diff --git a/src/Algorithms/AlgorithmLabelModifyKeys.cxx b/src/Algorithms/AlgorithmLabelModifyKeys.cxx index b845ffd9df5eed13c28631e9da6b87a66e6d0f27..900d197b1c6a28e690c8234d7481a94f430dd397 100644 --- a/src/Algorithms/AlgorithmLabelModifyKeys.cxx +++ b/src/Algorithms/AlgorithmLabelModifyKeys.cxx @@ -60,7 +60,7 @@ OperationParameters* AlgorithmLabelModifyKeys::getParameters() "This would change the current label with key '3' to use the key '5' instead, 5 would use 8, and 8 would use 2. " + "Any collision in key values results in the label that was not specified in the remap file getting remapped to an otherwise unused key. " + "Remapping more than one key to the same new key, or the same key to more than one new key, results in an error. " + - "This will not change the appearance of the file when displayed, it will change the keys in the data at the same time." + "This will not change the appearance of the file when displayed, as it will change the key values in the data at the same time." ); return ret; } @@ -107,7 +107,7 @@ AlgorithmLabelModifyKeys::AlgorithmLabelModifyKeys(ProgressObject* myProgObj, co for (map::const_iterator iter = remap.begin(); iter != remap.end(); ++iter) { const GiftiLabel* oldLabel = oldTable->getLabel(iter->first); - if (oldLabel == NULL) throw AlgorithmException("label " + AString::number(iter->first) + " does not exist in the input label file"); + if (oldLabel == NULL) throw AlgorithmException("label key " + AString::number(iter->first) + " does not exist in the input file"); GiftiLabel newLabel(*oldLabel); newLabel.setKey(iter->second); if (iter->first == oldUnlabeled) diff --git a/src/Algorithms/AlgorithmMetricDilate.cxx b/src/Algorithms/AlgorithmMetricDilate.cxx index cbc3dfc254936f8ace5f3aa8d534e7caf26c291c..4d7d3e8bbfa541d1457d90508245d362feda13b3 100644 --- a/src/Algorithms/AlgorithmMetricDilate.cxx +++ b/src/Algorithms/AlgorithmMetricDilate.cxx @@ -23,6 +23,7 @@ #include "CaretAssert.h" #include "CaretOMP.h" +#include "FastStatistics.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "PaletteColorMapping.h" @@ -71,10 +72,12 @@ OperationParameters* AlgorithmMetricDilate::getParameters() ret->createOptionalParameter(10, "-linear", "fill in values with linear interpolation along strongest gradient"); OptionalParameter* exponentOpt = ret->createOptionalParameter(8, "-exponent", "use a different exponent in the weighting function"); - exponentOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 2)"); + exponentOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 6)"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(11, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); + + ret->createOptionalParameter(12, "-legacy-cutoff", "use the old method of choosing how many vertices to use when calulating the dilated value with weighted method"); ret->setHelpText( AString("For all metric vertices that are designated as bad, if they neighbor a non-bad vertex with data or are within the specified distance of such a vertex, ") + @@ -84,8 +87,8 @@ OperationParameters* AlgorithmMetricDilate::getParameters() "If -bad-vertex-roi is specified, only vertices with a positive value in the ROI are bad. " + "If it is not specified, only vertices that have data, with a value of zero, are bad. " + "If -data-roi is not specified, all vertices are assumed to have data.\n\n" + - - "Note that the -corrected-areas option uses an approximate correction for the change in distances along a group average surface." + "Note that the -corrected-areas option uses an approximate correction for the change in distances along a group average surface.\n\n" + + "To get the behavior of version 1.3.2 or earlier, use '-legacy-cutoff -exponent 2'." ); return ret; } @@ -131,7 +134,7 @@ void AlgorithmMetricDilate::useParameters(OperationParameters* myParams, Progres methodSpecified = true; myMethod = LINEAR; } - float exponent = 2.0f; + float exponent = 6.0f; OptionalParameter* exponentOpt = myParams->getOptionalParameter(8); if (exponentOpt->m_present) { @@ -143,12 +146,13 @@ void AlgorithmMetricDilate::useParameters(OperationParameters* myParams, Progres { corrAreas = corrAreaOpt->getMetric(1); } - AlgorithmMetricDilate(myProgObj, myMetric, mySurf, distance, myMetricOut, badNodeRoi, dataRoi, columnNum, myMethod, exponent, corrAreas); + bool legacyCutoff = myParams->getOptionalParameter(12)->m_present; + AlgorithmMetricDilate(myProgObj, myMetric, mySurf, distance, myMetricOut, badNodeRoi, dataRoi, columnNum, myMethod, exponent, corrAreas, legacyCutoff); } AlgorithmMetricDilate::AlgorithmMetricDilate(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const float& distance, MetricFile* myMetricOut, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const int& columnNum, - const Method& myMethod, const float& exponent, const MetricFile* corrAreas) : AbstractAlgorithm(myProgObj) + const Method& myMethod, const float& exponent, const MetricFile* corrAreas, const bool legacyCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); @@ -196,7 +200,7 @@ AlgorithmMetricDilate::AlgorithmMetricDilate(ProgressObject* myProgObj, const Me { precomputeNearest(myNearest, mySurf, badNodeRoi, dataRoi, corrAreas, distance); } else { - precomputeStencils(myStencils, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, exponent); + precomputeStencils(myStencils, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, exponent, legacyCutoff); } } if (columnNum == -1) @@ -209,7 +213,7 @@ AlgorithmMetricDilate::AlgorithmMetricDilate(ProgressObject* myProgObj, const Me myMetricOut->setColumnName(thisCol, myMetric->getColumnName(thisCol)); if (badNodeRoi == NULL) { - processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent); + processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff); } else { switch (myMethod) { @@ -220,7 +224,7 @@ AlgorithmMetricDilate::AlgorithmMetricDilate(ProgressObject* myProgObj, const Me processColumn(colScratch.data(), numNodes, myInputData, myStencils); break; case LINEAR: - processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent); + processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff); break; } } @@ -233,7 +237,7 @@ AlgorithmMetricDilate::AlgorithmMetricDilate(ProgressObject* myProgObj, const Me myMetricOut->setColumnName(0, myMetric->getColumnName(columnNum)); if (badNodeRoi == NULL) { - processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent); + processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff); } else { switch (myMethod) { @@ -244,7 +248,7 @@ AlgorithmMetricDilate::AlgorithmMetricDilate(ProgressObject* myProgObj, const Me processColumn(colScratch.data(), numNodes, myInputData, myStencils); break; case LINEAR: - processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent); + processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff); break; } } @@ -302,16 +306,19 @@ void AlgorithmMetricDilate::processColumn(float* colScratch, const int& numNodes void AlgorithmMetricDilate::processColumn(float* colScratch, const float* myInputData, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, - const float& distance, const bool& nearest, const bool& linear, const float& exponent) + const float& distance, const bool& nearest, const bool& linear, const float& exponent, const bool legacyCutoff) { - float cutoffRatio = 1.5f, test = pow(10.0f, 1.0f / exponent);//find what cutoff ratio corresponds to a tenth of weight, but don't use more than a 1.5 * nearest cutoff - if (test > 1.0f && test < cutoffRatio)//if it is less than 1, the exponent is weird, so simply ignore it and use default - { + FastStatistics spacingStats; + mySurf->getNodesSpacingStatistics(spacingStats);//use mean spacing to help set minimum stencil distance, since native surfaces might have a minimum of 0 + float cutoffBase = max(2.0f * distance, 2.0f * spacingStats.getMean()), cutoffRatio = max(1.1f, pow(49.0f, 1.0f / (exponent - 2.0f)));//find what ratio from closest vertex corresponds to having 98% of total weight accounted for on a plane, assuming non-adverse ROI + float legacyCutoffRatio = 1.5f, test = pow(10.0f, 1.0f / exponent);//old logic: find what cutoff ratio corresponds to a tenth of weight, but don't use more than a 1.5 * nearest cutoff + if (test > 1.0f && test < legacyCutoffRatio)//if it is less than 1, the exponent is weird, so simply ignore it and use default + {//this generally cut off early, causing the result to behave like a higher exponent was used if (test > 1.1f) { - cutoffRatio = test; + legacyCutoffRatio = test; } else { - cutoffRatio = 1.1f; + legacyCutoffRatio = 1.1f; } } int numNodes = mySurf->getNumberOfNodes(); @@ -497,7 +504,17 @@ void AlgorithmMetricDilate::processColumn(float* colScratch, const float* myInpu colScratch[i] = myInputData[node1] + (myInputData[node2] - myInputData[node1]) * usableDists[bestj] / (usableDists[bestj] + usableDists[bestk]); } } else { - myGeoHelp->getNodesToGeoDist(i, closestDist * cutoffRatio, nodeList, distList);//NOTE: guaranteed to find at least the closest node + float cutoffDist = cutoffBase; + if (legacyCutoff) + { + cutoffDist = closestDist * legacyCutoffRatio; + } else { + if (exponent > 2.0f && cutoffRatio < 100.0f && cutoffRatio > 1.0f)//if the ratio is sane, use it, but never exceed cutoffBase + { + cutoffDist = max(min(cutoffRatio * closestDist, cutoffDist), cutoffBase * 0.25f);//but small kernels are rather cheap anyway, so have a minimum size just in case + } + } + myGeoHelp->getNodesToGeoDist(i, cutoffDist, nodeList, distList); int numInRange = (int)nodeList.size(); float totalWeight = 0.0f, weightedSum = 0.0f; for (int j = 0; j < numInRange; ++j) @@ -535,18 +552,21 @@ void AlgorithmMetricDilate::processColumn(float* colScratch, const float* myInpu void AlgorithmMetricDilate::precomputeStencils(vector >& myStencils, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, - const float& distance, const float& exponent) + const float& distance, const float& exponent, const bool legacyCutoff) { CaretAssert(badNodeRoi != NULL);//because it should never be called if we don't know exactly what nodes we are replacing const float* badNodeData = badNodeRoi->getValuePointerForColumn(0); - float cutoffRatio = 1.5f, test = pow(10.0f, 1.0f / exponent);//find what cutoff ratio corresponds to a tenth of weight, but don't use more than a 1.5 * nearest cutoff - if (test > 1.0f && test < cutoffRatio)//if it is less than 1, the exponent is weird, so simply ignore it and use default - { + FastStatistics spacingStats; + mySurf->getNodesSpacingStatistics(spacingStats);//use mean spacing to help set minimum stencil distance, since native surfaces might have a minimum of 0 + float cutoffBase = max(2.0f * distance, 2.0f * spacingStats.getMean()), cutoffRatio = max(1.1f, pow(49.0f, 1.0f / (exponent - 2.0f)));//find what ratio from closest vertex corresponds to having 98% of total weight accounted for on a plane, assuming non-adverse ROI + float legacyCutoffRatio = 1.5f, test = pow(10.0f, 1.0f / exponent);//old logic: find what cutoff ratio corresponds to a tenth of weight, but don't use more than a 1.5 * nearest cutoff + if (test > 1.0f && test < legacyCutoffRatio)//if it is less than 1, the exponent is weird, so simply ignore it and use default + {//this generally cut off early, causing the result to behave like a higher exponent was used if (test > 1.1f) { - cutoffRatio = test; + legacyCutoffRatio = test; } else { - cutoffRatio = 1.1f; + legacyCutoffRatio = 1.1f; } } int numNodes = mySurf->getNumberOfNodes(); @@ -637,7 +657,17 @@ void AlgorithmMetricDilate::precomputeStencils(vector >& { vector nodeList; vector distList; - myGeoHelp->getNodesToGeoDist(i, closestDist * cutoffRatio, nodeList, distList); + float cutoffDist = cutoffBase; + if (legacyCutoff) + { + cutoffDist = closestDist * legacyCutoffRatio; + } else { + if (exponent > 2.0f && cutoffRatio < 100.0f && cutoffRatio > 1.0f)//if the ratio is sane, use it, but never exceed cutoffBase + { + cutoffDist = max(min(cutoffRatio * closestDist, cutoffDist), cutoffBase * 0.25f);//but small kernels are rather cheap anyway, so have a minimum size just in case + } + } + myGeoHelp->getNodesToGeoDist(i, cutoffDist, nodeList, distList); int numInRange = (int)nodeList.size(); myElem.m_weightsum = 0.0f; for (int j = 0; j < numInRange; ++j) diff --git a/src/Algorithms/AlgorithmMetricDilate.h b/src/Algorithms/AlgorithmMetricDilate.h index 8130fed6fa1533545f50c414f3ecbb151a34dd47..153b1bc5604ea1762f96b61dfeef82c934e47a77 100644 --- a/src/Algorithms/AlgorithmMetricDilate.h +++ b/src/Algorithms/AlgorithmMetricDilate.h @@ -35,14 +35,14 @@ namespace caret { AlgorithmMetricDilate(); void precomputeStencils(std::vector >& myStencils, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, - const float& distance, const float& exponent); + const float& distance, const float& exponent, const bool legacyCutoff); void precomputeNearest(std::vector >& myNearest, const SurfaceFile* mySurf, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, const float& distance); void processColumn(float* colScratch, const int& numNodes, const float* myInputData, std::vector > myNearest); void processColumn(float* colScratch, const int& numNodes, const float* myInputData, std::vector > myStencils); void processColumn(float* colScratch, const float* myInputData, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, - const float& distance, const bool& nearest, const bool& linear, const float& exponent); + const float& distance, const bool& nearest, const bool& linear, const float& exponent, const bool legacyCutoff); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); @@ -55,7 +55,7 @@ namespace caret { }; AlgorithmMetricDilate(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const float& distance, MetricFile* myMetricOut, const MetricFile* badNodeRoi = NULL, const MetricFile* dataRoi = NULL, const int& columnNum = -1, - const Method& myMethod = WEIGHTED, const float& exponent = 2.0f, const MetricFile* corrAreas = NULL); + const Method& myMethod = WEIGHTED, const float& exponent = 6.0f, const MetricFile* corrAreas = NULL, const bool legacyCutoff = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmMetricFalseCorrelation.cxx b/src/Algorithms/AlgorithmMetricFalseCorrelation.cxx index 3c793baeddab127eb82f9a48d90b2b68ba28c843..4f44fdfa0b91274aabef93c399e7d54c1dfe71aa 100644 --- a/src/Algorithms/AlgorithmMetricFalseCorrelation.cxx +++ b/src/Algorithms/AlgorithmMetricFalseCorrelation.cxx @@ -141,11 +141,11 @@ AlgorithmMetricFalseCorrelation::AlgorithmMetricFalseCorrelation(ProgressObject* { AString rawDumpString;//build the entire string for a single node, then write it in one call within #pragma omp critical Vector3D myCoord = mySurf->getCoordinate(n); - set inRange = myLocator->pointsInRange(myCoord, max3D); + vector inRange = myLocator->pointsInRange(myCoord, max3D); int numInterested = (int)inRange.size(); vector interested(numInterested); int counter = 0; - for (set::iterator iter = inRange.begin(); iter != inRange.end(); ++iter) + for (vector::iterator iter = inRange.begin(); iter != inRange.end(); ++iter) { interested[counter] = iter->index; ++counter; @@ -153,7 +153,7 @@ AlgorithmMetricFalseCorrelation::AlgorithmMetricFalseCorrelation(ProgressObject* vector geoDists; myGeo->getGeoToTheseNodes(n, interested, geoDists); counter = 0; - for (set::iterator iter = inRange.begin(); iter != inRange.end(); ++iter) + for (vector::iterator iter = inRange.begin(); iter != inRange.end(); ++iter) { if (roiCol == NULL || (roiCol[iter->index] > 0.0f)) { diff --git a/src/Algorithms/AlgorithmMetricFindClusters.cxx b/src/Algorithms/AlgorithmMetricFindClusters.cxx index 318126413b7e5b08b5e7a6e61f2f67e80ee58e0f..64cc453eb8a02eb354b38775719a84c5156cac2d 100644 --- a/src/Algorithms/AlgorithmMetricFindClusters.cxx +++ b/src/Algorithms/AlgorithmMetricFindClusters.cxx @@ -78,6 +78,7 @@ OperationParameters* AlgorithmMetricFindClusters::getParameters() ret->setHelpText( AString("Outputs a metric with nonzero integers for all vertices within a large enough cluster, and zeros elsewhere. ") + "The integers denote cluster membership (by default, first cluster found will use value 1, second cluster 2, etc). " + + "Cluster values are not reused across maps of the output, but instead keep counting up. " + "By default, values greater than are considered to be in a cluster, use -less-than to test for values less than the threshold. " + "To apply this as a mask to the data, or to do more complicated thresholding, see -metric-math." ); diff --git a/src/Algorithms/AlgorithmMetricReduce.cxx b/src/Algorithms/AlgorithmMetricReduce.cxx index 8cac2671de8762939b4a87a2ad1739c944208c7e..c6cb98a6e7621b85890d21976ec5f3177c59f743 100644 --- a/src/Algorithms/AlgorithmMetricReduce.cxx +++ b/src/Algorithms/AlgorithmMetricReduce.cxx @@ -86,6 +86,10 @@ AlgorithmMetricReduce::AlgorithmMetricReduce(ProgressObject* myProgObj, const Me int numNodes = metricIn->getNumberOfNodes(); int numCols = metricIn->getNumberOfColumns(); if (numCols < 1 || numNodes < 1) throw AlgorithmException("input must have at least 1 column and 1 vertex"); + if (numCols == 1) + { + CaretLogWarning("-metric-reduce is being used for a length=1 reduction on file '" + metricIn->getFileName() + "'"); + } metricOut->setNumberOfNodesAndColumns(numNodes, 1); metricOut->setStructure(metricIn->getStructure()); metricOut->setColumnName(0, ReductionEnum::toName(myReduce)); diff --git a/src/Algorithms/AlgorithmSurfaceDistortion.cxx b/src/Algorithms/AlgorithmSurfaceDistortion.cxx index 28140294d8acd444d3cd88cbaaeb688011c156d1..6fbc716e230c6946f0d2ac3338a55bebbd68528a 100644 --- a/src/Algorithms/AlgorithmSurfaceDistortion.cxx +++ b/src/Algorithms/AlgorithmSurfaceDistortion.cxx @@ -61,7 +61,8 @@ OperationParameters* AlgorithmSurfaceDistortion::getParameters() ret->createOptionalParameter(6, "-edge-method", "calculate distortion of edge lengths rather than areas"); - ret->createOptionalParameter(7, "-local-affine-method", "calculate distortion by the local affines between triangles"); + OptionalParameter* strainOpt = ret->createOptionalParameter(7, "-local-affine-method", "calculate distortion by the local affines between triangles"); + strainOpt->createOptionalParameter(1, "-log2", "apply base-2 log transform"); ret->setHelpText( AString("This command, when not using -caret5-method, -edge-method, or -local-affine-method, is equivalent to using -surface-vertex-areas on each surface, ") + @@ -94,14 +95,22 @@ void AlgorithmSurfaceDistortion::useParameters(OperationParameters* myParams, Pr if (caret5method) ++methodCount; bool edgeMethod = myParams->getOptionalParameter(6)->m_present; if (edgeMethod) ++methodCount; - bool strainMethod = myParams->getOptionalParameter(7)->m_present; - if (strainMethod) ++methodCount; + bool strainMethod = false; + bool strainLog2 = false; + OptionalParameter* strainOpt = myParams->getOptionalParameter(7); + if (strainOpt->m_present) + { + strainMethod = true; + ++methodCount; + strainLog2 = strainOpt->getOptionalParameter(1)->m_present; + } if (methodCount > 1) throw AlgorithmException("you may not specify more than one of -caret5-method, -edge-method, or -local-affine-method"); - AlgorithmSurfaceDistortion(myProgObj, referenceSurf, distortedSurf, myMetricOut, smooth, caret5method, edgeMethod, strainMethod); + AlgorithmSurfaceDistortion(myProgObj, referenceSurf, distortedSurf, myMetricOut, smooth, caret5method, edgeMethod, strainMethod, strainLog2); } AlgorithmSurfaceDistortion::AlgorithmSurfaceDistortion(ProgressObject* myProgObj, const SurfaceFile* referenceSurf, const SurfaceFile* distortedSurf, - MetricFile* myMetricOut, const float& smooth, const bool& caret5method, const bool& edgeMethod, const bool& strainMethod) : AbstractAlgorithm(myProgObj) + MetricFile* myMetricOut, const float& smooth, const bool& caret5method, const bool& edgeMethod, + const bool& strainMethod, const bool& strainLog2) : AbstractAlgorithm(myProgObj) { int methodCount = 0; if (caret5method) ++methodCount; @@ -278,8 +287,14 @@ AlgorithmSurfaceDistortion::AlgorithmSurfaceDistortion(ProgressObject* myProgObj accumJ += thisJ;//not sure which areas to weight by, so for now do a straight average, relying on smoothness inherent in the measures accumR += thisR;//could maybe do some fancy interpolation of the affines in 3D sphere space } - myMetricOut->setValue(i, 0, accumJ / myTiles.size()); - myMetricOut->setValue(i, 1, accumR / myTiles.size()); + if (strainLog2) + { + myMetricOut->setValue(i, 0, log2(accumJ / myTiles.size())); + myMetricOut->setValue(i, 1, log2(accumR / myTiles.size())); + } else { + myMetricOut->setValue(i, 0, accumJ / myTiles.size()); + myMetricOut->setValue(i, 1, accumR / myTiles.size()); + } } } else { myMetricOut->setColumnName(0, "area distortion"); diff --git a/src/Algorithms/AlgorithmSurfaceDistortion.h b/src/Algorithms/AlgorithmSurfaceDistortion.h index e8c340a1ec13dfb4d47317fbb64632f1704bf828..c8e40d137b9fdcca8b89b2aa0f1f5dddb28e5533 100644 --- a/src/Algorithms/AlgorithmSurfaceDistortion.h +++ b/src/Algorithms/AlgorithmSurfaceDistortion.h @@ -34,7 +34,8 @@ namespace caret { public: AlgorithmSurfaceDistortion(ProgressObject* myProgObj, const SurfaceFile* referenceSurf, const SurfaceFile* distortedSurf, MetricFile* myMetricOut, const float& smooth = -1.0f, - const bool& caret5method = false, const bool& edgeMethod = false, const bool& strainMethod = false); + const bool& caret5method = false, const bool& edgeMethod = false, + const bool& strainMethod = false, const bool& strainLog2 = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmSurfaceSphereProjectUnproject.cxx b/src/Algorithms/AlgorithmSurfaceSphereProjectUnproject.cxx index 9fd61b09927927dd929549f69cde44d8ac6eff29..63cd83852df87aa7e5b8d29252ecde4bb5a52c59 100644 --- a/src/Algorithms/AlgorithmSurfaceSphereProjectUnproject.cxx +++ b/src/Algorithms/AlgorithmSurfaceSphereProjectUnproject.cxx @@ -38,25 +38,47 @@ AString AlgorithmSurfaceSphereProjectUnproject::getCommandSwitch() AString AlgorithmSurfaceSphereProjectUnproject::getShortDescription() { - return "DEFORM A SPHERE ACCORDING TO A REGISTRATION"; + return "COPY REGISTRATION DEFORMATIONS TO DIFFERENT SPHERE"; } OperationParameters* AlgorithmSurfaceSphereProjectUnproject::getParameters() { OperationParameters* ret = new OperationParameters(); - ret->addSurfaceParameter(1, "sphere-in", "the sphere with the desired output mesh"); + ret->addSurfaceParameter(1, "sphere-in", "a sphere with the desired output mesh"); ret->addSurfaceParameter(2, "sphere-project-to", "a sphere that aligns with sphere-in"); - ret->addSurfaceParameter(3, "sphere-unproject-from", "sphere-project-to deformed to the output space"); + ret->addSurfaceParameter(3, "sphere-unproject-from", " deformed to the desired output space"); ret->addSurfaceOutputParameter(4, "sphere-out", "the output sphere"); ret->setHelpText( - AString("Each vertex of is projected to to obtain barycentric weights, which are then used to unproject ") + - "from . This results in a sphere with the topology of , but coordinates shifted by the deformation between " + - " and . and must have the same topology as each other, " + - "but may have different topology." + AString("Background: A surface registration starts with an input sphere, and moves its vertices around on the sphere until it matches the template data. ") + + "This means that the registration deformation is actually represented as the difference between two separate files - the starting sphere, and the registered sphere. " + + "Since the starting sphere of the registration may not have vertex correspondence to any other sphere (often, it is a native sphere), it can be inconvenient to manipulate or compare these deformations across subjects, etc.\n\n" + + + "The purpose of this command is to be able to apply these deformations onto a new sphere of the user's choice, to make it easier to compare or manipulate them. " + + "Common uses are to concatenate two successive separate registrations (e.g. Human to Chimpanzee, and then Chimpanzee to Macaque) or inversion (for dedrifting or symmetric registration schemes).\n\n" + + + " must already be considered to be in alignment with one of the two ends of the registration (if your registration is Human to Chimpanzee, must be in register with either Human or Chimpanzee). " + + "The 'project-to' sphere must be the side of the registration that is aligned with (if your registration is Human to Chimpanzee, and is aligned with Human, then 'project-to' should be the original Human sphere). " + + "The 'unproject-from' sphere must be the remaining sphere of the registration (original vs deformed/registered). " + + "The output is as if you had run the same registration with as the starting sphere, in the direction of deforming the 'project-to' sphere to create the 'unproject-from' sphere.\n\n" + + + "Note that this command cannot check for you what spheres are aligned with other spheres, and using the wrong spheres or in the incorrect order will not necessarily cause an error message. " + + "In some cases, it may be useful to use a new, arbitrary sphere as the input, which can be created with the -surface-create-sphere command.\n\n" + + + "Example 1: You have a Human to Chimpanzee registration, and a Chimpanzee to Macaque registration, and want to combine them. " + + "If you use the Human sphere registered to Chimpanzee as sphere-in, the Chimpanzee standard sphere as project-to, and " + + "the Chimpanzee sphere registered to Macaque as unproject-from, the output will be the Human sphere in register with the Macaque.\n\n" + + + "Example 2: You have a Human to Chimpanzee registration, but what you really want is the inverse, that is, the sphere as if you had run the registration from Chimpanzee to Human. " + + "If you use the Chimpanzee standard sphere as sphere-in, the Human sphere registered to Chimpanzee as project-to, and the standard Human sphere as unproject-from, " + + "the output will be the Chimpanzee sphere in register with the Human.\n\n" + + + "Technical details: Each vertex of is projected to a triangle of , and its new position is determined by the position of the corresponding triangle in . " + + "The output is a sphere with the topology of , but coordinates shifted by the deformation from to . " + + " and must have the same topology as each other, but may have any topology." ); return ret; } diff --git a/src/Algorithms/AlgorithmTemplate.cxx.txt b/src/Algorithms/AlgorithmTemplate.cxx.txt index 107650d1f447af09509d20f3593bed5fc7b1a275..e6d29286a1dc115baead77af871525a5108ce498 100644 --- a/src/Algorithms/AlgorithmTemplate.cxx.txt +++ b/src/Algorithms/AlgorithmTemplate.cxx.txt @@ -42,8 +42,8 @@ OperationParameters* AlgorithmName::getParameters() //ret->addMetricOutputParameter(2, "metric-out", "the output metric"); - //OptionalParameter* columnSelect = ret->createOptionalParameter(3, "-column", "select a single column"); - //columnSelect->addStringParameter(1, "column", "the column number or name"); + //OptionalParameter* columnOpt = ret->createOptionalParameter(3, "-column", "select a single column"); + //columnOpt->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("This is where you set the help text. ") + @@ -59,15 +59,12 @@ void AlgorithmName::useParameters(OperationParameters* myParams, ProgressObject* { //SurfaceFile* mySurf = myParams->getSurface(1);//gets the surface with key 1 //MetricFile* myMetricOut = myParams->getOutputMetric(2);//gets the output metric with key 2 - /*OptionalParameter* columnSelect = myParams->getOptionalParameter(3);//gets optional parameter with key 3 - int columnNum = -1; - if (columnSelect->m_present) - {//set up to use the single column - columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); - if (columnNum < 0) - { - throw AlgorithmException("invalid column specified"); - } + /*OptionalParameter* columnOpt = myParams->getOptionalParameter(3);//gets option with key 3 + int column = -1; + if (columnOpt->m_present) + {//set up to use a single column + column = myMetric->getMapIndexFromNameOrNumber(columnOpt->getString(1)); + if (column < 0) throw AlgorithmException("invalid column specified"); }//*/ AlgorithmName(myProgObj /*INSERT PARAMETERS HERE*/);//executes the algorithm } diff --git a/src/Algorithms/AlgorithmVolumeAffineResample.cxx b/src/Algorithms/AlgorithmVolumeAffineResample.cxx index bd23d04346a6b3b5bdececf5fd397d90c34399a9..34dcf405f8a267aad22a364f01cd35b209547701 100644 --- a/src/Algorithms/AlgorithmVolumeAffineResample.cxx +++ b/src/Algorithms/AlgorithmVolumeAffineResample.cxx @@ -113,7 +113,7 @@ AlgorithmVolumeAffineResample::AlgorithmVolumeAffineResample(ProgressObject* myP outDims[1] = refDims[1]; outDims[2] = refDims[2]; int64_t numMaps = inVol->getNumberOfMaps(), numComponents = inVol->getNumberOfComponents(); - outVol->reinitialize(outDims, refSform, numComponents, inVol->getType()); + outVol->reinitialize(outDims, refSform, numComponents, inVol->getType(), inVol->m_header); FloatMatrix targetToSource = myAffine; targetToSource.resize(4, 4); targetToSource[3][0] = 0.0f; diff --git a/src/Algorithms/AlgorithmVolumeDilate.cxx b/src/Algorithms/AlgorithmVolumeDilate.cxx index 55fc9e4e112695aba732d087c0183a3ae905554a..66132f1c32c5763b210727dcb74ec0cf04285254 100644 --- a/src/Algorithms/AlgorithmVolumeDilate.cxx +++ b/src/Algorithms/AlgorithmVolumeDilate.cxx @@ -24,11 +24,13 @@ #include "CaretHeap.h" #include "CaretLogger.h" #include "CaretOMP.h" +#include "CaretPointLocator.h" #include "FloatMatrix.h" #include "Vector3D.h" #include "VolumeFile.h" #include "VoxelIJK.h" +#include #include #include @@ -57,7 +59,7 @@ OperationParameters* AlgorithmVolumeDilate::getParameters() ret->addVolumeOutputParameter(4, "volume-out", "the output volume"); OptionalParameter* exponentOpt = ret->createOptionalParameter(8, "-exponent", "use a different exponent in the weighting function"); - exponentOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 2)"); + exponentOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 7)"); OptionalParameter* badRoiOpt = ret->createOptionalParameter(5, "-bad-voxel-roi", "specify an roi of voxels to overwrite, rather than voxels with value zero"); badRoiOpt->addVolumeParameter(1, "roi-volume", "volume file, positive values denote voxels to have their values replaced"); @@ -68,12 +70,15 @@ OperationParameters* AlgorithmVolumeDilate::getParameters() OptionalParameter* subvolSelect = ret->createOptionalParameter(6, "-subvolume", "select a single subvolume to dilate"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); + ret->createOptionalParameter(9, "-legacy-cutoff", "use the old method of excluding voxels further than the dilation distance when calculating the dilated value"); + ret->setHelpText( AString("For all voxels that are designated as bad, if they neighbor a non-bad voxel with data or are within the specified distance of such a voxel, ") + "replace the value in the bad voxel with a value calculated from nearby non-bad voxels that have data, otherwise set the value to zero. " + "No matter how small is, dilation will always use at least the face neighbor voxels.\n\n" + "By default, voxels that have data with the value 0 are bad, specify -bad-voxel-roi to only count voxels as bad if they are selected by the roi. " + "If -data-roi is not specified, all voxels are assumed to have data.\n\n" + + "To get the behavior of version 1.3.2 or earlier, use '-legacy-cutoff -exponent 2'.\n\n" + "Valid values for are:\n\n" + "NEAREST - use the value from the nearest good voxel\n" + "WEIGHTED - use a weighted average based on distance" @@ -97,7 +102,7 @@ void AlgorithmVolumeDilate::useParameters(OperationParameters* myParams, Progres } VolumeFile* volOut = myParams->getOutputVolume(4); OptionalParameter* exponentOpt = myParams->getOptionalParameter(8); - float exponent = 2.0f; + float exponent = 7.0f; if (exponentOpt->m_present) { exponent = (float)exponentOpt->getDouble(1); @@ -121,445 +126,350 @@ void AlgorithmVolumeDilate::useParameters(OperationParameters* myParams, Progres subvol = volIn->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvol < 0) throw AlgorithmException("invalid subvolume specified"); } - AlgorithmVolumeDilate(myProgObj, volIn, distance, myMethod, volOut, badRoi, dataRoi, subvol, exponent); + bool legacyCutoff = myParams->getOptionalParameter(9)->m_present; + AlgorithmVolumeDilate(myProgObj, volIn, distance, myMethod, volOut, badRoi, dataRoi, subvol, exponent, legacyCutoff); } -AlgorithmVolumeDilate::AlgorithmVolumeDilate(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, const Method& myMethod, - VolumeFile* volOut, const VolumeFile* badRoi, const VolumeFile* dataRoi, const int& subvol, const float& exponent) : AbstractAlgorithm(myProgObj) +namespace { - LevelProgress myProgress(myProgObj); - vector myDims; - volIn->getDimensions(myDims); - if (subvol < -1 || subvol >= myDims[3]) - { - throw AlgorithmException("invalid subvolume specified"); - } - if (distance < 0.0f) - { - throw AlgorithmException("distance cannot be negative"); - } - if (badRoi != NULL && !volIn->matchesVolumeSpace(badRoi)) - { - throw AlgorithmException("bad voxel roi volume space does not match input volume"); - } - if (dataRoi != NULL && !volIn->matchesVolumeSpace(dataRoi)) - { - throw AlgorithmException("data roi volume space does not match input volume"); - } - bool isLabelData = false; - if (volIn->getType() == SubvolumeAttributes::LABEL) - { - isLabelData = true; - } - vector > volSpace = volIn->getSform(); - Vector3D ivec, jvec, kvec, origin, ijorth, jkorth, kiorth; - FloatMatrix(volSpace).getAffineVectors(ivec, jvec, kvec, origin); - ijorth = ivec.cross(jvec).normal();//find the bounding box that encloses a sphere of radius kernBox - jkorth = jvec.cross(kvec).normal(); - kiorth = kvec.cross(ivec).normal(); - int irange = (int)floor(abs(distance / ivec.dot(jkorth))); - int jrange = (int)floor(abs(distance / jvec.dot(kiorth))); - int krange = (int)floor(abs(distance / kvec.dot(ijorth))); - if (irange < 1) irange = 1;//don't underflow - if (jrange < 1) jrange = 1; - if (krange < 1) krange = 1; - Vector3D kscratch, jscratch, iscratch; - vector stencil; - vector stenWeights; - for (int k = -krange; k <= krange; ++k) - { - kscratch = kvec * k; - for (int j = -jrange; j <= jrange; ++j) + + inline bool copyVoxel(const bool labelMode, const int32_t unlabeledKey, const int64_t i, const int64_t j, const int64_t k, const VolumeFile* volIn, const int& insubvol, const int& component, + const VolumeFile* badRoi, const VolumeFile* dataRoi) + {//copy all voxels that are not to be replaced + if (badRoi == NULL) { - jscratch = kscratch + jvec * j; - for (int i = -irange; i <= irange; ++i) + if (labelMode) { - if (k == 0 && j == 0 && i == 0) continue; - iscratch = jscratch + ivec * i; - float tempf = iscratch.length(); - if (tempf <= distance || abs(i) + abs(j) + abs(k) == 1) - { - stencil.push_back(i); - stencil.push_back(j); - stencil.push_back(k); - switch (myMethod) - { - case NEAREST: - stenWeights.push_back(tempf); - break; - case WEIGHTED: - if (tempf == 0.0f) throw AlgorithmException("volume space is degenerate, aborting"); - stenWeights.push_back(1.0f / pow(tempf, exponent)); - break; - } - } + return (dataRoi != NULL && !(dataRoi->getValue(i, j, k) > 0.0f)) || floor(0.5f + volIn->getValue(i, j, k, insubvol, component)) != unlabeledKey; + } else { + return (dataRoi != NULL && !(dataRoi->getValue(i, j, k) > 0.0f)) || volIn->getValue(i, j, k, insubvol, component) != 0.0f; } + } else { + return !(badRoi->getValue(i, j, k) > 0.0f);//in case some clown uses NaNs instead of 0s in an roi } } - if (myMethod == NEAREST) - {//sort the stencil by distance, so we can stop early - CaretSimpleMinHeap myHeap; - int stencilSize = (int)stenWeights.size(); - myHeap.reserve(stencilSize); - for (int i = 0; i < stencilSize; ++i) - { - myHeap.push(VoxelIJK(stencil.data() + i * 3), stenWeights[i]); - } - stencil.clear(); - stenWeights.clear(); - while (!myHeap.isEmpty()) - { - float tempf; - VoxelIJK myTriple = myHeap.pop(&tempf); - stenWeights.push_back(tempf); - stencil.push_back(myTriple.m_ijk[0]); - stencil.push_back(myTriple.m_ijk[1]); - stencil.push_back(myTriple.m_ijk[2]); - } - } - if (subvol == -1) - { - volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType()); - for (int i = 0; i < myDims[3]; ++i) + + inline bool voxelUsable(const bool labelMode, const int32_t unlabeledKey, const int64_t i, const int64_t j, const int64_t k, const VolumeFile* volIn, const int& insubvol, const int& component, + const VolumeFile* badRoi, const VolumeFile* dataRoi) + {//only voxels that are inside the data ROI and not to be replaced + if (badRoi == NULL) { - if (volIn->getType() == SubvolumeAttributes::LABEL) + if (labelMode) { - *(volOut->getMapLabelTable(i)) = *(volIn->getMapLabelTable(i)); + return (dataRoi == NULL || dataRoi->getValue(i, j, k) > 0.0f) && floor(0.5f + volIn->getValue(i, j, k, insubvol, component)) != unlabeledKey; } else { - *(volOut->getMapPaletteColorMapping(i)) = *(volIn->getMapPaletteColorMapping(i)); + return (dataRoi == NULL || dataRoi->getValue(i, j, k) > 0.0f) && volIn->getValue(i, j, k, insubvol, component) != 0.0f; } - volOut->setMapName(i, volIn->getMapName(i) + " dilate " + AString::number(distance)); - } - } else { - vector outDims = myDims; - outDims.resize(3); - volOut->reinitialize(outDims, volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType()); - if (volIn->getType() == SubvolumeAttributes::LABEL) - { - *(volOut->getMapLabelTable(0)) = *(volIn->getMapLabelTable(subvol)); } else { - *(volOut->getMapPaletteColorMapping(0)) = *(volIn->getMapPaletteColorMapping(subvol)); + return (dataRoi == NULL || dataRoi->getValue(i, j, k) > 0.0f) && !(badRoi->getValue(i, j, k) > 0.0f); } - volOut->setMapName(0, volIn->getMapName(subvol) + " dilate " + AString::number(distance)); } - if (subvol == -1) - { - for (int s = 0; s < myDims[3]; ++s) + + void dilateFrame(const bool labelMode, const VolumeFile* volIn, const int& insubvol, const int& component, VolumeFile* volOut, const int& outsubvol, const VolumeFile* badRoi, + const VolumeFile* dataRoi, const float& distance, const AlgorithmVolumeDilate::Method& myMethod, const float& exponent, const bool& legacyCutoff) + {//copy data that is outside the dataROI, replace values where badROI is > 0 (with zero if nothing else), if no badROI, pretend badROI is (data == 0 && dataROI > 0) + int neighbors[18] = {0, 0, -1, + 0, -1, 0, + -1, 0, 0, + 1, 0, 0, + 0, 1, 0, + 0, 0, 1};//special behavior: when distance is 0, it still dilates by 1 voxel + Vector3D voxStep[3], origin; + const VolumeSpace& myVolSpace = volIn->getVolumeSpace(); + myVolSpace.getSpacingVectors(voxStep[0], voxStep[1], voxStep[2], origin); + //if the distance is within 1% of excluding a neighbor, we need to additionally check the neighbors + bool checkNeighbors = distance <= voxStep[0].length() * 1.01f || distance <= voxStep[1].length() * 1.01f || distance <= voxStep[2].length() * 1.01f; + //the single-voxel rule means we can't just base the maximum search distance on the dilation distance + float cutoffBase = max(2.0f * distance, 2.0f * min(min(voxStep[0].length(), voxStep[1].length()), voxStep[2].length())); + vector myDims = volIn->getDimensions(); + int32_t unlabeledKey = 0; + if (labelMode) unlabeledKey = volIn->getMapLabelTable(insubvol)->getUnassignedLabelKey(); + vector validPoints; + vector validIndices; + for (int64_t k = 0; k < myDims[2]; ++k) { - for (int c = 0; c < myDims[4]; ++c) + for (int64_t j = 0; j < myDims[1]; ++j) { - if (isLabelData) + for (int64_t i = 0; i < myDims[0]; ++i) { - dilateFrameLabel(volIn, s, c, volOut, s, badRoi, dataRoi, myMethod, stencil, stenWeights); - } else { - dilateFrame(volIn, s, c, volOut, s, badRoi, dataRoi, myMethod, stencil, stenWeights); + if (voxelUsable(labelMode, unlabeledKey, i, j, k, volIn, insubvol, component, badRoi, dataRoi)) + { + VoxelIJK tempVoxel(i, j, k); + Vector3D tempCoord = myVolSpace.indexToSpace(tempVoxel); + validPoints.push_back(tempCoord[0]); + validPoints.push_back(tempCoord[1]); + validPoints.push_back(tempCoord[2]); + validIndices.push_back(tempVoxel); + } } } } - } else { - for (int c = 0; c < myDims[4]; ++c) - { - if (isLabelData) - { - dilateFrameLabel(volIn, subvol, c, volOut, 0, badRoi, dataRoi, myMethod, stencil, stenWeights); - } else { - dilateFrame(volIn, subvol, c, volOut, 0, badRoi, dataRoi, myMethod, stencil, stenWeights); - } - } - } -} - -void AlgorithmVolumeDilate::dilateFrame(const VolumeFile* volIn, const int& insubvol, const int& component, VolumeFile* volOut, const int& outsubvol, - const VolumeFile* badRoi, const VolumeFile* dataRoi, const Method& myMethod, const vector& stencil, const vector& stenWeights) -{ - vector myDims; - volIn->getDimensions(myDims); - int stensize = (int)stenWeights.size(); + CaretPointLocator locator(validPoints); #pragma omp CARET_PARFOR schedule(dynamic) - for (int k = 0; k < myDims[2]; ++k) - { - for (int j = 0; j < myDims[1]; ++j) + for (int64_t k = 0; k < myDims[2]; ++k) { - for (int i = 0; i < myDims[0]; ++i) + for (int64_t j = 0; j < myDims[1]; ++j) { - bool copy = true; - if (badRoi == NULL) - { - copy = volIn->getValue(i, j, k, insubvol, component) != 0.0f || (dataRoi != NULL && !(dataRoi->getValue(i, j, k) > 0.0f)); - } else { - copy = !(badRoi->getValue(i, j, k) > 0.0f);//in case some clown uses NaNs as bad in an roi - } - if (copy) + for (int64_t i = 0; i < myDims[0]; ++i) { - volOut->setValue(volIn->getValue(i, j, k, insubvol, component), i, j, k, outsubvol, component); - } else { - Vector3D voxcoord; - volIn->indexToSpace(i, j, k, voxcoord); - switch (myMethod) + if (copyVoxel(labelMode, unlabeledKey, i, j, k, volIn, insubvol, component, badRoi, dataRoi)) { - case NEAREST: + if (labelMode) + { + volOut->setValue(floor(0.5f + volIn->getValue(i, j, k, insubvol, component)), i, j, k, outsubvol, component); + } else { + volOut->setValue(volIn->getValue(i, j, k, insubvol, component), i, j, k, outsubvol, component); + } + } else { + Vector3D voxcoord = myVolSpace.indexToSpace(i, j, k); + switch (myMethod) { - int best = -1; - if (badRoi == NULL) + case AlgorithmVolumeDilate::NEAREST: { - for (int stenind = 0; stenind < stensize; ++stenind) + int64_t index = locator.closestPointLimited(voxcoord, distance); + if (index < 0) { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) + if (checkNeighbors) { - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && volIn->getValue(tempindex, insubvol, component) != 0.0f) + float bestDist = -1.0f; + float bestVal = 0.0f; + for (int n = 0; n < 6; ++n) { - best = stenind; - break; + int neighbase = n * 3; + int64_t neighVox[3] = {i + neighbors[neighbase], j + neighbors[neighbase + 1], k + neighbors[neighbase + 2]}; + if (myVolSpace.indexValid(neighVox) && voxelUsable(labelMode, unlabeledKey, neighVox[0], neighVox[1], neighVox[2], volIn, insubvol, component, badRoi, dataRoi)) + { + float tempdist = (myVolSpace.indexToSpace(neighbors + neighbase) - myVolSpace.indexToSpace(0, 0, 0)).length();//slightly hacky, but won't have inconsistencies from different rounding per voxel + if (tempdist < bestDist || bestDist == -1.0f) + { + bestDist = tempdist; + bestVal = volIn->getValue(neighVox, insubvol, component); + } + } } - } - } - } else { - for (int stenind = 0; stenind < stensize; ++stenind) - { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) - { - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && !(badRoi->getValue(tempindex) > 0.0f)) + if (labelMode) { - best = stenind; - break; + volOut->setValue(floor(0.5f + bestVal), i, j, k, outsubvol, component); + } else { + volOut->setValue(bestVal, i, j, k, outsubvol, component); } + } else { + volOut->setValue(0.0f, i, j, k, outsubvol, component); + } + } else { + if (labelMode) + { + volOut->setValue(floor(0.5f + volIn->getValue(validIndices[index], insubvol, component)), i, j, k, outsubvol, component); + } else { + volOut->setValue(volIn->getValue(validIndices[index], insubvol, component), i, j, k, outsubvol, component); } } + break; } - if (best == -1) - { - volOut->setValue(0.0f, i, j, k, outsubvol, component); - } else { - int base = best * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - volOut->setValue(volIn->getValue(tempindex, insubvol, component), i, j, k, outsubvol, component); - } - break; - } - case WEIGHTED: - { - double sum = 0.0, weightsum = 0.0; - if (badRoi == NULL) + case AlgorithmVolumeDilate::WEIGHTED: { - for (int stenind = 0; stenind < stensize; ++stenind) + vector inRange; + if (legacyCutoff) { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) + inRange = locator.pointsInRange(voxcoord, distance);//immediate neighbor special case is handled below + } else { + float closeDist = -1.0f; + LocatorInfo myInfo; + int64_t index = locator.closestPointLimited(voxcoord, distance, &myInfo);//only need the distance + bool found = false; + if (index >= 0) { - float tempf = volIn->getValue(tempindex, insubvol, component); - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && tempf != 0.0f) - { - float weight = stenWeights[stenind]; - sum += weight * tempf; - weightsum += weight; + found = true; + closeDist = (myInfo.coords - voxcoord).length(); + } else { + if (checkNeighbors) + {//always dilate to neighbor voxels, regardless + for (int n = 0; n < 6; ++n) + { + int neighbase = n * 3; + int64_t neighVox[3] = {i + neighbors[neighbase], j + neighbors[neighbase + 1], k + neighbors[neighbase + 2]}; + if (myVolSpace.indexValid(neighVox) && voxelUsable(labelMode, unlabeledKey, neighVox[0], neighVox[1], neighVox[2], volIn, insubvol, component, badRoi, dataRoi)) + { + float tempdist = (myVolSpace.indexToSpace(neighbors + neighbase) - myVolSpace.indexToSpace(0, 0, 0)).length();//slightly hacky, but won't have inconsistencies from different rounding per voxel + if (tempdist < closeDist || !found) + { + found = true; + closeDist = tempdist; + } + } + } } } - } - } else { - for (int stenind = 0; stenind < stensize; ++stenind) - { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) + if (found) { - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && !(badRoi->getValue(tempindex) > 0.0f)) + //find what cutoff corresponds to 98% of the total weight being found compared to an infinite kernel + //to do this, assume a non-adversarial situation, where farther parts have at most equal angular area to closer ones + //49 = 98/(100-98) + float cutoffRatio = max(1.1f, pow(49.0f, 1.0f / (exponent - 3.0f))), cutoffDist = cutoffBase;//find what cutoff ratio corresponds to a hudredth of weight + if (exponent > 3.0f && cutoffRatio < 100.0f && cutoffRatio > 1.0f)//if the ratio is sane, use it, but never exceed cutoffBase { - float tempf = volIn->getValue(tempindex, insubvol, component); - float weight = stenWeights[stenind]; - sum += weight * tempf; - weightsum += weight; + cutoffDist = max(min(cutoffRatio * closeDist, cutoffDist), cutoffBase * 0.25f);//but small kernels are rather cheap anyway, so have a minimum size just in case } + inRange = locator.pointsInRange(voxcoord, cutoffDist); } } - } - if (weightsum != 0.0) - { - volOut->setValue(sum / weightsum, i, j, k, outsubvol, component); - } else { - volOut->setValue(0.0f, i, j, k, outsubvol, component); - } - break; - } - } - } - } - } - } -} - -void AlgorithmVolumeDilate::dilateFrameLabel(const VolumeFile* volIn, const int& insubvol, const int& component, VolumeFile* volOut, const int& outsubvol, - const VolumeFile* badRoi, const VolumeFile* dataRoi, const Method& myMethod, const vector& stencil, const vector& stenWeights) -{ - vector myDims; - volIn->getDimensions(myDims); - int stensize = (int)stenWeights.size(); - int32_t unlabeledKey = volIn->getMapLabelTable(insubvol)->getUnassignedLabelKey(); -#pragma omp CARET_PARFOR schedule(dynamic) - for (int k = 0; k < myDims[2]; ++k) - { - for (int j = 0; j < myDims[1]; ++j) - { - for (int i = 0; i < myDims[0]; ++i) - { - bool copy = true; - int32_t keyIn = floor(volIn->getValue(i, j, k, insubvol, component) + 0.5f);//fix non-integers - if (badRoi == NULL) - { - copy = keyIn != unlabeledKey || (dataRoi != NULL && !(dataRoi->getValue(i, j, k) > 0.0f)); - } else { - copy = !(badRoi->getValue(i, j, k) > 0.0f);//in case some clown uses NaNs as bad in an roi - } - if (copy) - { - volOut->setValue(keyIn, i, j, k, outsubvol, component); - } else { - Vector3D voxcoord; - volIn->indexToSpace(i, j, k, voxcoord); - switch (myMethod) - { - case NEAREST: - { - int best = -1; - if (badRoi == NULL) - { - for (int stenind = 0; stenind < stensize; ++stenind) - { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) + map labelSums; + double sum = 0.0, weightsum = 0.0; + if (legacyCutoff && checkNeighbors) + {//add valid neighbors only if they aren't already in the list, and the non-legacy mode is already handled above... + set voxelsToUse;//but looking up the neighbors' indices in validIndices is work we don't need to do, so copy the list and add to it + for (auto thisInfo : inRange) { - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && volIn->getValue(tempindex, insubvol, component) != 0.0f) - { - best = stenind; - break; - } + voxelsToUse.insert(validIndices[thisInfo.index]); } - } - } else { - for (int stenind = 0; stenind < stensize; ++stenind) - { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) + for (int n = 0; n < 6; ++n) { - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && !(badRoi->getValue(tempindex) > 0.0f)) + int neighbase = n * 3; + int64_t neighVox[3] = {i + neighbors[neighbase], j + neighbors[neighbase + 1], k + neighbors[neighbase + 2]}; + if (myVolSpace.indexValid(neighVox) && voxelUsable(labelMode, unlabeledKey, neighVox[0], neighVox[1], neighVox[2], volIn, insubvol, component, badRoi, dataRoi)) { - best = stenind; - break; + voxelsToUse.insert(neighVox);//set eliminates duplicates } } - } - } - if (best == -1) - { - volOut->setValue(unlabeledKey, i, j, k, outsubvol, component); - } else { - int base = best * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - volOut->setValue((int32_t)floor(volIn->getValue(tempindex, insubvol, component) + 0.5f), i, j, k, outsubvol, component);//fix non-integers - }//yes, the cast is undefined for silly things like NaN that shouldn't be in a label file, but so are the other paths - we just want consistency between behavior of old and new values - break; - } - case WEIGHTED: - { - map labelSums; - if (badRoi == NULL) - { - for (int stenind = 0; stenind < stensize; ++stenind) - { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) + for (auto thisVoxel : voxelsToUse)//unfortunately, this means we need to write a copy of the loop for the common case not to do unneeded work { - int32_t tempKey = floor(volIn->getValue(tempindex, insubvol, component) + 0.5f);//fix non-integers - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && tempKey != unlabeledKey) + float thisdist = (myVolSpace.indexToSpace(thisVoxel) - voxcoord).length(); + float weight = 1.0f / pow(thisdist, exponent); + if (labelMode) { - float weight = stenWeights[stenind]; - map::iterator iter = labelSums.find(tempKey); + int32_t thisKey = int32_t(floor(0.5f + volIn->getValue(thisVoxel, insubvol, component))); + map::iterator iter = labelSums.find(thisKey); if (iter == labelSums.end()) { - labelSums[tempKey] = weight; + labelSums[thisKey] = weight; } else { iter->second += weight; } + } else { + sum += weight * volIn->getValue(thisVoxel, insubvol, component); + weightsum += weight; } } - } - } else { - for (int stenind = 0; stenind < stensize; ++stenind) - { - int base = stenind * 3; - int64_t tempindex[3]; - tempindex[0] = stencil[base] + i; - tempindex[1] = stencil[base + 1] + j; - tempindex[2] = stencil[base + 2] + k; - if (volIn->indexValid(tempindex)) + } else { + for (auto thisInfo : inRange) { - if ((dataRoi == NULL || dataRoi->getValue(tempindex) > 0.0f) && !(badRoi->getValue(tempindex) > 0.0f)) + float thisdist = (thisInfo.coords - voxcoord).length(); + float weight = 1.0f / pow(thisdist, exponent); + if (labelMode) { - int32_t tempKey = floor(volIn->getValue(tempindex, insubvol, component) + 0.5f);//fix non-integers - float weight = stenWeights[stenind]; - map::iterator iter = labelSums.find(tempKey); + int32_t thisKey = int32_t(floor(0.5f + volIn->getValue(validIndices[thisInfo.index], insubvol, component))); + map::iterator iter = labelSums.find(thisKey); if (iter == labelSums.end()) { - labelSums[tempKey] = weight; + labelSums[thisKey] = weight; } else { iter->second += weight; } + } else { + sum += weight * volIn->getValue(validIndices[thisInfo.index], insubvol, component); + weightsum += weight; } } } - } - int32_t outVal = unlabeledKey; - float bestSum = -1.0f;//weights should all be positive, so should the sums - for (map::iterator iter = labelSums.begin(); iter != labelSums.end(); ++iter) - { - if (iter->second > bestSum) + if (labelMode) { - outVal = iter->first; - bestSum = iter->second; + float bestWeight = -1.0f;//all weights should be positive, so their sums should too + int32_t bestKey = unlabeledKey; + for (auto iter : labelSums) + { + if (iter.second > bestWeight) + { + bestWeight = iter.second; + bestKey = iter.first; + } + } + volOut->setValue(bestKey, i, j, k, outsubvol, component); + } else { + if (weightsum > 0.0) + { + volOut->setValue(sum / weightsum, i, j, k, outsubvol, component); + } else { + volOut->setValue(0.0f, i, j, k, outsubvol, component); + } } + break; } - volOut->setValue(outVal, i, j, k, outsubvol, component); - break; } } } } } } + +} + +AlgorithmVolumeDilate::AlgorithmVolumeDilate(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, const Method& myMethod, VolumeFile* volOut, + const VolumeFile* badRoi, const VolumeFile* dataRoi, const int& subvol, const float& exponent, const bool legacyCutoff) : AbstractAlgorithm(myProgObj) +{ + LevelProgress myProgress(myProgObj); + vector myDims; + volIn->getDimensions(myDims); + if (subvol < -1 || subvol >= myDims[3]) + { + throw AlgorithmException("invalid subvolume specified"); + } + if (distance < 0.0f) + { + throw AlgorithmException("distance cannot be negative"); + } + if (badRoi != NULL && !volIn->matchesVolumeSpace(badRoi)) + { + throw AlgorithmException("bad voxel roi volume space does not match input volume"); + } + if (dataRoi != NULL && !volIn->matchesVolumeSpace(dataRoi)) + { + throw AlgorithmException("data roi volume space does not match input volume"); + } + bool isLabelData = false; + if (volIn->getType() == SubvolumeAttributes::LABEL) + { + isLabelData = true; + } + if (subvol == -1) + { + volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); + for (int i = 0; i < myDims[3]; ++i) + { + if (volIn->getType() == SubvolumeAttributes::LABEL) + { + *(volOut->getMapLabelTable(i)) = *(volIn->getMapLabelTable(i)); + } else { + *(volOut->getMapPaletteColorMapping(i)) = *(volIn->getMapPaletteColorMapping(i)); + } + volOut->setMapName(i, volIn->getMapName(i) + " dilate " + AString::number(distance)); + } + } else { + vector outDims = myDims; + outDims.resize(3); + volOut->reinitialize(outDims, volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); + if (volIn->getType() == SubvolumeAttributes::LABEL) + { + *(volOut->getMapLabelTable(0)) = *(volIn->getMapLabelTable(subvol)); + } else { + *(volOut->getMapPaletteColorMapping(0)) = *(volIn->getMapPaletteColorMapping(subvol)); + } + volOut->setMapName(0, volIn->getMapName(subvol) + " dilate " + AString::number(distance)); + } + if (subvol == -1) + { + for (int s = 0; s < myDims[3]; ++s) + { + for (int c = 0; c < myDims[4]; ++c) + { + dilateFrame(isLabelData, volIn, s, c, volOut, s, badRoi, dataRoi, distance, myMethod, exponent, legacyCutoff); + } + } + } else { + for (int c = 0; c < myDims[4]; ++c) + { + dilateFrame(isLabelData, volIn, subvol, c, volOut, 0, badRoi, dataRoi, distance, myMethod, exponent, legacyCutoff); + } + } } float AlgorithmVolumeDilate::getAlgorithmInternalWeight() diff --git a/src/Algorithms/AlgorithmVolumeDilate.h b/src/Algorithms/AlgorithmVolumeDilate.h index ad3452d978404f103185a5bc85a29d45f87e83f3..7a9b7231f7343ef2db4bacd6a3bfa08d045ff93f 100644 --- a/src/Algorithms/AlgorithmVolumeDilate.h +++ b/src/Algorithms/AlgorithmVolumeDilate.h @@ -37,17 +37,12 @@ namespace caret { NEAREST, WEIGHTED }; - AlgorithmVolumeDilate(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, const Method& myMethod, - VolumeFile* volOut, const VolumeFile* badRoi = NULL, const VolumeFile* dataRoi = NULL, const int& subvol = -1, const float& exponent = 2.0f); + AlgorithmVolumeDilate(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, const Method& myMethod, VolumeFile* volOut, + const VolumeFile* badRoi = NULL, const VolumeFile* dataRoi = NULL, const int& subvol = -1, const float& exponent = 7.0f, const bool legacyCutoff = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); - private: - void dilateFrame(const VolumeFile* volIn, const int& insubvol, const int& component, VolumeFile* volOut, const int& outsubvol, const VolumeFile* badRoi, - const VolumeFile* dataRoi, const Method& myMethod, const std::vector& stencil, const std::vector& stenWeights); - void dilateFrameLabel(const VolumeFile* volIn, const int& insubvol, const int& component, VolumeFile* volOut, const int& outsubvol, const VolumeFile* badRoi, - const VolumeFile* dataRoi, const Method& myMethod, const std::vector& stencil, const std::vector& stenWeights); }; typedef TemplateAutoOperation AutoAlgorithmVolumeDilate; diff --git a/src/Algorithms/AlgorithmVolumeDistortion.cxx b/src/Algorithms/AlgorithmVolumeDistortion.cxx index 7b1e5673d108a6b89e1278cf5e3640f85f940657..4f8eab55a4ab047c47665020dc9f6a19cd948614 100644 --- a/src/Algorithms/AlgorithmVolumeDistortion.cxx +++ b/src/Algorithms/AlgorithmVolumeDistortion.cxx @@ -56,6 +56,8 @@ OperationParameters* AlgorithmVolumeDistortion::getParameters() ret->createOptionalParameter(4, "-circular", "use the circle-based formula for the anisotropic measure"); + ret->createOptionalParameter(5, "-log2", "apply base-2 log transform"); + ret->setHelpText( AString("Calculates isotropic and anisotropic distortions in the volume warpfield. ") + "At each voxel, the gradient of the absolute warpfield is computed to obtain the local affine transforms for each voxel (jacobian matrices), and strain tensors are derived from them. " + @@ -74,6 +76,7 @@ void AlgorithmVolumeDistortion::useParameters(OperationParameters* myParams, Pro OptionalParameter* fnirtOpt = myParams->getOptionalParameter(3); Method myMethod = ELONGATION; if (myParams->getOptionalParameter(4)->m_present) myMethod = CIRCULAR; + bool dolog2 = myParams->getOptionalParameter(5)->m_present; WarpfieldFile myWarp; if (fnirtOpt->m_present) { @@ -81,10 +84,10 @@ void AlgorithmVolumeDistortion::useParameters(OperationParameters* myParams, Pro } else { myWarp.readWorld(warpName); } - AlgorithmVolumeDistortion(myProgObj, myWarp, distortionOut, myMethod); + AlgorithmVolumeDistortion(myProgObj, myWarp, distortionOut, myMethod, dolog2); } -AlgorithmVolumeDistortion::AlgorithmVolumeDistortion(ProgressObject* myProgObj, const WarpfieldFile& myWarp, VolumeFile* distortionOut, Method myMethod) : AbstractAlgorithm(myProgObj) +AlgorithmVolumeDistortion::AlgorithmVolumeDistortion(ProgressObject* myProgObj, const WarpfieldFile& myWarp, VolumeFile* distortionOut, const Method myMethod, const bool dolog2) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); switch (myMethod) @@ -159,19 +162,24 @@ AlgorithmVolumeDistortion::AlgorithmVolumeDistortion(ProgressObject* myProgObj, break; case CIRCULAR: { - const float ASPHER_THRESH = 1.00001f; - if (shapes[2] > ASPHER_THRESH) - {//asphericity formula is somewhat unstable when near-spherical (shapes[0] will always be near 1 when shapes[2] is, so a reciprocal reformulation won't help much) - anisotropic = exp(-2.0f * log(shapes[0]) / cos(atan(sqrt(3.0f) * (-log(shapes[0]) / log(shapes[2]) - 1) / (log(shapes[0]) / log(shapes[2]) - 1)) + PI / 6.0f));//deceptively complicated - } else {//when unstable, reshape the elongation ratio to approximate it - anisotropic = pow(shapes[2] / shapes[0], 1.24f); - }//explanation time: per the help info, put the shape ratios into log space, so that geometry can be useful - //now consider an equilateral triangle centered at the origin, and these log-space shape values as the signed distance from the x=0 line + //new solution found by coincidence: square and sum the x coordinates of the vertices an equilateral triangle centered on the origin, you get (3r^2)/2, where r is the distance from the origin to a vertex + float logshapes[3]; + for (int a = 0; a < 3; ++a) + { + logshapes[a] = log(shapes[a]); + } + anisotropic = exp(sqrt(8.0f / 3.0f * (logshapes[0] * logshapes[0] + logshapes[1] * logshapes[1] + logshapes[2] * logshapes[2]))); + break;//explanation time: per the help info, put the shape ratios into log space, so that geometry can be useful + //now consider an equilateral triangle centered at the origin, and these log-space shape values as the x coordinates of the vertices //now, find the distance from the origin to any vertex, and multiply by 2 to get the circumscribing circle's diameter - //this solution relied on the the most-horizontal edge of the triangle being split by x=0 at the same ratio as the magnitudes of the two extreme log-shape values (don't forget the negative sign) - break; + //the old solution relied on the the most-horizontal edge of the triangle being split by the y-axis at the same ratio as the magnitudes of the two extreme log-shape values (don't forget the negative sign) } } + if (dolog2) + { + isotropic = log2(isotropic); + anisotropic = log2(anisotropic); + } distortionOut->setValue(isotropic, i, j, k, 0); distortionOut->setValue(anisotropic, i, j, k, 1); } diff --git a/src/Algorithms/AlgorithmVolumeDistortion.h b/src/Algorithms/AlgorithmVolumeDistortion.h index 4dbb75e9358bf7119a7bdf74b56e7a324fcc4146..4b7d3acbaab62987df7273febb65ff86edd0cb90 100644 --- a/src/Algorithms/AlgorithmVolumeDistortion.h +++ b/src/Algorithms/AlgorithmVolumeDistortion.h @@ -39,7 +39,7 @@ namespace caret { ELONGATION, CIRCULAR }; - AlgorithmVolumeDistortion(ProgressObject* myProgObj, const WarpfieldFile& myWarp, VolumeFile* distortionOut, Method myMethod = ELONGATION); + AlgorithmVolumeDistortion(ProgressObject* myProgObj, const WarpfieldFile& myWarp, VolumeFile* distortionOut, const Method myMethod = ELONGATION, const bool dolog2 = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmVolumeErode.cxx b/src/Algorithms/AlgorithmVolumeErode.cxx index b77d8a32aa234b6d5189253e5d8e73bdc2a591d1..75b1828ac5d7e194ef9711ac51f143c0eb498d7e 100644 --- a/src/Algorithms/AlgorithmVolumeErode.cxx +++ b/src/Algorithms/AlgorithmVolumeErode.cxx @@ -202,7 +202,7 @@ AlgorithmVolumeErode::AlgorithmVolumeErode(ProgressObject* myProgObj, const Volu } if (subvol == -1) { - volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType()); + volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); for (int i = 0; i < myDims[3]; ++i) { if (volIn->getType() == SubvolumeAttributes::LABEL) @@ -223,7 +223,7 @@ AlgorithmVolumeErode::AlgorithmVolumeErode(ProgressObject* myProgObj, const Volu } else { vector outDims = myDims; outDims.resize(3); - volOut->reinitialize(outDims, volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType()); + volOut->reinitialize(outDims, volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); if (volIn->getType() == SubvolumeAttributes::LABEL) { *(volOut->getMapLabelTable(0)) = *(volIn->getMapLabelTable(subvol)); diff --git a/src/Algorithms/AlgorithmVolumeExtrema.cxx b/src/Algorithms/AlgorithmVolumeExtrema.cxx index 7a685ed4ddfc41f7236beb480b849e7f5963b8c7..31002326c4566fc10c48eedebd8098934e4eb4ca 100644 --- a/src/Algorithms/AlgorithmVolumeExtrema.cxx +++ b/src/Algorithms/AlgorithmVolumeExtrema.cxx @@ -181,7 +181,7 @@ AlgorithmVolumeExtrema::AlgorithmVolumeExtrema(ProgressObject* myProgObj, const { outDims[3] = 1; } - myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4]); + myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4], SubvolumeAttributes::ANATOMY, myVolIn->m_header); if (sumSubvols) { myVolOut->setMapName(0, "sum of extrema"); @@ -228,7 +228,7 @@ AlgorithmVolumeExtrema::AlgorithmVolumeExtrema(ProgressObject* myProgObj, const vector minima, maxima; vector outDims = myDims; outDims.resize(3); - myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4]); + myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4], SubvolumeAttributes::ANATOMY, myVolIn->m_header); myVolOut->setMapName(0, "extrema of " + myVolIn->getMapName(subvol)); myVolOut->setValueAllVoxels(0.0f); for (int c = 0; c < myDims[4]; ++c) diff --git a/src/Algorithms/AlgorithmVolumeFillHoles.cxx b/src/Algorithms/AlgorithmVolumeFillHoles.cxx index 6104de85c6ef3fae9074ad2d108b0bdbb79cc0b1..9fa700bac8145cadfefc4cdc2aa8c2a1698422bf 100644 --- a/src/Algorithms/AlgorithmVolumeFillHoles.cxx +++ b/src/Algorithms/AlgorithmVolumeFillHoles.cxx @@ -70,7 +70,7 @@ AlgorithmVolumeFillHoles::AlgorithmVolumeFillHoles(ProgressObject* myProgObj, co 0, 0, 1 }; vector dims; myVolIn->getDimensions(dims); - myVolOut->reinitialize(myVolIn->getOriginalDimensions(), myVolIn->getSform(), myVolIn->getNumberOfComponents(), myVolIn->getType()); + myVolOut->reinitialize(myVolIn->getOriginalDimensions(), myVolIn->getSform(), myVolIn->getNumberOfComponents(), myVolIn->getType(), myVolIn->m_header); for (int s = 0; s < dims[3]; ++s) { myVolOut->setMapName(s, myVolIn->getMapName(s)); diff --git a/src/Algorithms/AlgorithmVolumeFindClusters.cxx b/src/Algorithms/AlgorithmVolumeFindClusters.cxx index f73ac240988ad2ad2fc064e652d5dcba5917ae2e..d50e038ad3e89c83004534d4554f1744d1462e78 100644 --- a/src/Algorithms/AlgorithmVolumeFindClusters.cxx +++ b/src/Algorithms/AlgorithmVolumeFindClusters.cxx @@ -75,6 +75,7 @@ OperationParameters* AlgorithmVolumeFindClusters::getParameters() ret->setHelpText( AString("Outputs a volume with nonzero integers for all voxels within a large enough cluster, and zeros elsewhere. ") + "The integers denote cluster membership (by default, first cluster found will use value 1, second cluster 2, etc). " + + "Cluster values are not reused across frames of the output, but instead keep counting up. " + "By default, values greater than are considered to be in a cluster, use -less-than to test for values less than the threshold. " + "To apply this as a mask to the data, or to do more complicated thresholding, see -volume-math." ); @@ -307,7 +308,7 @@ AlgorithmVolumeFindClusters::AlgorithmVolumeFindClusters(ProgressObject* myProgO int markVal = startVal; if (subvolNum == -1) { - volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), dims[4]); + volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), dims[4], SubvolumeAttributes::ANATOMY, volIn->m_header); volOut->setValueAllVoxels(0.0f); for (int64_t c = 0; c < dims[4]; ++c) { @@ -320,7 +321,7 @@ AlgorithmVolumeFindClusters::AlgorithmVolumeFindClusters(ProgressObject* myProgO } else { vector outDims = volIn->getOriginalDimensions(); outDims.resize(3); - volOut->reinitialize(outDims, volIn->getSform(), dims[4]); + volOut->reinitialize(outDims, volIn->getSform(), dims[4], SubvolumeAttributes::ANATOMY, volIn->m_header); volOut->setValueAllVoxels(0.0f); for (int64_t c = 0; c < dims[4]; ++c) { diff --git a/src/Algorithms/AlgorithmVolumeGradient.cxx b/src/Algorithms/AlgorithmVolumeGradient.cxx index 1b45e24fd9507e1b9e652eb49ba8f39dbed2e184..ac28e06e0b9cfed3822583ed8fd1f7f86446d5ad 100644 --- a/src/Algorithms/AlgorithmVolumeGradient.cxx +++ b/src/Algorithms/AlgorithmVolumeGradient.cxx @@ -154,7 +154,7 @@ AlgorithmVolumeGradient::AlgorithmVolumeGradient(ProgressObject* myProgObj, cons } if (subvolNum == -1) { - volOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType()); + volOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType(), volIn->m_header); if (vectorsOut != NULL) { while (origDims.size() < 4) @@ -405,7 +405,7 @@ AlgorithmVolumeGradient::AlgorithmVolumeGradient(ProgressObject* myProgObj, cons } } else { origDims.resize(3); - volOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType()); + volOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType(), volIn->m_header); if (vectorsOut != NULL) { origDims.push_back(3); diff --git a/src/Algorithms/AlgorithmVolumeLabelModifyKeys.cxx b/src/Algorithms/AlgorithmVolumeLabelModifyKeys.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dfa7cf8f28fd3053a60534c7146faefefb6fae78 --- /dev/null +++ b/src/Algorithms/AlgorithmVolumeLabelModifyKeys.cxx @@ -0,0 +1,226 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AlgorithmVolumeLabelModifyKeys.h" +#include "AlgorithmException.h" + +#include "FileInformation.h" +#include "GiftiLabel.h" +#include "GiftiLabelTable.h" +#include "VolumeFile.h" + +#include +#include +#include + +using namespace caret; +using namespace std; + +AString AlgorithmVolumeLabelModifyKeys::getCommandSwitch() +{ + return "-volume-label-modify-keys"; +} + +AString AlgorithmVolumeLabelModifyKeys::getShortDescription() +{ + return "CHANGE KEY VALUES IN A VOLUME LABEL FILE"; +} + +OperationParameters* AlgorithmVolumeLabelModifyKeys::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + ret->addVolumeParameter(1, "volume-in", "the input volume label file"); + ret->addStringParameter(2, "remap-file", "text file with old and new key values"); + ret->addVolumeOutputParameter(3, "volume-out", "the output volume label file"); + + OptionalParameter* subvolOpt = ret->createOptionalParameter(4, "-subvolume", "select a single subvolume"); + subvolOpt->addStringParameter(1, "subvolume", "the subvolume number or name"); + + ret->setHelpText( + AString(" should have lines of the form 'oldkey newkey', like so:\n\n") + + "3 5\n5 8\n8 2\n\n" + + "This would change the current label with key '3' to use the key '5' instead, 5 would use 8, and 8 would use 2. " + + "Any collision in key values results in the label that was not specified in the remap file getting remapped to an otherwise unused key. " + + "Remapping more than one key to the same new key, or the same key to more than one new key, results in an error. " + + "This will not change the appearance of the file when displayed, as it will change the key values in the data at the same time." + ); + return ret; +} + +void AlgorithmVolumeLabelModifyKeys::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) +{ + VolumeFile* volIn = myParams->getVolume(1); + AString remapName = myParams->getString(2); + VolumeFile* volOut = myParams->getOutputVolume(3); + OptionalParameter* subvolOpt = myParams->getOptionalParameter(4); + int subvol = -1; + if (subvolOpt->m_present) + {//set up to use a single column + subvol = volIn->getMapIndexFromNameOrNumber(subvolOpt->getString(1)); + if (subvol < 0) throw AlgorithmException("invalid column specified"); + } + FileInformation textFileInfo(remapName); + if (!textFileInfo.exists()) + { + throw AlgorithmException("label list file doesn't exist"); + } + fstream remapFile(remapName.toLocal8Bit().constData(), fstream::in); + if (!remapFile.good()) + { + throw AlgorithmException("error reading label list file"); + } + map remap; + int32_t oldkey, newkey; + while (remapFile >> oldkey >> newkey) + { + if (remap.find(oldkey) != remap.end()) throw AlgorithmException("remapping tried to duplicate label " + AString::number(oldkey)); + remap[oldkey] = newkey; + } + AlgorithmVolumeLabelModifyKeys(myProgObj, volIn, remap, volOut, subvol); +} + +AlgorithmVolumeLabelModifyKeys::AlgorithmVolumeLabelModifyKeys(ProgressObject* myProgObj, const VolumeFile* volIn, const map remap, VolumeFile* volOut, const int subvol) : AbstractAlgorithm(myProgObj) +{ + LevelProgress myProgress(myProgObj); + if (volIn->getType() != SubvolumeAttributes::LABEL) + { + throw AlgorithmException("input volume must be a label volume"); + } + vector indims = volIn->getDimensions(); + vector outdims = volIn->getOriginalDimensions(); + if (indims[4] != 1) + { + throw AlgorithmException("multiple components are not allowed in label volumes"); + } + int64_t startVol = 0, endVol = indims[3]; + if (subvol > -1) + { + startVol = subvol; + endVol = subvol + 1; + indims.resize(3); + } + volOut->reinitialize(outdims, volIn->getSform(), 1, SubvolumeAttributes::LABEL); + vector scratchFrame(outdims[0] * outdims[1] * outdims[2]); + for (int64_t s = startVol; s < endVol; ++s) + { + volOut->setMapName(s - startVol, volIn->getMapName(s)); + const GiftiLabelTable* oldTable = volIn->getMapLabelTable(s); + int32_t oldUnlabeled = oldTable->getUnassignedLabelKey();//because GiftiLabelTable is quirky, we need to check if the unlabeled value ends up as something other than 0 + GiftiLabelTable newTable;//careful, label 0 is created by the constructor + bool setZero = false;//because of this, we need to track if we overwrote it, so that we can pretend it isn't there + for (map::const_iterator iter = remap.begin(); iter != remap.end(); ++iter) + { + const GiftiLabel* oldLabel = oldTable->getLabel(iter->first); + if (oldLabel == NULL) throw AlgorithmException("label key " + AString::number(iter->first) + " does not exist in the input file"); + GiftiLabel newLabel(*oldLabel); + newLabel.setKey(iter->second); + if (iter->first == oldUnlabeled) + { + if (iter->second != 0)//if it isn't the default unlabeled value, then we have to do something + { + if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + newTable.deleteLabel(0);//delete the default, since we don't know what overwrites it, if anything + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) + } else {//otherwise, just error checking + if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + setZero = true;//we do have to track that zero now contains something that can't be overwritten + } + } else { + if (iter->second == 0)//if it remaps to the default unlabeled key, we have to check it differently + { + if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + setZero = true; + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, so it will overwrite the existing default 0 key + } else {//finally, the simple case + if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) + } + } + } + set keys = oldTable->getKeys(), collisions; + for (set::const_iterator iter = keys.begin(); iter != keys.end(); ++iter) + { + if (remap.find(*iter) == remap.end())//skip if it was remapped + { + if (*iter == 0)//again with the special default 0 key + { + if (setZero)//check for collision + { + collisions.insert(*iter); + } else { + setZero = true; + if (*iter != oldUnlabeled)//if its merely the unassigned label already, we can just keep the existing default + { + newTable.insertLabel(oldTable->getLabel(*iter)); + } + } + } else { + if (newTable.getLabel(*iter) == NULL) + { + newTable.insertLabel(oldTable->getLabel(*iter)); + } else {//collision + collisions.insert(*iter); + } + } + } + } + map valueChanges = remap;//start with the specified changes, then add the collision changes + for (set::const_iterator iter = collisions.begin(); iter != collisions.end(); ++iter) + {//now deal with collisions + int32_t newKey = newTable.generateUnusedKey(); + GiftiLabel newLabel(*(oldTable->getLabel(*iter))); + newLabel.setKey(newKey); + newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) + valueChanges[*iter] = newKey; + } + *(volOut->getMapLabelTable(s - startVol)) = newTable; + const float* inframe = volIn->getFrame(s); + for (int64_t k = 0; k < indims[2]; ++k) + { + for (int64_t j = 0; j < indims[1]; ++j) + { + for (int64_t i = 0; i < indims[0]; ++i) + { + int64_t index = volIn->getIndex(i, j, k); + int32_t oldkey = int32_t(floor(inframe[index] + 0.5)); + auto iter = valueChanges.find(oldkey); + if (iter == valueChanges.end()) + { + scratchFrame[index] = oldkey; + } else { + scratchFrame[index] = iter->second; + } + } + } + } + volOut->setFrame(scratchFrame.data(), s - startVol); + } +} + +float AlgorithmVolumeLabelModifyKeys::getAlgorithmInternalWeight() +{ + return 1.0f;//override this if needed, if the progress bar isn't smooth +} + +float AlgorithmVolumeLabelModifyKeys::getSubAlgorithmWeight() +{ + //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm + return 0.0f; +} diff --git a/src/Algorithms/AlgorithmVolumeLabelModifyKeys.h b/src/Algorithms/AlgorithmVolumeLabelModifyKeys.h new file mode 100644 index 0000000000000000000000000000000000000000..6ef19d16e2d9688015eafb1bcfee1913270f1f03 --- /dev/null +++ b/src/Algorithms/AlgorithmVolumeLabelModifyKeys.h @@ -0,0 +1,48 @@ +#ifndef __ALGORITHM_VOLUME_LABEL_MODIFY_KEYS_H__ +#define __ALGORITHM_VOLUME_LABEL_MODIFY_KEYS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AbstractAlgorithm.h" + +#include + +namespace caret { + + class AlgorithmVolumeLabelModifyKeys : public AbstractAlgorithm + { + AlgorithmVolumeLabelModifyKeys(); + protected: + static float getSubAlgorithmWeight(); + static float getAlgorithmInternalWeight(); + public: + AlgorithmVolumeLabelModifyKeys(ProgressObject* myProgObj, const VolumeFile* volIn, const std::map remap, VolumeFile* volOut, const int subvol = -1); + static OperationParameters* getParameters(); + static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); + static AString getCommandSwitch(); + static AString getShortDescription(); + }; + + typedef TemplateAutoOperation AutoAlgorithmVolumeLabelModifyKeys; + +} + +#endif //__ALGORITHM_VOLUME_LABEL_MODIFY_KEYS_H__ diff --git a/src/Algorithms/AlgorithmVolumeParcelResampling.cxx b/src/Algorithms/AlgorithmVolumeParcelResampling.cxx index e61957d3e1349ee1b3021f62508d8529cfbd8297..d6bb354e02a59e5657ea6d7496332e681aea7b30 100644 --- a/src/Algorithms/AlgorithmVolumeParcelResampling.cxx +++ b/src/Algorithms/AlgorithmVolumeParcelResampling.cxx @@ -228,11 +228,11 @@ void AlgorithmVolumeParcelResampling::resample(LevelProgress& myProgress, const inVol->getDimensions(myDims); if (subvolNum == -1) { - outVol->reinitialize(inVol->getOriginalDimensions(), inVol->getSform(), myDims[4], inVol->getType()); + outVol->reinitialize(inVol->getOriginalDimensions(), inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } else { vector newDims = inVol->getOriginalDimensions(); newDims.resize(3);//discard nonspatial dimentions - outVol->reinitialize(newDims, inVol->getSform(), myDims[4], inVol->getType()); + outVol->reinitialize(newDims, inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } outVol->setValueAllVoxels(0.0f); const GiftiLabelTable* curTable = curLabel->getMapLabelTable(0); @@ -475,11 +475,11 @@ void AlgorithmVolumeParcelResampling::resampleFixZeros(LevelProgress& myProgress inVol->getDimensions(myDims); if (subvolNum == -1) { - outVol->reinitialize(inVol->getOriginalDimensions(), inVol->getSform(), myDims[4], inVol->getType()); + outVol->reinitialize(inVol->getOriginalDimensions(), inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } else { vector newDims = inVol->getOriginalDimensions(); newDims.resize(3);//discard nonspatial dimentions - outVol->reinitialize(newDims, inVol->getSform(), myDims[4], inVol->getType()); + outVol->reinitialize(newDims, inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } outVol->setValueAllVoxels(0.0f); const GiftiLabelTable* curTable = curLabel->getMapLabelTable(0); diff --git a/src/Algorithms/AlgorithmVolumeParcelResamplingGeneric.cxx b/src/Algorithms/AlgorithmVolumeParcelResamplingGeneric.cxx index eb55b9bcf03b9716d5c1f37ef567781d465d85d4..2b6ea2192552d2ff08d731665773aaed38821afa 100644 --- a/src/Algorithms/AlgorithmVolumeParcelResamplingGeneric.cxx +++ b/src/Algorithms/AlgorithmVolumeParcelResamplingGeneric.cxx @@ -168,11 +168,11 @@ AlgorithmVolumeParcelResamplingGeneric::AlgorithmVolumeParcelResamplingGeneric(P { outDims.push_back(inDims[i]); } - outVol->reinitialize(outDims, newLabel->getSform(), myDims[4], inVol->getType()); + outVol->reinitialize(outDims, newLabel->getSform(), myDims[4], inVol->getType(), inVol->m_header); } else { vector outDims = newLabel->getOriginalDimensions(); outDims.resize(3);//discard nonspatial dimentions - outVol->reinitialize(outDims, newLabel->getSform(), myDims[4], inVol->getType()); + outVol->reinitialize(outDims, newLabel->getSform(), myDims[4], inVol->getType(), inVol->m_header); } outVol->setValueAllVoxels(0.0f); const float* labelFrame = curLabel->getFrame(); diff --git a/src/Algorithms/AlgorithmVolumeParcelSmoothing.cxx b/src/Algorithms/AlgorithmVolumeParcelSmoothing.cxx index ee68f017d56bf82a240a48796940bb5ba4d6d375..788924fd39baf5b1936dfd761a8d2b68cf0189c1 100644 --- a/src/Algorithms/AlgorithmVolumeParcelSmoothing.cxx +++ b/src/Algorithms/AlgorithmVolumeParcelSmoothing.cxx @@ -140,7 +140,7 @@ AlgorithmVolumeParcelSmoothing::AlgorithmVolumeParcelSmoothing(ProgressObject* m } if (subvolNum == -1) { - myOutVol->reinitialize(myVol->getOriginalDimensions(), myVol->getSform(), myDims[4], myVol->getType()); + myOutVol->reinitialize(myVol->getOriginalDimensions(), myVol->getSform(), myDims[4], myVol->getType(), myVol->m_header); myOutVol->setValueAllVoxels(0.0f); for (int whichList = 0; whichList < numLabels; ++whichList) { @@ -204,7 +204,7 @@ AlgorithmVolumeParcelSmoothing::AlgorithmVolumeParcelSmoothing(ProgressObject* m } else { vector newDims = myVol->getOriginalDimensions(); newDims.resize(3);//discard non-spatial extra dimensions - myOutVol->reinitialize(newDims, myVol->getSform(), myDims[4], myVol->getType());//keep components + myOutVol->reinitialize(newDims, myVol->getSform(), myDims[4], myVol->getType(), myVol->m_header);//keep components myOutVol->setValueAllVoxels(0.0f); for (int whichList = 0; whichList < numLabels; ++whichList) { diff --git a/src/Algorithms/AlgorithmVolumeROIsFromExtrema.cxx b/src/Algorithms/AlgorithmVolumeROIsFromExtrema.cxx index 0f119c7eb23144ee9ab1dd6073d08e1a00ea2d85..41e48e09fce0ee9186db647551f16c3d99bbc2b0 100644 --- a/src/Algorithms/AlgorithmVolumeROIsFromExtrema.cxx +++ b/src/Algorithms/AlgorithmVolumeROIsFromExtrema.cxx @@ -236,7 +236,7 @@ AlgorithmVolumeROIsFromExtrema::AlgorithmVolumeROIsFromExtrema(ProgressObject* m vector outDims = myDims; outDims.resize(4); outDims[3] = extremaCount; - myVolOut->reinitialize(outDims, myVol->getSform()); + myVolOut->reinitialize(outDims, myVol->getSform(), 1, SubvolumeAttributes::ANATOMY, myVol->m_header); vector tempFrame(frameSize, 0.0f); if (sigma > 0.0f) { diff --git a/src/Algorithms/AlgorithmVolumeReduce.cxx b/src/Algorithms/AlgorithmVolumeReduce.cxx index 3e048e5734c73a0105c463aa8802b7cc7ec90b38..3ab252bf33700b9bdc950ce2acaa45f6b580e7ab 100644 --- a/src/Algorithms/AlgorithmVolumeReduce.cxx +++ b/src/Algorithms/AlgorithmVolumeReduce.cxx @@ -87,6 +87,10 @@ AlgorithmVolumeReduce::AlgorithmVolumeReduce(ProgressObject* myProgObj, const Vo vector myDims, newDims = volumeIn->getOriginalDimensions(); newDims.resize(3, 1);//have only one subvolume volumeIn->getDimensions(myDims); + if (myDims[3] == 1) + { + CaretLogWarning("-volume-reduce is being used for a length=1 reduction on file '" + volumeIn->getFileName() + "'"); + } volumeOut->reinitialize(newDims, volumeIn->getSform(), myDims[4], volumeIn->getType()); if (volumeIn->getType() == SubvolumeAttributes::LABEL) { diff --git a/src/Algorithms/AlgorithmVolumeRemoveIslands.cxx b/src/Algorithms/AlgorithmVolumeRemoveIslands.cxx index 3f669d6ce4cfa2a47ecd4d467b4527b2d4fc4439..f8a8547a3a84e10f6c6d85efde23323e5c6577f1 100644 --- a/src/Algorithms/AlgorithmVolumeRemoveIslands.cxx +++ b/src/Algorithms/AlgorithmVolumeRemoveIslands.cxx @@ -70,7 +70,7 @@ AlgorithmVolumeRemoveIslands::AlgorithmVolumeRemoveIslands(ProgressObject* myPro 0, 0, 1 }; vector dims; myVolIn->getDimensions(dims); - myVolOut->reinitialize(myVolIn->getOriginalDimensions(), myVolIn->getSform(), myVolIn->getNumberOfComponents(), myVolIn->getType()); + myVolOut->reinitialize(myVolIn->getOriginalDimensions(), myVolIn->getSform(), myVolIn->getNumberOfComponents(), myVolIn->getType(), myVolIn->m_header); for (int s = 0; s < dims[3]; ++s) { myVolOut->setMapName(s, myVolIn->getMapName(s)); diff --git a/src/Algorithms/AlgorithmVolumeSmoothing.cxx b/src/Algorithms/AlgorithmVolumeSmoothing.cxx index d3572aa69083ca075ff2c89d84f57cd0eb4033b0..ae9540f17ac9a4fdec0991248420edc73a053944 100644 --- a/src/Algorithms/AlgorithmVolumeSmoothing.cxx +++ b/src/Algorithms/AlgorithmVolumeSmoothing.cxx @@ -160,7 +160,7 @@ AlgorithmVolumeSmoothing::AlgorithmVolumeSmoothing(ProgressObject* myProgObj, co if (subvol == -1) { vector origDims = inVol->getOriginalDimensions(); - outVol->reinitialize(origDims, volSpace, myDims[4]); + outVol->reinitialize(origDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); vector lists[3]; for (int s = 0; s < myDims[3]; ++s) { @@ -183,7 +183,7 @@ AlgorithmVolumeSmoothing::AlgorithmVolumeSmoothing(ProgressObject* myProgObj, co newDims[0] = origDims[0]; newDims[1] = origDims[1]; newDims[2] = origDims[2]; - outVol->reinitialize(newDims, volSpace, myDims[4]); + outVol->reinitialize(newDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); vector lists[3]; outVol->setMapName(0, inVol->getMapName(subvol) + ", smooth " + AString::number(kernel)); for (int c = 0; c < myDims[4]; ++c) @@ -244,7 +244,7 @@ AlgorithmVolumeSmoothing::AlgorithmVolumeSmoothing(ProgressObject* myProgObj, co if (subvol == -1) { vector origDims = inVol->getOriginalDimensions(); - outVol->reinitialize(origDims, volSpace, myDims[4]); + outVol->reinitialize(origDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); for (int s = 0; s < myDims[3]; ++s) { outVol->setMapName(s, inVol->getMapName(s) + ", smooth " + AString::number(kernel)); @@ -261,7 +261,7 @@ AlgorithmVolumeSmoothing::AlgorithmVolumeSmoothing(ProgressObject* myProgObj, co newDims[0] = origDims[0]; newDims[1] = origDims[1]; newDims[2] = origDims[2]; - outVol->reinitialize(newDims, volSpace, myDims[4]); + outVol->reinitialize(newDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); outVol->setMapName(0, inVol->getMapName(subvol) + ", smooth " + AString::number(kernel)); for (int c = 0; c < myDims[4]; ++c) { diff --git a/src/Algorithms/AlgorithmVolumeTFCE.cxx b/src/Algorithms/AlgorithmVolumeTFCE.cxx index a4ba0bb2487e55117dbc31683227c234d2f9862f..42c059c7efccd6de6689fc5098ea72d274d91124 100644 --- a/src/Algorithms/AlgorithmVolumeTFCE.cxx +++ b/src/Algorithms/AlgorithmVolumeTFCE.cxx @@ -125,7 +125,7 @@ AlgorithmVolumeTFCE::AlgorithmVolumeTFCE(ProgressObject* myProgObj, const Volume if (myRoi != NULL) roiFrame = myRoi->getFrame(); if (subvolNum == -1) { - myVolOut->reinitialize(myVol->getOriginalDimensions(), myVol->getSform(), dims[4]); + myVolOut->reinitialize(myVol->getOriginalDimensions(), myVol->getSform(), dims[4], myVol->getType(), myVol->m_header); const VolumeFile* toUse = myVol; VolumeFile smoothed; if (presmooth > 0.0f) @@ -149,7 +149,7 @@ AlgorithmVolumeTFCE::AlgorithmVolumeTFCE(ProgressObject* myProgObj, const Volume } else { vector outDims = dims; outDims.resize(3); - myVolOut->reinitialize(outDims, myVol->getSform(), dims[4]); + myVolOut->reinitialize(outDims, myVol->getSform(), dims[4], myVol->getType(), myVol->m_header); const VolumeFile* toUse = myVol; int useFrame = subvolNum; VolumeFile smoothed; diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx index 4e84ab5eb743e28b5decc443953b6e6abe81d1bc..050eb6e4dc22edc01a0a3e2eba7eec2578d0c715 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx @@ -74,6 +74,8 @@ OperationParameters* AlgorithmVolumeToSurfaceMapping::getParameters() ribbonOpt->createOptionalParameter(7, "-thin-columns", "use non-overlapping polyhedra"); OptionalParameter* gaussianOpt = ribbonOpt->createOptionalParameter(8, "-gaussian", "reduce weight to voxels that aren't near "); gaussianOpt->addDoubleParameter(1, "scale", "value to multiply the local thickness by, to get the gaussian sigma"); + OptionalParameter* badVertOpt = ribbonOpt->createOptionalParameter(9, "-bad-vertices-out", "output an ROI of which vertices didn't intersect any valid voxels"); + badVertOpt->addMetricOutputParameter(1, "roi-out", "the output metric file of vertices that have no data"); OptionalParameter* ribbonWeights = ribbonOpt->createOptionalParameter(5, "-output-weights", "write the voxel weights for a vertex to a volume file"); ribbonWeights->addIntegerParameter(1, "vertex", "the vertex number to get the voxel weights for, 0-based"); ribbonWeights->addVolumeOutputParameter(2, "weights-out", "volume to write the weights to"); @@ -216,6 +218,12 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam gaussScale = (float)gaussianOpt->getDouble(1); if (!(gaussScale > 0.0f)) throw AlgorithmException("gaussian scale must be positive"); } + MetricFile* badVertices = NULL; + OptionalParameter* badVertOpt = ribbonOpt->getOptionalParameter(9); + if (badVertOpt->m_present) + { + badVertices = badVertOpt->getOutputMetric(1); + } int weightsOutVertex = -1; VolumeFile* weightsOut = NULL; OptionalParameter* ribbonWeights = ribbonOpt->getOptionalParameter(5); @@ -225,7 +233,7 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam weightsOut = ribbonWeights->getOutputVolume(2); } AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, innerSurf, outerSurf, myRoiVol, subdivisions, thinColumns, - mySubVol, gaussScale, weightsOutVertex, weightsOut); + mySubVol, gaussScale, badVertices, weightsOutVertex, weightsOut); OptionalParameter* ribbonWeightsText = ribbonOpt->getOptionalParameter(6); if (ribbonWeightsText->m_present) {//do this after the algorithm, to let it do the error condition checking @@ -362,7 +370,7 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* //ribbon mapping AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol, - const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol, const float& gaussScale, + const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol, const float& gaussScale, MetricFile* badVertices, const int& weightsOutVertex, VolumeFile* weightsOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); @@ -382,6 +390,13 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* int64_t numNodes = mySurface->getNumberOfNodes(); myMetricOut->setNumberOfNodesAndColumns(numNodes, numColumns); myMetricOut->setStructure(mySurface->getStructure()); + vector badVertScratch; + if (badVertices != NULL) + { + badVertices->setNumberOfNodesAndColumns(numNodes, 1); + badVertices->setStructure(mySurface->getStructure()); + badVertScratch.resize(numNodes, 0.0f); + } if (!mySurface->hasNodeCorrespondence(*outerSurf) || !mySurface->hasNodeCorrespondence(*innerSurf)) { throw AlgorithmException("all surfaces must have vertex correspondence"); @@ -444,6 +459,10 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myScratch[node] /= totalWeight; } else { myScratch[node] = 0.0f; + if (thisCol == 0 && badVertices != NULL) + { + badVertScratch[node] = 1.0f; + } } } myMetricOut->setValuesForColumn(thisCol, myScratch); @@ -477,11 +496,19 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myScratch[node] /= totalWeight; } else { myScratch[node] = 0.0f; + if (badVertices != NULL) + { + badVertScratch[node] = 1.0f; + } } } myMetricOut->setValuesForColumn(thisCol, myScratch); } } + if (badVertices != NULL) + { + badVertices->setValuesForColumn(0, badVertScratch.data()); + } } void AlgorithmVolumeToSurfaceMapping::precomputeWeightsRibbon(vector >& myWeights, const VolumeSpace& volSpace, diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h index 902f316ccaee49f55b04e424f465c1cb57b02de6..485147ec7504fae2f52ef8bea3416878dc6a60e3 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h @@ -55,7 +55,7 @@ namespace caret { AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol = NULL, const int32_t& subdivisions = 3, const bool& thinColumns = false, - const int64_t& mySubVol = -1, const float& gaussScale = -1.0f, + const int64_t& mySubVol = -1, const float& gaussScale = -1.0f, MetricFile* badVertices = NULL, const int& weightsOutVertex = -1, VolumeFile* weightsOut = NULL); AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const int64_t& mySubVol = -1, const bool& oldCutoffBug = false); diff --git a/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx b/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx index e79e211c7a36701263e383ddde05de9486163471..e8baea1c6496e50c71032487e914f4bec32bf6c3 100644 --- a/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx +++ b/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx @@ -111,7 +111,7 @@ AlgorithmVolumeWarpfieldResample::AlgorithmVolumeWarpfieldResample(ProgressObjec outDims[1] = refDims[1]; outDims[2] = refDims[2]; int64_t numMaps = inVol->getNumberOfMaps(), numComponents = inVol->getNumberOfComponents(); - outVol->reinitialize(outDims, refSform, numComponents, inVol->getType()); + outVol->reinitialize(outDims, refSform, numComponents, inVol->getType(), inVol->m_header); if (inVol->isMappedWithLabelTable()) { if (myMethod != VolumeFile::ENCLOSING_VOXEL) diff --git a/src/Algorithms/CMakeLists.txt b/src/Algorithms/CMakeLists.txt index e7ff9b755c6a79bdcffd76d4e1ba30aa0c30fa02..ea6411e498e97973daafddf9bcbcaf7e35d57c99 100644 --- a/src/Algorithms/CMakeLists.txt +++ b/src/Algorithms/CMakeLists.txt @@ -23,6 +23,7 @@ ENDIF () # ADD_LIBRARY(Algorithms AbstractAlgorithm.h +AlgorithmAnnotationResample.h AlgorithmBorderResample.h AlgorithmBorderToVertices.h AlgorithmCiftiAllLabelsToROIs.h @@ -42,6 +43,7 @@ AlgorithmCiftiFalseCorrelation.h AlgorithmCiftiFindClusters.h AlgorithmCiftiGradient.h AlgorithmCiftiLabelAdjacency.h +AlgorithmCiftiLabelModifyKeys.h AlgorithmCiftiLabelProbability.h AlgorithmCiftiLabelToBorder.h AlgorithmCiftiLabelToROI.h @@ -123,6 +125,7 @@ AlgorithmVolumeExtrema.h AlgorithmVolumeFillHoles.h AlgorithmVolumeFindClusters.h AlgorithmVolumeGradient.h +AlgorithmVolumeLabelModifyKeys.h AlgorithmVolumeLabelProbability.h AlgorithmVolumeLabelToROI.h AlgorithmVolumeLabelToSurfaceMapping.h @@ -141,6 +144,7 @@ AlgorithmVolumeWarpfieldResample.h OverlapLogicEnum.h AbstractAlgorithm.cxx +AlgorithmAnnotationResample.cxx AlgorithmBorderResample.cxx AlgorithmBorderToVertices.cxx AlgorithmCiftiAllLabelsToROIs.cxx @@ -160,6 +164,7 @@ AlgorithmCiftiFalseCorrelation.cxx AlgorithmCiftiFindClusters.cxx AlgorithmCiftiGradient.cxx AlgorithmCiftiLabelAdjacency.cxx +AlgorithmCiftiLabelModifyKeys.cxx AlgorithmCiftiLabelProbability.cxx AlgorithmCiftiLabelToBorder.cxx AlgorithmCiftiLabelToROI.cxx @@ -241,6 +246,7 @@ AlgorithmVolumeExtrema.cxx AlgorithmVolumeFillHoles.cxx AlgorithmVolumeFindClusters.cxx AlgorithmVolumeGradient.cxx +AlgorithmVolumeLabelModifyKeys.cxx AlgorithmVolumeLabelProbability.cxx AlgorithmVolumeLabelToROI.cxx AlgorithmVolumeLabelToSurfaceMapping.cxx diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index f18baee24691517c90cd8836393c96f7da08d013..dac133aaad434a5b622cc2f0ae8104b6989b84ea 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -25,6 +25,7 @@ #include "AnnotationBox.h" #include "AnnotationColorBar.h" +#include "AnnotationCoordinate.h" #include "AnnotationGroup.h" #include "AnnotationImage.h" #include "AnnotationLine.h" @@ -37,6 +38,7 @@ #include "CaretLogger.h" #include "DisplayGroupAndTabItemHelper.h" #include "MathFunctions.h" +#include "Matrix4x4.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -123,6 +125,7 @@ Annotation::copyHelperAnnotation(const Annotation& obj) m_uniqueKey = -1; m_coordinateSpace = obj.m_coordinateSpace; m_tabIndex = obj.m_tabIndex; + m_spacerTabIndex = obj.m_spacerTabIndex; m_windowIndex = obj.m_windowIndex; m_viewportCoordinateSpaceViewport[0] = obj.m_viewportCoordinateSpaceViewport[0]; m_viewportCoordinateSpaceViewport[1] = obj.m_viewportCoordinateSpaceViewport[1]; @@ -383,6 +386,7 @@ Annotation::initializeAnnotationMembers() m_coordinateSpace = AnnotationCoordinateSpaceEnum::TAB; m_tabIndex = -1; + m_spacerTabIndex = SpacerTabIndex(); m_windowIndex = -1; m_viewportCoordinateSpaceViewport[0] = 0; m_viewportCoordinateSpaceViewport[1] = 0; @@ -536,8 +540,22 @@ Annotation::initializeAnnotationMembers() initializeProperties(); - if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { - setPropertiesForSpecializedUsage(PropertiesSpecializedUsage::VIEWPORT_ANNOTATION); + switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + setPropertiesForSpecializedUsage(PropertiesSpecializedUsage::VIEWPORT_ANNOTATION); + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; } /* @@ -665,6 +683,380 @@ Annotation::setCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordin } } +/** + * @return Is this annotation in surface coordinate space + * with tangent selected for the surface offset vector? + */ +bool +Annotation::isInSurfaceSpaceWithTangentOffset() const +{ + bool flag = false; + + switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + switch (getSurfaceOffsetVectorType()) { + case AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX: + break; + case AnnotationSurfaceOffsetVectorTypeEnum::SURFACE_NORMAL: + break; + case AnnotationSurfaceOffsetVectorTypeEnum::TANGENT: + flag = true; + break; + } + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + return flag; +} + +/** + * Change a surface space annotation to TANGENT offset and update offset length. + * If the annotation is already TANGENT space, no changes are made. + */ +void +Annotation::changeSurfaceSpaceToTangentOffset() +{ + std::vector coords; + if (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE) { + AnnotationOneDimensionalShape* oneDimAnn = castToOneDimensionalShape(); + if (oneDimAnn != NULL) { + coords.push_back(oneDimAnn->getStartCoordinate()); + coords.push_back(oneDimAnn->getEndCoordinate()); + } + else { + AnnotationTwoDimensionalShape* twoDimAnn = castToTwoDimensionalShape(); + if (twoDimAnn != NULL) { + coords.push_back(twoDimAnn->getCoordinate()); + } + } + + for (auto c : coords) { + StructureEnum::Enum structure; + int32_t surfaceNumberOfNodes; + int32_t surfaceNodeIndex; + float surfaceOffsetLength; + AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType; + c->getSurfaceSpace(structure, + surfaceNumberOfNodes, + surfaceNodeIndex, + surfaceOffsetLength, + surfaceOffsetVectorType); + if (surfaceOffsetVectorType != AnnotationSurfaceOffsetVectorTypeEnum::TANGENT) { + surfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::TANGENT; + surfaceOffsetLength = 1.0; + c->setSurfaceSpace(structure, + surfaceNumberOfNodes, + surfaceNodeIndex, + surfaceOffsetLength, + surfaceOffsetVectorType); + } + } + } +} + +/** + * Get the rotation for an annotation in surface space with tangent + * offset using the given normal vector from the vertex to which the + * annotation is attached. + * + * @param structure + * The surface structure. + * @param vertexNormal + * Normal vector of surface vertex. + * @return + * Rotation angle so text is oriented up with 'best axis' + */ +float +Annotation::getSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, + const float vertexNormal[3]) const +{ + float angleOut(0.0); + + const AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(this); + if (twoDimAnn != NULL) { + if (isInSurfaceSpaceWithTangentOffset()) { + enum class OrientationType { + LEFT_TO_RIGHT = 0, + RIGHT_TO_LEFT = 1, + POSTERIOR_TO_ANTERIOR = 2, + ANTERIOR_TO_POSTERIOR = 3, + INFERIOR_TO_SUPERIOR = 4, + SUPERIOR_TO_INFERIOR = 5 + }; + + const OrientationType orientations[6] = { + OrientationType::LEFT_TO_RIGHT, + OrientationType::RIGHT_TO_LEFT, + OrientationType::POSTERIOR_TO_ANTERIOR, + OrientationType::ANTERIOR_TO_POSTERIOR, + OrientationType::INFERIOR_TO_SUPERIOR, + OrientationType::SUPERIOR_TO_INFERIOR + }; + const float orientationVectors[6][3] { + { 1.0, 0.0, 0.0 }, + { -1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 }, + { 0.0, -1.0, 0.0 }, + { 0.0, 0.0, 1.0 }, + { 0.0, 0.0, -1.0 } + }; + + + /* + * Find orientation that aligns with the vertex's normal vector + */ + OrientationType matchingOrientation = OrientationType::LEFT_TO_RIGHT; + float matchingAngle = 10000.0f; + for (int32_t i = 0; i < 6; i++) { + const float angle = MathFunctions::angleInDegreesBetweenVectors(orientationVectors[i], + vertexNormal); + if (angle < matchingAngle) { + matchingAngle = angle; + matchingOrientation = orientations[i]; + } + } + + float surfaceUpAxisVector[3] = { 0.0f, 0.0f, 1.0f }; + switch (matchingOrientation) { + case OrientationType::LEFT_TO_RIGHT: + break; + case OrientationType::RIGHT_TO_LEFT: + break; + case OrientationType::POSTERIOR_TO_ANTERIOR: + break; + case OrientationType::ANTERIOR_TO_POSTERIOR: + break; + case OrientationType::INFERIOR_TO_SUPERIOR: + surfaceUpAxisVector[0] = 1.0; + surfaceUpAxisVector[0] = 0.0; + surfaceUpAxisVector[0] = 0.0; + break; + case OrientationType::SUPERIOR_TO_INFERIOR: + surfaceUpAxisVector[0] = -1.0; + surfaceUpAxisVector[0] = 0.0; + surfaceUpAxisVector[0] = 0.0; + break; + } + + /* + * Vector for annotation's Y (vector from bottom to top of annotation) + */ + const float annotationUpYVector[3] { + 0.0, + 1.0, + 0.0 + }; + + /* + * Initialize the rotation angle so that the annotation's vertical axis + * is aligned with the screen vertical axis when the surface is in the + * analogous surface view. For a text annotation, the text should be + * flowing left to right across screen. + */ + Matrix4x4 rotationMatrix; + rotationMatrix.setMatrixToOpenGLRotationFromVector(vertexNormal); + Matrix4x4 inverseMatrix(rotationMatrix); + inverseMatrix.invert(); + inverseMatrix.multiplyPoint3(surfaceUpAxisVector); + const float alignRotationAngle = MathFunctions::angleInDegreesBetweenVectors(annotationUpYVector, + surfaceUpAxisVector); + float rotationAngle = alignRotationAngle; + switch (matchingOrientation) { + case OrientationType::LEFT_TO_RIGHT: + rotationAngle = 360.0 - rotationAngle; + break; + case OrientationType::RIGHT_TO_LEFT: + break; + case OrientationType::POSTERIOR_TO_ANTERIOR: + if (StructureEnum::isRight(structure)) { + rotationAngle = 360.0 - rotationAngle; + } + break; + case OrientationType::ANTERIOR_TO_POSTERIOR: + if (StructureEnum::isRight(structure)) { + rotationAngle = 360.0 - rotationAngle; + } + break; + case OrientationType::INFERIOR_TO_SUPERIOR: + if (StructureEnum::isRight(structure)) { + rotationAngle += 180.0; + } + break; + case OrientationType::SUPERIOR_TO_INFERIOR: + rotationAngle += 90.0; + break; + } + + angleOut = rotationAngle; + } + } + + return angleOut; +} + +/** + * Initialize the rotation for an annotation in surface space with tangent + * offset using the given normal vector from the vertex to which the + * annotation is attached. + * + * @param structure + * The surface structure. + * @param vertexNormal + * Normal vector of surface vertex. + */ +void +Annotation::initializeSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, + const float vertexNormal[3]) +{ + return; + + + AnnotationTwoDimensionalShape* twoDimAnn = castToTwoDimensionalShape(); + if (twoDimAnn != NULL) { + if (isInSurfaceSpaceWithTangentOffset()) { + const float angle = getSurfaceSpaceWithTangentOffsetRotation(structure, + vertexNormal); + twoDimAnn->setRotationAngle(angle); + } + } + + return; + + + + + +// AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(this); +// if (twoDimAnn != NULL) { +// if (isInSurfaceSpaceWithTangentOffset()) { +// enum class OrientationType { +// LEFT_TO_RIGHT = 0, +// RIGHT_TO_LEFT = 1, +// POSTERIOR_TO_ANTERIOR = 2, +// ANTERIOR_TO_POSTERIOR = 3, +// INFERIOR_TO_SUPERIOR = 4, +// SUPERIOR_TO_INFERIOR = 5 +// }; +// +// const OrientationType orientations[6] = { +// OrientationType::LEFT_TO_RIGHT, +// OrientationType::RIGHT_TO_LEFT, +// OrientationType::POSTERIOR_TO_ANTERIOR, +// OrientationType::ANTERIOR_TO_POSTERIOR, +// OrientationType::INFERIOR_TO_SUPERIOR, +// OrientationType::SUPERIOR_TO_INFERIOR +// }; +// const float orientationVectors[6][3] { +// { 1.0, 0.0, 0.0 }, +// { -1.0, 0.0, 0.0 }, +// { 0.0, 1.0, 0.0 }, +// { 0.0, -1.0, 0.0 }, +// { 0.0, 0.0, 1.0 }, +// { 0.0, 0.0, -1.0 } +// }; +// +// +// /* +// * Find orientation that aligns with the vertex's normal vector +// */ +// OrientationType matchingOrientation = OrientationType::LEFT_TO_RIGHT; +// float matchingAngle = 10000.0f; +// for (int32_t i = 0; i < 6; i++) { +// const float angle = MathFunctions::angleInDegreesBetweenVectors(orientationVectors[i], +// vertexNormal); +// if (angle < matchingAngle) { +// matchingAngle = angle; +// matchingOrientation = orientations[i]; +// } +// } +// +// float surfaceUpAxisVector[3] = { 0.0f, 0.0f, 1.0f }; +// switch (matchingOrientation) { +// case OrientationType::LEFT_TO_RIGHT: +// break; +// case OrientationType::RIGHT_TO_LEFT: +// break; +// case OrientationType::POSTERIOR_TO_ANTERIOR: +// break; +// case OrientationType::ANTERIOR_TO_POSTERIOR: +// break; +// case OrientationType::INFERIOR_TO_SUPERIOR: +// surfaceUpAxisVector[0] = 1.0; +// surfaceUpAxisVector[0] = 0.0; +// surfaceUpAxisVector[0] = 0.0; +// break; +// case OrientationType::SUPERIOR_TO_INFERIOR: +// surfaceUpAxisVector[0] = -1.0; +// surfaceUpAxisVector[0] = 0.0; +// surfaceUpAxisVector[0] = 0.0; +// break; +// } +// +// /* +// * Vector for annotation's Y (vector from bottom to top of annotation) +// */ +// const float annotationUpYVector[3] { +// 0.0, +// 1.0, +// 0.0 +// }; +// +// /* +// * Initialize the rotation angle so that the annotation's vertical axis +// * is aligned with the screen vertical axis when the surface is in the +// * analogous surface view. For a text annotation, the text should be +// * flowing left to right across screen. +// */ +// Matrix4x4 rotationMatrix; +// rotationMatrix.setMatrixToOpenGLRotationFromVector(vertexNormal); +// Matrix4x4 inverseMatrix(rotationMatrix); +// inverseMatrix.invert(); +// inverseMatrix.multiplyPoint3(surfaceUpAxisVector); +// const float alignRotationAngle = MathFunctions::angleInDegreesBetweenVectors(annotationUpYVector, +// surfaceUpAxisVector); +// float rotationAngle = alignRotationAngle; +// switch (matchingOrientation) { +// case OrientationType::LEFT_TO_RIGHT: +// rotationAngle = 360.0 - rotationAngle; +// break; +// case OrientationType::RIGHT_TO_LEFT: +// break; +// case OrientationType::POSTERIOR_TO_ANTERIOR: +// if (StructureEnum::isRight(structure)) { +// rotationAngle = 360.0 - rotationAngle; +// } +// break; +// case OrientationType::ANTERIOR_TO_POSTERIOR: +// if (StructureEnum::isRight(structure)) { +// rotationAngle = 360.0 - rotationAngle; +// } +// break; +// case OrientationType::INFERIOR_TO_SUPERIOR: +// if (StructureEnum::isRight(structure)) { +// rotationAngle += 180.0; +// } +// break; +// case OrientationType::SUPERIOR_TO_INFERIOR: +// rotationAngle += 90.0; +// break; +// } +// +// twoDimAnn->setRotationAngle(rotationAngle); +// } +// } +} + /** * @return The tab index. Valid only for tab coordinate space annotations. */ @@ -688,6 +1080,30 @@ Annotation::setTabIndex(const int32_t tabIndex) } } +/** + * @return Index of the spacer tab. + */ +SpacerTabIndex +Annotation::getSpacerTabIndex() const +{ + return m_spacerTabIndex; +} + +/** + * Set index of the spacer tab. + * + * @param spacerTabIndex + * Index of the spacer tab. + */ +void +Annotation::setSpacerTabIndex(const SpacerTabIndex& spacerTabIndex) +{ + if (spacerTabIndex != m_spacerTabIndex) { + m_spacerTabIndex = spacerTabIndex; + setModified(); + } +} + /** * @return The window index. Valid only for window coordinate space annotations. */ @@ -1187,7 +1603,7 @@ Annotation::initializeProperties() setProperty(Property::LINE_ARROWS, lineArrowsFlag); setProperty(Property::TEXT_ALIGNMENT, textFlag); setProperty(Property::TEXT_EDIT, textFlag); - setProperty(Property::TEXT_COLOR, textFlag); + setProperty(Property::TEXT_COLOR, colorBarFlag | textFlag); setProperty(Property::TEXT_FONT_NAME, colorBarFlag | textFlag); setProperty(Property::TEXT_FONT_SIZE, colorBarFlag | textFlag); setProperty(Property::TEXT_FONT_STYLE, textFlag); @@ -1209,7 +1625,6 @@ Annotation::initializeProperties() resetProperty(Property::GROUP); resetProperty(Property::LINE_COLOR); resetProperty(Property::LINE_THICKNESS); - resetProperty(Property::TEXT_COLOR); resetProperty(Property::TEXT_EDIT); setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); @@ -1921,12 +2336,29 @@ bool Annotation::isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { - if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { - return m_displayGroupAndTabItemHelper->isExpandedInWindow(m_windowIndex); + switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + return m_displayGroupAndTabItemHelper->isExpandedInWindow(m_windowIndex); + break; } + const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndex); + return m_displayGroupAndTabItemHelper->isExpanded(displayGroup, - tabIndex); + itemTabIndex); } /** @@ -1948,16 +2380,32 @@ Annotation::setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) { - if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { - m_displayGroupAndTabItemHelper->setExpandedInWindow(m_windowIndex, - status); - } - else { - m_displayGroupAndTabItemHelper->setExpanded(displayGroup, - tabIndex, - status); + switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + m_displayGroupAndTabItemHelper->setExpandedInWindow(m_windowIndex, + status); + return; + break; } - + + const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndex); + + m_displayGroupAndTabItemHelper->setExpanded(displayGroup, + itemTabIndex, + status); } /** @@ -1977,12 +2425,31 @@ Annotation::getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { if (testProperty(Annotation::Property::DISPLAY_GROUP)) { - if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { - return m_displayGroupAndTabItemHelper->getSelectedInWindow(m_windowIndex); + switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::SPACER: + return m_displayGroupAndTabItemHelper->getSelectedInSpacerTab(); + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + return m_displayGroupAndTabItemHelper->getSelectedInWindow(m_windowIndex); + break; } + + const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndex); + return m_displayGroupAndTabItemHelper->getSelected(displayGroup, - tabIndex); + itemTabIndex); } /* @@ -2010,17 +2477,60 @@ Annotation::setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status) { - if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { - m_displayGroupAndTabItemHelper->setSelectedInWindow(m_windowIndex, - status); + switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::SPACER: + m_displayGroupAndTabItemHelper->setSelectedInSpacerTab(status); + return; + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + m_displayGroupAndTabItemHelper->setSelectedInWindow(m_windowIndex, + status); + return; + break; } - else { - m_displayGroupAndTabItemHelper->setSelected(displayGroup, - tabIndex, - status); + + const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndex); + + m_displayGroupAndTabItemHelper->setSelected(displayGroup, + itemTabIndex, + status); +} + +/** + * Update the tab index to correspond to the tab index used for this + * annotation if it is in tab annotation space. This functionality + * was added to resolve WB-831. + * + * @param displayGroup + * The display group. + * @param tabIndex + * Index of the tab. + */ +int32_t +Annotation::updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex) const +{ + int32_t tabIndexOut(tabIndex); + if (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { + if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { + tabIndexOut = getTabIndex(); + } } + return tabIndexOut; } + /** * Is this item selected for editing in the given window? * diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index 07062994edc5166c665efe823e8d1784e071dd80..1a3e7a20a5112229895467b07aedc8e21132e41a 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -27,14 +27,19 @@ #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationGroupKey.h" #include "AnnotationSizingHandleTypeEnum.h" +#include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "AnnotationTypeEnum.h" #include "CaretColorEnum.h" #include "CaretObjectTracksModification.h" #include "DisplayGroupAndTabItemInterface.h" #include "SceneableInterface.h" +#include "SpacerTabIndex.h" +#include "StructureEnum.h" namespace caret { + class AnnotationOneDimensionalShape; + class AnnotationTwoDimensionalShape; class AnnotationSpatialModification; class DisplayGroupAndTabItemHelper; class SceneClassAssistant; @@ -119,6 +124,14 @@ namespace caret { Annotation* clone() const; + virtual AnnotationOneDimensionalShape* castToOneDimensionalShape() = 0; + + virtual const AnnotationOneDimensionalShape* castToOneDimensionalShape() const = 0; + + virtual AnnotationTwoDimensionalShape* castToTwoDimensionalShape() = 0; + + virtual const AnnotationTwoDimensionalShape* castToTwoDimensionalShape() const = 0; + bool testProperty(const Property property) const; bool testPropertiesAny(const Property propertyOne, @@ -155,10 +168,26 @@ namespace caret { void setCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordinateSpace); + virtual AnnotationSurfaceOffsetVectorTypeEnum::Enum getSurfaceOffsetVectorType() const = 0; + + bool isInSurfaceSpaceWithTangentOffset() const; + + void changeSurfaceSpaceToTangentOffset(); + + float getSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, + const float vertexNormal[3]) const; + + void initializeSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, + const float vertexNormal[3]); + int32_t getTabIndex() const; void setTabIndex(const int32_t tabIndex); + SpacerTabIndex getSpacerTabIndex() const; + + void setSpacerTabIndex(const SpacerTabIndex& spacerTabIndex); + int32_t getWindowIndex() const; void setWindowIndex(const int32_t windowIndex); @@ -357,12 +386,17 @@ namespace caret { void setUniqueKey(const int32_t uniqueKey); + int32_t updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex) const; + SceneClassAssistant* m_sceneAssistant; DisplayGroupAndTabItemHelper* m_displayGroupAndTabItemHelper; AnnotationCoordinateSpaceEnum::Enum m_coordinateSpace; + SpacerTabIndex m_spacerTabIndex; + int32_t m_tabIndex; int32_t m_windowIndex; diff --git a/src/Annotations/AnnotationCoordinate.cxx b/src/Annotations/AnnotationCoordinate.cxx index 2b5bd4b057de0566f6200239c50b1ebd385d0135..65a1bc16a7e81483ab46a800978745675b2fdaf9 100644 --- a/src/Annotations/AnnotationCoordinate.cxx +++ b/src/Annotations/AnnotationCoordinate.cxx @@ -41,8 +41,10 @@ using namespace caret; /** * Constructor. */ -AnnotationCoordinate::AnnotationCoordinate() -: CaretObjectTracksModification() +AnnotationCoordinate::AnnotationCoordinate(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) +: CaretObjectTracksModification(), +SceneableInterface(), +m_attributeDefaultType(attributeDefaultType) { initializeAnnotationCoordinateMembers(); @@ -63,7 +65,8 @@ AnnotationCoordinate::~AnnotationCoordinate() */ AnnotationCoordinate::AnnotationCoordinate(const AnnotationCoordinate& obj) : CaretObjectTracksModification(obj), -SceneableInterface(obj) +SceneableInterface(obj), +m_attributeDefaultType(obj.m_attributeDefaultType) { initializeAnnotationCoordinateMembers(); this->copyHelperAnnotationCoordinate(obj); @@ -118,8 +121,17 @@ AnnotationCoordinate::initializeAnnotationCoordinateMembers() m_surfaceSpaceStructure = StructureEnum::INVALID; m_surfaceSpaceNumberOfNodes = -1; m_surfaceSpaceNodeIndex = -1; - m_surfaceOffsetLength = getDefaultSurfaceOffsetLength(); - m_surfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; + + switch (m_attributeDefaultType) { + case AnnotationAttributesDefaultTypeEnum::NORMAL: + m_surfaceOffsetLength = getDefaultSurfaceOffsetLength(); + m_surfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::TANGENT; + break; + case AnnotationAttributesDefaultTypeEnum::USER: + m_surfaceOffsetLength = s_userDefaultSurfaceOffsetLength; + m_surfaceOffsetVectorType = s_userDefaultSurfaceOffsetVectorType; + break; + } m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addArray("m_xyz", @@ -453,6 +465,30 @@ AnnotationCoordinate::toString() const return "AnnotationCoordinate"; } +/** + * Set the user default for the surface offset vector type. + * + * @param surfaceOffsetVectorType + * new default value. + */ +void +AnnotationCoordinate::setUserDefautlSurfaceOffsetVectorType(const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType) +{ + s_userDefaultSurfaceOffsetVectorType = surfaceOffsetVectorType; +} + +/** + * Set the user default for the surface offset length. + * + * @param surfaceOffsetLength + * New default value. + */ +void +AnnotationCoordinate::setUserDefaultSurfaceOffsetLength(const float surfaceOffsetLength) +{ + s_userDefaultSurfaceOffsetLength = surfaceOffsetLength; +} + /** * Save information specific to this type of model to the scene. * diff --git a/src/Annotations/AnnotationCoordinate.h b/src/Annotations/AnnotationCoordinate.h index 1234146f752ab757ca5f66a9d3bff37f5388dfeb..d62121b85ee2388199d62020e7c01c57acff7701 100644 --- a/src/Annotations/AnnotationCoordinate.h +++ b/src/Annotations/AnnotationCoordinate.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include "AnnotationAttributesDefaultTypeEnum.h" #include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "CaretObjectTracksModification.h" #include "SceneableInterface.h" @@ -33,7 +34,7 @@ namespace caret { class AnnotationCoordinate : public CaretObjectTracksModification, public SceneableInterface { public: - AnnotationCoordinate(); + AnnotationCoordinate(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationCoordinate(); @@ -106,7 +107,9 @@ namespace caret { static float getDefaultSurfaceOffsetLength(); + static void setUserDefautlSurfaceOffsetVectorType(const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType); + static void setUserDefaultSurfaceOffsetLength(const float surfaceOffsetLength); // If there will be sub-classes of this class that need to save @@ -124,6 +127,8 @@ namespace caret { void initializeAnnotationCoordinateMembers(); + const AnnotationAttributesDefaultTypeEnum::Enum m_attributeDefaultType; + SceneClassAssistant* m_sceneAssistant; float m_xyz[3]; @@ -138,12 +143,18 @@ namespace caret { AnnotationSurfaceOffsetVectorTypeEnum::Enum m_surfaceOffsetVectorType; + + static float s_userDefaultSurfaceOffsetLength; + + static AnnotationSurfaceOffsetVectorTypeEnum::Enum s_userDefaultSurfaceOffsetVectorType; + // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COORDINATE_DECLARE__ - // + float AnnotationCoordinate::s_userDefaultSurfaceOffsetLength = 1.0f; + AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationCoordinate::s_userDefaultSurfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::TANGENT; #endif // __ANNOTATION_COORDINATE_DECLARE__ } // namespace diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx index 0c767caaea15bbc276c3d3e399659fe7d80160b3..6520ee53e58d19ffbc299bef8b40bed686816da9 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx @@ -115,6 +115,11 @@ AnnotationCoordinateSpaceEnum::initialize() "Chart", "Ch")); + enumData.push_back(AnnotationCoordinateSpaceEnum(SPACER, + "SPACER", + "Spacer", + "Sp")); + enumData.push_back(AnnotationCoordinateSpaceEnum(STEREOTAXIC, "STEREOTAXIC", "Stereotaxic", @@ -307,6 +312,9 @@ AnnotationCoordinateSpaceEnum::toToolTip(Enum enumValue) case CHART: text = "New annotation is drawn at a chart data XYZ coordinate"; break; + case SPACER: + text = "New annotation is drawn at an XY coordinate in the spacer"; + break; case STEREOTAXIC: text = "New annotation is drawn at a surface/volume XYZ coordinate"; break; diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.h b/src/Annotations/AnnotationCoordinateSpaceEnum.h index 3dc4a839fe5a09a7a874f1418e249d4131ea9890..1a2e3519829ef371dadd22fc74032b7a7b634904 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.h +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.h @@ -37,6 +37,8 @@ public: enum Enum { /** Chart space */ CHART, + /** Annotation in spacer */ + SPACER, /** Annotation in stereotaxic (3D) space */ STEREOTAXIC, /** Annotation on surface node */ diff --git a/src/Annotations/AnnotationGroup.cxx b/src/Annotations/AnnotationGroup.cxx index 4f71c5bbf76c0bcdb0f308fa0afd29b0b8485309..005373c05cdeb6177e317bd52c37871a3366ef3b 100644 --- a/src/Annotations/AnnotationGroup.cxx +++ b/src/Annotations/AnnotationGroup.cxx @@ -57,12 +57,15 @@ using namespace caret; * Annotation coordinate space for the group. * @param tabOrWindowIndex * Index of tab or window for tab or window space. + * @param spacerTabIndex + * Index of a spacer tab. */ AnnotationGroup::AnnotationGroup(AnnotationFile* annotationFile, const AnnotationGroupTypeEnum::Enum groupType, const int32_t uniqueKey, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, - const int32_t tabOrWindowIndex) + const int32_t tabOrWindowIndex, + const SpacerTabIndex& spacerTabIndex) : CaretObjectTracksModification(), DisplayGroupAndTabItemInterface(), SceneableInterface() @@ -91,10 +94,14 @@ SceneableInterface() m_coordinateSpace = coordinateSpace; m_tabOrWindowIndex = tabOrWindowIndex; + m_spacerTabIndex = spacerTabIndex; switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + CaretAssert(m_spacerTabIndex.isValid()); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -169,6 +176,7 @@ AnnotationGroup::copyHelperAnnotationGroup(const AnnotationGroup& obj) m_coordinateSpace = obj.m_coordinateSpace; m_name = obj.m_name; m_tabOrWindowIndex = obj.m_tabOrWindowIndex; + m_spacerTabIndex = obj.m_spacerTabIndex; *m_displayGroupAndTabItemHelper = *obj.m_displayGroupAndTabItemHelper; CaretAssertMessage(0, "What to do with annotations remove copy constructor/operator="); @@ -184,6 +192,7 @@ AnnotationGroup::initializeInstance() m_coordinateSpace = AnnotationCoordinateSpaceEnum::VIEWPORT; m_name = ""; m_tabOrWindowIndex = -1; + m_spacerTabIndex = SpacerTabIndex(); m_displayGroupAndTabItemHelper = new DisplayGroupAndTabItemHelper(); @@ -263,6 +272,10 @@ AnnotationGroup::getName() const switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + spaceName.append(" " + + m_spacerTabIndex.getWindowRowColumnGuiText()); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -314,6 +327,15 @@ AnnotationGroup::getTabOrWindowIndex() const return m_tabOrWindowIndex; } +/** + * Index of a spacer tab. + */ +SpacerTabIndex +AnnotationGroup::getSpacerTabIndex() const +{ + return m_spacerTabIndex; +} + /** * @return Unique key displayed in annotation group name. */ @@ -425,6 +447,13 @@ AnnotationGroup::validateAddedAnnotation(const Annotation* annotation) switch (space) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + if (m_spacerTabIndex != annotation->getSpacerTabIndex()) { + CaretLogSevere("Attempting to add anntation with non-matching spacer tab index"); + CaretAssert(0); + return false; + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -898,17 +927,19 @@ AnnotationGroup::isItemExpandable() const * * @param displayGroup * The display group. - * @param tabIndex + * @param tabIndexIn * Index of the tab. */ bool AnnotationGroup::isItemExpanded(const DisplayGroupEnum::Enum displayGroup, - const int32_t tabIndex) const + const int32_t tabIndexIn) const { if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { return m_displayGroupAndTabItemHelper->isExpandedInWindow(m_tabOrWindowIndex); } + const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndexIn); return m_displayGroupAndTabItemHelper->isExpanded(displayGroup, tabIndex); } @@ -918,14 +949,14 @@ AnnotationGroup::isItemExpanded(const DisplayGroupEnum::Enum displayGroup, * * @param displayGroup * The display group. - * @param tabIndex + * @param tabIndexIn * Index of the tab. * @param status * New expanded status. */ void AnnotationGroup::setItemExpanded(const DisplayGroupEnum::Enum displayGroup, - const int32_t tabIndex, + const int32_t tabIndexIn, const bool status) { if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { @@ -933,6 +964,8 @@ AnnotationGroup::setItemExpanded(const DisplayGroupEnum::Enum displayGroup, status); } else { + const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndexIn); m_displayGroupAndTabItemHelper->setExpanded(displayGroup, tabIndex, status); @@ -944,13 +977,16 @@ AnnotationGroup::setItemExpanded(const DisplayGroupEnum::Enum displayGroup, * * @param displayGroup * The display group. - * @param tabIndex + * @param tabIndexIn * Index of the tab. */ TriStateSelectionStatusEnum::Enum AnnotationGroup::getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, - const int32_t tabIndex) const + const int32_t tabIndexIn) const { + const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndexIn); + TriStateSelectionStatusEnum::Enum status = TriStateSelectionStatusEnum::UNSELECTED; const int numChildren = getNumberOfAnnotations(); @@ -987,14 +1023,14 @@ AnnotationGroup::getItemDisplaySelected(const DisplayGroupEnum::Enum displayGrou * * @param displayGroup * The display group. - * @param tabIndex + * @param tabIndexIn * Index of the tab. * @param status * New selection status. */ void AnnotationGroup::setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, - const int32_t tabIndex, + const int32_t tabIndexIn, const TriStateSelectionStatusEnum::Enum status) { switch (status) { @@ -1008,18 +1044,43 @@ AnnotationGroup::setItemDisplaySelected(const DisplayGroupEnum::Enum displayGrou break; } + const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, + tabIndexIn); + /* * Note: An annotation group's selection status is based * of the the group's annotations so we do not need to set * an explicit selection status for the group. */ - DisplayGroupAndTabItemInterface::setChildrenDisplaySelectedHelper(this, displayGroup, tabIndex, status); } +/** + * Update the tab index to correspond to the tab index used for this + * annotation group if it is in tab annotation space. This functionality + * was added to resolve WB-831. + * + * @param displayGroup + * The display group. + * @param tabIndex + * Index of the tab. + */ +int32_t +AnnotationGroup::updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex) const +{ + int32_t tabIndexOut(tabIndex); + if (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { + if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { + tabIndexOut = getTabOrWindowIndex(); + } + } + return tabIndexOut; +} + /** * Is this item selected for editing in the given window? * diff --git a/src/Annotations/AnnotationGroup.h b/src/Annotations/AnnotationGroup.h index b904402210f073e746979b381919cc6e6de15ff9..87f8a2312e1797752aa522c8436518c9f5f8b7c3 100644 --- a/src/Annotations/AnnotationGroup.h +++ b/src/Annotations/AnnotationGroup.h @@ -28,6 +28,7 @@ #include "CaretObjectTracksModification.h" #include "DisplayGroupAndTabItemInterface.h" #include "SceneableInterface.h" +#include "SpacerTabIndex.h" namespace caret { @@ -42,7 +43,8 @@ namespace caret { const AnnotationGroupTypeEnum::Enum groupType, const int32_t uniqueKey, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, - const int32_t tabOrWindowIndex); + const int32_t tabOrWindowIndex, + const SpacerTabIndex& spacerTabIndex); virtual ~AnnotationGroup(); @@ -62,6 +64,8 @@ namespace caret { int32_t getTabOrWindowIndex() const; + SpacerTabIndex getSpacerTabIndex() const; + int32_t getNumberOfAnnotations() const; Annotation* getAnnotation(const int32_t index); @@ -162,6 +166,9 @@ namespace caret { void initializeInstance(); + int32_t updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex) const; + SceneClassAssistant* m_sceneAssistant; DisplayGroupAndTabItemHelper* m_displayGroupAndTabItemHelper; @@ -170,6 +177,8 @@ namespace caret { AnnotationCoordinateSpaceEnum::Enum m_coordinateSpace; + SpacerTabIndex m_spacerTabIndex; + int32_t m_tabOrWindowIndex; mutable AString m_name; diff --git a/src/Annotations/AnnotationOneDimensionalShape.cxx b/src/Annotations/AnnotationOneDimensionalShape.cxx index 30416ca2dfe551ac4fcd134a7cc69e1f48a64fb5..3a1d3a032781323790d408d00458458e8aaa8668 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.cxx +++ b/src/Annotations/AnnotationOneDimensionalShape.cxx @@ -112,8 +112,8 @@ AnnotationOneDimensionalShape::copyHelperAnnotationOneDimensionalShape(const Ann void AnnotationOneDimensionalShape::initializeMembersAnnotationOneDimensionalShape() { - m_startCoordinate.grabNew(new AnnotationCoordinate()); - m_endCoordinate.grabNew(new AnnotationCoordinate()); + m_startCoordinate.grabNew(new AnnotationCoordinate(m_attributeDefaultType)); + m_endCoordinate.grabNew(new AnnotationCoordinate(m_attributeDefaultType)); m_sceneAssistant.grabNew(new SceneClassAssistant()); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { @@ -126,6 +126,42 @@ AnnotationOneDimensionalShape::initializeMembersAnnotationOneDimensionalShape() } } +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. + */ +AnnotationOneDimensionalShape* +AnnotationOneDimensionalShape::castToOneDimensionalShape() +{ + return this; +} + +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. + */ +const AnnotationOneDimensionalShape* +AnnotationOneDimensionalShape::castToOneDimensionalShape() const +{ + return this; +} + +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. + */ +AnnotationTwoDimensionalShape* +AnnotationOneDimensionalShape::castToTwoDimensionalShape() +{ + return NULL; +} + +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. + */ +const AnnotationTwoDimensionalShape* +AnnotationOneDimensionalShape::castToTwoDimensionalShape() const +{ + return NULL; +} + /** * @return The start coordinate for the one dimensional shape. */ @@ -162,6 +198,16 @@ AnnotationOneDimensionalShape::getEndCoordinate() const return m_endCoordinate; } +/** + * @return The surface offset vector type for this annotation. + */ +AnnotationSurfaceOffsetVectorTypeEnum::Enum +AnnotationOneDimensionalShape::getSurfaceOffsetVectorType() const +{ + CaretAssert(m_startCoordinate); + return m_startCoordinate->getSurfaceOffsetVectorType(); +} + /** * Is the object modified? * @return true if modified, else false. @@ -323,24 +369,26 @@ AnnotationOneDimensionalShape::setRotationAngle(const float viewportWidth, bool AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { - bool chartFlag = false; - bool tabWindowFlag = false; + bool xyPlaneFlag = false; switch (getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: - chartFlag = true; + xyPlaneFlag = true; + break; + case AnnotationCoordinateSpaceEnum::SPACER: + xyPlaneFlag = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: - tabWindowFlag = true; + xyPlaneFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: - tabWindowFlag = true; + xyPlaneFlag = true; break; } @@ -370,13 +418,12 @@ AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp validFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: - if (chartFlag - || tabWindowFlag) { + if (xyPlaneFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: - if (tabWindowFlag) { + if (xyPlaneFlag) { validFlag = true; } break; @@ -469,6 +516,21 @@ AnnotationOneDimensionalShape::applySpatialModificationSurfaceSpace(const Annota return validFlag; } +/** + * Apply a spatial modification to an annotation in spacer tab space. + * + * @param spatialModification + * Contains information about the spatial modification. + * @return + * True if the annotation was modified, else false. + */ +bool +AnnotationOneDimensionalShape::applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification) +{ + return applySpatialModificationTabOrWindowSpace(spatialModification); +} + + /** * Apply a spatial modification to an annotation in tab or window space. * @@ -746,6 +808,9 @@ AnnotationOneDimensionalShape::applySpatialModification(const AnnotationSpatialM case AnnotationCoordinateSpaceEnum::CHART: return applySpatialModificationChartSpace(spatialModification); break; + case AnnotationCoordinateSpaceEnum::SPACER: + return applySpatialModificationSpacerTabSpace(spatialModification); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationStereotaxicSpace(spatialModification); break; diff --git a/src/Annotations/AnnotationOneDimensionalShape.h b/src/Annotations/AnnotationOneDimensionalShape.h index e9f05f9dcfd3e7edf9c04e992bcc7eacdf407d87..8b40ed6f04531709ad589d3417ba31c33bc72e4a 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.h +++ b/src/Annotations/AnnotationOneDimensionalShape.h @@ -41,6 +41,14 @@ namespace caret { AnnotationOneDimensionalShape& operator=(const AnnotationOneDimensionalShape& obj); + virtual AnnotationOneDimensionalShape* castToOneDimensionalShape() override; + + virtual const AnnotationOneDimensionalShape* castToOneDimensionalShape() const override; + + virtual AnnotationTwoDimensionalShape* castToTwoDimensionalShape() override; + + virtual const AnnotationTwoDimensionalShape* castToTwoDimensionalShape() const override; + AnnotationCoordinate* getStartCoordinate(); const AnnotationCoordinate* getStartCoordinate() const; @@ -49,6 +57,8 @@ namespace caret { const AnnotationCoordinate* getEndCoordinate() const; + virtual AnnotationSurfaceOffsetVectorTypeEnum::Enum getSurfaceOffsetVectorType() const override; + virtual bool isModified() const; virtual void clearModified(); @@ -94,6 +104,8 @@ namespace caret { bool applySpatialModificationTabOrWindowSpace(const AnnotationSpatialModification& spatialModification); + bool applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification); + CaretPointer m_sceneAssistant; CaretPointer m_startCoordinate; diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index df16def5dc97eaced726bbf20b90f1be50624ab8..c13e77b1463d59bb6159a49ff0bd23dacf192b32 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -1418,6 +1418,8 @@ AnnotationRedoUndoCommand::setModeRotationAngle(const float newRotationAngle, switch (oneDimAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -1881,6 +1883,8 @@ AnnotationRedoUndoCommand::setModeTextFontPercentSize(const float newFontPercent switch (redoAnnotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: percentSize *= surfaceSpaceRowCount; break; diff --git a/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.cxx b/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.cxx index 48f6d22bb6211f1f1b8e76a07547ae41307a20c5..1e29aa0dd9ee30cdf449ff62924fae5d522d0535 100644 --- a/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.cxx +++ b/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.cxx @@ -114,10 +114,15 @@ AnnotationSurfaceOffsetVectorTypeEnum::initialize() "C", "Centroid Thru Vertex")); - enumData.push_back(AnnotationSurfaceOffsetVectorTypeEnum(SURACE_NORMAL, - "SURACE_NORMAL", + enumData.push_back(AnnotationSurfaceOffsetVectorTypeEnum(SURFACE_NORMAL, + "SURFACE_NORMAL", "N", - "Surace Normal")); + "Surface Normal")); + + enumData.push_back(AnnotationSurfaceOffsetVectorTypeEnum(TANGENT, + "TANGENT", + "T", + "Tangent")); } /** @@ -160,7 +165,7 @@ AnnotationSurfaceOffsetVectorTypeEnum::toName(Enum enumValue) { /** * Get an enumerated value corresponding to its name. - * @param name + * @param nameIn * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a @@ -169,10 +174,19 @@ AnnotationSurfaceOffsetVectorTypeEnum::toName(Enum enumValue) { * Enumerated value. */ AnnotationSurfaceOffsetVectorTypeEnum::Enum -AnnotationSurfaceOffsetVectorTypeEnum::fromName(const AString& name, bool* isValidOut) +AnnotationSurfaceOffsetVectorTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); + /* + * SURFACE_NORMAL was spelled incorrectly prior to 24aug2018 + * (was missing 'F'). + */ + AString name(nameIn); + if (name == "SURACE_NORMAL") { + name = "SURFACE_NORMAL"; + } + bool validFlag = false; Enum enumValue = AnnotationSurfaceOffsetVectorTypeEnum::enumData[0].enumValue; diff --git a/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.h b/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.h index 613be01d700eab3fc4120d00933478ed9e8479a8..4aa79032f5d9d06e3f92ad729404ae30a514c4b0 100644 --- a/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.h +++ b/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.h @@ -38,7 +38,9 @@ public: /** Vector starts at centroid and extends through vertex */ CENTROID_THRU_VERTEX, /** Vector is surface normal */ - SURACE_NORMAL + SURFACE_NORMAL, + /** Tangent to surface */ + TANGENT }; diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 6bba52e359d242b585dcea84309fa36972421c45..53fd316153364646d9ca4483f45c3ef18ec194a1 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -117,7 +117,7 @@ AnnotationTwoDimensionalShape::copyHelperAnnotationTwoDimensionalShape(const Ann void AnnotationTwoDimensionalShape::initializeMembersAnnotationTwoDimensionalShape() { - m_coordinate.grabNew(new AnnotationCoordinate()); + m_coordinate.grabNew(new AnnotationCoordinate(m_attributeDefaultType)); switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: @@ -151,6 +151,42 @@ AnnotationTwoDimensionalShape::initializeMembersAnnotationTwoDimensionalShape() } } +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. + */ +AnnotationOneDimensionalShape* +AnnotationTwoDimensionalShape::castToOneDimensionalShape() +{ + return NULL; +} + +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. + */ +const AnnotationOneDimensionalShape* +AnnotationTwoDimensionalShape::castToOneDimensionalShape() const +{ + return NULL; +} + +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. + */ +AnnotationTwoDimensionalShape* +AnnotationTwoDimensionalShape::castToTwoDimensionalShape() +{ + return this; +} + +/** + * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. + */ +const AnnotationTwoDimensionalShape* +AnnotationTwoDimensionalShape::castToTwoDimensionalShape() const +{ + return this; +} + /** * @return The coordinate for the two dimensional shape. */ @@ -169,6 +205,16 @@ AnnotationTwoDimensionalShape::getCoordinate() const return m_coordinate; } +/** + * @return The surface offset vector type for this annotation. + */ +AnnotationSurfaceOffsetVectorTypeEnum::Enum +AnnotationTwoDimensionalShape::getSurfaceOffsetVectorType() const +{ + CaretAssert(m_coordinate); + return m_coordinate->getSurfaceOffsetVectorType(); +} + /** * @return Height for "two-dimensional" annotations in percentage zero to one-hundred. */ @@ -328,23 +374,9 @@ AnnotationTwoDimensionalShape::applyCoordinatesSizeAndRotationFromOther(const An bool AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { - bool viewportFlag = false; + const bool viewportFlag = (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::VIEWPORT); - switch (getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::CHART: - break; - case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - break; - case AnnotationCoordinateSpaceEnum::SURFACE: - break; - case AnnotationCoordinateSpaceEnum::TAB: - break; - case AnnotationCoordinateSpaceEnum::VIEWPORT: - viewportFlag = true; - break; - case AnnotationCoordinateSpaceEnum::WINDOW: - break; - } + const bool surfaceTangentOffsetFlag = isInSurfaceSpaceWithTangentOffset(); bool allowsMovingFlag = false; bool allowsCornerResizingFlag = false; @@ -383,6 +415,11 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp break; } + if (surfaceTangentOffsetFlag) { + allowsCornerResizingFlag = false; + allowsSideResizingFlag = false; + } + bool validFlag = false; if (! viewportFlag) { @@ -662,6 +699,9 @@ AnnotationTwoDimensionalShape::applySpatialModificationSurfaceOrStereotaxicSpace case AnnotationCoordinateSpaceEnum::CHART: badSpaceFlag = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + badSpaceFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereoSpaceFlag = true; break; @@ -888,6 +928,21 @@ AnnotationTwoDimensionalShape::applySpatialModificationSurfaceOrStereotaxicSpace return validFlag; } +/** + * Apply a spatial modification to an annotation in spacer tab space. + * + * @param spatialModification + * Contains information about the spatial modification. + * @return + * True if the annotation was modified, else false. + */ +bool +AnnotationTwoDimensionalShape::applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification) +{ + return applySpatialModificationTabOrWindowSpace(spatialModification); +} + + /** * Apply a spatial modification to an annotation in tab or window space. * @@ -1300,6 +1355,9 @@ AnnotationTwoDimensionalShape::applySpatialModification(const AnnotationSpatialM case AnnotationCoordinateSpaceEnum::CHART: return applySpatialModificationChartSpace(spatialModification); break; + case AnnotationCoordinateSpaceEnum::SPACER: + return applySpatialModificationSpacerTabSpace(spatialModification); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationSurfaceOrStereotaxicSpace(spatialModification, space); diff --git a/src/Annotations/AnnotationTwoDimensionalShape.h b/src/Annotations/AnnotationTwoDimensionalShape.h index 9bc0117d922b3c1fa4a4b3ddb95e1afa4156e196..e49c988435f77126adcb820ce9a7c06ebed3abb2 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.h +++ b/src/Annotations/AnnotationTwoDimensionalShape.h @@ -42,10 +42,20 @@ namespace caret { AnnotationTwoDimensionalShape& operator=(const AnnotationTwoDimensionalShape& obj); + virtual AnnotationOneDimensionalShape* castToOneDimensionalShape() override; + + virtual const AnnotationOneDimensionalShape* castToOneDimensionalShape() const override; + + virtual AnnotationTwoDimensionalShape* castToTwoDimensionalShape() override; + + virtual const AnnotationTwoDimensionalShape* castToTwoDimensionalShape() const override; + AnnotationCoordinate* getCoordinate(); const AnnotationCoordinate* getCoordinate() const; + virtual AnnotationSurfaceOffsetVectorTypeEnum::Enum getSurfaceOffsetVectorType() const override; + float getHeight() const; void setHeight(const float height); @@ -116,6 +126,8 @@ namespace caret { const float addX, const float addY); + bool applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification); + bool applySpatialModificationSurfaceOrStereotaxicSpace(const AnnotationSpatialModification& spatialModification, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace); diff --git a/src/Brain/AnnotationArrangerExecutor.cxx b/src/Brain/AnnotationArrangerExecutor.cxx index 01f2f3c910a9738302676848274e7bdeadf51ae5..aead692c6762b9adbcada38b61b9551498a24762 100644 --- a/src/Brain/AnnotationArrangerExecutor.cxx +++ b/src/Brain/AnnotationArrangerExecutor.cxx @@ -542,6 +542,7 @@ AnnotationArrangerExecutor::getAnnotationsForArranging(const AnnotationArrangerI annotationsOut.clear(); std::vector spaces; + spaces.push_back(AnnotationCoordinateSpaceEnum::SPACER); spaces.push_back(AnnotationCoordinateSpaceEnum::TAB); spaces.push_back(AnnotationCoordinateSpaceEnum::WINDOW); @@ -616,6 +617,10 @@ AnnotationArrangerExecutor::setupAnnotationInfo(const AnnotationArrangerInputs& case AnnotationCoordinateSpaceEnum::CHART: CaretAssert(0); break; + case AnnotationCoordinateSpaceEnum::SPACER: + getSpacerTabViewport(annotation->getSpacerTabIndex(), + annViewport); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: CaretAssert(0); break; @@ -864,7 +869,9 @@ void AnnotationArrangerExecutor::getTabViewport(const int32_t tabIndex, int32_t tabViewportOut[4]) { - + /* + * Check cached viewports to avoid retrieving it a second time + */ std::map::iterator iter = m_tabViewports.find(tabIndex); if (iter != m_tabViewports.end()) { tabViewportOut[0] = iter->second.m_viewport[0]; @@ -893,6 +900,31 @@ AnnotationArrangerExecutor::getTabViewport(const int32_t tabIndex, } } +/** + * Get the viewport for the given spacer tab. Viewports are cached for efficiency. + * + * @param spacerTabIndex + * Index of the spacer tab. + * @param tabViewportOut + * Viewport of the tab. + * @throw CaretException + * If there is an error. + */ +void +AnnotationArrangerExecutor::getSpacerTabViewport(const SpacerTabIndex& spacerTabIndex, + int32_t tabViewportOut[4]) +{ + EventGetViewportSize vpEvent(spacerTabIndex); + EventManager::get()->sendEvent(vpEvent.getPointer()); + if (vpEvent.isViewportSizeValid()) { + vpEvent.getViewportSize(tabViewportOut); + } + else { + throw CaretException("Failed to get viewport size for spacer tab index " + + spacerTabIndex.toString()); + } +} + /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Brain/AnnotationArrangerExecutor.h b/src/Brain/AnnotationArrangerExecutor.h index c2ddc92e749cbe67dcba5c614d487cb32f91acc8..2d11250b41899d2800c4beac253d735fe1e7b9e5 100644 --- a/src/Brain/AnnotationArrangerExecutor.h +++ b/src/Brain/AnnotationArrangerExecutor.h @@ -27,8 +27,7 @@ #include "AnnotationDistributeEnum.h" #include "BoundingBox.h" #include "CaretObject.h" - - +#include "SpacerTabIndex.h" namespace caret { @@ -126,6 +125,9 @@ namespace caret { void getAnnotationsForArranging(const AnnotationArrangerInputs& arrangerInputs, std::vector& annotationsOut) const; + void getSpacerTabViewport(const SpacerTabIndex& spacerTabIndex, + int32_t tabViewportOut[4]); + void getTabViewport(const int32_t tabIndex, int32_t tabViewportOut[4]); diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 46549ac3412f7965fb52457107104d9508d9d1a7..d45af9e5a68d4d880f6653e54850749d74b3a9ae 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -932,6 +932,9 @@ AnnotationManager::getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displ case AnnotationCoordinateSpaceEnum::CHART: displayedFlag = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + displayedFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: displayedFlag = true; break; diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index 2f4766406144c2dca008525ea3ef4863aba94843..e0dd7ae874ade116b352cffce91b7c4c01cee7e0 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -82,6 +82,7 @@ #include "EventModelGetAllDisplayed.h" #include "EventPaletteGetByName.h" #include "EventProgressUpdate.h" +#include "EventSceneActive.h" #include "EventSpecFileReadDataFiles.h" #include "EventManager.h" #include "FiberOrientationSamplesLoader.h" @@ -92,6 +93,7 @@ #include "IdentificationManager.h" #include "ImageFile.h" #include "MathFunctions.h" +#include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "ModelChart.h" #include "ModelChartTwo.h" @@ -104,6 +106,7 @@ #include "OverlaySet.h" #include "PaletteFile.h" #include "RgbaFile.h" +#include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" @@ -117,6 +120,7 @@ #include "Surface.h" #include "SurfaceProjectedItem.h" #include "SystemUtilities.h" +#include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineSetModel.h" @@ -182,6 +186,8 @@ Brain::Brain(const CaretPreferences* caretPreferences) m_displayPropertiesVolume = new DisplayPropertiesVolume(); m_displayProperties.push_back(m_displayPropertiesVolume); + m_surfaceMatchingToAnatomicalFlag = false; + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_DATA_FILES_GET); EventManager::get()->addEventListener(this, @@ -200,6 +206,8 @@ Brain::Brain(const CaretPreferences* caretPreferences) EventTypeEnum::EVENT_SPEC_FILE_READ_DATA_FILES); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_PALETTE_GET_BY_NAME); + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_SCENE_ACTIVE); m_isSpecFileBeingRead = false; @@ -249,6 +257,8 @@ Brain::Brain(const CaretPreferences* caretPreferences) m_sceneAssistant->add("m_gapsAndMargins", "GapsAndMargins", m_gapsAndMargins); + m_sceneAssistant->add("m_surfaceMatchingToAnatomicalFlag", + &m_surfaceMatchingToAnatomicalFlag); m_selectionManager = new SelectionManager(); @@ -491,6 +501,9 @@ Brain::resetBrain(const ResetBrainKeepSceneFiles keepSceneFiles, const ResetBrainKeepSpecFile keepSpecFile) { m_isSpecFileBeingRead = false; + m_activeScene = NULL; + + m_surfaceMatchingToAnatomicalFlag = false; /* * Clear the counters used to prevent duplicate file names. @@ -823,6 +836,8 @@ Brain::resetBrainKeepSceneFiles() break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: keepFileFlag = false; break; @@ -841,6 +856,8 @@ Brain::resetBrainKeepSceneFiles() break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } if (keepFileFlag) { @@ -1551,6 +1568,8 @@ Brain::addReadOrReloadVolumeFile(const FileModeAddReadReload fileMode, m_volumeFiles.push_back(vf); } + initializeVolumeFile(vf); + return vf; } @@ -1577,6 +1596,73 @@ Brain::getVolumeFile(const int32_t volumeFileIndex) return m_volumeFiles[volumeFileIndex]; } +/** + * Get the volume dynamic connecivity files + * + * @param volumeDynamicConnectivityFilesOut + * Output with volume dynamic connectivity files + */ +void +Brain::getVolumeDynamicConnectivityFiles(std::vector& volumeDynamicConnectivityFilesOut) const +{ + volumeDynamicConnectivityFilesOut.clear(); + + for (auto vf : m_volumeFiles) { + CaretAssert(vf); + VolumeDynamicConnectivityFile* volDynConn = vf->getVolumeDynamicConnectivityFile(); + if (volDynConn != NULL) { + if (volDynConn->isDataValid()) { + volumeDynamicConnectivityFilesOut.push_back(volDynConn); + } + } + } +} + +/** + * Get the metric dynamic connecivity files + * + * @param metricDynamicConnectivityFilesOut + * Output with metric dynamic connectivity files + */ +void +Brain::getMetricDynamicConnectivityFiles(std::vector& metricDynamicConnectivityFilesOut) const +{ + metricDynamicConnectivityFilesOut.clear(); + + for (auto bs : m_brainStructures) { + std::vector metricFiles; + bs->getMetricFiles(metricFiles); + + for (auto mf : metricFiles) { + MetricDynamicConnectivityFile* metricDynConn = mf->getMetricDynamicConnectivityFile(); + if (metricDynConn != NULL) { + if (metricDynConn->isDataValid()) { + metricDynamicConnectivityFilesOut.push_back(metricDynConn); + } + } + } + } +} + +/** + * Initialize a volume file. If it is functional data and contains more than one timepoint + * setup its volume dynamic connectivity file. + */ +void +Brain::initializeVolumeFile(VolumeFile* volumeFile) +{ + CaretAssert(volumeFile); + /* + * Enable dynamic connectivity using preferences + */ + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + VolumeDynamicConnectivityFile* volDynConn = volumeFile->getVolumeDynamicConnectivityFile(); + if (volDynConn != NULL) { + volDynConn->setEnabledAsLayer(prefs->isDynamicConnectivityDefaultedOn()); + } +} + + /** * Get the volume file at the given index. * @param volumeFileIndex @@ -3346,6 +3432,14 @@ Brain::addReadOrReloadSceneFile(const FileModeAddReadReload fileMode, if (readFlag) { try { try { + /* + * Add to recent scene files + */ + if (FileInformation(filename).exists()) { + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->addToPreviousSceneFiles(filename); + } + sf->readFile(filename); } catch (const std::bad_alloc&) { @@ -3375,10 +3469,6 @@ Brain::addReadOrReloadSceneFile(const FileModeAddReadReload fileMode, m_sceneFiles.push_back(sf); } - -// CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); -// prefs->addToPreviousSceneFiles(sf->getFileName()); - return sf; } @@ -4418,6 +4508,9 @@ Brain::addDataFile(CaretDataFile* caretDataFile) true); } break; + case DataFileTypeEnum::METRIC_DYNAMIC: + CaretAssertMessage(0, "Metric dynamic files should never be added to brain"); + break; case DataFileTypeEnum::PALETTE: { throw DataFileException(caretDataFile->getFileName(), @@ -4480,9 +4573,13 @@ Brain::addDataFile(CaretDataFile* caretDataFile) { VolumeFile* file = dynamic_cast(caretDataFile); CaretAssert(file); + initializeVolumeFile(file); m_volumeFiles.push_back(file); } break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + CaretAssertMessage(0, "Volume Dynamic files are never added to the brain"); + break; } m_specFile->addCaretDataFile(caretDataFile); @@ -5305,6 +5402,9 @@ Brain::addReadOrReloadDataFile(const FileModeAddReadReload fileMode, structure, markDataFileAsModified); break; + case DataFileTypeEnum::METRIC_DYNAMIC: + CaretAssertMessage(0, "Metric dynamic files are never read by Brain"); + break; case DataFileTypeEnum::PALETTE: caretDataFileRead = addReadOrReloadPaletteFile(fileMode, caretDataFile, @@ -5343,6 +5443,9 @@ Brain::addReadOrReloadDataFile(const FileModeAddReadReload fileMode, caretDataFile, dataFileName); break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + CaretAssertMessage(0, "Volume dynamic files are never read by the Brain"); + break; } if (caretDataFileRead != NULL) { @@ -5482,8 +5585,23 @@ Brain::loadFilesSelectedInSpecFile(EventSpecFileReadDataFiles* readSpecFileDataF resetBrain(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->invalidateSceneDataValues(); prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); + const AString specFileName = sf->getFileName(); + if (DataFile::isFileOnNetwork(specFileName)) { + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->addToPreviousSpecFiles(specFileName); + } + else { + FileInformation specFileInfo(specFileName); + if (specFileInfo.exists() + && specFileInfo.isAbsolute()) { + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->addToPreviousSpecFiles(specFileName); + } + } + try { m_specFile->clear(); *m_specFile = *sf; @@ -5569,20 +5687,6 @@ Brain::loadFilesSelectedInSpecFile(EventSpecFileReadDataFiles* readSpecFileDataF m_specFile->clearModified(); - const AString specFileName = sf->getFileName(); - if (DataFile::isFileOnNetwork(specFileName)) { - CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); - prefs->addToPreviousSpecFiles(specFileName); - } - else { - FileInformation specFileInfo(specFileName); - if (specFileInfo.exists() - && specFileInfo.isAbsolute()) { - CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); - prefs->addToPreviousSpecFiles(specFileName); - } - } - if (errorMessage.isEmpty() == false) { readSpecFileDataFilesEvent->setErrorMessage(errorMessage); } @@ -6129,6 +6233,43 @@ Brain::receiveEvent(Event* event) } } } + else if (event->getEventType() == EventTypeEnum::EVENT_SCENE_ACTIVE) { + EventSceneActive* sceneEvent = dynamic_cast(event); + CaretAssert(sceneEvent); + + switch (sceneEvent->getMode()) { + case EventSceneActive::MODE_GET: + { + if (m_activeScene != NULL) { + bool sceneFoundFlag = false; + + for (auto sf : m_sceneFiles) { + const int32_t numScenes = sf->getNumberOfScenes(); + for (int32_t i = 0; i < numScenes; i++) { + if (sf->getSceneAtIndex(i) == m_activeScene) { + sceneFoundFlag = true; + break; + } + } + if (sceneFoundFlag) { + break; + } + } + + if ( ! sceneFoundFlag) { + m_activeScene = NULL; + } + } + + sceneEvent->setScene(m_activeScene); + sceneEvent->setEventProcessed(); + } + break; + case EventSceneActive::MODE_SET: + m_activeScene = sceneEvent->getScene(); + break; + } + } } /** @@ -6500,9 +6641,13 @@ Brain::getAllDataFiles(std::vector& allDataFilesOut, m_sceneFiles.begin(), m_sceneFiles.end()); - allDataFilesOut.insert(allDataFilesOut.end(), - m_volumeFiles.begin(), - m_volumeFiles.end()); + for (auto vf : m_volumeFiles) { + allDataFilesOut.push_back(vf); + VolumeDynamicConnectivityFile* volDynConnFile = vf->getVolumeDynamicConnectivityFile(); + if (volDynConnFile != NULL) { + allDataFilesOut.push_back(volDynConnFile); + } + } } /** @@ -6701,6 +6846,8 @@ Brain::writeDataFile(CaretDataFile* caretDataFile) break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -6722,6 +6869,8 @@ Brain::writeDataFile(CaretDataFile* caretDataFile) break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } } @@ -6743,10 +6892,75 @@ Brain::removeWithoutDeleteDataFile(const CaretDataFile* caretDataFile) } /* - * Dense dynamic files are encapsulated in a dense-series file - * so they do not get removed. + * dynamic files are not removable. */ - if (caretDataFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { + bool canBeRemovedFlag(true); + switch (caretDataFile->getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + canBeRemovedFlag = false; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + canBeRemovedFlag = false; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + canBeRemovedFlag = false; + break; + } + if ( ! canBeRemovedFlag) { return false; } @@ -7204,20 +7418,22 @@ Brain::saveToScene(const SceneAttributes* sceneAttributes, iter != allCaretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; - - const AString caretDataFileName = cdf->getFileName(); // use full path 7/16/2015 cdf->getFileNameNoPath(); + + const AString caretDataFileName = cdf->getFileNameNoPath(); SceneClass* caretDataFileSceneClass = cdf->saveToScene(sceneAttributes, - caretDataFileName); + caretDataFileName); if (caretDataFileSceneClass != NULL) { + caretDataFileSceneClass->addPathName("dataFileName_V2", + cdf->getFileName()); allCaretDataFileScenes.push_back(caretDataFileSceneClass); } } if (allCaretDataFileScenes.empty() == false) { - SceneClassArray* caretDataFileSceneArray = new SceneClassArray("allCaretDataFiles", + SceneClassArray* caretDataFileSceneArray = new SceneClassArray("allCaretDataFiles_V2", allCaretDataFileScenes); sceneClass->addChild(caretDataFileSceneArray); } - + if (isSaveSpecFile) { SpecFile sf; sf.setFileName(m_specFile->getFileName()); @@ -7371,10 +7587,42 @@ Brain::restoreFromScene(const SceneAttributes* sceneAttributes, getAllDataFiles(allCaretDataFiles); /* - * Restore data files + * Restore data files. Try to restore "V2" and if not found, restore older version */ + const SceneClassArray* caretDataFileSceneArrayV2 = sceneClass->getClassArray("allCaretDataFiles_V2"); const SceneClassArray* caretDataFileSceneArray = sceneClass->getClassArray("allCaretDataFiles"); - if (caretDataFileSceneArray != NULL) { + if (caretDataFileSceneArrayV2 != NULL) { + /* + * Note: Name of element is name of file without path. + * A child of the element contains a ScenePathName containing + * name of file (full path in memory and relative to scene + * file name when file is written. + */ + for (auto caretDataFile : allCaretDataFiles) { + CaretAssert(caretDataFile); + const AString caretDataFileNameFullPath = caretDataFile->getFileName(); + const AString caretDataFileName = caretDataFile->getFileNameNoPath(); + + const int32_t numCaretDataFileScenes = caretDataFileSceneArrayV2->getNumberOfArrayElements(); + for (int32_t i = 0; i < numCaretDataFileScenes; i++) { + const SceneClass* fileSceneClass = caretDataFileSceneArrayV2->getClassAtIndex(i); + const AString fileName = fileSceneClass->getName(); + if (fileName == caretDataFileName) { + const AString fullPathFileName = fileSceneClass->getPathNameValue("dataFileName_V2"); + if (fullPathFileName == caretDataFileNameFullPath) { + caretDataFile->restoreFromScene(sceneAttributes, + fileSceneClass); + loadMatrixChartingFileDefaultRowOrColumn(caretDataFile); + break; // get out of inner file loop + } + } + } + } + } + else if (caretDataFileSceneArray != NULL) { + /* + * Restore old file data that used full pathss + */ for (std::vector::iterator iter = allCaretDataFiles.begin(); iter != allCaretDataFiles.end(); iter++) { @@ -7542,6 +7790,8 @@ Brain::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAnnotationFile->clearModified(); EventManager::get()->sendEvent(EventAnnotationTextSubstitutionInvalidate().getPointer()); + + setSurfaceMatchingToAnatomical(m_surfaceMatchingToAnatomicalFlag); } /** @@ -7677,5 +7927,28 @@ Brain::getFiberOrientationSphericalSamplesVectors(std::vectormatchSurfacesToPrimaryAnatomical(m_surfaceMatchingToAnatomicalFlag); + } +} + + diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index 946ac5277c45bfd546e841f87f4ff40906c5f1cb..a136fa8cd5573427576461faa295ed833a19bf6d 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -86,6 +86,7 @@ namespace caret { class ImageFile; class LabelFile; class MetricFile; + class MetricDynamicConnectivityFile; class ModelChart; class ModelChartTwo; class ModelSurfaceMontage; @@ -94,12 +95,14 @@ namespace caret { class PaletteFile; class RgbaFile; class SceneClassAssistant; + class Scene; class SceneFile; class SelectionManager; class SpecFile; class Surface; class SurfaceFile; class SurfaceProjectedItem; + class VolumeDynamicConnectivityFile; class VolumeFile; class Brain : public CaretObject, public EventListenerInterface, public SceneableInterface { @@ -187,6 +190,10 @@ namespace caret { const VolumeFile* getVolumeFile(const int32_t volumeFileIndex) const; + void getVolumeDynamicConnectivityFiles(std::vector& volumeDynamicConnectivityFilesOut) const; + + void getMetricDynamicConnectivityFiles(std::vector& metricDynamicConnectivityFilesOut) const; + void resetBrain(); void resetBrainKeepSceneFiles(); @@ -436,6 +443,10 @@ namespace caret { const GapsAndMargins* getGapsAndMargins() const; + bool isSurfaceMatchingToAnatomical() const; + + void setSurfaceMatchingToAnatomical(const bool matchStatus); + private: /** * Reset the brain scene file mode @@ -707,6 +718,8 @@ namespace caret { void initializeDenseDataSeriesFile(CiftiBrainordinateDataSeriesFile* dataSeriesFile); + void initializeVolumeFile(VolumeFile* volumeFile); + void updateChartModel(); void updateVolumeSliceModel(); @@ -868,6 +881,10 @@ namespace caret { std::map m_duplicateFileNameCounter; GapsAndMargins* m_gapsAndMargins; + + Scene* m_activeScene = NULL; + + bool m_surfaceMatchingToAnatomicalFlag = false; }; } // namespace diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 0e21fbd0b4b14c937513fb1ddaf80195d975aba5..b51d38094e14629ae767fa175b12a921474c96df 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -200,6 +200,8 @@ BrainOpenGL::receiveEvent(Event* event) * * @param windowIndex * Index of window for drawing. + * @param windowsUserInputMode + * User input mode for window * @param brain * The brain (must be valid!) * @param contextSharingGroupPointer @@ -208,6 +210,7 @@ BrainOpenGL::receiveEvent(Event* event) * Viewport info for drawing. */ void BrainOpenGL::drawModels(const int32_t windowIndex, + const UserInputModeEnum::Enum windowsUserInputMode, Brain* brain, void* contextSharingGroupPointer, const std::vector& viewportContents) @@ -222,6 +225,7 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, drawModelsImplementation(windowIndex, + windowsUserInputMode, brain, vpContents); @@ -235,6 +239,8 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, * * @param windowIndex * Index of window for selection. + * @param windowsUserInputMode + * User input mode for window * @param brain * The brain (must be valid!) * @param contextSharingGroupPointer @@ -254,6 +260,7 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, * selected. */ void BrainOpenGL::selectModel(const int32_t windowIndex, + const UserInputModeEnum::Enum windowsUserInputMode, Brain* brain, void* contextSharingGroupPointer, const BrainOpenGLViewportContent* viewportContent, @@ -264,6 +271,7 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, m_contextSharingGroupPointer = contextSharingGroupPointer; selectModelImplementation(windowIndex, + windowsUserInputMode, brain, viewportContent, mouseX, @@ -283,6 +291,8 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, * * @param windowIndex * Index of window for projection + * @param windowsUserInputMode + * User input mode for window * @param brain * The brain (must be valid!) * @param contextSharingGroupPointer @@ -297,16 +307,18 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, * Output with projection result. */ void BrainOpenGL::projectToModel(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, - void* contextSharingGroupPointer, - const BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - SurfaceProjectedItem& projectionOut) + void* contextSharingGroupPointer, + const BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + SurfaceProjectedItem& projectionOut) { m_contextSharingGroupPointer = contextSharingGroupPointer; projectToModelImplementation(windowIndex, + windowUserInputMode, brain, viewportContent, mouseX, @@ -638,226 +650,6 @@ BrainOpenGL::getOpenGLMajorMinorVersions(const AString& versionString, } } -///** -// * Initialize the drawing mode using the most optimal drawing given -// * the compile time and run time constraints. -// */ -//void -//BrainOpenGL::initializeOpenGL() -//{ -// AString compileVersions = "OpenGL Header File Versions Supported: "; -//#ifdef GL_VERSION_1_1 -// compileVersions += " 1.1"; -//#endif -//#ifdef GL_VERSION_1_2 -// compileVersions += " 1.2"; -//#endif -//#ifdef GL_VERSION_1_3 -// compileVersions += " 1.3"; -//#endif -//#ifdef GL_VERSION_1_4 -// compileVersions += " 1.4"; -//#endif -//#ifdef GL_VERSION_1_5 -// compileVersions += " 1.5"; -//#endif -//#ifdef GL_VERSION_2_0 -// compileVersions += " 2.0"; -//#endif -//#ifdef GL_VERSION_2_1 -// compileVersions += " 2.1"; -//#endif -//#ifdef GL_VERSION_3_0 -// compileVersions += " 3.0"; -//#endif -//#ifdef GL_VERSION_3_1 -// compileVersions += " 3.1"; -//#endif -//#ifdef GL_VERSION_3_2 -// compileVersions += " 3.2"; -//#endif -//#ifdef GL_VERSION_3_3 -// compileVersions += " 3.3"; -//#endif -//#ifdef GL_VERSION_4_0 -// compileVersions += " 4.0"; -//#endif -//#ifdef GL_VERSION_4_1 -// compileVersions += " 4.1"; -//#endif -//#ifdef GL_VERSION_4_2 -// compileVersions += " 4.2"; -//#endif -//#ifdef GL_VERSION_4_3 -// compileVersions += " 4.3"; -//#endif -//#ifdef GL_VERSION_4_4 -// compileVersions += " 4.4"; -//#endif -//#ifdef GL_VERSION_4_4 -// compileVersions += " 4.4"; -//#endif -//#ifdef GL_VERSION_4_5 -// compileVersions += " 4.5"; -//#endif -//#ifdef GL_VERSION_5_0 -// compileVersions += " 5.0"; -//#endif -// -//#ifdef GL_OES_VERSION_1_0 -// compileVersions += " ES_1.0"; -//#endif -//#ifdef GL_ES_VERSION_2_0 -// compileVersions += " ES_2.0"; -//#endif -//#ifdef GL_ES_VERSION_3_0 -// compileVersions += " ES_3.0"; -//#endif -// -// s_runtimeLibraryVersionOfOpenGL = QLatin1String(reinterpret_cast(glGetString(GL_VERSION))); -// if (s_runtimeLibraryVersionOfOpenGL.isEmpty()) { -// s_runtimeLibraryVersionOfOpenGL = "1.1"; -// } -// getOpenGLMajorMinorVersions(s_runtimeLibraryVersionOfOpenGL, -// s_runtimeLibraryMajorVersionOfOpenGL, -// s_runtimeLibraryMinorVersionOfOpenGL); -// -// // -// // Note: The version string might be something like 1.2.4. std::atof() -// // will get just the 1.2 which is okay. -// // -// const char* vendorStr = (char*)(glGetString(GL_VENDOR)); -// const char* renderStr = (char*)(glGetString(GL_RENDERER)); -// AString lineInfo = (compileVersions -// + "\nOpenGL Runtime Version: " + s_runtimeLibraryVersionOfOpenGL -// + "\nMajor Runtime Version: " + BrainOpenGL::s_runtimeLibraryMajorVersionOfOpenGL -// + "\nMinor Runtime Version: " + BrainOpenGL::s_runtimeLibraryMinorVersionOfOpenGL -// + "\nOpenGL Vendor: " + AString(vendorStr) -// + "\nOpenGL Renderer: " + AString(renderStr)); -// -// lineInfo += "\n"; -// lineInfo += ("\nFont Renderer: " + m_textRenderer->getName()); -// lineInfo += "\n"; -// -//#ifdef GL_VERSION_2_0 -// if (testForVersionOfOpenGLSupported("2.0")) { -// GLfloat values[2]; -// glGetFloatv (GL_ALIASED_LINE_WIDTH_RANGE, values); -// const AString aliasedLineWidthRange = ("GL_ALIASED_LINE_WIDTH_RANGE value is " -// + AString::fromNumbers(values, 2, ", ")); -// -// glGetFloatv (GL_SMOOTH_LINE_WIDTH_RANGE, values); -// const AString smoothLineWidthRange = ("GL_SMOOTH_LINE_WIDTH_RANGE value is " -// + AString::fromNumbers(values, 2, ", ")); -// -// glGetFloatv (GL_SMOOTH_LINE_WIDTH_GRANULARITY, values); -// const AString smoothLineWidthGranularity = ("GL_SMOOTH_LINE_WIDTH_GRANULARITY value is " -// + AString::number(values[0])); -// -// lineInfo += ("\n" + aliasedLineWidthRange -// + "\n" + smoothLineWidthRange -// + "\n" + smoothLineWidthGranularity); -// } -//#endif // GL_VERSION_2_0 -////#else // GL_VERSION_2_0 -// GLfloat values[2]; -// glGetFloatv (GL_LINE_WIDTH_RANGE, values); -// const AString lineWidthRange = ("GL_LINE_WIDTH_RANGE value is " -// + AString::fromNumbers(values, 2, ", ")); -// -// glGetFloatv (GL_LINE_WIDTH_GRANULARITY, values); -// const AString lineWidthGranularity = ("GL_LINE_WIDTH_GRANULARITY value is " -// + AString::number(values[0])); -// lineInfo += ("\n" + lineWidthRange -// + "\n" + lineWidthGranularity); -////#endif // GL_VERSION_2_0 -// -// float sizes[2]; -// glGetFloatv(GL_POINT_SIZE_RANGE, sizes); -// s_minPointSize = sizes[0]; -// s_maxPointSize = sizes[1]; -// glGetFloatv(GL_LINE_WIDTH_RANGE, sizes); -// s_minLineWidth = sizes[0]; -// s_maxLineWidth = sizes[1]; -// -// s_supportsDisplayLists = false; -// s_supportsImmediateMode = false; -// s_supportsVertexBuffers = false; -// -// GLint maximumNumberOfClipPlanes; -// glGetIntegerv(GL_MAX_CLIP_PLANES, -// & maximumNumberOfClipPlanes); -// lineInfo += ("\n\nMaximum number of clipping planes is " -// + AString::number(maximumNumberOfClipPlanes)); -// -// GLint redBits, greenBits, blueBits, alphaBits; -// glGetIntegerv(GL_RED_BITS, &redBits); -// glGetIntegerv(GL_GREEN_BITS, &greenBits); -// glGetIntegerv(GL_BLUE_BITS, &blueBits); -// glGetIntegerv(GL_ALPHA_BITS, &alphaBits); -// lineInfo += ("\n\nBuffer bits red/green/blue/apha: (" -// + AString::number(redBits) + ", " -// + AString::number(greenBits) + ", " -// + AString::number(blueBits) + ", " -// + AString::number(alphaBits) + ")"); -// -// /* -// * Get the OpenGL Extensions. -// */ -// bool haveARBCompatibility = false; -// const QString extensionsString((char*)glGetString(GL_EXTENSIONS)); -// const QStringList extensionsList = extensionsString.split(QChar(' ')); -// QStringListIterator extensionsIterator(extensionsList); -// AString extInfo = ("\n\nOpenGL Extensions:"); -// while (extensionsIterator.hasNext()) { -// const QString ext = extensionsIterator.next(); -// extInfo += ("\n " + ext); -// -// if (ext == "GL_ARB_compatibility") { -// haveARBCompatibility = true; -// } -// } -// -// if (testForVersionOfOpenGLSupported("3.1")) { -// if (haveARBCompatibility == false) { -// CaretLogSevere("OpenGL 3.1 or later and ARB compatibilty extensions not found.\n" -// "OpenGL may fail."); -// } -// } -// -//#if BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE -// s_supportsImmediateMode = true; -//#endif // BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE -// -//#if BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS -// s_supportsDisplayLists = true; -//#endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS -// -//#ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS -// s_supportsVertexBuffers = true; -//#endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS -// -// lineInfo += ("\n\nBest Drawing Mode: " -// + BrainOpenGL::getBestDrawingModeName()); -// lineInfo += ("\nDisplay Lists Supported: " -// + AString::fromBool(s_supportsDisplayLists)); -// lineInfo += ("\nImmediate Mode Supported: " -// + AString::fromBool(s_supportsImmediateMode)); -// lineInfo += ("\nVertex Buffers Supported: " -// + AString::fromBool(s_supportsVertexBuffers)); -// -// lineInfo += extInfo; -// -// CaretLogConfig(lineInfo); -// -// m_openGLInformation = lineInfo; -// -// /* -// * Call to validate the draw mode selection logic. -// */ -// getBestDrawingMode(); -//} - /** * Initialize the drawing mode using the most optimal drawing given * the compile time and run time constraints. @@ -1031,6 +823,9 @@ BrainOpenGL::getOpenGLInformation() #ifdef GL_VERSION_2_0 if (testForVersionOfOpenGLSupported("2.0")) { + const char* glslVersionString = (char*)glGetString(GL_SHADING_LANGUAGE_VERSION); + lineInfo += ("\nOpenGL Shading Language (GLSL) Version: " + AString(glslVersionString) + "\n"); + GLfloat values[2]; glGetFloatv (GL_ALIASED_LINE_WIDTH_RANGE, values); const AString aliasedLineWidthRange = ("GL_ALIASED_LINE_WIDTH_RANGE value is " @@ -1118,6 +913,16 @@ BrainOpenGL::getOpenGLInformation() lineInfo += ("\nSamples Count: " + AString::number(sampleCount)); lineInfo += ("\nMultisampling Enabled: " + AString::fromBool(glIsEnabled(GL_MULTISAMPLE))); + GLint textureMax, texture3DMax; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, + &textureMax); + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, + &texture3DMax); + lineInfo += "\n"; + lineInfo += ("\nTexture Max: " + AString::number(textureMax)); + lineInfo += ("\nTexture 3D Max: " + AString::number(texture3DMax)); + lineInfo += "\n"; + lineInfo += "\n"; lineInfo += "\n"; lineInfo += "Note that State of OpenGL may be different when drawing objects.\n"; diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index 38d41d4749b6ebcd3b4e33cabd64e98de32803c0..83ddf55ec1cdfb27de15a129d6829611d3fe8d67 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -29,8 +29,8 @@ #include #include "CaretOpenGLInclude.h" - #include "CaretObject.h" +#include "UserInputModeEnum.h" #undef BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS #undef BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE @@ -103,11 +103,13 @@ namespace caret { BrainOpenGLTextRenderInterface* getTextRenderer(); void drawModels(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, void* contextSharingGroupPointer, const std::vector& viewportContents); void selectModel(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, void* contextSharingGroupPointer, const BrainOpenGLViewportContent* viewportContent, @@ -116,6 +118,7 @@ namespace caret { const bool applySelectionBackgroundFiltering); void projectToModel(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, void* contextSharingGroupPointer, const BrainOpenGLViewportContent* viewportContent, @@ -233,12 +236,15 @@ namespace caret { * * @param windowIndex * Index of window for drawing + * @param windowUserInputMode + * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContents * Viewport info for drawing. */ virtual void drawModelsImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const std::vector& viewportContents) = 0; @@ -247,6 +253,8 @@ namespace caret { * * @param windowIndex * Index of window for selection + * @param userInputMode + * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent @@ -264,12 +272,13 @@ namespace caret { * selected. */ virtual void selectModelImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, - const BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - const bool applySelectionBackgroundFiltering) = 0; - + const BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + const bool applySelectionBackgroundFiltering) = 0; + /** * Project the given window coordinate to the active models. * If the projection is successful, The 'original' XYZ @@ -278,6 +287,8 @@ namespace caret { * * @param windowIndex * Index of window for projection + * @param userInputMode + * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent @@ -290,11 +301,12 @@ namespace caret { * Output with projection result. */ virtual void projectToModelImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, - const BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - SurfaceProjectedItem& projectionOut) = 0; + const BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + SurfaceProjectedItem& projectionOut) = 0; AString getOpenGLEnabledEnumAsText(const AString& enumName, const GLenum enumValue) const; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 1fa7cc4902523951a399af0c4a30d5e17011bbf0..75c5a92c756fb0daf64899a314632173136ef708 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -56,14 +56,17 @@ #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fN3f.h" #include "GraphicsPrimitiveV3fT3f.h" #include "GraphicsShape.h" +#include "GraphicsUtilitiesOpenGL.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "SelectionManager.h" #include "SelectionItemAnnotation.h" #include "Surface.h" +#include "TopologyHelper.h" using namespace caret; @@ -144,8 +147,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::viewportToOpenGLWindowCoordinate(cons * The annotation. * @param coordinate * The annotation coordinate whose window coordinate is computed. - * @param annotationCoordSpace - * The annotation coordinate space. * @param surfaceDisplayed * Surface that is displayed (may be NULL !) * @param xyzOut @@ -159,6 +160,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c const Surface* surfaceDisplayed, float xyzOut[3]) const { + CaretAssert(annotation); const AnnotationCoordinateSpaceEnum::Enum annotationCoordSpace = annotation->getCoordinateSpace(); float modelXYZ[3] = { 0.0, 0.0, 0.0 }; @@ -177,6 +179,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c modelXYZ[2] = annotationXYZ[2]; modelXYZValid = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + viewportToOpenGLWindowCoordinate(annotationXYZ, drawingSpaceXYZ); + drawingSpaceXYZValid = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: modelXYZ[0] = annotationXYZ[0]; modelXYZ[1] = annotationXYZ[1]; @@ -217,6 +223,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c annotationOffsetLength, annotationOffsetVector); + /* + * Always use surface offset vector reported by annotation since + * annotations with multiple coordinates must use the same offset + */ + annotationOffsetVector = annotation->getSurfaceOffsetVectorType(); + const StructureEnum::Enum surfaceStructure = surfaceDisplayed->getStructure(); const int32_t surfaceNumberOfNodes = surfaceDisplayed->getNumberOfNodes(); if ((surfaceStructure == annotationStructure) @@ -241,7 +253,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c * */ if (surfaceDisplayed->getSurfaceType() == SurfaceTypeEnum::FLAT) { - annotationOffsetVector = AnnotationSurfaceOffsetVectorTypeEnum::SURACE_NORMAL; + annotationOffsetVector = AnnotationSurfaceOffsetVectorTypeEnum::SURFACE_NORMAL; } switch (annotationOffsetVector) { @@ -256,12 +268,18 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c surfaceCenter, offsetUnitVector); MathFunctions::normalizeVector(offsetUnitVector); - } break; - case AnnotationSurfaceOffsetVectorTypeEnum::SURACE_NORMAL: + } + break; + case AnnotationSurfaceOffsetVectorTypeEnum::SURFACE_NORMAL: + { const float* normalVector = surfaceDisplayed->getNormalVector(annotationNodeIndex); offsetUnitVector[0] = normalVector[0]; offsetUnitVector[1] = normalVector[1]; offsetUnitVector[2] = normalVector[2]; + } + break; + case AnnotationSurfaceOffsetVectorTypeEnum::TANGENT: + CaretAssert(0); break; } @@ -465,6 +483,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic { CaretAssert(inputs); m_inputs = inputs; + m_surfaceViewScaling = 1.0f; m_volumeSpacePlaneValid = false; if (plane.isValidPlane()) { @@ -497,16 +516,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic * Annotations that are not in a file but need to be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. + * @param surfaceViewScaling + * Scaling of the viewed surface. */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, std::vector& notInFileAnnotations, - const Surface* surfaceDisplayed) + const Surface* surfaceDisplayed, + const float surfaceViewScaling) { CaretAssert(inputs); m_inputs = inputs; + m_surfaceViewScaling = surfaceViewScaling; m_volumeSpacePlaneValid = false; @@ -581,6 +604,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat switch (drawingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + haveDisplayGroupFlag = false; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -695,6 +721,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat switch (drawingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -828,40 +856,90 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat continue; } - /* - * Skip annotation in a different window - */ - if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { - const int32_t annotationWindowIndex = annotation->getWindowIndex(); - if ((annotationWindowIndex < 0) - || (annotationWindowIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { - CaretLogSevere("Annotation has invalid window index=" - + AString::number(annotationWindowIndex) - + " " - + annotation->toString()); - } - if (m_inputs->m_windowIndex != annotationWindowIndex) { - continue; + switch (annotationCoordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::SPACER: + { + const SpacerTabIndex spacerTabIndex = annotation->getSpacerTabIndex(); + CaretAssert(spacerTabIndex.isValid()); + if (m_inputs->m_spacerTabIndex != spacerTabIndex) { + continue; + } } - } - - /* - * Skip annotations in a different tab - */ - if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::TAB) { - const int32_t annotationTabIndex = annotation->getTabIndex(); - if ((annotationTabIndex < 0) - || (annotationTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { - CaretLogSevere("Annotation has invalid tab index=" - + AString::number(annotationTabIndex) - + " " - + annotation->toString()); + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + { + const int32_t annotationTabIndex = annotation->getTabIndex(); + if ((annotationTabIndex < 0) + || (annotationTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { + CaretLogSevere("Annotation has invalid tab index=" + + AString::number(annotationTabIndex) + + " " + + annotation->toString()); + } + if (m_inputs->m_tabIndex != annotationTabIndex) { + continue; + } } - if (m_inputs->m_tabIndex != annotationTabIndex) { - continue; + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + { + const int32_t annotationWindowIndex = annotation->getWindowIndex(); + if ((annotationWindowIndex < 0) + || (annotationWindowIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { + CaretLogSevere("Annotation has invalid window index=" + + AString::number(annotationWindowIndex) + + " " + + annotation->toString()); + } + if (m_inputs->m_windowIndex != annotationWindowIndex) { + continue; + } } + break; } +// /* +// * Skip annotation in a different window +// */ +// if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { +// const int32_t annotationWindowIndex = annotation->getWindowIndex(); +// if ((annotationWindowIndex < 0) +// || (annotationWindowIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { +// CaretLogSevere("Annotation has invalid window index=" +// + AString::number(annotationWindowIndex) +// + " " +// + annotation->toString()); +// } +// if (m_inputs->m_windowIndex != annotationWindowIndex) { +// continue; +// } +// } +// +// /* +// * Skip annotations in a different tab +// */ +// if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::TAB) { +// const int32_t annotationTabIndex = annotation->getTabIndex(); +// if ((annotationTabIndex < 0) +// || (annotationTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { +// CaretLogSevere("Annotation has invalid tab index=" +// + AString::number(annotationTabIndex) +// + " " +// + annotation->toString()); +// } +// if (m_inputs->m_tabIndex != annotationTabIndex) { +// continue; +// } +// } + drawAnnotation(annotationFile, annotation, surfaceDisplayed); @@ -1066,58 +1144,391 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annota bool drawnFlag = false; - switch (annotation->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::CHART: - break; - case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - break; - case AnnotationCoordinateSpaceEnum::SURFACE: - break; - case AnnotationCoordinateSpaceEnum::TAB: - break; - case AnnotationCoordinateSpaceEnum::VIEWPORT: - break; - case AnnotationCoordinateSpaceEnum::WINDOW: - break; + if (annotation->isInSurfaceSpaceWithTangentOffset()) { + AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); + if (twoDimAnn != NULL) { + drawnFlag = drawTwoDimAnnotationSurfaceTextureOffset(annotationFile, + twoDimAnn, + surfaceDisplayed); + } + else { + AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); + drawnFlag = drawOneDimAnnotationSurfaceTextureOffset(annotationFile, + oneDimAnn, + surfaceDisplayed); + } + } + else { + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + drawnFlag = drawBox(annotationFile, + dynamic_cast(annotation), + surfaceDisplayed); + break; + case AnnotationTypeEnum::COLOR_BAR: + drawColorBar(annotationFile, + dynamic_cast(annotation)); + break; + case AnnotationTypeEnum::IMAGE: + drawnFlag = drawImage(annotationFile, + dynamic_cast(annotation), + surfaceDisplayed); + break; + case AnnotationTypeEnum::LINE: + drawnFlag = drawLine(annotationFile, + dynamic_cast(annotation), + surfaceDisplayed); + break; + case AnnotationTypeEnum::OVAL: + drawnFlag = drawOval(annotationFile, + dynamic_cast(annotation), + surfaceDisplayed); + break; + case AnnotationTypeEnum::TEXT: + drawnFlag = drawText(annotationFile, + dynamic_cast(annotation), + surfaceDisplayed); + break; + } + } + + if (drawnFlag) { + annotation->setDrawnInWindowStatus(m_inputs->m_windowIndex); + } +} + +/** + * Draw a two-dimensional annotation that is in surface space with a texture offset. + * + * @param annotationFile + * File containing the annotation. + * @param annotation + * Annotation to draw. + * @param surfaceDisplayed + * Surface that is displayed (may be NULL). + * @return + * True if the anntotation was drawn, else false. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawTwoDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, + AnnotationTwoDimensionalShape* annotation, + const Surface* surfaceDisplayed) +{ + bool drawnFlag = false; + + CaretAssert(annotationFile); + CaretAssert(annotation); + CaretAssert(surfaceDisplayed); + + + const AnnotationCoordinate* coord = annotation->getCoordinate(); + CaretAssert(coord->getSurfaceOffsetVectorType() == AnnotationSurfaceOffsetVectorTypeEnum::TANGENT); + StructureEnum::Enum structure; + int32_t surfaceNumberOfNodes(0); + int32_t vertexIndex(0); + float offsetLength(0.0f); + AnnotationSurfaceOffsetVectorTypeEnum::Enum offsetVectorType; + coord->getSurfaceSpace(structure, surfaceNumberOfNodes, vertexIndex, offsetLength, offsetVectorType); + + if (structure != surfaceDisplayed->getStructure()) { + return false; + } + if (surfaceDisplayed->getNumberOfNodes() != surfaceNumberOfNodes) { + return false; + } + float vertexXYZ[3]; + surfaceDisplayed->getCoordinate(vertexIndex, + vertexXYZ); + float normalXYZ[3]; + getSurfaceNormalVector(surfaceDisplayed, vertexIndex, normalXYZ); + const BoundingBox* boundingBox = surfaceDisplayed->getBoundingBox(); + const float surfaceExtentZ = ((surfaceDisplayed->getSurfaceType() == SurfaceTypeEnum::FLAT) + ? boundingBox->getDifferenceY() + : boundingBox->getDifferenceZ()); + + /* + * Need to restore model space + * Recall that all other annotation spaces are drawn in window space + */ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixd(m_modelSpaceProjectionMatrix); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixd(m_modelSpaceModelMatrix); + int32_t savedViewport[4]; + glGetIntegerv(GL_VIEWPORT, + savedViewport); + glViewport(m_modelSpaceViewport[0], + m_modelSpaceViewport[1], + m_modelSpaceViewport[2], + m_modelSpaceViewport[3]); + + glPushMatrix(); + + /* + * Matrix that rotates annotation to plane of vertex's normal vector + */ + Matrix4x4 rotationMatrix; + rotationMatrix.setMatrixToOpenGLRotationFromVector(normalXYZ); + double rotationArray[16]; + rotationMatrix.getMatrixForOpenGL(rotationArray); + + + /* + * Translate to the vertex and then translate using offset + * vector of text. + */ + const float offsetVectorXYZ[3] { + normalXYZ[0] * offsetLength, + normalXYZ[1] * offsetLength, + normalXYZ[2] * offsetLength + }; + glTranslatef(vertexXYZ[0], vertexXYZ[1], vertexXYZ[2]); + glTranslatef(offsetVectorXYZ[0], offsetVectorXYZ[1], offsetVectorXYZ[2]); + + /* + * Rotate into plane of surface normal vector + */ + glMultMatrixd(rotationArray); + + /* + * Up vector in local coordinates (text drawing plane) + * Z points out of text + */ + const float len(25.0f); + const float localUpXYZ[3] { + 0.0, + len, + 0.0 + }; + + /* + * Inverse matrix goes back to surface coordinate system + */ + Matrix4x4 inverseMatrix(rotationMatrix); + inverseMatrix.invert(); + + /* + * Create the plane in which text is drawn + * (plane is not used for drawing text but is used + * to orient the text). The plane is constructed + * from the vertex's normal vector and the the + * vertex's XYZ-coordinate. + */ + Plane textDrawingPlane(normalXYZ, + vertexXYZ); + + /* + * Project a point with a large Z-coordinate to the plane + * and use it to creat the 'text up orientation vector'. + */ + const float zBig[3] { 0.0, 0.0, 10000.0 }; + float textUpOrientationVectorXYZ[3]; + textDrawingPlane.projectPointToPlane(zBig, textUpOrientationVectorXYZ); + inverseMatrix.multiplyPoint3(textUpOrientationVectorXYZ); + + /* + * Vector is parallel to surface Z-axis + */ + float vectorSurfaceAxisZ[3] = { 0.0f, 0.0f, 100.0f }; + inverseMatrix.multiplyPoint3(vectorSurfaceAxisZ); + + if (debugFlag) { + /* + * Red line is normal vector + * Green line is "text up" vector + * Blue points to surface Z-vector + * Yellow is parallel to surface Z-axis + */ + const float startXYZ[3] { + 0.0, + 0.0, + 0.0 + }; + const float endXYZ[3] { + 0.0, + 0.0, + len + }; + glBegin(GL_LINES); + glColor3f(1.0, 0.0, 0.0); + glVertex3fv(startXYZ); + glVertex3fv(endXYZ); + glColor3f(0.0, 1.0, 0.0); + glVertex3fv(startXYZ); + glVertex3fv(localUpXYZ); + glColor3f(0.0, 0.0, 1.0); + glVertex3fv(startXYZ); + glVertex3fv(textUpOrientationVectorXYZ); + glColor3f(1.0, 1.0, 0.0); + glVertex3fv(startXYZ); + glVertex3fv(vectorSurfaceAxisZ); + glEnd(); + } + + /* + * Rotate the text so that the horzontal flow of the text + * is orthogonal to the 'text up orientation vector'. + */ + const float orientationUpAngle = MathFunctions::angleInDegreesBetweenVectors(localUpXYZ, + vectorSurfaceAxisZ); + + if (debugFlag) { + std::cout << "Annotation: " << annotation->toString() << std::endl; + std::cout << " Plane: " << textDrawingPlane.toString() << std::endl; + std::cout << " Local Up Vector: " << AString::fromNumbers(localUpXYZ, 3, ", ") << std::endl; + std::cout << " Angle: " << orientationUpAngle << std::endl; + } + + /* + * Do not adjust tangent text on flat surfaces + */ + if (surfaceDisplayed->getSurfaceType() != SurfaceTypeEnum::FLAT) { + /* + * Rotates annotation so that its horizontal axis is aligned with the + * 'best matching' cartesian axis. + */ + const float angle = annotation->getSurfaceSpaceWithTangentOffsetRotation(structure, + normalXYZ); + glRotated(angle, 0.0, 0.0, -1.0); + } + + + /* + * Note that text is rotated by the text renderer + */ + if (annotation->getType() != AnnotationTypeEnum::TEXT) { + glRotated(annotation->getRotationAngle(), 0.0, 0.0, -1.0); } switch (annotation->getType()) { case AnnotationTypeEnum::BOX: - drawnFlag = drawBox(annotationFile, - dynamic_cast(annotation), - surfaceDisplayed); + drawnFlag = drawBoxSurfaceTangentOffset(annotationFile, + dynamic_cast(annotation), + surfaceExtentZ, + vertexXYZ); break; case AnnotationTypeEnum::COLOR_BAR: - drawColorBar(annotationFile, - dynamic_cast(annotation)); + CaretAssertMessage(0, "Color Bar is NEVER drawn in surface space"); break; case AnnotationTypeEnum::IMAGE: - drawnFlag = drawImage(annotationFile, - dynamic_cast(annotation), - surfaceDisplayed); + drawnFlag = drawImageSurfaceTangentOffset(annotationFile, + dynamic_cast(annotation), + surfaceExtentZ, + vertexXYZ); break; case AnnotationTypeEnum::LINE: - drawnFlag = drawLine(annotationFile, - dynamic_cast(annotation), - surfaceDisplayed); + CaretAssert(0); break; case AnnotationTypeEnum::OVAL: - drawnFlag = drawOval(annotationFile, - dynamic_cast(annotation), - surfaceDisplayed); + drawnFlag = drawOvalSurfaceTangentOffset(annotationFile, + dynamic_cast(annotation), + surfaceExtentZ, + vertexXYZ); break; case AnnotationTypeEnum::TEXT: - drawnFlag = drawText(annotationFile, - dynamic_cast(annotation), - surfaceDisplayed); + drawnFlag = drawTextSurfaceTangentOffset(annotationFile, + dynamic_cast(annotation), + surfaceExtentZ, + vertexXYZ, + normalXYZ); break; } - if (drawnFlag) { - annotation->setDrawnInWindowStatus(m_inputs->m_windowIndex); - } + glPopMatrix(); /* restore MODELVIEW */ + + glViewport(savedViewport[0], + savedViewport[1], + savedViewport[2], + savedViewport[3]); + glPopMatrix(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + return drawnFlag; } +/** + * Draw a one-dimensional annotation that is in surface space with a texture offset. + * + * @param annotationFile + * File containing the annotation. + * @param annotation + * Annotation to draw. + * @param surfaceDisplayed + * Surface that is displayed (may be NULL). + * @return + * True if the anntotation was drawn, else false. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawOneDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, + AnnotationOneDimensionalShape* annotation, + const Surface* surfaceDisplayed) +{ + CaretAssert(annotationFile); + CaretAssert(annotation); + CaretAssert(surfaceDisplayed); + + bool drawnFlag = false; + + + const BoundingBox* boundingBox = surfaceDisplayed->getBoundingBox(); + const float surfaceExtentZ = boundingBox->getDifferenceZ(); + + /* + * Need to restore model space + * Recall that all other annotation spaces are drawn in window space + */ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixd(m_modelSpaceProjectionMatrix); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixd(m_modelSpaceModelMatrix); + int32_t savedViewport[4]; + glGetIntegerv(GL_VIEWPORT, + savedViewport); + glViewport(m_modelSpaceViewport[0], + m_modelSpaceViewport[1], + m_modelSpaceViewport[2], + m_modelSpaceViewport[3]); + + glPushMatrix(); + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + case AnnotationTypeEnum::COLOR_BAR: + case AnnotationTypeEnum::IMAGE: + case AnnotationTypeEnum::OVAL: + case AnnotationTypeEnum::TEXT: + CaretAssert(0); + break; + case AnnotationTypeEnum::LINE: + drawnFlag = drawLineSurfaceTextureOffset(annotationFile, + dynamic_cast(annotation), + surfaceDisplayed, + surfaceExtentZ); + break; + } + + glPopMatrix(); /* restore MODELVIEW */ + + glViewport(savedViewport[0], + savedViewport[1], + savedViewport[2], + savedViewport[3]); + glPopMatrix(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + return drawnFlag; +} /** * Draw an annotation box. @@ -1203,13 +1614,14 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ + const float percentHeight = getLineWidthPercentageInSelectionMode(box); GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, - box->getLineWidthPercentage()); + percentHeight); } m_selectionInfo.push_back(SelectionInfo(annotationFile, @@ -1256,7 +1668,137 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil } /** - * Draw an annotation box. + * Draw an annotation box in surface tangent offset space + * + * @param annotationFile + * File containing the annotation. + * @param box + * box to draw. + * @param surfaceExtentZ + * Z-extent of the surface. + * @param vertexXYZ + * Coordinate of the vertex. + * @return + * True if the annotation was drawn while NOT selecting annotations. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawBoxSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationBox* box, + const float surfaceExtentZ, + const float vertexXYZ[3]) +{ + CaretAssert(annotationFile); + CaretAssert(box); + CaretAssert(box->getType() == AnnotationTypeEnum::BOX); + + const float halfWidth = ((box->getWidth() / 100.0) * surfaceExtentZ) / 2.0; + const float halfHeight = ((box->getHeight() / 100.0) * surfaceExtentZ) / 2.0; + float bottomLeft[3] { -halfWidth, -halfHeight, 0.0f }; + float bottomRight[3] { halfWidth, -halfHeight, 0.0f }; + float topRight[3] { halfWidth, halfHeight, 0.0f }; + float topLeft[3] { -halfWidth, halfHeight, 0.0f }; + + const float selectionCenterXYZ[3] = { + vertexXYZ[0], + vertexXYZ[1], + vertexXYZ[2] + }; + + float lineThickness = ((box->getLineWidthPercentage() / 100.0) + * surfaceExtentZ); + if (m_selectionModeFlag) { + lineThickness = std::max(lineThickness, + s_selectionLineMinimumPixelWidth); + } + + uint8_t backgroundRGBA[4]; + box->getBackgroundColorRGBA(backgroundRGBA); + uint8_t foregroundRGBA[4]; + box->getLineColorRGBA(foregroundRGBA); + + const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); + const bool drawForegroundFlag = (foregroundRGBA[3] > 0); + const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); + + bool drawnFlag = false; + + if (drawAnnotationFlag) { + if (m_selectionModeFlag) { + uint8_t selectionColorRGBA[4]; + getIdentificationColor(selectionColorRGBA); + + if (drawBackgroundFlag) { + /* + * When selecting draw only background if it is enabled + * since it is opaque and prevents "behind" annotations + * from being selected + */ + GraphicsShape::drawBoxFilledByteColor(bottomLeft, + bottomRight, + topRight, + topLeft, + selectionColorRGBA); + } + else { + /* + * Drawing foreground as line will still allow user to + * select annotation that are inside of the box + */ + GraphicsShape::drawBoxOutlineByteColor(bottomLeft, + bottomRight, + topRight, + topLeft, + selectionColorRGBA, + GraphicsPrimitive::LineWidthType::PIXELS, + lineThickness); + } + + m_selectionInfo.push_back(SelectionInfo(annotationFile, + box, + AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, + selectionCenterXYZ)); + } + else { + if (drawBackgroundFlag) { + GraphicsShape::drawBoxFilledByteColor(bottomLeft, + bottomRight, + topRight, + topLeft, + backgroundRGBA); + drawnFlag = true; + } + + if (drawForegroundFlag) { + glPolygonOffset(-1.0, -1.0); + glEnable(GL_POLYGON_OFFSET_FILL); + GraphicsShape::drawOutlineRectangleVerticesInMiddle(bottomLeft, + bottomRight, + topRight, + topLeft, + lineThickness, + foregroundRGBA); + drawnFlag = true; + glDisable(GL_POLYGON_OFFSET_FILL); + } + } + if (box->isSelectedForEditing(m_inputs->m_windowIndex)) { + drawAnnotationTwoDimSizingHandles(annotationFile, + box, + bottomLeft, + bottomRight, + topRight, + topLeft, + s_sizingHandleLineWidthInPixels, + box->getRotationAngle()); + } + } + + return drawnFlag; +} + + +/** + * Draw an annotation color bar. * * @param annotationFile * File containing the annotation. @@ -1461,7 +2003,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati bgTopLeft[i] = topLeft[i]; bgTopRight[i] = topRight[i]; } - expandBox(bgBottomLeft, bgBottomRight, bgTopRight, bgTopLeft, 2, 0); + MathFunctions::expandBox(bgBottomLeft, bgBottomRight, bgTopRight, bgTopLeft, 2, 0); std::vector bgCoords; bgCoords.insert(bgCoords.end(), bgBottomLeft, bgBottomLeft + 3); @@ -1570,7 +2112,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarTickMarks(const Annotatio * and end ticks are at the ends of the color bar. */ const float tickThickness = 2.0; - expandBox(bottomLeft, bottomRight, topRight, topLeft, (-tickThickness / 2.0), 0); + MathFunctions::expandBox(bottomLeft, bottomRight, topRight, topLeft, (-tickThickness / 2.0), 0); float bottomToTopUnitVector[3]; MathFunctions::createUnitVector(bottomLeft, @@ -2127,11 +2669,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ + const float percentHeight = getLineWidthPercentageInSelectionMode(oval); GraphicsShape::drawEllipseOutlineByteColor(majorAxis * 2.0f, minorAxis * 2.0f, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, - oval->getLineWidthPercentage()); + percentHeight); } m_selectionInfo.push_back(SelectionInfo(annotationFile, @@ -2175,6 +2718,135 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi return drawnFlag; } +/** + * Draw an annotation oval in surface tangent offset space + * + * @param annotationFile + * File containing the annotation. + * @param oval + * oval to draw. + * @param surfaceExtentZ + * Z-extent of the surface. + * @param vertexXYZ + * Coordinate of the vertex. + * @return + * True if the annotation was drawn while NOT selecting annotations. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawOvalSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationOval* oval, + const float surfaceExtentZ, + const float vertexXYZ[3]) +{ + CaretAssert(annotationFile); + CaretAssert(oval); + CaretAssert(oval->getType() == AnnotationTypeEnum::OVAL); + + const float halfWidth = ((oval->getWidth() / 100.0) * surfaceExtentZ) / 2.0; + const float halfHeight = ((oval->getHeight() / 100.0) * surfaceExtentZ) / 2.0; + float bottomLeft[3] { -halfWidth, -halfHeight, 0.0f }; + float bottomRight[3] { halfWidth, -halfHeight, 0.0f }; + float topRight[3] { halfWidth, halfHeight, 0.0f }; + float topLeft[3] { -halfWidth, halfHeight, 0.0f }; + + const float selectionCenterXYZ[3] = { + vertexXYZ[0], + vertexXYZ[1], + vertexXYZ[2] + }; + + float lineThickness = ((oval->getLineWidthPercentage() / 100.0) + * surfaceExtentZ); + if (m_selectionModeFlag) { + lineThickness = std::max(lineThickness, + s_selectionLineMinimumPixelWidth); + } + + uint8_t backgroundRGBA[4]; + oval->getBackgroundColorRGBA(backgroundRGBA); + uint8_t foregroundRGBA[4]; + oval->getLineColorRGBA(foregroundRGBA); + + const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); + const bool drawForegroundFlag = (foregroundRGBA[3] > 0); + const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); + + bool drawnFlag = false; + + const float majorAxis = ((oval->getWidth() / 100.0f) * surfaceExtentZ); + const float minorAxis = ((oval->getHeight() / 100.0f) * surfaceExtentZ); + + if (drawAnnotationFlag) { + if (m_selectionModeFlag) { + uint8_t selectionColorRGBA[4]; + getIdentificationColor(selectionColorRGBA); + + if (drawBackgroundFlag) { + /* + * When selecting draw only background if it is enabled + * since it is opaque and prevents "behind" annotations + * from being selected + */ + GraphicsShape::drawEllipseFilledByteColor(majorAxis, + minorAxis, + selectionColorRGBA); + } + else { + /* + * Drawing foreground as line will still allow user to + * select annotation that are inside of the box + */ + GraphicsShape::drawEllipseOutlineByteColor(majorAxis, + minorAxis, + selectionColorRGBA, + GraphicsPrimitive::LineWidthType::PIXELS, + lineThickness); + } + + m_selectionInfo.push_back(SelectionInfo(annotationFile, + oval, + AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, + selectionCenterXYZ)); + } + else { + if (drawBackgroundFlag) { + GraphicsShape::drawEllipseFilledByteColor(majorAxis, + minorAxis, + backgroundRGBA); + drawnFlag = true; + } + + if (drawForegroundFlag) { + glPolygonOffset(-1.0, 1.0); + glEnable(GL_POLYGON_OFFSET_FILL); + GraphicsShape::drawEllipseOutlineModelSpaceByteColor(majorAxis, + minorAxis, + foregroundRGBA, + lineThickness); +// GraphicsShape::drawEllipseOutlineByteColor(majorAxis, +// minorAxis, +// foregroundRGBA, +// GraphicsPrimitive::LineWidthType::PIXELS, +// lineThickness); + glDisable(GL_POLYGON_OFFSET_FILL); + drawnFlag = true; + } + } + if (oval->isSelectedForEditing(m_inputs->m_windowIndex)) { + drawAnnotationTwoDimSizingHandles(annotationFile, + oval, + bottomLeft, + bottomRight, + topRight, + topLeft, + s_sizingHandleLineWidthInPixels, + oval->getRotationAngle()); + } + } + + return drawnFlag; +} + /** * Get coordinate for drawing a line that connects text to brainordinate. * @@ -2363,11 +3035,214 @@ BrainOpenGLAnnotationDrawingFixedPipeline::clipLineAtTextBox(const float bottomL } } - if (clippedValid) { - endXYZ[0] = clippedXYZ[0]; - endXYZ[1] = clippedXYZ[1]; - endXYZ[2] = clippedXYZ[2]; - } + if (clippedValid) { + endXYZ[0] = clippedXYZ[0]; + endXYZ[1] = clippedXYZ[1]; + endXYZ[2] = clippedXYZ[2]; + } +} + +/** + * Get the normal vector for a surface vector. + * + * @param surface + * The surface. + * @param vertexIndex + * Index of the vertex. + * @param normalVectorOut + * Output containing the normal vector. + */ +void +BrainOpenGLAnnotationDrawingFixedPipeline::getSurfaceNormalVector(const Surface* surfaceDisplayed, + const int32_t vertexIndex, + float normalVectorOut[3]) const +{ + const float* normalXYZ = surfaceDisplayed->getNormalVector(vertexIndex); + normalVectorOut[0] = normalXYZ[0]; + normalVectorOut[1] = normalXYZ[1]; + normalVectorOut[2] = normalXYZ[2]; + + const bool useAverageFlag = false; + if ( ! useAverageFlag) { + return; + } + + CaretPointer th = surfaceDisplayed->getTopologyHelper(); + int32_t numNeighbors(0); + const int32_t* neighbors = th->getNodeNeighbors(vertexIndex, numNeighbors); + + normalVectorOut[0] = 0.0; + normalVectorOut[1] = 0.0; + normalVectorOut[2] = 0.0; + for (int32_t n = 0; n < numNeighbors; n++) { + const float* normalXYZ = surfaceDisplayed->getNormalVector(neighbors[n]); + normalVectorOut[0] += normalXYZ[0]; + normalVectorOut[1] += normalXYZ[1]; + normalVectorOut[2] += normalXYZ[2]; + } + + if (numNeighbors > 0) { + normalVectorOut[0] /= numNeighbors; + normalVectorOut[1] /= numNeighbors; + normalVectorOut[2] /= numNeighbors; + } +} + +/** + * @return True If the coordinate/normal vector backfacing (facing away from viewer)? + * + * @param xyz + * Coordinate. + * @param normal + * Normal vector. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::isBackFacing(const float xyz[3], + const float normal[3]) const +{ + /* + * We don't know where the viewer is located in relation to the view of the model. + * But, we can transform the XYZ coordinate and another XYZ coordinate along the + * normal vector from model space to window space. Then, we can compare the transformed + * Z-coordinates and if the Window Z along the normal vector is greater than Window Z + * of the coordinate, the normal vector is pointing to the viewer (if NOT then backfacing). + */ + CaretAssert(m_transformEvent.get()); + CaretAssert(m_transformEvent->isValid()); + float windowXYZ[3]; + const float length(25); + float offsetXYZ[3] { + xyz[0] + (normal[0] * length), + xyz[1] + (normal[1] * length), + xyz[2] + (normal[2] * length) + }; + m_transformEvent->transformPoint(xyz, windowXYZ); + float windowOffsetXYZ[3]; + m_transformEvent->transformPoint(offsetXYZ, windowOffsetXYZ); + const float diff = windowOffsetXYZ[2] - windowXYZ[2]; + return (diff < 0.0f); +} + +/** + * Draw an annotation text with surface tangent offset + * + * @param annotationFile + * File containing the annotation. + * @param text + * Annotation text to draw. + * @param surfaceExtentZ + * Z-extent of the surface. + * @param vertexXYZ, + * Coordinate of the vertex. + * @param vertexNormalXYZ + * Normal vector of vertex. + * @return + * True if the annotation was drawn while NOT selecting annotations. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawTextSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationText* text, + const float surfaceExtentZ, + const float vertexXYZ[3], + const float vertexNormalXYZ[3]) +{ + CaretAssert(annotationFile); + CaretAssert(text); + + /* + * Annotations with "DISPLAY_GROUP" propery may be turned on/off by user. + */ + DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); + if (text->testProperty(Annotation::Property::DISPLAY_GROUP)) { + if ( ! dpa->isDisplayTextAnnotations()) { + return false; + } + } + + if (isBackFacing(vertexXYZ, + vertexNormalXYZ)) { + return false; + } + + double bottomLeft[3]; + double bottomRight[3]; + double topRight[3]; + double topLeft[3]; + double underlineStart[3]; + double underlineEnd[3]; + m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextInModelSpace(*text, m_surfaceViewScaling, surfaceExtentZ, m_textDrawingFlags, + bottomLeft, bottomRight, topRight, topLeft, + underlineStart, underlineEnd); + + bool textDrawnFlag = false; + if (m_selectionModeFlag) { + uint8_t selectionColorRGBA[4] = { 0, 0, 0, 0 }; + getIdentificationColor(selectionColorRGBA); + GraphicsPrimitiveV3fN3f primitive(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, + selectionColorRGBA); + const double doubleNormalXYZ[3] { + vertexNormalXYZ[0], + vertexNormalXYZ[1], + vertexNormalXYZ[2] + }; + primitive.addVertex(topLeft, doubleNormalXYZ); + primitive.addVertex(bottomLeft, doubleNormalXYZ); + primitive.addVertex(topRight, doubleNormalXYZ); + primitive.addVertex(bottomRight, doubleNormalXYZ); + GraphicsEngineDataOpenGL::draw(&primitive); + m_selectionInfo.push_back(SelectionInfo(annotationFile, + text, + AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, + vertexXYZ)); + } + else { + glPushMatrix(); + m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextInModelSpace(*text, + m_surfaceViewScaling, + surfaceExtentZ, + vertexNormalXYZ, + m_textDrawingFlags); + glPopMatrix(); + + textDrawnFlag = true; + } + + if (text->isSelectedForEditing(m_inputs->m_windowIndex)) { + glPushAttrib(GL_POLYGON_BIT + | GL_LIGHTING_BIT); + + /* + * So that text and background do not mix together + * in the Z-buffer + */ + glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + glEnable(GL_POLYGON_OFFSET_POINT); + glPolygonOffset(-1.0, 1.0); + glDisable(GL_LIGHTING); + + float floatBottomLeft[3]; + float floatBottomRight[3]; + float floatTopRight[3]; + float floatTopLeft[3]; + for (int32_t i = 0; i < 3; i++) { + floatBottomLeft[i] = bottomLeft[i]; + floatBottomRight[i] = bottomRight[i]; + floatTopLeft[i] = topLeft[i]; + floatTopRight[i] = topRight[i]; + } + drawAnnotationTwoDimSizingHandles(annotationFile, + text, + floatBottomLeft, + floatBottomRight, + floatTopRight, + floatTopLeft, + s_sizingHandleLineWidthInPixels, + text->getRotationAngle()); + glPopAttrib(); + } + + return textDrawnFlag; } /** @@ -2399,7 +3274,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi return false; } } - float annXYZ[3]; if ( ! getAnnotationDrawingSpaceCoordinate(text, @@ -2722,6 +3596,121 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF return drawnFlag; } +/** + * Draw an annotation image in surface tangent offset space + * + * @param annotationFile + * File containing the annotation. + * @param image + * Image to draw. + * @param surfaceExtentZ + * Z-extent of the surface. + * @param vertexXYZ + * Coordinate of the vertex. + * @return + * True if the annotation was drawn while NOT selecting annotations. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawImageSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationImage* image, + const float surfaceExtentZ, + const float vertexXYZ[3]) +{ + CaretAssert(annotationFile); + CaretAssert(image); + CaretAssert(image->getType() == AnnotationTypeEnum::IMAGE); + + const float halfWidth = ((image->getWidth() / 100.0) * surfaceExtentZ) / 2.0; + const float halfHeight = ((image->getHeight() / 100.0) * surfaceExtentZ) / 2.0; + float bottomLeft[3] { -halfWidth, -halfHeight, 0.0f }; + float bottomRight[3] { halfWidth, -halfHeight, 0.0f }; + float topRight[3] { halfWidth, halfHeight, 0.0f }; + float topLeft[3] { -halfWidth, halfHeight, 0.0f }; + + const float selectionCenterXYZ[3] = { + vertexXYZ[0], + vertexXYZ[1], + vertexXYZ[2] + }; + + float lineThickness = ((image->getLineWidthPercentage() / 100.0) + * surfaceExtentZ); + if (m_selectionModeFlag) { + lineThickness = std::max(lineThickness, + s_selectionLineMinimumPixelWidth); + } + + uint8_t backgroundRGBA[4]; + image->getBackgroundColorRGBA(backgroundRGBA); + uint8_t foregroundRGBA[4]; + image->getLineColorRGBA(foregroundRGBA); + + const bool drawForegroundFlag = (foregroundRGBA[3] > 0); + const bool drawAnnotationFlag = true; + + bool drawnFlag = false; + + if (drawAnnotationFlag) { + if (m_selectionModeFlag) { + uint8_t selectionColorRGBA[4]; + getIdentificationColor(selectionColorRGBA); + + /* + * When selecting draw only background if it is enabled + * since it is opaque and prevents "behind" annotations + * from being selected + */ + GraphicsShape::drawBoxFilledByteColor(bottomLeft, + bottomRight, + topRight, + topLeft, + selectionColorRGBA); + m_selectionInfo.push_back(SelectionInfo(annotationFile, + image, + AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, + selectionCenterXYZ)); + } + else { + image->setVertexBounds(bottomLeft, + bottomRight, + topRight, + topLeft); + GraphicsPrimitiveV3fT3f* primitive = image->getGraphicsPrimitive(); + if (primitive != NULL) { + if (primitive->isValid()) { + GraphicsEngineDataOpenGL::draw(primitive); + } + drawnFlag = true; + } + + if (drawForegroundFlag) { + glPolygonOffset(-1.0, -1.0); + glEnable(GL_POLYGON_OFFSET_FILL); + GraphicsShape::drawOutlineRectangleVerticesInMiddle(bottomLeft, + bottomRight, + topRight, + topLeft, + lineThickness, + foregroundRGBA); + drawnFlag = true; + glDisable(GL_POLYGON_OFFSET_FILL); + } + } + if (image->isSelectedForEditing(m_inputs->m_windowIndex)) { + drawAnnotationTwoDimSizingHandles(annotationFile, + image, + bottomLeft, + bottomRight, + topRight, + topLeft, + s_sizingHandleLineWidthInPixels, + image->getRotationAngle()); + } + } + + return drawnFlag; +} + /** * Create the coordinates for drawing a line with optional arrows at the end points. * @@ -2735,8 +3724,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF * Add an arrow at the start of the line * @param validEndArrow * Add an arrow at the end of the line - * @param coordinatesOut + * @param lineCoordinatesOut * Output containing coordinates for drawing the line + * @param startArrowCoordinatesOut + * Output containing coordinates for drawing the line's start arrow + * @param endArrowCoordinatesOut + * Output containing coordinates for drawing the line's end arrow */ void BrainOpenGLAnnotationDrawingFixedPipeline::createLineCoordinates(const float lineHeadXYZ[3], @@ -2923,10 +3916,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); + const float percentHeight = getLineWidthPercentageInSelectionMode(line); GraphicsShape::drawLinesByteColor(lineCoordinates, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, - line->getLineWidthPercentage()); + percentHeight); if ( ! startArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, selectionColorRGBA, @@ -2980,6 +3974,211 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi return drawnFlag; } +/** + * Draw an annotation line that is in surface space with tangent offset. + * + * @param annotationFile + * File containing the annotation. + * @param line + * Annotation line to draw. + * @param surfaceDisplayed + * Surface that is displayed (may be NULL). + * @return + * True if the annotation was drawn while NOT selecting annotations. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawLineSurfaceTextureOffset(AnnotationFile* annotationFile, + AnnotationLine* line, + const Surface* surfaceDisplayed, + const float surfaceExtentZ) +{ + CaretAssert(line); + CaretAssert(line->getType() == AnnotationTypeEnum::LINE); + + StructureEnum::Enum structureOne(StructureEnum::INVALID); + StructureEnum::Enum structureTwo(StructureEnum::INVALID); + int32_t numberOfVerticesOne(0); + int32_t numberOfVerticesTwo(0); + int32_t vertexIndexOne(-1); + int32_t vertexIndexTwo(-1); + float offsetLengthOne(0.0f); + float offsetLengthTwo(0.0f); + AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorOne(AnnotationSurfaceOffsetVectorTypeEnum::TANGENT); + AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorTwo(AnnotationSurfaceOffsetVectorTypeEnum::TANGENT); + line->getStartCoordinate()->getSurfaceSpace(structureOne, numberOfVerticesOne, vertexIndexOne, + offsetLengthOne, surfaceOffsetVectorOne); + line->getEndCoordinate()->getSurfaceSpace(structureTwo, numberOfVerticesTwo, vertexIndexTwo, + offsetLengthTwo, surfaceOffsetVectorTwo); + + if ((surfaceDisplayed->getStructure() != structureOne) + || (surfaceDisplayed->getStructure() != structureTwo) + || (surfaceDisplayed->getNumberOfNodes() != numberOfVerticesOne) + || (surfaceDisplayed->getNumberOfNodes() != numberOfVerticesTwo) + || (vertexIndexOne < 0) + || (vertexIndexTwo < 0)) { + return false; + } + float lineHeadXYZ[3]; + float lineTailXYZ[3]; + surfaceDisplayed->getCoordinate(vertexIndexOne, lineHeadXYZ); + surfaceDisplayed->getCoordinate(vertexIndexTwo, lineTailXYZ); + + float offsetVectorOne[3]; + float offsetVectorTwo[3]; + surfaceDisplayed->getNormalVector(vertexIndexOne, + offsetVectorOne); + surfaceDisplayed->getNormalVector(vertexIndexTwo, + offsetVectorTwo); + for (int32_t i = 0; i < 3; i++) { + lineHeadXYZ[i] += (offsetVectorOne[i] * offsetLengthOne); + lineTailXYZ[i] += (offsetVectorTwo[i] * offsetLengthTwo); + } + + const float selectionCenterXYZ[3] = { + (lineHeadXYZ[0] + lineTailXYZ[0]) / 2.0f, + (lineHeadXYZ[1] + lineTailXYZ[1]) / 2.0f, + (lineHeadXYZ[2] + lineTailXYZ[2]) / 2.0f + }; + + if (line->getLineWidthPercentage() <= 0.0) { + convertObsoleteLineWidthPixelsToPercentageWidth(line); + } + float lineThickness = ((line->getLineWidthPercentage() / 100.0) + * surfaceExtentZ); + lineThickness *= m_surfaceViewScaling; + if (m_selectionModeFlag) { + lineThickness = std::max(lineThickness, + s_selectionLineMinimumPixelWidth); + } + lineThickness = GraphicsUtilitiesOpenGL::convertMillimetersToPixels(lineThickness); + + bool drawnFlag = false; + + std::vector lineCoordinates; + std::vector startArrowCoordinates; + std::vector endArrowCoordinates; + + createLineCoordinates(lineHeadXYZ, + lineTailXYZ, + lineThickness, + line->isDisplayStartArrow(), + line->isDisplayEndArrow(), + lineCoordinates, + startArrowCoordinates, + endArrowCoordinates); + uint8_t foregroundRGBA[4]; + line->getLineColorRGBA(foregroundRGBA); + + const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0f); + + if (drawForegroundFlag) { + if (m_selectionModeFlag) { + uint8_t selectionColorRGBA[4]; + getIdentificationColor(selectionColorRGBA); + + GraphicsShape::drawLinesByteColor(lineCoordinates, + selectionColorRGBA, + GraphicsPrimitive::LineWidthType::PIXELS, + lineThickness); + // if ( ! startArrowCoordinates.empty()) { + // GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, + // selectionColorRGBA, + // GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, + // lineThickness); + // } + // if ( ! endArrowCoordinates.empty()) { + // GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, + // selectionColorRGBA, + // GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, + // lineThickness); + // } + m_selectionInfo.push_back(SelectionInfo(annotationFile, + line, + AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, + selectionCenterXYZ)); + } + else { + if (drawForegroundFlag) { + // float floatRGBA[4]; + // line->getLineColorRGBA(floatRGBA); + // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, + // lineHeadXYZ, + // lineTailXYZ, + // lineThickness / 2); + GraphicsShape::drawLinesByteColor(lineCoordinates, + foregroundRGBA, + GraphicsPrimitive::LineWidthType::PIXELS, + lineThickness); + // if ( ! startArrowCoordinates.empty()) { + // if (startArrowCoordinates.size() == 9) { + // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, + // &startArrowCoordinates[0], + // &startArrowCoordinates[3], + // lineThickness / 2); + // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, + // &startArrowCoordinates[3], + // &startArrowCoordinates[6], + // lineThickness / 2); + // } + // else { + // GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, + // foregroundRGBA, + // GraphicsPrimitive::LineWidthType::PIXELS, + // lineThickness); + // } + // } + // if ( ! endArrowCoordinates.empty()) { + // GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, + // foregroundRGBA, + // GraphicsPrimitive::LineWidthType::PIXELS, + // lineThickness); + // } + drawnFlag = true; + } + } + + if (line->isSelectedForEditing(m_inputs->m_windowIndex)) { + const float minPixelSize = 30.0; + const float minSizeMM = (GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(minPixelSize) + * m_surfaceViewScaling); + const float handleThickness = std::max(minSizeMM, + lineThickness * 2.0f); + drawAnnotationOneDimSizingHandles(annotationFile, + line, + lineHeadXYZ, + lineTailXYZ, + handleThickness); //lineThickness * 2.0); //s_sizingHandleLineWidthInPixels); + } + } + + return drawnFlag; +} + +/** + * When lines are very thin, they can be difficult to select. This method will + * return the line thickness percentage, adjusted so that is thick enough that + * the user will be able to select the annotation. + * + * @param + * Annotation drawn as line + * @return + * Percentage thickness for drawing that may be increased to ensure that + the annotation is selectable. + */ +float +BrainOpenGLAnnotationDrawingFixedPipeline::getLineWidthPercentageInSelectionMode(const Annotation* annotation) const +{ + CaretAssert(annotation); + const float minPercentHeight = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(s_selectionLineMinimumPixelWidth); + float percentHeight = annotation->getLineWidthPercentage(); + if (percentHeight < minPercentHeight) { + percentHeight = minPercentHeight; + } + + return percentHeight; +} + + /** * Draw a sizing handle at the given coordinate. * @@ -3019,6 +4218,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi bool drawFilledCircleFlag = false; bool drawOutlineCircleFlag = false; bool drawSquareFlag = false; + bool drawSphereFlag = false; switch (handleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: @@ -3046,10 +4246,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi drawFilledCircleFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: - drawFilledCircleFlag = true; + if (annotation->isInSurfaceSpaceWithTangentOffset()) { + drawSphereFlag = true; + } + else { + drawFilledCircleFlag = true; + } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: - drawFilledCircleFlag = true; + if (annotation->isInSurfaceSpaceWithTangentOffset()) { + drawSphereFlag = true; + } + else { + drawFilledCircleFlag = true; + } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: break; @@ -3094,6 +4304,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi 1.0f); glPopMatrix(); } + else if (drawSphereFlag) { + float zeros[3] { 0.0f, 0.0f, 0.0f }; + GraphicsShape::drawSphereByteColor(zeros, m_selectionBoxRGBA, halfWidthHeight); + } } glPopMatrix(); @@ -3120,6 +4334,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(Ann const float secondPoint[3], const float lineThickness) { + if ( ! m_inputs->m_annotationUserInputModeFlag) { + return; + } + + CaretAssert(annotation); float lengthVector[3]; MathFunctions::subtractVectors(secondPoint, firstPoint, lengthVector); MathFunctions::normalizeVector(lengthVector); @@ -3127,12 +4346,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(Ann const float dx = secondPoint[0] - firstPoint[0]; const float dy = secondPoint[1] - firstPoint[1]; - const float cornerSquareSize = 3.0 + lineThickness; - const float directionVector[3] = { - lengthVector[0] * cornerSquareSize, - lengthVector[1] * cornerSquareSize, - 0.0 - }; + const bool tangentSurfaceOffsetFlag = annotation->isInSurfaceSpaceWithTangentOffset(); + + float cornerSquareSize = 3.0 + lineThickness; + if (tangentSurfaceOffsetFlag) { + cornerSquareSize = lineThickness;// * 4.0; + cornerSquareSize = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(cornerSquareSize); + } + + float directionVector[3] { 0.0f, 0.0f, 0.0f }; + if ( ! tangentSurfaceOffsetFlag) { + directionVector[0] = lengthVector[0] * cornerSquareSize; + directionVector[1] = lengthVector[1] * cornerSquareSize; + directionVector[2] = 0.0; + } const float firstPointSymbolXYZ[3] = { firstPoint[0] - directionVector[0], @@ -3152,15 +4379,19 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(Ann rotationAngle = MathFunctions::toDegrees(angleRadians); } - /* - * Symbol for first coordinate is a little bigger - */ if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START)) { + /* + * Symbol for first coordinate is a little bigger + */ + float startSquareSize = cornerSquareSize + 2.0; + if (tangentSurfaceOffsetFlag) { + startSquareSize = cornerSquareSize;// * 1.5; + } drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START, annotationFile, annotation, firstPointSymbolXYZ, - cornerSquareSize + 2.0, + startSquareSize, rotationAngle); } @@ -3188,58 +4419,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(Ann } } -/** - * Expand a box by given amounts in X and Y. - * - * @param bottomLeft - * Bottom left corner of annotation. - * @param bottomRight - * Bottom right corner of annotation. - * @param topRight - * Top right corner of annotation. - * @param topLeft - * Top left corner of annotation. - * @param extraSpaceX - * Extra space to add in X. - * @param extraSpaceY - * Extra space to add in Y. - */ -void -BrainOpenGLAnnotationDrawingFixedPipeline::expandBox(float bottomLeft[3], - float bottomRight[3], - float topRight[3], - float topLeft[3], - const float extraSpaceX, - const float extraSpaceY) -{ - float widthVector[3]; - MathFunctions::subtractVectors(topRight, topLeft, widthVector); - MathFunctions::normalizeVector(widthVector); - - float heightVector[3]; - MathFunctions::subtractVectors(topLeft, bottomLeft, heightVector); - MathFunctions::normalizeVector(heightVector); - - const float widthSpacingX = extraSpaceX * widthVector[0]; - const float widthSpacingY = extraSpaceY * widthVector[1]; - - const float heightSpacingX = extraSpaceX * heightVector[0]; - const float heightSpacingY = extraSpaceY * heightVector[1]; - - - topLeft[0] += (-widthSpacingX + heightSpacingX); - topLeft[1] += (-widthSpacingY + heightSpacingY); - - topRight[0] += (widthSpacingX + heightSpacingX); - topRight[1] += (widthSpacingY + heightSpacingY); - - bottomLeft[0] += (-widthSpacingX - heightSpacingX); - bottomLeft[1] += (-widthSpacingY - heightSpacingY); - - bottomRight[0] += (widthSpacingX - heightSpacingX); - bottomRight[1] += (widthSpacingY - heightSpacingY); -} - /** * Draw sizing handles around a two-dimensional annotation. * @@ -3264,28 +4443,40 @@ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(AnnotationFile* annotationFile, Annotation* annotation, const float bottomLeft[3], - const float bottomRight[3], - const float topRight[3], - const float topLeft[3], - const float lineThickness, - const float rotationAngle) + const float bottomRight[3], + const float topRight[3], + const float topLeft[3], + const float lineThickness, + const float rotationAngle) { + if ( ! m_inputs->m_annotationUserInputModeFlag) { + return; + } + + CaretAssert(annotation); + AnnotationText* textAnn = dynamic_cast(annotation); + const bool modelSpaceTangentTextFlag = annotation->isInSurfaceSpaceWithTangentOffset(); + float heightVector[3]; MathFunctions::subtractVectors(topLeft, bottomLeft, heightVector); MathFunctions::normalizeVector(heightVector); - - const float innerSpacing = 2.0f + (lineThickness / 2.0f); - float handleTopLeft[3]; - float handleTopRight[3]; - float handleBottomRight[3]; - float handleBottomLeft[3]; - for (int32_t i = 0; i < 3; i++) { - handleTopLeft[i] = topLeft[i]; - handleTopRight[i] = topRight[i]; - handleBottomRight[i] = bottomRight[i]; - handleBottomLeft[i] = bottomLeft[i]; - } - expandBox(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, innerSpacing, innerSpacing); + + float innerSpacing = 2.0f + (lineThickness / 2.0f); + if (modelSpaceTangentTextFlag) { + innerSpacing = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(innerSpacing); + } + float handleTopLeft[3]; + float handleTopRight[3]; + float handleBottomRight[3]; + float handleBottomLeft[3]; + for (int32_t i = 0; i < 3; i++) { + handleTopLeft[i] = topLeft[i]; + handleTopRight[i] = topRight[i]; + handleBottomRight[i] = bottomRight[i]; + handleBottomLeft[i] = bottomLeft[i]; + } + + MathFunctions::expandBox(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, innerSpacing, innerSpacing); if (! m_selectionModeFlag) { GraphicsShape::drawBoxOutlineByteColor(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, @@ -3316,7 +4507,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann (handleTopLeft[2] + handleTopRight[2]) / 2.0f, }; - const float sizeHandleSize = 5.0; + float sizeHandleSize = 5.0; + if (modelSpaceTangentTextFlag) { + sizeHandleSize = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(sizeHandleSize); + } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT, @@ -3384,17 +4578,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { - float handleOffset[3] = { handleTop[0], handleTop[1], handleTop[2] }; - if (annotation->getType() == AnnotationTypeEnum::TEXT) { - const AnnotationText* textAnn = dynamic_cast(annotation); - CaretAssert(textAnn); - + if (textAnn != NULL) { /* * The rotation point of a text annotation * is adjusted for the horizontal alignment. @@ -3414,7 +4604,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann break; } } - + const float rotationOffset = sizeHandleSize * 3.0; const float handleRotation[3] = { handleOffset[0] + (rotationOffset * heightVector[0]), @@ -3503,6 +4693,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotat switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: testFlatSurfaceFlag = true; break; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 921a0f9f47ec216efea6a7696d5c1d25c3cf19ed..0207f0f6e16696972c8c809fcc762f290be6a12a 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -26,11 +26,13 @@ #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationSizingHandleTypeEnum.h" +#include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" #include "CaretObject.h" #include "CaretOpenGLInclude.h" #include "Plane.h" +#include "SpacerTabIndex.h" namespace caret { @@ -42,6 +44,7 @@ namespace caret { class AnnotationFile; class AnnotationImage; class AnnotationLine; + class AnnotationOneDimensionalShape; class AnnotationOval; class AnnotationText; class AnnotationTwoDimensionalShape; @@ -65,13 +68,17 @@ namespace caret { const float centerToEyeDistance, const int32_t windowIndex, const int32_t tabIndex, - const WindowDrawingMode windowDrawingMode) + const SpacerTabIndex &spacerTabIndex, + const WindowDrawingMode windowDrawingMode, + const bool annotationUserInputModeFlag) : m_brain(brain), m_drawingMode(drawingMode), m_centerToEyeDistance(centerToEyeDistance), m_windowIndex(windowIndex), m_tabIndex(tabIndex), - m_windowDrawingMode(windowDrawingMode) { + m_spacerTabIndex(spacerTabIndex), + m_windowDrawingMode(windowDrawingMode), + m_annotationUserInputModeFlag(annotationUserInputModeFlag) { } Brain* m_brain; @@ -79,7 +86,9 @@ namespace caret { const float m_centerToEyeDistance; const int32_t m_windowIndex; const int32_t m_tabIndex; + const SpacerTabIndex m_spacerTabIndex; const WindowDrawingMode m_windowDrawingMode; + const bool m_annotationUserInputModeFlag; }; BrainOpenGLAnnotationDrawingFixedPipeline(BrainOpenGLFixedPipeline* brainOpenGLFixedPipeline); @@ -90,7 +99,8 @@ namespace caret { const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, std::vector& notInFileAnnotations, - const Surface* surfaceDisplayed); + const Surface* surfaceDisplayed, + const float surfaceViewScaling); void drawModelSpaceAnnotationsOnVolumeSlice(Inputs* inputs, const Plane& plane, @@ -186,6 +196,14 @@ namespace caret { Annotation* annotation, const Surface* surfaceDisplayed); + bool drawTwoDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, + AnnotationTwoDimensionalShape* annotation, + const Surface* surfaceDisplayed); + + bool drawOneDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, + AnnotationOneDimensionalShape* annotation, + const Surface* surfaceDisplayed); + void drawColorBar(AnnotationFile* annotationFile, AnnotationColorBar* colorBar); @@ -193,22 +211,48 @@ namespace caret { AnnotationBox* box, const Surface* surfaceDisplayed); + bool drawBoxSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationBox* box, + const float surfaceExtentZ, + const float vertexXYZ[3]); + bool drawImage(AnnotationFile* annotationFile, AnnotationImage* image, - const Surface* surfaceDisplayed); + const Surface* surfaceDisplayed); + + bool drawImageSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationImage* image, + const float surfaceExtentZ, + const float vertexXYZ[3]); bool drawLine(AnnotationFile* annotationFile, AnnotationLine* line, const Surface* surfaceDisplayed); + bool drawLineSurfaceTextureOffset(AnnotationFile* annotationFile, + AnnotationLine* line, + const Surface* surfaceDisplayed, + const float surfaceExtentZ); + bool drawOval(AnnotationFile* annotationFile, AnnotationOval* oval, const Surface* surfaceDisplayed); + bool drawOvalSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationOval* oval, + const float surfaceExtentZ, + const float vertexXYZ[3]); + bool drawText(AnnotationFile* annotationFile, AnnotationText* text, const Surface* surfaceDisplayed); + bool drawTextSurfaceTangentOffset(AnnotationFile* annotationFile, + AnnotationText* text, + const float surfaceExtentZ, + const float vertexXYZ[3], + const float vertexNormalXYZ[3]); + void drawColorBarSections(const AnnotationColorBar* colorBar, const float bottomLeft[3], const float bottomRight[3], @@ -284,14 +328,7 @@ namespace caret { const float topLeft[3], std::vector& lineCoordinatesOut, std::vector& arrowCoordinatesOut) const; - - static void expandBox(float bottomLeft[3], - float bottomRight[3], - float topRight[3], - float topLeft[3], - const float extraSpaceX, - const float extraSpaceY); - + void setSelectionBoxColor(); void startOpenGLForDrawing(GLint* savedShadeModelOut, @@ -311,13 +348,24 @@ namespace caret { float getLineWidthFromPercentageHeight(const float percentageHeight) const; + float getLineWidthPercentageInSelectionMode(const Annotation* annotation) const; + float estimateColorBarWidth(const AnnotationColorBar* colorBar, const float textHeightInPixels) const; + void getSurfaceNormalVector(const Surface* surfaceDisplayed, + const int32_t vertexIndex, + float normalVectorOut[3]) const; + + bool isBackFacing(const float xyz[3], + const float normal[3]) const; + BrainOpenGLFixedPipeline* m_brainOpenGLFixedPipeline; Inputs* m_inputs; + float m_surfaceViewScaling; + /** * Dummy annotation file is used for annotations that * do not belong to a file. This includes the @@ -358,14 +406,16 @@ namespace caret { std::unique_ptr m_transformEvent; - static constexpr float s_sizingHandleLineWidthInPixels = 2.0f; + static const float s_sizingHandleLineWidthInPixels; + static const float s_selectionLineMinimumPixelWidth; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ - // + const float BrainOpenGLAnnotationDrawingFixedPipeline::s_sizingHandleLineWidthInPixels = 2.0f; + const float BrainOpenGLAnnotationDrawingFixedPipeline::s_selectionLineMinimumPixelWidth = 5.0f; #endif // __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ } // namespace diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 96dfd563c37670adf5b1d7ae99d7906e9da1c8e1..70bd290f1a842e6bb85e6fd9e679313402da707a 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -177,6 +177,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, switch (cb->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 5cd1181552e95b8509f02120d9b77610d5c39103..8f4002f62214c144ae4008574abf85a5277af9e7 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -47,6 +47,7 @@ #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLVolumeObliqueSliceDrawing.h" #include "BrainOpenGLVolumeSliceDrawing.h" +#include "BrainOpenGLVolumeTextureSliceDrawing.h" #include "BrainOpenGLShapeCone.h" #include "BrainOpenGLShapeCube.h" #include "BrainOpenGLShapeCylinder.h" @@ -117,6 +118,7 @@ #include "SelectionItemSurfaceNodeIdentificationSymbol.h" #include "SelectionItemSurfaceTriangle.h" #include "SelectionItemVoxel.h" +#include "SpacerTabContent.h" #include "SurfaceMontageConfigurationCerebellar.h" #include "SurfaceMontageConfigurationCerebral.h" #include "SurfaceMontageConfigurationFlatMaps.h" @@ -153,6 +155,8 @@ using namespace caret; +static Surface* annotationDrawingNullSurface(NULL); +static float annotationDrawingUnusedSurfaceScaling(1.0f); /** * Constructor. * @@ -223,6 +227,8 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() * * @param windowIndex * Index of window for selection + * @param userInputMode + * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent @@ -241,14 +247,17 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() */ void BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, - const BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - const bool applySelectionBackgroundFiltering) + const BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + const bool applySelectionBackgroundFiltering) { m_brain = brain; m_windowIndex = windowIndex; + m_windowUserInputMode = windowUserInputMode; + CaretAssert(m_brain); CaretAssert((m_windowIndex >= 0) && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); @@ -286,7 +295,12 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, * everything else. */ glClear(GL_DEPTH_BUFFER_BIT); - drawTabAnnotations(viewportContent); + if (viewportContent->getSpacerTabContent() != NULL) { + drawSpacerAnnotations(viewportContent); + } + else { + drawTabAnnotations(viewportContent); + } int windowViewport[4]; viewportContent->getWindowViewport(windowViewport); @@ -296,6 +310,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, m_brain = NULL; m_windowIndex = -1; + m_windowUserInputMode = UserInputModeEnum::INVALID; } /** @@ -306,6 +321,8 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, * * @param windowIndex * Index of window for projection + * @param userInputMode + * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent @@ -319,14 +336,16 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, */ void BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, - const BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - SurfaceProjectedItem& projectionOut) + const BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + SurfaceProjectedItem& projectionOut) { m_brain = brain; m_windowIndex = windowIndex; + m_windowUserInputMode = windowUserInputMode; CaretAssert(m_brain); CaretAssert((m_windowIndex >= 0) && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); @@ -360,6 +379,7 @@ BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex this->modeProjectionData = NULL; m_brain = NULL; m_windowIndex = -1; + m_windowUserInputMode = UserInputModeEnum::INVALID; } /** @@ -404,12 +424,12 @@ void BrainOpenGLFixedPipeline::updateForegroundAndBackgroundColors(const BrainOpenGLViewportContent* vpContent) { /* - * Default to colors for surface + * Default to colors for window */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); - prefs->getBackgroundAndForegroundColors()->getColorForegroundSurfaceView(m_foregroundColorByte); + prefs->getBackgroundAndForegroundColors()->getColorForegroundWindow(m_foregroundColorByte); m_foregroundColorByte[3] = 255; - prefs->getBackgroundAndForegroundColors()->getColorBackgroundSurfaceView(m_backgroundColorByte); + prefs->getBackgroundAndForegroundColors()->getColorBackgroundWindow(m_backgroundColorByte); m_backgroundColorByte[3] = 255; if (vpContent != NULL) { @@ -483,8 +503,6 @@ BrainOpenGLFixedPipeline::setTabViewport(const BrainOpenGLViewportContent* vpCon * * @param viewportContents * Contents of the viewports. - * @param windowColorBarsOut - * Output with window color bars in the viewports. */ void BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(const std::vector& viewportContents) @@ -492,37 +510,44 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(const std::vectorsendEvent(colorBarEvent.getPointer()); - m_annotationColorBarsForDrawing = colorBarEvent.getAnnotationColorBars(); + std::vector allColorBars = colorBarEvent.getAnnotationColorBars(); /* - * Tab index is always set in BrowserTabContent when it receives - * EventAnnotationColorBarGet event. So, the tab index should always - * be valid. The user can place the color bar in window space so - * update the window index so that color bar's in window space - * are drawn and drawn only in the window containing the color bar. + * Find the color bars contained in the viewports and + * exclude color bars not in the viewports (color bars that + * are in other windows or other tabs while in single + * tab view). */ - for (auto colorBar : m_annotationColorBarsForDrawing) { + for (auto colorBar : allColorBars) { const int32_t tabIndex = colorBar->getTabIndex(); for (auto vc : viewportContents) { if (vc->getTabIndex() == tabIndex) { + /* + * While color bars are associated with tabs, the color bar + * may be in window space so always update the window index + * (users can move tabs to other windows). + */ colorBar->setWindowIndex(vc->getWindowIndex()); + m_annotationColorBarsForDrawing.push_back(colorBar); + break; } } } } + /** * Draw models in their respective viewports. * * @param windowIndex * Index of window for drawing + * @param userInputMode + * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContents @@ -530,11 +555,13 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(const std::vector& viewportContents) + const std::vector& viewportContents) { m_brain = brain; m_windowIndex = windowIndex; + m_windowUserInputMode = windowUserInputMode; CaretAssert(m_brain); CaretAssert((m_windowIndex >= 0) && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); @@ -553,15 +580,9 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, this->checkForOpenGLError(NULL, "At beginning of drawModels()"); /* - * Default the background colors to first model - * NOTE: If there are no models, the surface background color is used + * NULL will retrieve Window colors (window colors added on 07jul2019) */ - if (viewportContents.empty()) { - updateForegroundAndBackgroundColors(NULL); - } - else { - updateForegroundAndBackgroundColors(viewportContents[0]); - } + updateForegroundAndBackgroundColors(NULL); /* * Use the background color as the clear color. @@ -585,10 +606,51 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, this->checkForOpenGLError(NULL, "At middle of drawModels()"); for (int32_t i = 0; i < static_cast(viewportContents.size()); i++) { + const BrainOpenGLViewportContent* vpContent = viewportContents[i]; + /* + * Don't draw if off-screen + */ + { + int32_t windowViewport[4]; + vpContent->getWindowViewport(windowViewport); + + int32_t tabViewport[4]; + vpContent->getTabViewportBeforeApplyingMargins(tabViewport); + + /* + * Test for tab offscreen to right (tabs flow left-to-right) + */ + if (tabViewport[0] > (windowViewport[0] + windowViewport[2])) { + continue; + } + + /* + * Test for tab offscreen to bottom (tabs flow top-to-bottom) + */ + const int32_t tabTop = tabViewport[1] + tabViewport[3]; + if (tabTop < 0) { + continue; + } + + if (tabViewport[2] <= 0) { + CaretLogSevere("Invalid TAB width=" + + AString::number(tabViewport[2]) + + " for index=" + + AString::number(i)); + continue; + } + if (tabViewport[3] <= 0) { + CaretLogSevere("Invalid TAB height=" + + AString::number(tabViewport[3]) + + " for index=" + + AString::number(i)); + continue; + } + } + /* * Viewport of window. */ - const BrainOpenGLViewportContent* vpContent = viewportContents[i]; setTabViewport(vpContent); glViewport(m_tabViewport[0], m_tabViewport[1], m_tabViewport[2], m_tabViewport[3]); @@ -598,36 +660,33 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, updateForegroundAndBackgroundColors(vpContent); /* - * If this is NOT the first viewport content, - * AND the background color for this viewport content is + * If the background color for this viewport content is * different that the clear color, THEN * draw a rectangle with the background color. */ - if (i > 0) { - if ((m_backgroundColorByte[0] != clearColorByte[0]) - || (m_backgroundColorByte[1] != clearColorByte[1]) - || (m_backgroundColorByte[2] != clearColorByte[2])) { - GLboolean depthEnabledFlag; - glGetBooleanv(GL_DEPTH_TEST, - &depthEnabledFlag); - glDisable(GL_DEPTH_TEST); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glColor3ubv(m_backgroundColorByte); - glBegin(GL_POLYGON); - glVertex2f(0.0, 0.0); - glVertex2f(1.0, 0.0); - glVertex2f(1.0, 1.0); - glVertex2f(0.0, 1.0); - glEnd(); - - if (depthEnabledFlag) { - glEnable(GL_DEPTH_TEST); - } + if ((m_backgroundColorByte[0] != clearColorByte[0]) + || (m_backgroundColorByte[1] != clearColorByte[1]) + || (m_backgroundColorByte[2] != clearColorByte[2])) { + GLboolean depthEnabledFlag; + glGetBooleanv(GL_DEPTH_TEST, + &depthEnabledFlag); + glDisable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glColor3ubv(m_backgroundColorByte); + glBegin(GL_POLYGON); + glVertex2f(0.0, 0.0); + glVertex2f(1.0, 0.0); + glVertex2f(1.0, 1.0); + glVertex2f(0.0, 1.0); + glEnd(); + + if (depthEnabledFlag) { + glEnable(GL_DEPTH_TEST); } } @@ -665,7 +724,12 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, */ updateForegroundAndBackgroundColors(vpContent); - drawTabAnnotations(vpContent); + if (vpContent->getSpacerTabContent() != NULL) { + drawSpacerAnnotations(vpContent); + } + else { + drawTabAnnotations(vpContent); + } } /* @@ -683,6 +747,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, m_brain = NULL; m_windowIndex = -1; + m_windowUserInputMode = UserInputModeEnum::INVALID; } /** @@ -810,19 +875,23 @@ BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(const BrainOpenGLV * Draw annotations for this surface and maybe draw * the model annotations. */ + const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + SpacerTabIndex(), + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::CHART, emptyColorBars, emptyViewportAnnotations, - NULL); + NULL, + 1.0); @@ -835,6 +904,65 @@ BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(const BrainOpenGLV glPopAttrib(); } +/** + * Draw the spacer tag annotations. + * + * @param tabContent + * Viewport content + */ +void +BrainOpenGLFixedPipeline::drawSpacerAnnotations(const BrainOpenGLViewportContent* tabContent) +{ + if (tabContent->getSpacerTabContent() == NULL) { + return; + } + + int tabViewport[4]; + tabContent->getModelViewport(tabViewport); + CaretAssertMessage(m_brain, "m_brain must NOT be NULL for drawing spacer tab annotations."); + glViewport(tabViewport[0], + tabViewport[1], + tabViewport[2], + tabViewport[3]); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glOrtho(0.0, tabViewport[2], 0.0, tabViewport[3], -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + CaretAssert(m_windowIndex == tabContent->getWindowIndex()); + this->browserTabContent = NULL; + m_clippingPlaneGroup = NULL; //const_cast(tabContent->getBrowserTabContent()->getClippingPlaneGroup()); + + this->windowTabIndex = -1; + + SpacerTabIndex spacerTabIndex; + SpacerTabContent* spacerTabContent = tabContent->getSpacerTabContent(); + CaretAssert(spacerTabContent); + spacerTabIndex = spacerTabContent->getSpacerTabIndex(); + + const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, + this->mode, + BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, + m_windowIndex, + this->windowTabIndex, + spacerTabIndex, + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); + m_annotationDrawing->drawAnnotations(&inputs, + AnnotationCoordinateSpaceEnum::SPACER, + m_annotationColorBarsForDrawing, + m_specialCaseGraphicsAnnotations, + annotationDrawingNullSurface, + annotationDrawingUnusedSurfaceScaling); + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); +} /** * Draw the tab annotations. @@ -870,17 +998,21 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(const BrainOpenGLViewportContent* t this->windowTabIndex = this->browserTabContent->getTabNumber(); + const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + SpacerTabIndex(), + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, m_specialCaseGraphicsAnnotations, - NULL); + annotationDrawingNullSurface, + annotationDrawingUnusedSurfaceScaling); glPopMatrix(); glMatrixMode(GL_PROJECTION); @@ -929,18 +1061,22 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) */ this->windowTabIndex = -1; + const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, - windowDrawingMode); + SpacerTabIndex(), + windowDrawingMode, + annotationModeFlag); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::WINDOW, m_annotationColorBarsForDrawing, m_specialCaseGraphicsAnnotations, - NULL); + annotationDrawingNullSurface, + annotationDrawingUnusedSurfaceScaling); glPopMatrix(); glMatrixMode(GL_PROJECTION); @@ -1017,7 +1153,9 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, } else if (surfaceModel != NULL) { m_mirroredClippingEnabled = true; - this->drawSurfaceModel(surfaceModel, viewport); + this->drawSurfaceModel(browserTabContent, + surfaceModel, + viewport); } else if (surfaceMontageModel != NULL) { m_mirroredClippingEnabled = true; @@ -1692,6 +1830,8 @@ BrainOpenGLFixedPipeline::disableLighting() void BrainOpenGLFixedPipeline::enableLineAntiAliasing() { + glPushAttrib(GL_ENABLE_BIT + | GL_COLOR_BUFFER_BIT); /* * If multi-sampling is enabled, it handle anti-aliasing */ @@ -1713,6 +1853,8 @@ BrainOpenGLFixedPipeline::enableLineAntiAliasing() void BrainOpenGLFixedPipeline::disableLineAntiAliasing() { + glPopAttrib(); + /* * If multi-sampling is enabled, it handle anti-aliasing */ @@ -1720,20 +1862,23 @@ BrainOpenGLFixedPipeline::disableLineAntiAliasing() return; } - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); +// glDisable(GL_LINE_SMOOTH); +// glDisable(GL_BLEND); } /** * Draw contents of a surface model. + * @param browserTabContent + * Browser tab containing surface model. * @param surfaceModel * Model that is drawn. * @param viewport * Viewport for drawing region. */ void -BrainOpenGLFixedPipeline::drawSurfaceModel(ModelSurface* surfaceModel, - const int32_t viewport[4]) +BrainOpenGLFixedPipeline::drawSurfaceModel(BrowserTabContent* browserTabContent, + ModelSurface* surfaceModel, + const int32_t viewport[4]) { Surface* surface = surfaceModel->getSurface(); float center[3]; @@ -1752,6 +1897,7 @@ BrainOpenGLFixedPipeline::drawSurfaceModel(ModelSurface* surfaceModel, this->windowTabIndex); this->drawSurface(surface, + browserTabContent->getScaling(), nodeColoringRGBA, true); } @@ -1782,6 +1928,8 @@ BrainOpenGLFixedPipeline::drawSurfaceAxes() * * @param surface * Surface that is drawn. + * @param surfaceScaling + * User scaling of surface. * @param nodeColoringRGBA * RGBA coloring for the nodes. * @param drawAnnotationsInModelSpaceFlag @@ -1789,9 +1937,12 @@ BrainOpenGLFixedPipeline::drawSurfaceAxes() */ void BrainOpenGLFixedPipeline::drawSurface(Surface* surface, + const float surfaceScaling, const float* nodeColoringRGBA, const bool drawAnnotationsInModelSpaceFlag) { + glPushAttrib(GL_COLOR_BUFFER_BIT); + const DisplayPropertiesSurface* dps = m_brain->getDisplayPropertiesSurface(); glMatrixMode(GL_MODELVIEW); @@ -1856,8 +2007,11 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, glPolygonOffset(factor, units); } + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_CULL_FACE); this->drawSurfaceTrianglesWithVertexArrays(surface, nodeColoringRGBA); + glPopAttrib(); if (borderAboveSurfaceOffset != 0.0) { glDisable(GL_POLYGON_OFFSET_FILL); @@ -1883,25 +2037,32 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, * Draw annotations for this surface and maybe draw * the model annotations. */ + const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + SpacerTabIndex(), + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; + + m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, emptyViewportAnnotations, - surface); + surface, + surfaceScaling); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, emptyViewportAnnotations, - NULL); + annotationDrawingNullSurface, + annotationDrawingUnusedSurfaceScaling); } } break; @@ -1931,25 +2092,30 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, * Draw annotations for this surface and maybe draw * the model annotations. */ + const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + SpacerTabIndex(), + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, emptyViewportAnnotations, - surface); + surface, + surfaceScaling); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, emptyViewportAnnotations, - NULL); + annotationDrawingNullSurface, + annotationDrawingUnusedSurfaceScaling); } /* @@ -1977,6 +2143,8 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, this->disableLighting(); this->disableClippingPlanes(); + + glPopAttrib(); } /** @@ -2650,32 +2818,21 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) const int32_t numBorderPoints = borderDrawInfo.border->getNumberOfPoints(); const bool isHighlightEndPoints = borderDrawInfo.isHighlightEndPoints; - float pointDiameter = 2.0; - float lineWidth = 2.0; - BorderDrawingTypeEnum::Enum drawType = BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES; - if (borderDrawInfo.borderFileIndex >= 0) { - const BrainStructure* bs = borderDrawInfo.surface->getBrainStructure(); - const Brain* brain = bs->getBrain(); - const DisplayPropertiesBorders* dpb = brain->getDisplayPropertiesBorders(); - const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(this->windowTabIndex); - pointDiameter = dpb->getPointSize(displayGroup, - this->windowTabIndex); - lineWidth = dpb->getLineWidth(displayGroup, - this->windowTabIndex); - drawType = dpb->getDrawingType(displayGroup, - this->windowTabIndex); - } - + CaretAssert(m_brain); + const DisplayPropertiesBorders* dpb = m_brain->getDisplayPropertiesBorders(); + const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(this->windowTabIndex); + const float pointDiameter = dpb->getPointSize(displayGroup, + this->windowTabIndex); + const float lineWidth = dpb->getLineWidth(displayGroup, + this->windowTabIndex); + BorderDrawingTypeEnum::Enum drawType = dpb->getDrawingType(displayGroup, + this->windowTabIndex); + + /* + * When a border is being drawn, always use spheres + */ if (borderDrawInfo.border == this->borderBeingDrawn) { - if (borderDrawInfo.surface != NULL) { - const BoundingBox* bb = borderDrawInfo.surface->getBoundingBox(); - const float maxSize = std::max(bb->getDifferenceX(), - std::max(bb->getDifferenceY(), bb->getDifferenceZ())); - if (maxSize > 0.0f) { - const float percentSize = 0.03f; - pointDiameter = maxSize * percentSize; - } - } + drawType = BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES; } bool drawSphericalPoints = false; @@ -3012,7 +3169,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } glPopAttrib(); -}//p-> +} /** @@ -3171,9 +3328,6 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) colorLabel->getColor(rgbaFloat); focus->setClassRgba(rgbaFloat); } -// else { -// focus->setClassRgba(rgbaFloat); -// } } focus->getClassRgba(rgbaFloat); break; @@ -3190,9 +3344,6 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) colorLabel->getColor(rgbaFloat); focus->setNameRgba(rgbaFloat); } -// else { -// focus->setNameRgba(rgbaFloat); -// } } focus->getNameRgba(rgbaFloat); break; @@ -3544,9 +3695,6 @@ BrainOpenGLFixedPipeline::setupVolumeDrawInfo(BrowserTabContent* browserTabConte VolumeMappableInterface* vf = dynamic_cast(mapFile); if (vf != NULL) { float opacity = overlay->getOpacity(); - if (volumeDrawInfoOut.empty()) { - opacity = 1.0; - } WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode = overlay->getWholeBrainVoxelDrawingMode(); @@ -3666,25 +3814,57 @@ BrainOpenGLFixedPipeline::drawVolumeModel(BrowserTabContent* browserTabContent, break; } + /* + * Allow blending of volume slices and volume surface outline + */ + glPushAttrib(GL_COLOR_BUFFER_BIT); + applyVolumePropertiesOpacity(); + if (useNewDrawingFlag) { - BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; - volumeSliceDrawing.draw(this, - browserTabContent, - volumeDrawInfo, - sliceDrawingType, - sliceProjectionType, - viewport); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_TEXTURE_VOLUME)) { + BrainOpenGLVolumeTextureSliceDrawing textureSliceDrawing; + textureSliceDrawing.draw(this, + browserTabContent, + volumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueMaskType, + viewport); + } + else { + BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; + volumeSliceDrawing.draw(this, + browserTabContent, + volumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + viewport); + } } else { - BrainOpenGLVolumeObliqueSliceDrawing obliqueVolumeSliceDrawing; - obliqueVolumeSliceDrawing.draw(this, - browserTabContent, - volumeDrawInfo, - sliceDrawingType, - sliceProjectionType, - obliqueMaskType, - viewport); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_TEXTURE_VOLUME)) { + BrainOpenGLVolumeTextureSliceDrawing textureSliceDrawing; + textureSliceDrawing.draw(this, + browserTabContent, + volumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueMaskType, + viewport); + } + else { + BrainOpenGLVolumeObliqueSliceDrawing obliqueVolumeSliceDrawing; + obliqueVolumeSliceDrawing.draw(this, + browserTabContent, + volumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueMaskType, + viewport); + } } + + glPopAttrib(); } /** @@ -5050,6 +5230,7 @@ BrainOpenGLFixedPipeline::drawSurfaceMontageModel(BrowserTabContent* browserTabC mvp->getProjectionViewType()); this->drawSurface(mvp->getSurface(), + browserTabContent->getScaling(), nodeColoringRGBA, true); } @@ -5080,6 +5261,30 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte tabNumberIndex); Surface* rightSurface = wholeBrainModel->getSelectedSurface(StructureEnum::CORTEX_RIGHT, tabNumberIndex); + + if (m_brain->isSurfaceMatchingToAnatomical()) { + /* + * Use the primary anatomical surface for sizing any surface in the same + * structure so that size of viewport is the same. Otherwise, the viewport + * is scaled uniquely for each structure + */ + BrainStructure* leftStructure = m_brain->getBrainStructure(StructureEnum::CORTEX_LEFT, false); + if (leftStructure != NULL) { + Surface* leftPrimaryAnat = leftStructure->getPrimaryAnatomicalSurface(); + if (leftPrimaryAnat != NULL) { + leftSurface = leftPrimaryAnat; + } + } + BrainStructure* rightStructure = m_brain->getBrainStructure(StructureEnum::CORTEX_RIGHT, false); + if (rightStructure != NULL) { + Surface* rightPrimaryAnat = rightStructure->getPrimaryAnatomicalSurface(); + if (rightPrimaryAnat != NULL) { + rightSurface = rightPrimaryAnat; + } + } + /* 2/22/19 ALL SURFACES SAME VIEWPORT */ + } + /* * Center using volume, if it is available * Otherwise, see if surface is available, but a surface is offset @@ -5177,38 +5382,59 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte } if ( ! twoDimSliceDrawVolumeDrawInfo.empty()) { + /* + * Allow blending of volume slices and volume surface outline + */ + glPushAttrib(GL_COLOR_BUFFER_BIT); + applyVolumePropertiesOpacity(); + /* * Check for oblique slice drawing */ VolumeSliceDrawingTypeEnum::Enum sliceDrawingType = browserTabContent->getSliceDrawingType(); VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = browserTabContent->getSliceProjectionType(); - switch (sliceProjectionType) { - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: - { - VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); - BrainOpenGLVolumeObliqueSliceDrawing volumeSliceDrawing; - volumeSliceDrawing.draw(this, - browserTabContent, - twoDimSliceDrawVolumeDrawInfo, - sliceDrawingType, - sliceProjectionType, - obliqueMaskType, - viewport); - } - break; - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: - { - BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; - volumeSliceDrawing.draw(this, - browserTabContent, - twoDimSliceDrawVolumeDrawInfo, - sliceDrawingType, - sliceProjectionType, - viewport); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_TEXTURE_VOLUME)) { + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); + BrainOpenGLVolumeTextureSliceDrawing textureSliceDrawing; + textureSliceDrawing.draw(this, + browserTabContent, + twoDimSliceDrawVolumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueMaskType, + viewport); + } + else { + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); + BrainOpenGLVolumeObliqueSliceDrawing volumeSliceDrawing; + volumeSliceDrawing.draw(this, + browserTabContent, + twoDimSliceDrawVolumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueMaskType, + viewport); + } + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + { + BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; + volumeSliceDrawing.draw(this, + browserTabContent, + twoDimSliceDrawVolumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + viewport); + } + break; } - break; } + + glPopAttrib(); } } } @@ -5219,6 +5445,7 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte /* * Draw surfaces last so that opacity works. */ + std::set uniqueStructuresToDraw; std::vector surfacesToDraw; const int32_t numberOfBrainStructures = m_brain->getNumberOfBrainStructures(); for (int32_t i = 0; i < numberOfBrainStructures; i++) { @@ -5244,11 +5471,22 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte } if (drawIt) { + uniqueStructuresToDraw.insert(structure); surfacesToDraw.push_back(surface); } } } + /* + * When only one surface structure is displayed, disable offset of surfaces + */ + bool allowLeftRightSeparationFlag(true); + if (m_brain->isSurfaceMatchingToAnatomical()) { + if (uniqueStructuresToDraw.size() == 1) { + allowLeftRightSeparationFlag = false; + } + } + const int32_t numSurfaceToDraw = static_cast(surfacesToDraw.size()); for (int32_t i = 0; i < numSurfaceToDraw; i++) { CaretAssertVectorIndex(surfacesToDraw, i); @@ -5258,27 +5496,29 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte float dx = 0.0; float dy = 0.0; float dz = 0.0; - switch (surface->getStructure()) { - case StructureEnum::CORTEX_LEFT: - dx = -browserTabContent->getWholeBrainLeftRightSeparation(); - if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) - && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { - dx -= surface->getBoundingBox()->getMaxX(); - } - break; - case StructureEnum::CORTEX_RIGHT: - dx = browserTabContent->getWholeBrainLeftRightSeparation(); - if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) - && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { - dx -= surface->getBoundingBox()->getMinX(); - } - break; - case StructureEnum::CEREBELLUM: - dz = browserTabContent->getWholeBrainCerebellumSeparation(); - break; - default: - CaretLogWarning("programmer-issure: Surface type not left/right/cerebellum"); - break; + if (allowLeftRightSeparationFlag) { + switch (surface->getStructure()) { + case StructureEnum::CORTEX_LEFT: + dx = -browserTabContent->getWholeBrainLeftRightSeparation(); + if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) + && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { + dx -= surface->getBoundingBox()->getMaxX(); + } + break; + case StructureEnum::CORTEX_RIGHT: + dx = browserTabContent->getWholeBrainLeftRightSeparation(); + if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) + && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { + dx -= surface->getBoundingBox()->getMinX(); + } + break; + case StructureEnum::CEREBELLUM: + dz = browserTabContent->getWholeBrainCerebellumSeparation(); + break; + default: + CaretLogWarning("programmer-issure: Surface type not left/right/cerebellum"); + break; + } } if (surface != NULL) { @@ -5294,6 +5534,7 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte glPushMatrix(); glTranslatef(dx, dy, dz); this->drawSurface(surface, + browserTabContent->getScaling(), nodeColoringRGBA, drawModelSpaceAnnotationsFlag); glPopMatrix(); @@ -5301,6 +5542,24 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte } } +/** + * Apply opacity from the volume properties + */ +void +BrainOpenGLFixedPipeline::applyVolumePropertiesOpacity() +{ + const DisplayPropertiesVolume* dpv = m_brain->getDisplayPropertiesVolume(); + const float opacity = dpv->getOpacity(); + const bool useBlendingFlag(opacity < 1.0f); + + if (useBlendingFlag) { + glEnable(GL_BLEND); + glBlendColor(opacity, opacity, opacity, opacity); + glBlendFunc(GL_CONSTANT_ALPHA, + GL_ONE_MINUS_CONSTANT_ALPHA); + } +} + /** * Draw a chart model. * @@ -6675,7 +6934,7 @@ BrainOpenGLFixedPipeline::drawTextAtModelCoords(const double modelX, const AnnotationText& annotationText) { if (getTextRenderer() != NULL) { - getTextRenderer()->drawTextAtModelCoords(modelX, + getTextRenderer()->drawTextAtModelCoordsFacingUser(modelX, modelY, modelZ, annotationText, @@ -6697,7 +6956,7 @@ BrainOpenGLFixedPipeline::drawTextAtModelCoords(const double modelXYZ[3], const AnnotationText& annotationText) { if (getTextRenderer() != NULL) { - getTextRenderer()->drawTextAtModelCoords(modelXYZ, + getTextRenderer()->drawTextAtModelCoordsFacingUser(modelXYZ, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } @@ -6717,7 +6976,7 @@ BrainOpenGLFixedPipeline::drawTextAtModelCoords(const float modelXYZ[3], const AnnotationText& annotationText) { if (getTextRenderer() != NULL) { - getTextRenderer()->drawTextAtModelCoords(modelXYZ, + getTextRenderer()->drawTextAtModelCoordsFacingUser(modelXYZ, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 32ed9dca7660f262df7228868c554ba67fd6f472..172935495af2133a9ea55fd3d4e9b9ff3079e30d 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -115,10 +115,12 @@ namespace caret { protected: void drawModelsImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const std::vector& viewportContents) override; void selectModelImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, @@ -126,6 +128,7 @@ namespace caret { const bool applySelectionBackgroundFiltering) override; void projectToModelImplementation(const int32_t windowIndex, + const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, @@ -192,10 +195,12 @@ namespace caret { ModelChartTwo* chartData, const int32_t viewport[4]); - void drawSurfaceModel(ModelSurface* surfaceModel, - const int32_t viewport[4]); + void drawSurfaceModel(BrowserTabContent* browserTabContent, + ModelSurface* surfaceModel, + const int32_t viewport[4]); void drawSurface(Surface* surface, + const float surfaceScaling, const float* nodeColoringRGBA, const bool drawAnnotationsInModelSpaceFlag); @@ -448,6 +453,8 @@ namespace caret { void drawWindowAnnotations(const int windowViewport[4]); + void drawSpacerAnnotations(const BrainOpenGLViewportContent* tabContent); + void drawTabAnnotations(const BrainOpenGLViewportContent* tabContent); void drawChartCoordinateSpaceAnnotations(const BrainOpenGLViewportContent* viewportContent); @@ -506,9 +513,14 @@ namespace caret { const float height, const float rgb[3]); + void applyVolumePropertiesOpacity(); + /** Index of window */ int32_t m_windowIndex = -1; + /** User input mode for window */ + UserInputModeEnum::Enum m_windowUserInputMode; + /** Indicates OpenGL has been initialized */ bool initializedOpenGLFlag; @@ -612,7 +624,7 @@ namespace caret { friend class BrainOpenGLChartTwoDrawingFixedPipeline; friend class BrainOpenGLVolumeObliqueSliceDrawing; friend class BrainOpenGLVolumeSliceDrawing; - friend class OldBrainOpenGLVolumeSliceDrawing; + friend class BrainOpenGLVolumeTextureSliceDrawing; }; #ifdef __BRAIN_OPENGL_FIXED_PIPELINE_DEFINE_H diff --git a/src/Brain/BrainOpenGLTextRenderInterface.h b/src/Brain/BrainOpenGLTextRenderInterface.h index 5450c369ea218ecf1ff095bbd8bfcb0679be1031..1b7784deabc63aae42b5a61b2167bf1eea06c9ea 100644 --- a/src/Brain/BrainOpenGLTextRenderInterface.h +++ b/src/Brain/BrainOpenGLTextRenderInterface.h @@ -74,6 +74,8 @@ namespace caret { * Viewport Y-coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, @@ -94,6 +96,8 @@ namespace caret { * Viewport Z-coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, @@ -104,6 +108,7 @@ namespace caret { /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. + * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * @@ -115,8 +120,10 @@ namespace caret { * Model Z-coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ - virtual void drawTextAtModelCoords(const double modelX, + virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, @@ -125,6 +132,7 @@ namespace caret { /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. + * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * @@ -132,16 +140,19 @@ namespace caret { * Model XYZ coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ - void drawTextAtModelCoords(const double modelXYZ[3], + void drawTextAtModelCoordsFacingUser(const double modelXYZ[3], const AnnotationText& annotationText, const DrawingFlags& flags) { - drawTextAtModelCoords(modelXYZ[0], modelXYZ[1], modelXYZ[2], annotationText, flags); + drawTextAtModelCoordsFacingUser(modelXYZ[0], modelXYZ[1], modelXYZ[2], annotationText, flags); } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. + * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * @@ -149,13 +160,71 @@ namespace caret { * Model XYZ coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ - void drawTextAtModelCoords(const float modelXYZ[3], - const AnnotationText& annotationText, - const DrawingFlags& flags) { - drawTextAtModelCoords(modelXYZ[0], modelXYZ[1], modelXYZ[2], annotationText, flags); + void drawTextAtModelCoordsFacingUser(const float modelXYZ[3], + const AnnotationText& annotationText, + const DrawingFlags& flags) { + drawTextAtModelCoordsFacingUser(modelXYZ[0], modelXYZ[1], modelXYZ[2], annotationText, flags); } + /** + * Get the bounds of text drawn in model space using the current model transformations. + * + * @param annotationText + * Text that is to be drawn. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * Size of region used when converting percentage size to a fixed size + * @param flags + * Drawing flags. + * @param bottomLeftOut + * The bottom left corner of the text bounds. + * @param bottomRightOut + * The bottom right corner of the text bounds. + * @param topRightOut + * The top right corner of the text bounds. + * @param topLeftOut + * The top left corner of the text bounds. + * @param underlineStartOut + * Starting coordinate for drawing text underline. + * @param underlineEndOut + * Ending coordinate for drawing text underline. + */ + virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const DrawingFlags& flags, + double bottomLeftOut[3], + double bottomRightOut[3], + double topRightOut[3], + double topLeftOut[3], + double underlineStartOut[3], + double underlineEndOut[3]) = 0; + /** + * Draw text in model space using the current model transformations. + * + * Depth testing is ENABLED when drawing text with this method. + * + * @param annotationText + * Annotation text and attributes. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * If positive, use it to override width/height of viewport. + * @param backgroundOverrideRGBA + * If alpha is greater that zero, draw background with this color + * @param flags + * Drawing flags. + */ + virtual void drawTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const float normalVector[3], + const DrawingFlags& flags) = 0; + /** * Get the estimated width and height of text (in pixels) using the given text * attributes. diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 699840d9e353e36e7e3a8dfb9c64ce9f8ef6d65c..48f3768200803760dd99230aa2ecb4a2d28c21a8 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -34,9 +34,11 @@ #include "CaretLogger.h" #include "EventBrowserWindowContent.h" #include "EventManager.h" +#include "EventSpacerTabGet.h" #include "GapsAndMargins.h" #include "MathFunctions.h" #include "ModelSurfaceMontage.h" +#include "SpacerTabContent.h" #include "SurfaceMontageConfigurationAbstract.h" #include "TileTabsConfiguration.h" @@ -68,18 +70,22 @@ using namespace caret; * Tile Tabs mode so user knows graphics region corresponding * to the tab that was recently selected). * @param browserTabContent - * Tab's content that is being drawn. + * Browser Tab content that is being drawn (if not NULL) + * @param spacerTabContent + * Spacer Tab content that is being drawn (if not NULL) */ BrainOpenGLViewportContent::BrainOpenGLViewportContent(const int windowViewport[4], const int tabViewport[4], const int modelViewport[4], const int windowIndex, const bool highlightTabFlag, - BrowserTabContent* browserTabContent) + BrowserTabContent* browserTabContent, + SpacerTabContent* spacerTabContent) : CaretObject(), m_windowIndex(windowIndex), m_highlightTab(highlightTabFlag), -m_browserTabContent(browserTabContent) +m_browserTabContent(browserTabContent), +m_spacerTabContent(spacerTabContent) { m_windowX = windowViewport[0]; m_windowY = windowViewport[1]; @@ -169,6 +175,8 @@ BrainOpenGLViewportContent::initializeMembersBrainOpenGLViewportContent() m_windowY = 0; m_windowWidth = 0; m_windowHeight = 0; + m_browserTabContent = NULL; + m_spacerTabContent = NULL; } /** @@ -200,6 +208,7 @@ BrainOpenGLViewportContent::copyHelperBrainOpenGLViewportContent(const BrainOpen m_windowHeight = obj.m_windowHeight; m_browserTabContent = obj.m_browserTabContent; + m_spacerTabContent = obj.m_spacerTabContent; } /** @@ -417,7 +426,7 @@ BrainOpenGLViewportContent::getWindowIndex() const } /** - * @return Pointer to tab content in viewport. + * @return Pointer to browser tab content in viewport (NULL if no browser tab in viewport) */ BrowserTabContent* BrainOpenGLViewportContent::getBrowserTabContent() const @@ -425,6 +434,15 @@ BrainOpenGLViewportContent::getBrowserTabContent() const return m_browserTabContent; } +/** + * @return Pointer to spacer tab content in viewport (NULL if no spacer tab in viewport) + */ +SpacerTabContent* +BrainOpenGLViewportContent::getSpacerTabContent() const +{ + return m_spacerTabContent; +} + /** * @return Index of browser tab or -1 if there is not browser tab for this viewport. */ @@ -551,7 +569,8 @@ BrainOpenGLViewportContent::createViewportForSingleTab(std::vector tabConfigRowHeights; - std::vector tabConfigColumnWidths; + std::vector rowHeights; + std::vector columnWidths; TileTabsConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, windowHeight, numberOfTabs, browserWindowContent->getTileTabsConfigurationMode(), - tabConfigRowHeights, - tabConfigColumnWidths); + rowHeights, + columnWidths); - const int32_t numRows = static_cast(tabConfigRowHeights.size()); - const int32_t numColumns = static_cast(tabConfigColumnWidths.size()); + const int32_t numRows = static_cast(rowHeights.size()); + const int32_t numColumns = static_cast(columnWidths.size()); const int32_t numCells = numRows * numColumns; if (numCells <= 0) { return viewportContentsOut; @@ -616,15 +640,6 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vector 0); CaretAssert(numColumns > 0); - /* - * Due to aspect ratios, the width or height - * of tab viewports may shrink so we will - * need to recompute the row heights and column - * widths. - */ - std::vector rowHeights(numRows, 0); - std::vector columnWidths(numColumns, 0); - const bool allTabsAspectLockedFlag = browserWindowContent->isAllTabsInWindowAspectRatioLocked(); /* @@ -634,10 +649,53 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vector tabSizeInfoVector; int32_t iTab = 0; for (int32_t iRowFromTop = 0; iRowFromTop < numRows; iRowFromTop++) { - const int32_t vpHeight = tabConfigRowHeights[iRowFromTop]; + CaretAssertVectorIndex(rowHeights, iRowFromTop); + const int32_t vpHeight = rowHeights[iRowFromTop]; + for (int32_t jCol = 0; jCol < numColumns; jCol++) { - const int32_t vpWidth = tabConfigColumnWidths[jCol]; - if (iTab < numberOfTabs) { + bool spacerTabFlag = false; + const TileTabsGridRowColumnContentTypeEnum::Enum rowContentType = tileTabsConfiguration->getRow(iRowFromTop)->getContentType(); + switch (rowContentType) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + spacerTabFlag = true; + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + break; + } + + const TileTabsGridRowColumnContentTypeEnum::Enum tabContentType = tileTabsConfiguration->getColumn(jCol)->getContentType(); + switch (tabContentType) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + spacerTabFlag = true; + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + break; + } + + CaretAssertVectorIndex(columnWidths, jCol); + const int32_t vpWidth = columnWidths[jCol]; + + if (spacerTabFlag) { + EventSpacerTabGet spacerTabEvent(windowIndex, iRowFromTop, jCol); + EventManager::get()->sendEvent(spacerTabEvent.getPointer()); + SpacerTabContent* spacerTabContent = spacerTabEvent.getSpacerTabContent(); + if (spacerTabContent != NULL) { + BrowserTabContent* invalidBrowserTab(NULL); + TileTabsViewportSizingInfo tsi(invalidBrowserTab, + spacerTabContent, + iRowFromTop, + jCol, + vpWidth, + vpHeight); + tabSizeInfoVector.push_back(tsi); + } + else { + AString msg("Failed to get SpacerTabContent for windowIndex=%1, row=%2, column=%3"); + msg = msg.arg(windowIndex).arg(iRowFromTop).arg(jCol); + CaretLogSevere(msg); + } + } + else if (iTab < numberOfTabs) { CaretAssertVectorIndex(tabContents, iTab); @@ -667,61 +725,75 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorisCenteringCorrectionEnabled()) { + /* + * Kludge that fixes old scenes + * NEED TO ADJUST FOR X too ? + * THIS WILL NEED TO BE AN OPTION SOMEWHERE + * TRY MORE THAN TWO ROWS + */ + std::vector tabRowHeights(numRows, 0); + std::vector tabColumnWidths(numColumns, 0); + { + for (auto tsi : tabSizeInfoVector) { + const int32_t rowIndex = tsi.m_rowIndexFromTop; + tabRowHeights[rowIndex] = std::max(tabRowHeights[rowIndex], + tsi.m_height); + + const int32_t columnIndex(tsi.m_columnIndex); + tabColumnWidths[columnIndex] = std::max(tabColumnWidths[columnIndex], + tsi.m_width); + } + + for (int32_t i = 0; i < numRows; i++) { + rowHeights[i] = tabRowHeights[i]; + } + for (int32_t i = 0; i < numColumns; i++) { + columnWidths[i] = tabColumnWidths[i]; } } + const int32_t allTabsHeight = std::accumulate(tabRowHeights.begin(), tabRowHeights.end(), 0); + windowY -= ((windowHeight - allTabsHeight) / 2); + + const int32_t allTabsWidth = std::accumulate(tabColumnWidths.begin(), tabColumnWidths.end(), 0); + const int32_t offset = (windowWidth - allTabsWidth) / 2; + windowX += offset; } - + + + /* * Note: There may be more tabs than there are cells (rows * columns) * so some tabs may not be displayed. */ const int32_t numberOfDisplayedTabs = static_cast(tabSizeInfoVector.size()); - /* - * Now that we know the height of each row, and width of each column, - * we can get the total width and height of ALL tab viewports. - */ - const int32_t allTabsHeight = std::accumulate(rowHeights.begin(), rowHeights.end(), 0); - const int32_t allTabsWidth = std::accumulate(columnWidths.begin(), columnWidths.end(), 0); - - /* - * The total width/height of the tabs may be less than the size - * of the window viewport. We want to center the tabs inside of - * the window viewport so find any extra space in the window. - */ - const int32_t windowExtraWidth = windowWidth - allTabsWidth; - const int32_t windowExtraHeight = windowHeight - allTabsHeight; - CaretAssert(windowExtraWidth >= 0); - CaretAssert(windowExtraHeight >= 0); - /* * Set the X and Y-coordinates for the tab viewports * We start at the bottom row, left corner. */ - int32_t vpY = windowViewport[1] + (windowExtraHeight / 2); - for (int32_t iRow = (numRows - 1); iRow >= 0; iRow--) { - int32_t vpX = windowViewport[0] + (windowExtraWidth / 2); + int32_t vpY = windowHeight + windowY; + for (int32_t iRow = 0; iRow < numRows; iRow++) { + CaretAssertVectorIndex(rowHeights, iRow); + vpY -= rowHeights[iRow]; + int32_t vpX = windowX; for (int32_t jCol = 0; jCol < numColumns; jCol++) { + TileTabsViewportSizingInfo* tabSizePtr = NULL; for (int32_t iTab = 0; iTab < numberOfDisplayedTabs; iTab++) { CaretAssertVectorIndex(tabSizeInfoVector, iTab); @@ -735,14 +807,32 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorm_width; - const int32_t tabExtraHeight = rowHeights[iRow] - tabSizePtr->m_height; + CaretAssertVectorIndex(columnWidths, jCol); + const int32_t extraWidth = columnWidths[jCol] - tabSizePtr->m_width; + if (extraWidth > 1) { + const int32_t halfExtraWidth = extraWidth / 2; + tabX += halfExtraWidth; + } - const int32_t tabX = vpX + (tabExtraWidth / 2); - const int32_t tabY = vpY + (tabExtraHeight / 2); + /* + * Adjust Tab's Y-coord so centered in tab + * when lock aspect causes tab's height to be smaller + * than the row's height + */ + CaretAssertVectorIndex(rowHeights, iRow); + const int32_t extraHeight = rowHeights[iRow] - tabSizePtr->m_height; + if (extraHeight > 1) { + const int32_t halfExtraHeight = extraHeight / 2; + tabY += halfExtraHeight; + } const int tabViewport[4] = { tabX, @@ -754,21 +844,25 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorm_browserTabContent->getTabNumber(); + int32_t tabIndex = -1; + bool highlightTabFlag = false; + if (tabSizePtr->m_browserTabContent != NULL) { + tabIndex = tabSizePtr->m_browserTabContent->getTabNumber(); + highlightTabFlag = (highlightTabIndex == tabIndex); + } int modelViewport[4] = { 0, 0, 0, 0 }; createModelViewport(tabViewport, tabIndex, gapsAndMargins, modelViewport); - - //tabSizePtr->print(tabX, tabY); BrainOpenGLViewportContent* vpContent = new BrainOpenGLViewportContent(windowViewport, tabViewport, modelViewport, browserWindowContent->getWindowIndex(), - (highlightTabIndex ==tabIndex), - tabSizePtr->m_browserTabContent); + highlightTabFlag, + tabSizePtr->m_browserTabContent, + tabSizePtr->m_spacerTabContent); viewportContentsOut.push_back(vpContent); } else { @@ -788,6 +882,7 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorgetWindowIndex(), false, + NULL, NULL); viewportContentsOut.push_back(vpContent); } @@ -795,10 +890,13 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorgetTabIndex() == 0) { +// std::cout << "TAB 1: " << vpc->toString() << std::endl << std::endl; +// } +// } return viewportContentsOut; } @@ -830,33 +928,35 @@ BrainOpenGLViewportContent::createModelViewport(const int tabViewport[4], modelViewportOut[2] = tabViewport[2]; modelViewportOut[3] = tabViewport[3]; - if (gapsAndMargins != NULL) { - gapsAndMargins->getMarginsInPixelsForDrawing(tabIndex, - tabViewport[2], - tabViewport[3], - leftMargin, - rightMargin, - bottomMargin, - topMargin); - const int32_t marginHorizSize = (leftMargin + rightMargin); - const int32_t marginVertSize = (bottomMargin + topMargin); - if ((marginHorizSize < modelViewportOut[2]) - && (marginVertSize < modelViewportOut[3])) { - modelViewportOut[0] += leftMargin; - modelViewportOut[1] += bottomMargin; - modelViewportOut[2] -= marginHorizSize; - modelViewportOut[3] -= marginVertSize; - } - else { - CaretLogSevere("Margins are too big for tab " - + AString::number(tabIndex + 1) - + " viewport. Viewport (x,y,w,h)=" - + AString::fromNumbers(modelViewportOut, 4, ",") - + " margin (l,r,b,t)=" - + AString::number(leftMargin) + "," - + AString::number(rightMargin) + "," - + AString::number(bottomMargin) + "," - + AString::number(topMargin)); + if (tabIndex >= 0) { + if (gapsAndMargins != NULL) { + gapsAndMargins->getMarginsInPixelsForDrawing(tabIndex, + tabViewport[2], + tabViewport[3], + leftMargin, + rightMargin, + bottomMargin, + topMargin); + const int32_t marginHorizSize = (leftMargin + rightMargin); + const int32_t marginVertSize = (bottomMargin + topMargin); + if ((marginHorizSize < modelViewportOut[2]) + && (marginVertSize < modelViewportOut[3])) { + modelViewportOut[0] += leftMargin; + modelViewportOut[1] += bottomMargin; + modelViewportOut[2] -= marginHorizSize; + modelViewportOut[3] -= marginVertSize; + } + else { + CaretLogSevere("Margins are too big for tab " + + AString::number(tabIndex + 1) + + " viewport. Viewport (x,y,w,h)=" + + AString::fromNumbers(modelViewportOut, 4, ",") + + " margin (l,r,b,t)=" + + AString::number(leftMargin) + "," + + AString::number(rightMargin) + "," + + AString::number(bottomMargin) + "," + + AString::number(topMargin)); + } } } } @@ -894,8 +994,8 @@ BrainOpenGLViewportContent::getSurfaceMontageModelViewport(const int32_t montage msm->getSurfaceMontageViewportsForTransformation(m_browserTabContent->getTabNumber(), montageViewports); - const int x = montageX; // + m_tabX; - const int y = montageY; // + m_tabY; + const int x = montageX; + const int y = montageY; for (std::vector::const_iterator iter = montageViewports.begin(); iter != montageViewports.end(); @@ -938,11 +1038,13 @@ BrainOpenGLViewportContent::getSurfaceMontageModelViewport(const int32_t montage * Initial height of the tab prior to application of aspect ratio. */ BrainOpenGLViewportContent::TileTabsViewportSizingInfo::TileTabsViewportSizingInfo(BrowserTabContent* browserTabContent, + SpacerTabContent* spacerTabContent, const int32_t rowIndexFromTop, const int32_t columnIndex, const float initialWidth, const float initialHeight) : m_browserTabContent(browserTabContent), +m_spacerTabContent(spacerTabContent), m_rowIndexFromTop(rowIndexFromTop), m_columnIndex(columnIndex), m_initialWidth(initialWidth), @@ -950,12 +1052,14 @@ m_initialHeight(initialHeight), m_width(initialWidth), m_height(initialHeight) { - if (browserTabContent->isAspectRatioLocked()) { - const float aspectRatio = browserTabContent->getAspectRatio(); - if (aspectRatio > 0.0) { - BrainOpenGLViewportContent::adjustWidthHeightForAspectRatio(aspectRatio, - m_width, - m_height); + if (m_browserTabContent != NULL) { + if (m_browserTabContent->isAspectRatioLocked()) { + const float aspectRatio = m_browserTabContent->getAspectRatio(); + if (aspectRatio > 0.0) { + BrainOpenGLViewportContent::adjustWidthHeightForAspectRatio(aspectRatio, + m_width, + m_height); + } } } } @@ -970,6 +1074,7 @@ BrainOpenGLViewportContent::TileTabsViewportSizingInfo::operator=(const TileTabs { if (this != &obj) { m_browserTabContent = obj.m_browserTabContent; + m_spacerTabContent = obj.m_spacerTabContent; m_rowIndexFromTop = obj.m_rowIndexFromTop; m_columnIndex = obj.m_columnIndex; m_initialWidth = obj.m_initialWidth; @@ -993,7 +1098,14 @@ void BrainOpenGLViewportContent::TileTabsViewportSizingInfo::print(const int32_t x, const int32_t y) { - const QString msg("Model: " + m_browserTabContent->getTabName() + AString name; + if (m_browserTabContent != NULL) { + name = m_browserTabContent->getTabName(); + } + else if (m_spacerTabContent != NULL) { + name = m_spacerTabContent->getTabName(); + } + const QString msg("Model: " + name + "\n row/col: " + QString::number(m_rowIndexFromTop) + ", " + QString::number(m_columnIndex) + "\n x/y: " + QString::number(x) + ", " + QString::number(y) + "\n width/height: " + QString::number(m_width) + ", " + QString::number(m_height)); @@ -1114,13 +1226,13 @@ BrainOpenGLViewportContent::getSliceAllViewViewport(const int32_t tabViewport[4] viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::CORONAL: - viewportOut[0] = tabViewportX; + viewportOut[0] = tabViewportX + vpOffsetX; viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: - viewportOut[0] = tabViewportX + vpOffsetX; + viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index a0baf3d65e567dd6c3fd88efeb14d5821059f178..c8def250850a3bda74e98410004c2baff9593ddc 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -31,6 +31,7 @@ namespace caret { class BrowserTabContent; class BrowserWindowContent; class GapsAndMargins; + class SpacerTabContent; class TileTabsConfiguration; class BrainOpenGLViewportContent : public CaretObject { @@ -64,6 +65,8 @@ namespace caret { BrowserTabContent* getBrowserTabContent() const; + SpacerTabContent* getSpacerTabContent() const; + int32_t getTabIndex() const; bool isTabHighlighted() const; @@ -79,6 +82,7 @@ namespace caret { BrowserWindowContent* browserWindowContent, const GapsAndMargins* gapsAndMargins, const int32_t windowViewport[4], + const int32_t windowIndex, const int32_t highlightTabIndex); static BrainOpenGLViewportContent* createViewportForSingleTab(std::vector& allTabContents, @@ -104,6 +108,7 @@ namespace caret { class TileTabsViewportSizingInfo { public: TileTabsViewportSizingInfo(BrowserTabContent* browserTabContent, + SpacerTabContent* spacerTabContent, const int32_t rowIndexFromTop, const int32_t columnIndex, const float initialWidth, @@ -115,6 +120,7 @@ namespace caret { const int32_t y); BrowserTabContent* m_browserTabContent; + SpacerTabContent* m_spacerTabContent; int32_t m_rowIndexFromTop; int32_t m_columnIndex; @@ -132,7 +138,8 @@ namespace caret { const int modelViewport[4], const int windowIndex, const bool highlightTabFlag, - BrowserTabContent* browserTabContent); + BrowserTabContent* browserTabContent, + SpacerTabContent* spacerTabContent); void initializeMembersBrainOpenGLViewportContent(); @@ -194,6 +201,8 @@ namespace caret { BrowserTabContent* m_browserTabContent; + SpacerTabContent* m_spacerTabContent; + public: virtual AString toString() const; }; diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 3f63c8fa85782ea6b5836ceb6892e43e12abeb10..084a568352141261731b473309b882d4221a5e7b 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -37,11 +37,13 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" +#include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "CiftiMappableDataFile.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesFoci.h" #include "DisplayPropertiesLabels.h" +#include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "FociFile.h" #include "Focus.h" @@ -52,6 +54,7 @@ #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" +#include "GraphicsUtilitiesOpenGL.h" #include "IdentificationWithColor.h" #include "LabelDrawingProperties.h" #include "MathFunctions.h" @@ -64,6 +67,7 @@ #include "SelectionItemVoxelEditing.h" #include "SelectionManager.h" #include "SessionManager.h" +#include "SpacerTabIndex.h" #include "Surface.h" #include "SurfacePlaneIntersectionToContour.h" #include "VolumeFile.h" @@ -656,8 +660,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewTypeMontage(const Brain glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); if (m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed()) { - drawAxesCrosshairsOrthoAndOblique(sliceProjectionType, - sliceViewPlane, + drawAxesCrosshairsOblique(sliceViewPlane, sliceCoordinates, false, true); @@ -844,12 +847,15 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewProjection(const BrainO } } } + const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + SpacerTabIndex(), + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); @@ -1094,7 +1100,11 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnu glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { - BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(m_modelType, + BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(m_underlayVolume, + m_modelType, + sliceProjectionType, + sliceViewPlane, + sliceCoordinates, slicePlane, m_browserTabContent->getVolumeSurfaceOutlineSet(), m_fixedPipelineDrawing, @@ -1403,11 +1413,10 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjec { glPushMatrix(); glLoadIdentity(); - drawAxesCrosshairsOrthoAndOblique(sliceProjectionType, - sliceViewPlane, - sliceCoordinates, - drawCrosshairsFlag, - drawCrosshairLabelsFlag); + drawAxesCrosshairsOblique(sliceViewPlane, + sliceCoordinates, + drawCrosshairsFlag, + drawCrosshairLabelsFlag); glPopMatrix(); } break; @@ -1421,7 +1430,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjec * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The slice plane view. - * @param sliceCoordinates + * @param sliceCoordinatesIn * Coordinates of the selected slices. * @param drawCrosshairsFlag * If true, draw the crosshairs. @@ -1429,112 +1438,65 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjec * If true, draw the crosshair labels. */ void -BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const float sliceCoordinates[3], - const bool drawCrosshairsFlag, - const bool drawCrosshairLabelsFlag) +BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinatesIn[3], + const bool drawCrosshairsFlag, + const bool drawCrosshairLabelsFlag) { - bool obliqueModeFlag = false; - switch (sliceProjectionType) { - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: - obliqueModeFlag = true; - break; - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: - CaretAssert(0); - break; - } + const float gapPercentViewportHeight = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); + const float gapMM = GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(gapPercentViewportHeight); + const std::array sliceCoordinates { sliceCoordinatesIn[0], sliceCoordinatesIn[1], sliceCoordinatesIn[2] }; GLboolean depthEnabled = GL_FALSE; glGetBooleanv(GL_DEPTH_TEST, &depthEnabled); glDisable(GL_DEPTH_TEST); - const float bigValue = 10000.0; - - float horizontalAxisStartXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; - float horizontalAxisEndXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; + const float bigValue = 10000.0 + gapMM; - float verticalAxisStartXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; - float verticalAxisEndXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; + std::array horizontalAxisPosStartXYZ = sliceCoordinates; float trans[3]; m_browserTabContent->getTranslation(trans); - - float horizTrans[3] = { trans[0], trans[1], trans[2] }; - float vertTrans[3] = { trans[0], trans[1], trans[2] }; - if (obliqueModeFlag) { - switch (sliceViewPlane) { - case VolumeSliceViewPlaneEnum::ALL: - break; - case VolumeSliceViewPlaneEnum::AXIAL: - break; - case VolumeSliceViewPlaneEnum::CORONAL: - horizontalAxisStartXYZ[0] = sliceCoordinates[0]; - horizontalAxisStartXYZ[1] = sliceCoordinates[2]; - horizontalAxisStartXYZ[2] = sliceCoordinates[1]; - horizontalAxisEndXYZ[0] = sliceCoordinates[0]; - horizontalAxisEndXYZ[1] = sliceCoordinates[2]; - horizontalAxisEndXYZ[2] = sliceCoordinates[1]; - - horizTrans[0] = trans[0]; - horizTrans[1] = trans[2]; - horizTrans[2] = trans[1]; - - verticalAxisStartXYZ[0] = sliceCoordinates[0]; - verticalAxisStartXYZ[1] = sliceCoordinates[1]; - verticalAxisStartXYZ[2] = sliceCoordinates[2]; - verticalAxisEndXYZ[0] = sliceCoordinates[0]; - verticalAxisEndXYZ[1] = sliceCoordinates[1]; - verticalAxisEndXYZ[2] = sliceCoordinates[2]; - - vertTrans[0] = trans[0]; - vertTrans[1] = trans[1]; - vertTrans[2] = trans[2]; - break; - case VolumeSliceViewPlaneEnum::PARASAGITTAL: - horizontalAxisStartXYZ[0] = sliceCoordinates[1]; - horizontalAxisStartXYZ[1] = sliceCoordinates[2]; - horizontalAxisStartXYZ[2] = sliceCoordinates[0]; - horizontalAxisEndXYZ[0] = sliceCoordinates[1]; - horizontalAxisEndXYZ[1] = sliceCoordinates[2]; - horizontalAxisEndXYZ[2] = sliceCoordinates[0]; - - horizTrans[0] = trans[1]; - horizTrans[1] = trans[2]; - horizTrans[2] = trans[0]; - - verticalAxisStartXYZ[0] = -sliceCoordinates[1]; - verticalAxisStartXYZ[1] = sliceCoordinates[0]; - verticalAxisStartXYZ[2] = sliceCoordinates[2]; - verticalAxisEndXYZ[0] = -sliceCoordinates[1]; - verticalAxisEndXYZ[1] = sliceCoordinates[0]; - verticalAxisEndXYZ[2] = sliceCoordinates[2]; - - vertTrans[0] = -trans[1]; - vertTrans[1] = trans[0]; - vertTrans[2] = trans[2]; - break; - } + std::array horizTrans { trans[0], trans[1], trans[2] }; + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + break; + case VolumeSliceViewPlaneEnum::AXIAL: + break; + case VolumeSliceViewPlaneEnum::CORONAL: + horizontalAxisPosStartXYZ[0] = sliceCoordinates[0]; + horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; + horizontalAxisPosStartXYZ[2] = sliceCoordinates[1]; + + horizTrans[0] = trans[0]; + horizTrans[1] = trans[2]; + horizTrans[2] = trans[1]; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + horizontalAxisPosStartXYZ[0] = -sliceCoordinates[1]; + horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; + horizontalAxisPosStartXYZ[2] = sliceCoordinates[0]; + + horizTrans[0] = -trans[1]; + horizTrans[1] = trans[2]; + horizTrans[2] = trans[0]; + break; } + std::array horizontalAxisPosEndXYZ = horizontalAxisPosStartXYZ; + std::array verticalAxisPosStartXYZ = horizontalAxisPosStartXYZ; + std::array verticalAxisPosEndXYZ = horizontalAxisPosStartXYZ; + + std::array horizontalAxisNegStartXYZ = horizontalAxisPosStartXYZ; + std::array horizontalAxisNegEndXYZ = horizontalAxisPosEndXYZ; + std::array verticalAxisNegStartXYZ = verticalAxisPosStartXYZ; + std::array verticalAxisNegEndXYZ = verticalAxisPosEndXYZ; + + std::array vertTrans = horizTrans; + float axialRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::AXIAL, axialRGBA); @@ -1562,64 +1524,52 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = coronalRGBA; - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; - + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; + verticalBottomText = "P"; verticalTopText = "A"; verticalAxisRGBA = paraRGBA; - verticalAxisStartXYZ[1] -= bigValue; - verticalAxisEndXYZ[1] += bigValue; + verticalAxisPosStartXYZ[1] += gapMM; + verticalAxisPosEndXYZ[1] += bigValue; + verticalAxisNegStartXYZ[1] -= gapMM; + verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::CORONAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = axialRGBA; - if (obliqueModeFlag) { - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; - } - else { - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; - } - + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; + verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = paraRGBA; - if (obliqueModeFlag) { - verticalAxisStartXYZ[1] -= bigValue; - verticalAxisEndXYZ[1] += bigValue; - } - else { - verticalAxisStartXYZ[2] -= bigValue; - verticalAxisEndXYZ[2] += bigValue; - } + verticalAxisPosStartXYZ[1] += gapMM; + verticalAxisPosEndXYZ[1] += bigValue; + verticalAxisNegStartXYZ[1] -= gapMM; + verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: horizontalLeftText = "A"; horizontalRightText = "P"; horizontalAxisRGBA = axialRGBA; - if (obliqueModeFlag) { - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; - } - else { - horizontalAxisStartXYZ[1] -= bigValue; - horizontalAxisEndXYZ[1] += bigValue; - } - + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; + verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = coronalRGBA; - if (obliqueModeFlag) { - verticalAxisStartXYZ[1] -= bigValue; - verticalAxisEndXYZ[1] += bigValue; - } - else { - verticalAxisStartXYZ[2] -= bigValue; - verticalAxisEndXYZ[2] += bigValue; - } + verticalAxisPosStartXYZ[1] += gapMM; + verticalAxisPosEndXYZ[1] += bigValue; + verticalAxisNegStartXYZ[1] -= gapMM; + verticalAxisNegEndXYZ[1] -= bigValue; break; } @@ -1655,8 +1605,10 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo glPushMatrix(); glTranslatef(horizTrans[0], horizTrans[1], horizTrans[2]); std::unique_ptr horizHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); - horizHairPrimitive->addVertex(horizontalAxisStartXYZ, horizontalAxisRGBA); - horizHairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); + horizHairPrimitive->addVertex(&horizontalAxisPosStartXYZ[0], horizontalAxisRGBA); + horizHairPrimitive->addVertex(&horizontalAxisPosEndXYZ[0], horizontalAxisRGBA); + horizHairPrimitive->addVertex(&horizontalAxisNegStartXYZ[0], horizontalAxisRGBA); + horizHairPrimitive->addVertex(&horizontalAxisNegEndXYZ[0], horizontalAxisRGBA); horizHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(horizHairPrimitive.get()); glPopMatrix(); @@ -1664,8 +1616,10 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo glPushMatrix(); glTranslatef(vertTrans[0], vertTrans[1], vertTrans[2]); std::unique_ptr vertHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); - vertHairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); - vertHairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); + vertHairPrimitive->addVertex(&verticalAxisPosStartXYZ[0], verticalAxisRGBA); + vertHairPrimitive->addVertex(&verticalAxisPosEndXYZ[0], verticalAxisRGBA); + vertHairPrimitive->addVertex(&verticalAxisNegStartXYZ[0], verticalAxisRGBA); + vertHairPrimitive->addVertex(&verticalAxisNegEndXYZ[0], verticalAxisRGBA); vertHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(vertHairPrimitive.get()); glPopMatrix(); @@ -1790,7 +1744,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(horizontalAxisRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); - + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setText(horizontalLeftText); @@ -1812,7 +1766,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo m_fixedPipelineDrawing->drawTextAtViewportCoords(textBottomWindowXY[0], textBottomWindowXY[1], annotationText); - + annotationText.setText(verticalTopText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); @@ -2905,6 +2859,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSliceWithOutlines(const VolumeS const DisplayPropertiesLabels* displayPropertiesLabels = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); + bool haveAlphaBlendingFlag(false); std::vector slices; for (int32_t iVol = 0; iVol < numVolumes; iVol++) { const BrainOpenGLFixedPipeline::VolumeDrawInfo& vdi = m_volumeDrawInfo[iVol]; @@ -2916,6 +2871,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSliceWithOutlines(const VolumeS volumeEditDrawAllVoxelsFlag = true; } } + + const bool bottomLayerFlag(iVol == 0); ObliqueSlice* slice = new ObliqueSlice(m_fixedPipelineDrawing, volInter, m_volumeDrawInfo[iVol].opacity, @@ -2931,16 +2888,28 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSliceWithOutlines(const VolumeS m_obliqueSliceMaskingType, voxelEditingValue, volumeEditDrawAllVoxelsFlag, - m_identificationModeFlag); + m_identificationModeFlag, + bottomLayerFlag); slices.push_back(slice); + + if (m_volumeDrawInfo[iVol].opacity < 1.0) { + haveAlphaBlendingFlag = true; + } } const int32_t numSlices = static_cast(slices.size()); if (numSlices > 0) { - bool drawAllSlicesFlag = true; - const bool compositeFlag = true; - if (compositeFlag - && ( ! m_identificationModeFlag)) { + bool drawEachSliceFlag = true; + bool compositeFlag = true; + if (haveAlphaBlendingFlag + || m_identificationModeFlag) { + /* + * Do not composite slices if blending is used + * or if in identification mode + */ + compositeFlag = false; + } + if (compositeFlag) { CaretAssertVectorIndex(slices, 0); ObliqueSlice* underlaySlice = slices[0]; if (numSlices > 1) { @@ -2951,12 +2920,12 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSliceWithOutlines(const VolumeS } if (underlaySlice->compositeSlicesRGBA(overlaySlices)) { underlaySlice->draw(m_fixedPipelineDrawing); - drawAllSlicesFlag = false; + drawEachSliceFlag = false; } } } - if (drawAllSlicesFlag) { + if (drawEachSliceFlag) { for (auto s : slices) { s->draw(m_fixedPipelineDrawing); } @@ -3005,6 +2974,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSliceWithOutlines(const VolumeS * Draw all voxels when editing a volume. * @param identificationModeFlag * True if identification mode is active. + * @param bottomLayerFlag + * True if bottom layer. */ BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::ObliqueSlice(BrainOpenGLFixedPipeline* fixedPipelineDrawing, VolumeMappableInterface* volumeInterface, @@ -3021,7 +2992,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::ObliqueSlice(BrainOpenGLFixe const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType, const float voxelEditingValue, const bool volumeEditingDrawAllVoxelsFlag, - const bool identificationModeFlag) + const bool identificationModeFlag, + const bool bottomLayerFlag) : m_volumeInterface(volumeInterface), m_opacity(opacity), @@ -3034,7 +3006,8 @@ m_displayPropertiesLabels(displayPropertiesLabels), m_displayGroup(displayGroup), m_identificationX(fixedPipelineDrawing->mouseX), m_identificationY(fixedPipelineDrawing->mouseY), -m_identificationModeFlag(identificationModeFlag) +m_identificationModeFlag(identificationModeFlag), +m_bottomLayerFlag(bottomLayerFlag) { CaretAssert(volumeInterface); CaretAssert(m_mapFile); @@ -3772,6 +3745,15 @@ BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::draw(BrainOpenGLFixedPipelin m_originXYZ[2] }; + uint8_t sliceAlpha = 255; + bool drawWithBlendingFlag(false); +// if (m_bottomLayerFlag) { + if (m_opacity < 1.0) { + sliceAlpha = static_cast(m_opacity * 255.0); + drawWithBlendingFlag = true; + } +// } + std::vector selectionIJK; for (int32_t iRow = 0; iRow < m_numberOfRows; iRow++) { float voxelXYZ[3] = { @@ -3802,7 +3784,14 @@ BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::draw(BrainOpenGLFixedPipelin nextXYZ[1] + m_bottomToTopStepXYZ[1], nextXYZ[2] + m_bottomToTopStepXYZ[2] }; - const uint8_t* rgba = &m_rgba[rgbaIndex]; + uint8_t* rgba = &m_rgba[rgbaIndex]; + if (drawWithBlendingFlag) { + if ((rgba[0] > 0) + || (rgba[1] > 0) + || (rgba[2] > 0)) { + rgba[3] = sliceAlpha; + } + } /* * Each voxel is drawn with two triangles because: @@ -3920,7 +3909,20 @@ BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::draw(BrainOpenGLFixedPipelin } } else { + /* + * Only allow layer blending when overall volume opacity is off (>= 1.0) + */ + //const DisplayPropertiesVolume* dpv = brain->getDisplayPropertiesVolume(); + const bool allowBlendingFlag(true); //dpv->getOpacity() >= 1.0f); + + glPushAttrib(GL_COLOR_BUFFER_BIT); + if (drawWithBlendingFlag + && allowBlendingFlag) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } GraphicsEngineDataOpenGL::draw(primitive.get()); + glPopAttrib(); } } } diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h index bf4075b749c156ba74099abab3d9199f2bd59d71..17b2f79b0bdf58b07c5c0e5ef8d6402c047cc5d3 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h @@ -90,7 +90,8 @@ namespace caret { const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType, const float voxelEditingValue, const bool volumeEditingDrawAllVoxelsFlag, - const bool identificationModeFlag); + const bool identificationModeFlag, + const bool bottomLayerFlag); void assignRgba(const bool volumeEditingDrawAllVoxelsFlag); @@ -134,6 +135,8 @@ namespace caret { const bool m_identificationModeFlag; + const bool m_bottomLayerFlag; + CiftiMappableDataFile* m_ciftiMappableFile = NULL; VolumeFile* m_volumeFile = NULL; @@ -219,12 +222,11 @@ namespace caret { const float sliceCoordinates[3], Plane& planeOut); - void drawAxesCrosshairsOrthoAndOblique(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const float sliceCoordinates[3], - const bool drawCrosshairsFlag, - const bool drawCrosshairLabelsFlag); - + void drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3], + const bool drawCrosshairsFlag, + const bool drawCrosshairLabelsFlag); + void setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane, diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 080c28c0ad4f4a009f80a43e03ac45d1df061da4..93bb46fc20c233bcbd8fa6f31d189e9e8241cd4d 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -38,11 +38,13 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" +#include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "CiftiMappableDataFile.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesFoci.h" #include "DisplayPropertiesLabels.h" +#include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "FociFile.h" #include "Focus.h" @@ -68,6 +70,7 @@ #include "SelectionItemVoxelIdentificationSymbol.h" #include "SelectionManager.h" #include "SessionManager.h" +#include "SpacerTabIndex.h" #include "SurfacePlaneIntersectionToContour.h" #include "Surface.h" #include "VolumeFile.h" @@ -483,13 +486,6 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewTypeMontage(const AllSliceView const int32_t montageCoordPrecision = m_browserTabContent->getVolumeMontageCoordinatePrecision(); const GapsAndMargins* gapsAndMargins = m_brain->getGapsAndMargins(); -// const int32_t horizontalMargin = static_cast(viewport[2] * gapsAndMargins->getVolumeMontageHorizontalGap()); -// const int32_t verticalMargin = static_cast(viewport[3] * gapsAndMargins->getVolumeMontageVerticalGap()); -// -// const int32_t totalGapX = horizontalMargin * (numCols - 1); -// const int32_t vpSizeX = (viewport[2] - totalGapX) / numCols; -// const int32_t totalGapY = verticalMargin * (numRows - 1); -// const int32_t vpSizeY = (viewport[3] - totalGapY) / numRows; const int32_t windowIndex = m_fixedPipelineDrawing->m_windowIndex; @@ -666,11 +662,10 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewTypeMontage(const AllSliceView if (m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed()) { - drawAxesCrosshairsOrthoAndOblique(sliceProjectionType, - sliceViewPlane, - sliceCoordinates, - false, - true); + drawAxesCrosshairsOrtho(sliceViewPlane, + sliceCoordinates, + false, + true); } } @@ -886,12 +881,15 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewProjection(const AllSliceViewM } } } + const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + SpacerTabIndex(), + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); @@ -1509,9 +1507,15 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSlice(const VolumeSliceViewPlaneEnu /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. + * + * Only allow layer blending when overall volume opacity is off (>= 1.0) */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + const bool allowBlendingFlag(true); + glPushAttrib(GL_COLOR_BUFFER_BIT); + if (allowBlendingFlag) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } /* * Flat shading voxels not interpolated @@ -1640,7 +1644,6 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSlice(const VolumeSliceViewPlaneEnu int64_t sliceVoxelIndices[3] = { 0, 0, 0 }; float sliceVoxelXYZ[3] = { 0.0, 0.0, 0.0 }; sliceVoxelXYZ[sliceViewingPlaneIndexIntoXYZ] = selectedSliceCoordinate; - //volumeFile->indexToSpace(sliceVoxelIndices, sliceVoxelXYZ); volumeFile->enclosingVoxel(sliceVoxelXYZ[0], sliceVoxelXYZ[1], sliceVoxelXYZ[2], sliceVoxelIndices[0], sliceVoxelIndices[1], sliceVoxelIndices[2]); @@ -1789,8 +1792,8 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSlice(const VolumeSliceViewPlaneEnu showBrainordinateHighlightRegionOfInterest(sliceViewingPlane, sliceCoordinates, sliceNormalVector); - - glDisable(GL_BLEND); + glPopAttrib(); + //glDisable(GL_BLEND); glShadeModel(GL_SMOOTH); } @@ -2064,13 +2067,7 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceWithCulling(const VolumeSliceV const int32_t browserTabIndex = m_browserTabContent->getTabNumber(); const DisplayPropertiesLabels* displayPropertiesLabels = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); - /* - * Enable alpha blending so voxels that are not drawn from higher layers - * allow voxels from lower layers to be seen. - */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + /* * Flat shading voxels not interpolated */ @@ -2081,6 +2078,19 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceWithCulling(const VolumeSliceV return; } + /* + * Enable alpha blending so voxels that are not drawn from higher layers + * allow voxels from lower layers to be seen. + * + * Only allow layer blending when overall volume opacity is off (>= 1.0) + */ + const bool allowBlendingFlag(true); + glPushAttrib(GL_COLOR_BUFFER_BIT); + if (allowBlendingFlag) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + /* * Compute coordinate of point in center of first slice */ @@ -2434,7 +2444,7 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceWithCulling(const VolumeSliceV sliceCoordinates, sliceNormalVector); - glDisable(GL_BLEND); + glPopAttrib(); glShadeModel(GL_SMOOTH); } @@ -2687,7 +2697,11 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { - drawSurfaceOutline(m_modelType, + drawSurfaceOutline(m_underlayVolume, + m_modelType, + sliceProjectionType, + sliceViewPlane, + sliceCoordinates, slicePlane, m_browserTabContent->getVolumeSurfaceOutlineSet(), m_fixedPipelineDrawing, @@ -2747,8 +2761,16 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum /** * Draw surface outlines on the volume slices * + * @param underlayVolume + * The underlay volume * @param modelType * Type of model being drawn. + * @param sliceProjectionType + * Projection type (oblique/orthogonal) + * @param sliceViewPlane + * Slice view plane (axial, coronal, parasagittal) + * @param sliceXYZ + * Coordinates of slices * @param plane * Plane of the volume slice on which surface outlines are drawn. * @param outlineSet @@ -2759,16 +2781,80 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum * If true, use a negative offset for polygon offset */ void -BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum modelType, +BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const VolumeMappableInterface* underlayVolume, + const ModelTypeEnum::Enum modelType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceXYZ[3], const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const bool useNegativePolygonOffsetFlag) +{ + /* + * Code still here to allow comparison with + * previous algorithm + */ + bool drawCachedFlag(true); + if (drawCachedFlag) { + drawSurfaceOutlineCached(underlayVolume, + modelType, + sliceProjectionType, + sliceViewPlane, + sliceXYZ, + plane, + outlineSet, + fixedPipelineDrawing, + useNegativePolygonOffsetFlag); + } + else { + drawSurfaceOutlineNotCached(modelType, + plane, + outlineSet, + fixedPipelineDrawing, + useNegativePolygonOffsetFlag); + } +} + +/** + * Draw surface outlines on the volume slices + * + * @param underlayVolume + * The underlay volume + * @param modelType + * Type of model being drawn. + * @param sliceProjectionType + Type of slice projection + * @param sliceProjectionType + * Type of slice projection + * @param sliceViewPlane + * Slice view plane (axial, coronal, parasagittal) + * @param sliceXYZ + * Coordinates of slices + * @param plane + * Plane of the volume slice on which surface outlines are drawn. + * @param outlineSet + * The surface outline set. + * @param fixedPipelineDrawing + * The fixed pipeline drawing. + * @param useNegativePolygonOffsetFlag + * If true, use a negative offset for polygon offset + */ +void +BrainOpenGLVolumeSliceDrawing::drawSurfaceOutlineCached(const VolumeMappableInterface* underlayVolume, + const ModelTypeEnum::Enum modelType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceXYZ[3], + const Plane& plane, + VolumeSurfaceOutlineSetModel* outlineSet, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + const bool useNegativePolygonOffsetFlag) { glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - + switch (modelType) { case ModelTypeEnum::MODEL_TYPE_CHART: break; @@ -2792,7 +2878,184 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum mode glEnable(GL_DEPTH_TEST); break; } + + float sliceCoordinate(0.0); + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + break; + case VolumeSliceViewPlaneEnum::AXIAL: + sliceCoordinate = sliceXYZ[2]; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + sliceCoordinate = sliceXYZ[1]; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + sliceCoordinate = sliceXYZ[0]; + break; + } + + /* + * Key for outline cache + */ + VolumeSurfaceOutlineModelCacheKey outlineCacheKey(underlayVolume, + sliceViewPlane, + sliceCoordinate); + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + outlineCacheKey = VolumeSurfaceOutlineModelCacheKey(underlayVolume, + plane); + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + break; + } + + /* + * Process each surface outline + * As of 24 May, "zero" is on top so draw in reverse order + */ + const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); + for (int32_t io = (numberOfOutlines - 1); + io >= 0; + io--) { + std::vector contourPrimitives; + + VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); + if (outline->isDisplayed()) { + Surface* surface = outline->getSurface(); + if (surface != NULL) { + float thicknessPercentage = outline->getThicknessPercentageViewportHeight(); + const float thicknessPixels = outline->getThicknessPixelsObsolete(); + + /* + * Thickness was changed from pixels to percentage viewport height on Feb 02, 2018 + * If thickness percentage is negative, it was not present in an old + * scene so convert pixels to percentage using viewports dimensions + */ + if (thicknessPercentage < 0.0f) { + thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessPixels); + if (thicknessPercentage > 0.0f) { + outline->setThicknessPercentageViewportHeight(thicknessPercentage); + } + } + + if (outline->getOutlineCachePrimitives(underlayVolume, + outlineCacheKey, + contourPrimitives)) { + /* OK, have cached primitives to draw */ + } + else { + CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; + int32_t colorSourceBrowserTabIndex = -1; + + VolumeSurfaceOutlineColorOrTabModel* colorOrTabModel = outline->getColorOrTabModel(); + VolumeSurfaceOutlineColorOrTabModel::Item* selectedColorOrTabItem = colorOrTabModel->getSelectedItem(); + switch (selectedColorOrTabItem->getItemType()) { + case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: + colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); + outlineColor = CaretColorEnum::CUSTOM; + break; + case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: + outlineColor = selectedColorOrTabItem->getColor(); + break; + } + const bool surfaceColorFlag = (colorSourceBrowserTabIndex >= 0); + + float* nodeColoringRGBA = NULL; + if (surfaceColorFlag) { + nodeColoringRGBA = fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, + surface, + colorSourceBrowserTabIndex); + } + + SurfacePlaneIntersectionToContour contour(surface, + plane, + outlineColor, + nodeColoringRGBA, + thicknessPercentage); + AString errorMessage; + if ( ! contour.createContours(contourPrimitives, + errorMessage)) { + CaretLogSevere(errorMessage); + } + + outline->setOutlineCachePrimitives(underlayVolume, + outlineCacheKey, + contourPrimitives); + } + } + } + + /** + * Draw the contours. + * Note: The primitives are now cached so DO NOT delete them. + */ + for (auto primitive : contourPrimitives) { + if (useNegativePolygonOffsetFlag) { + glPolygonOffset(-1.0, -1.0); + } + else { + glPolygonOffset(1.0, 1.0); + } + glEnable(GL_POLYGON_OFFSET_FILL); + + GraphicsEngineDataOpenGL::draw(primitive); + + glDisable(GL_POLYGON_OFFSET_FILL); + } + } + + glPopAttrib(); +} +/** + * Draw surface outlines on the volume slices WITHOUT caching + * + * @param modelType + * Type of model being drawn. + * @param plane + * Plane of the volume slice on which surface outlines are drawn. + * @param outlineSet + * The surface outline set. + * @param fixedPipelineDrawing + * The fixed pipeline drawing. + * @param useNegativePolygonOffsetFlag + * If true, use a negative offset for polygon offset + */ +void +BrainOpenGLVolumeSliceDrawing::drawSurfaceOutlineNotCached(const ModelTypeEnum::Enum modelType, + const Plane& plane, + VolumeSurfaceOutlineSetModel* outlineSet, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + const bool useNegativePolygonOffsetFlag) +{ + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + + switch (modelType) { + case ModelTypeEnum::MODEL_TYPE_CHART: + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + /* + * Enable depth so outlines in front or in back + * of the slices. Without this the volume surface + * outlines "behind" the slices are visible and + * it looks weird + */ + glEnable(GL_DEPTH_TEST); + break; + } + /* * Process each surface outline * As of 24 May, "zero" is on top so draw in reverse order @@ -2818,7 +3081,6 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum mode if (thicknessPercentage < 0.0f) { thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessPixels); if (thicknessPercentage > 0.0f) { - //std::cout << "Converted pixel thickness=" << thicknessPixels << " to millimeters=" << thicknessMillimeters << std::endl; outline->setThicknessPercentageViewportHeight(thicknessPercentage); } } @@ -2842,8 +3104,8 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum mode float* nodeColoringRGBA = NULL; if (surfaceColorFlag) { nodeColoringRGBA = fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, - surface, - colorSourceBrowserTabIndex); + surface, + colorSourceBrowserTabIndex); } //const float thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessMillimeters); @@ -2881,7 +3143,8 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum mode glPopAttrib(); } - + + /** * Draw foci on volume slice. * @@ -3128,11 +3391,10 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTyp } switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: - drawAxesCrosshairsOrthoAndOblique(sliceProjectionType, - sliceViewPlane, - sliceCoordinates, - drawCrosshairsFlag, - drawCrosshairLabelsFlag); + drawAxesCrosshairsOrtho(sliceViewPlane, + sliceCoordinates, + drawCrosshairsFlag, + drawCrosshairLabelsFlag); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { @@ -3147,11 +3409,10 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTyp float trans[3]; m_browserTabContent->getTranslation(trans); glTranslatef(trans[0], trans[1], trans[2]); - drawAxesCrosshairsOrthoAndOblique(sliceProjectionType, - sliceViewPlane, - sliceCoordinates, - drawCrosshairsFlag, - drawCrosshairLabelsFlag); + drawAxesCrosshairsOrtho(sliceViewPlane, + sliceCoordinates, + drawCrosshairsFlag, + drawCrosshairLabelsFlag); glPopMatrix(); } break; @@ -3161,11 +3422,9 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTyp /** * Draw the axes crosshairs for an orthogonal slice. * - * @param sliceProjectionType - * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The slice plane view. - * @param sliceCoordinates + * @param sliceCoordinatesIn * Coordinates of the selected slices. * @param drawCrosshairsFlag * If true, draw the crosshairs. @@ -3173,89 +3432,33 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTyp * If true, draw the crosshair labels. */ void -BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const float sliceCoordinates[3], - const bool drawCrosshairsFlag, - const bool drawCrosshairLabelsFlag) +BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrtho(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinatesIn[3], + const bool drawCrosshairsFlag, + const bool drawCrosshairLabelsFlag) { - bool obliqueModeFlag = false; - switch (sliceProjectionType) { - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: - obliqueModeFlag = true; - break; - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: - break; - } + const float gapPercentViewportHeight = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); + const float gapMM = GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(gapPercentViewportHeight); + std::array sliceCoordinates { sliceCoordinatesIn[0], sliceCoordinatesIn[1], sliceCoordinatesIn[2] }; + GLboolean depthEnabled = GL_FALSE; glGetBooleanv(GL_DEPTH_TEST, &depthEnabled); glDisable(GL_DEPTH_TEST); - const float bigValue = 10000.0; - - float horizontalAxisStartXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; - float horizontalAxisEndXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; + const float bigValue = 10000.0 + gapMM; - float verticalAxisStartXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; - float verticalAxisEndXYZ[3] = { - sliceCoordinates[0], - sliceCoordinates[1], - sliceCoordinates[2] - }; - - if (obliqueModeFlag) { - switch (sliceViewPlane) { - case VolumeSliceViewPlaneEnum::ALL: - break; - case VolumeSliceViewPlaneEnum::AXIAL: - break; - case VolumeSliceViewPlaneEnum::CORONAL: - horizontalAxisStartXYZ[0] = sliceCoordinates[0]; - horizontalAxisStartXYZ[1] = sliceCoordinates[2]; - horizontalAxisStartXYZ[2] = sliceCoordinates[1]; - horizontalAxisEndXYZ[0] = sliceCoordinates[0]; - horizontalAxisEndXYZ[1] = sliceCoordinates[2]; - horizontalAxisEndXYZ[2] = sliceCoordinates[1]; - - verticalAxisStartXYZ[0] = sliceCoordinates[0]; - verticalAxisStartXYZ[1] = sliceCoordinates[1]; - verticalAxisStartXYZ[2] = sliceCoordinates[2]; - verticalAxisEndXYZ[0] = sliceCoordinates[0]; - verticalAxisEndXYZ[1] = sliceCoordinates[1]; - verticalAxisEndXYZ[2] = sliceCoordinates[2]; - break; - case VolumeSliceViewPlaneEnum::PARASAGITTAL: - horizontalAxisStartXYZ[0] = sliceCoordinates[1]; - horizontalAxisStartXYZ[1] = sliceCoordinates[2]; - horizontalAxisStartXYZ[2] = sliceCoordinates[0]; - horizontalAxisEndXYZ[0] = sliceCoordinates[1]; - horizontalAxisEndXYZ[1] = sliceCoordinates[2]; - horizontalAxisEndXYZ[2] = sliceCoordinates[0]; - - verticalAxisStartXYZ[0] = -sliceCoordinates[1]; - verticalAxisStartXYZ[1] = sliceCoordinates[0]; - verticalAxisStartXYZ[2] = sliceCoordinates[2]; - verticalAxisEndXYZ[0] = -sliceCoordinates[1]; - verticalAxisEndXYZ[1] = sliceCoordinates[0]; - verticalAxisEndXYZ[2] = sliceCoordinates[2]; - break; - } - } + std::array horizontalAxisPosStartXYZ = sliceCoordinates; + std::array horizontalAxisPosEndXYZ = sliceCoordinates; + std::array verticalAxisPosStartXYZ = sliceCoordinates; + std::array verticalAxisPosEndXYZ = sliceCoordinates; + std::array horizontalAxisNegStartXYZ = horizontalAxisPosStartXYZ; + std::array horizontalAxisNegEndXYZ = horizontalAxisPosEndXYZ; + std::array verticalAxisNegStartXYZ = verticalAxisPosStartXYZ; + std::array verticalAxisNegEndXYZ = verticalAxisPosEndXYZ; + float axialRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::AXIAL, axialRGBA); @@ -3283,64 +3486,52 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = coronalRGBA; - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "P"; verticalTopText = "A"; verticalAxisRGBA = paraRGBA; - verticalAxisStartXYZ[1] -= bigValue; - verticalAxisEndXYZ[1] += bigValue; + verticalAxisPosStartXYZ[1] += gapMM; + verticalAxisPosEndXYZ[1] += bigValue; + verticalAxisNegStartXYZ[1] -= gapMM; + verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::CORONAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = axialRGBA; - if (obliqueModeFlag) { - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; - } - else { - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; - } - + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; + verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = paraRGBA; - if (obliqueModeFlag) { - verticalAxisStartXYZ[1] -= bigValue; - verticalAxisEndXYZ[1] += bigValue; - } - else { - verticalAxisStartXYZ[2] -= bigValue; - verticalAxisEndXYZ[2] += bigValue; - } + verticalAxisPosStartXYZ[2] += gapMM; + verticalAxisPosEndXYZ[2] += bigValue; + verticalAxisNegStartXYZ[2] -= gapMM; + verticalAxisNegEndXYZ[2] -= bigValue; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: horizontalLeftText = "A"; horizontalRightText = "P"; horizontalAxisRGBA = axialRGBA; - if (obliqueModeFlag) { - horizontalAxisStartXYZ[0] -= bigValue; - horizontalAxisEndXYZ[0] += bigValue; - } - else { - horizontalAxisStartXYZ[1] -= bigValue; - horizontalAxisEndXYZ[1] += bigValue; - } + horizontalAxisPosStartXYZ[1] += gapMM; + horizontalAxisPosEndXYZ[1] += bigValue; + horizontalAxisNegStartXYZ[1] -= gapMM; + horizontalAxisNegEndXYZ[1] -= bigValue; verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = coronalRGBA; - if (obliqueModeFlag) { - verticalAxisStartXYZ[1] -= bigValue; - verticalAxisEndXYZ[1] += bigValue; - } - else { - verticalAxisStartXYZ[2] -= bigValue; - verticalAxisEndXYZ[2] += bigValue; - } + verticalAxisPosStartXYZ[2] += gapMM; + verticalAxisPosEndXYZ[2] += bigValue; + verticalAxisNegStartXYZ[2] -= gapMM; + verticalAxisNegEndXYZ[2] -= bigValue; break; } @@ -3374,11 +3565,17 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli */ if (drawCrosshairsFlag) { std::unique_ptr xhairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); - xhairPrimitive->addVertex(horizontalAxisStartXYZ, horizontalAxisRGBA); - xhairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); - xhairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); - xhairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); + xhairPrimitive->addVertex(&horizontalAxisPosStartXYZ[0], horizontalAxisRGBA); + xhairPrimitive->addVertex(&horizontalAxisPosEndXYZ[0], horizontalAxisRGBA); + xhairPrimitive->addVertex(&horizontalAxisNegStartXYZ[0], horizontalAxisRGBA); + xhairPrimitive->addVertex(&horizontalAxisNegEndXYZ[0], horizontalAxisRGBA); + + xhairPrimitive->addVertex(&verticalAxisPosStartXYZ[0], verticalAxisRGBA); + xhairPrimitive->addVertex(&verticalAxisPosEndXYZ[0], verticalAxisRGBA); + xhairPrimitive->addVertex(&verticalAxisNegStartXYZ[0], verticalAxisRGBA); + xhairPrimitive->addVertex(&verticalAxisNegEndXYZ[0], verticalAxisRGBA); xhairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); + GraphicsEngineDataOpenGL::draw(xhairPrimitive.get()); } @@ -3397,7 +3594,7 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(horizontalAxisRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); - + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setText(horizontalLeftText); @@ -3413,7 +3610,7 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli annotationText); annotationText.setCustomTextColor(verticalAxisRGBA); - + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setText(verticalBottomText); @@ -3789,6 +3986,9 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceVoxels(const float sliceNormal drawWithQuadIndicesFlag = true; } + GLboolean blendOn = GL_FALSE; + glGetBooleanv(GL_BLEND, &blendOn); + if (drawWithQuadIndicesFlag) { drawOrthogonalSliceVoxelsQuadIndicesAndStrips(sliceNormalVector, coordinate, @@ -3815,7 +4015,8 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceVoxels(const float sliceNormal mapIndex, sliceOpacity); } - + glGetBooleanv(GL_BLEND, &blendOn); + } /** @@ -5351,9 +5552,15 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceAllView(const VolumeSliceViewP /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. + * + * Only allow layer blending when overall volume opacity is off (>= 1.0) */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + const bool allowBlendingFlag(true); + glPushAttrib(GL_COLOR_BUFFER_BIT); + if (allowBlendingFlag) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } /* * Flat shading voxels not interpolated @@ -5681,7 +5888,8 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceAllView(const VolumeSliceViewP sliceCoordinates, sliceNormalVector); - glDisable(GL_BLEND); +// glDisable(GL_BLEND); + glPopAttrib(); glShadeModel(GL_SMOOTH); } diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.h b/src/Brain/BrainOpenGLVolumeSliceDrawing.h index 5fbdf9d0494d36e085b7bb82b572beba9bd89df4..73afc88443feef9dc9e5f8c5a3f609a1fe1c2396 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.h @@ -46,6 +46,15 @@ namespace caret { class BrainOpenGLVolumeSliceDrawing : public CaretObject { public: + /** + * Indicates drawing volume sclice "ALL that shows + * axial, coronal, and parasagittal at same time + */ + enum class AllSliceViewMode { + ALL_YES, + ALL_NO + }; + BrainOpenGLVolumeSliceDrawing(); virtual ~BrainOpenGLVolumeSliceDrawing(); @@ -57,18 +66,26 @@ namespace caret { const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]); + static void setOrthographicProjection(const AllSliceViewMode allSliceViewMode, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const BoundingBox& boundingBox, + const float zoomFactor, + const int viewport[4], + double orthographicBoundsOut[6]); + + static void drawSurfaceOutline(const VolumeMappableInterface* underlayVolume, + const ModelTypeEnum::Enum modelType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceXYZ[3], + const Plane& plane, + VolumeSurfaceOutlineSetModel* outlineSet, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + const bool useNegativePolygonOffsetFlag); + // ADD_NEW_METHODS_HERE private: - /** - * Indicates drawing volume sclice "ALL that shows - * axial, coronal, and parasagittal at same time - */ - enum class AllSliceViewMode { - ALL_YES, - ALL_NO - }; - /** * Holds values in the slice for a volume so that they * can be colored all at once which is more efficient than @@ -232,12 +249,11 @@ namespace caret { const float sliceCoordinates[3], Plane& planeOut); - void drawAxesCrosshairsOrthoAndOblique(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const float sliceCoordinates[3], - const bool drawCrosshairsFlag, - const bool drawCrosshairLabelsFlag); - + void drawAxesCrosshairsOrtho(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3], + const bool drawCrosshairsFlag, + const bool drawCrosshairLabelsFlag); + void setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane); @@ -251,12 +267,22 @@ namespace caret { const Plane& slicePlane, const float sliceCoordinates[3]); - static void drawSurfaceOutline(const ModelTypeEnum::Enum modelType, - const Plane& plane, - VolumeSurfaceOutlineSetModel* outlineSet, - BrainOpenGLFixedPipeline* fixedPipelineDrawing, - const bool useNegativePolygonOffsetFlag); - + static void drawSurfaceOutlineCached(const VolumeMappableInterface* underlayVolume, + const ModelTypeEnum::Enum modelType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceXYZ[3], + const Plane& plane, + VolumeSurfaceOutlineSetModel* outlineSet, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + const bool useNegativePolygonOffsetFlag); + + static void drawSurfaceOutlineNotCached(const ModelTypeEnum::Enum modelType, + const Plane& plane, + VolumeSurfaceOutlineSetModel* outlineSet, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + const bool useNegativePolygonOffsetFlag); + void drawVolumeSliceFoci(const Plane& plane); void drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, @@ -274,13 +300,6 @@ namespace caret { const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int viewport[4]); - static void setOrthographicProjection(const AllSliceViewMode allSliceViewMode, - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const BoundingBox& boundingBox, - const float zoomFactor, - const int viewport[4], - double orthographicBoundsOut[6]); - void drawOrthogonalSliceVoxels(const float sliceNormalVector[3], const float coordinate[3], const float rowStep[3], @@ -380,8 +399,6 @@ namespace caret { static const int32_t IDENTIFICATION_INDICES_PER_VOXEL; - friend class BrainOpenGLVolumeObliqueSliceDrawing; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx new file mode 100644 index 0000000000000000000000000000000000000000..89c1444a2ed3b16902ff807ae084b2a2a6851ca9 --- /dev/null +++ b/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx @@ -0,0 +1,3596 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include +#include +#include + +#define __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ +#include "BrainOpenGLVolumeTextureSliceDrawing.h" +#undef __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ + +#include "AnnotationCoordinate.h" +#include "AnnotationPercentSizeText.h" +#include "BoundingBox.h" +#include "Brain.h" +#include "BrainOpenGLAnnotationDrawingFixedPipeline.h" +#include "BrainOpenGLPrimitiveDrawing.h" +#include "BrainOpenGLViewportContent.h" +#include "BrainOpenGLVolumeSliceDrawing.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "CaretOpenGLInclude.h" +#include "CaretPreferenceDataValue.h" +#include "CaretPreferences.h" +#include "CiftiMappableDataFile.h" +#include "DeveloperFlagsEnum.h" +#include "DisplayPropertiesFoci.h" +#include "DisplayPropertiesLabels.h" +#include "DisplayPropertiesVolume.h" +#include "ElapsedTimer.h" +#include "FociFile.h" +#include "Focus.h" +#include "GapsAndMargins.h" +#include "GiftiLabel.h" +#include "GiftiLabelTable.h" +#include "GroupAndNameHierarchyModel.h" +#include "GraphicsEngineDataOpenGL.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fC4ub.h" +#include "GraphicsUtilitiesOpenGL.h" +#include "IdentificationWithColor.h" +#include "LabelDrawingProperties.h" +#include "MathFunctions.h" +#include "Matrix4x4.h" +#include "ModelVolume.h" +#include "ModelWholeBrain.h" +#include "NodeAndVoxelColoring.h" +#include "SelectionItemFocusVolume.h" +#include "SelectionItemVoxel.h" +#include "SelectionItemVoxelEditing.h" +#include "SelectionManager.h" +#include "SessionManager.h" +#include "SpacerTabIndex.h" +#include "Surface.h" +#include "SurfacePlaneIntersectionToContour.h" +#include "VolumeFile.h" +#include "VolumeSurfaceOutlineColorOrTabModel.h" +#include "VolumeSurfaceOutlineModel.h" +#include "VolumeSurfaceOutlineSetModel.h" + +using namespace caret; + +static const bool debugFlag = false; + +/** + * \class caret::BrainOpenGLVolumeTextureSliceDrawing + * \brief Draws volume slices using OpenGL + * \ingroup Brain + */ + +/** + * Constructor. + */ +BrainOpenGLVolumeTextureSliceDrawing::BrainOpenGLVolumeTextureSliceDrawing() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +BrainOpenGLVolumeTextureSliceDrawing::~BrainOpenGLVolumeTextureSliceDrawing() +{ +} + +/** + * Draw Volume Slices or slices for ALL Stuctures View. + * + * @param fixedPipelineDrawing + * The OpenGL drawing. + * @param browserTabContent + * Content of browser tab that is to be drawn. + * @param volumeDrawInfo + * Info on each volume layers for drawing. + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param obliqueSliceMaskingType + * Masking for oblique slice drawing + * @param viewport + * The viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, + BrowserTabContent* browserTabContent, + std::vector& volumeDrawInfo, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, + const int32_t viewport[4]) +{ +// CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); + + if (volumeDrawInfo.empty()) { + return; + } + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + drawPrivate(fixedPipelineDrawing, + browserTabContent, + volumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueSliceMaskingType, + viewport); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + +/** + * Draw Volume Slices or slices for ALL Stuctures View. + * + * @param fixedPipelineDrawing + * The OpenGL drawing. + * @param browserTabContent + * Content of browser tab that is to be drawn. + * @param volumeDrawInfo + * Info on each volume layers for drawing. + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param obliqueSliceMaskingType + * Masking for oblique slice drawing + * @param viewport + * The viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawPrivate(BrainOpenGLFixedPipeline* fixedPipelineDrawing, + BrowserTabContent* browserTabContent, + std::vector& volumeDrawInfo, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, + const int32_t viewport[4]) +{ + // CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); + + if (volumeDrawInfo.empty()) { + return; + } + CaretAssert(fixedPipelineDrawing); + CaretAssert(browserTabContent); + m_browserTabContent = browserTabContent; + m_fixedPipelineDrawing = fixedPipelineDrawing; + m_obliqueSliceMaskingType = obliqueSliceMaskingType; + /* + * No lighting for drawing slices + */ + m_fixedPipelineDrawing->disableLighting(); + + /* + * Initialize class members which help reduce the number of + * parameters that are passed to methods. + */ + m_brain = NULL; + m_modelVolume = NULL; + m_modelWholeBrain = NULL; + m_modelType = ModelTypeEnum::MODEL_TYPE_INVALID; + if (m_browserTabContent->getDisplayedVolumeModel() != NULL) { + m_modelVolume = m_browserTabContent->getDisplayedVolumeModel(); + m_brain = m_modelVolume->getBrain(); + m_modelType = m_modelVolume->getModelType(); + } + else if (m_browserTabContent->getDisplayedWholeBrainModel() != NULL) { + m_modelWholeBrain = m_browserTabContent->getDisplayedWholeBrainModel(); + m_brain = m_modelWholeBrain->getBrain(); + m_modelType = m_modelWholeBrain->getModelType(); + } + else { + CaretAssertMessage(0, "Invalid model for volume slice drawing."); + } + CaretAssert(m_brain); + CaretAssert(m_modelType != ModelTypeEnum::MODEL_TYPE_INVALID); + + m_volumeDrawInfo = volumeDrawInfo; + if (m_volumeDrawInfo.empty()) { + return; + } + m_underlayVolume = m_volumeDrawInfo[0].volumeFile; + + const DisplayPropertiesLabels* dsl = m_brain->getDisplayPropertiesLabels(); + m_displayGroup = dsl->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); + + m_tabIndex = m_browserTabContent->getTabNumber(); + + /* + * Cifti files are slow at getting individual voxels since they + * provide no access to individual voxels. The reason is that + * the data may be on a server (Dense data) and accessing a single + * voxel would require requesting the entire map. So, for + * each Cifti file, get the enter map. This also, eliminate multiple + * requests for the same map when drawing an ALL view. + */ + const int32_t numVolumes = static_cast(m_volumeDrawInfo.size()); + for (int32_t i = 0; i < numVolumes; i++) { + std::vector ciftiMapData; + m_ciftiMappableFileData.push_back(ciftiMapData); + + const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(m_volumeDrawInfo[i].volumeFile); + if (ciftiMapFile != NULL) { + ciftiMapFile->getMapData(m_volumeDrawInfo[i].mapIndex, + m_ciftiMappableFileData[i]); + } + } + + if (browserTabContent->getDisplayedVolumeModel() != NULL) { + drawVolumeSliceViewPlane(sliceDrawingType, + sliceProjectionType, + browserTabContent->getSliceViewPlane(), + browserTabContent->getSlicePlanesAllViewLayout(), + viewport); + } + else if (browserTabContent->getDisplayedWholeBrainModel() != NULL) { + drawVolumeSlicesForAllStructuresView(sliceProjectionType, + viewport); + } +} + +/** + * Draw volume view slices for the given view plane. + * + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceViewPlane + * The plane for slice drawing. + * @param allPlanesLayout + * The layout in ALL slices view. + * @param viewport + * The viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + const int32_t viewport[4]) +{ + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + { + int32_t paraVP[4] = { 0, 0, 0, 0 }; + int32_t coronalVP[4] = { 0, 0, 0, 0 }; + int32_t axialVP[4] = { 0, 0, 0, 0 }; + + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::PARASAGITTAL, + allPlanesLayout, + paraVP); + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::CORONAL, + allPlanesLayout, + coronalVP); + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::AXIAL, + allPlanesLayout, + axialVP); + + /* + * Draw parasagittal slice + */ + glPushMatrix(); + drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, + sliceDrawingType, + sliceProjectionType, + VolumeSliceViewPlaneEnum::PARASAGITTAL, + paraVP); + glPopMatrix(); + + + /* + * Draw coronal slice + */ + glPushMatrix(); + drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, + sliceDrawingType, + sliceProjectionType, + VolumeSliceViewPlaneEnum::CORONAL, + coronalVP); + glPopMatrix(); + + + /* + * Draw axial slice + */ + glPushMatrix(); + drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, + sliceDrawingType, + sliceProjectionType, + VolumeSliceViewPlaneEnum::AXIAL, + axialVP); + glPopMatrix(); + + if (allPlanesLayout == VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT) { + /* + * 4th quadrant is used for axis showing orientation + */ + int32_t allVP[4] = { 0, 0, 0, 0 }; + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::ALL, + allPlanesLayout, + allVP); + + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + drawOrientationAxes(allVP); + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + break; + } + } + } + break; + case VolumeSliceViewPlaneEnum::AXIAL: + case VolumeSliceViewPlaneEnum::CORONAL: + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, + sliceDrawingType, + sliceProjectionType, + sliceViewPlane, + viewport); + break; + } +} + +/** + * Draw slices for the all structures view. + * + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param viewport + * The viewport. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const int32_t viewport[4]) +{ + m_orthographicBounds[0] = m_fixedPipelineDrawing->orthographicLeft; + m_orthographicBounds[1] = m_fixedPipelineDrawing->orthographicRight; + m_orthographicBounds[2] = m_fixedPipelineDrawing->orthographicBottom; + m_orthographicBounds[3] = m_fixedPipelineDrawing->orthographicTop; + m_orthographicBounds[4] = m_fixedPipelineDrawing->orthographicNear; + m_orthographicBounds[5] = m_fixedPipelineDrawing->orthographicFar; + + /* + * Enlarge the region + */ + { + const float left = m_fixedPipelineDrawing->orthographicLeft; + const float right = m_fixedPipelineDrawing->orthographicRight; + const float bottom = m_fixedPipelineDrawing->orthographicBottom; + const float top = m_fixedPipelineDrawing->orthographicTop; + + const float scale = 2.0; + + const float centerX = (left + right) / 2.0; + const float dx = (right - left) / 2.0; + const float newLeft = centerX - (dx * scale); + const float newRight = centerX + (dx * scale); + + const float centerY = (bottom + top) / 2.0; + const float dy = (top - bottom) / 2.0; + const float newBottom = centerY - (dy * scale); + const float newTop = centerY + (dy * scale); + + m_orthographicBounds[0] = newLeft; + m_orthographicBounds[1] = newRight; + m_orthographicBounds[2] = newBottom; + m_orthographicBounds[3] = newTop; + } + + const float sliceCoordinates[3] = { + m_browserTabContent->getSliceCoordinateParasagittal(), + m_browserTabContent->getSliceCoordinateCoronal(), + m_browserTabContent->getSliceCoordinateAxial() + }; + + if (m_browserTabContent->isSliceAxialEnabled()) { + glPushMatrix(); + drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, + VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, + sliceProjectionType, + VolumeSliceViewPlaneEnum::AXIAL, + sliceCoordinates, + viewport); + glPopMatrix(); + } + + if (m_browserTabContent->isSliceCoronalEnabled()) { + glPushMatrix(); + drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, + VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, + sliceProjectionType, + VolumeSliceViewPlaneEnum::CORONAL, + sliceCoordinates, + viewport); + glPopMatrix(); + } + + if (m_browserTabContent->isSliceParasagittalEnabled()) { + glPushMatrix(); + drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, + VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, + sliceProjectionType, + VolumeSliceViewPlaneEnum::PARASAGITTAL, + sliceCoordinates, + viewport); + glPopMatrix(); + } +} + +/** + * Draw single or montage volume view slices. + * + * @param allSliceViewMode + * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceViewPlane + * The plane for slice drawing. + * @param viewport + * The viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewType(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const int32_t viewport[4]) +{ + switch (sliceDrawingType) { + case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: + drawVolumeSliceViewTypeMontage(allSliceViewMode, + sliceDrawingType, + sliceProjectionType, + sliceViewPlane, + viewport); + break; + case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: + { + const float sliceCoordinates[3] = { + m_browserTabContent->getSliceCoordinateParasagittal(), + m_browserTabContent->getSliceCoordinateCoronal(), + m_browserTabContent->getSliceCoordinateAxial() + }; + drawVolumeSliceViewProjection(allSliceViewMode, + sliceDrawingType, + sliceProjectionType, + sliceViewPlane, + sliceCoordinates, + viewport); + } + break; + } + +} + +/** + * Draw montage slices. + * + * @param allSliceViewMode + * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceViewPlane + * The plane for slice drawing. + * @param viewport + * The viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewTypeMontage(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const int32_t viewport[4]) +{ + const int32_t numRows = m_browserTabContent->getMontageNumberOfRows(); + CaretAssert(numRows > 0); + const int32_t numCols = m_browserTabContent->getMontageNumberOfColumns(); + CaretAssert(numCols > 0); + + const int32_t montageCoordPrecision = m_browserTabContent->getVolumeMontageCoordinatePrecision(); + + const GapsAndMargins* gapsAndMargins = m_brain->getGapsAndMargins(); + + const int32_t windowIndex = m_fixedPipelineDrawing->m_windowIndex; + + int32_t vpSizeY = 0; + int32_t verticalMargin = 0; + BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[3], + gapsAndMargins->getVolumeMontageVerticalGapForWindow(windowIndex), + -1, + numRows, + vpSizeY, + verticalMargin); + + int32_t vpSizeX = 0; + int32_t horizontalMargin = 0; + BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[2], + gapsAndMargins->getVolumeMontageHorizontalGapForWindow(windowIndex), + -1, + numCols, + vpSizeX, + horizontalMargin); + + /* + * Voxel sizes for underlay volume + */ + float originX, originY, originZ; + float x1, y1, z1; + m_underlayVolume->indexToSpace(0, 0, 0, originX, originY, originZ); + m_underlayVolume->indexToSpace(1, 1, 1, x1, y1, z1); + float sliceThickness = 0.0; + float sliceOrigin = 0.0; + + AString axisLetter = ""; + + float sliceCoordinates[3] = { + m_browserTabContent->getSliceCoordinateParasagittal(), + m_browserTabContent->getSliceCoordinateCoronal(), + m_browserTabContent->getSliceCoordinateAxial() + }; + + int32_t sliceIndex = -1; + int32_t maximumSliceIndex = -1; + int64_t dimI, dimJ, dimK, numMaps, numComponents; + m_underlayVolume->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); + const int32_t sliceStep = m_browserTabContent->getMontageSliceSpacing(); + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + sliceIndex = -1; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + sliceIndex = m_browserTabContent->getSliceIndexAxial(m_underlayVolume); + maximumSliceIndex = dimK; + sliceThickness = z1 - originZ; + sliceOrigin = originZ; + axisLetter = "Z"; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + sliceIndex = m_browserTabContent->getSliceIndexCoronal(m_underlayVolume); + maximumSliceIndex = dimJ; + sliceThickness = y1 - originY; + sliceOrigin = originY; + axisLetter = "Y"; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + sliceIndex = m_browserTabContent->getSliceIndexParasagittal(m_underlayVolume); + maximumSliceIndex = dimI; + sliceThickness = x1 - originX; + sliceOrigin = originX; + axisLetter = "X"; + break; + } + + /* + * Foreground color for slice coordinate text + */ + const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + uint8_t foregroundRGBA[4]; + prefs->getBackgroundAndForegroundColors()->getColorForegroundVolumeView(foregroundRGBA); + foregroundRGBA[3] = 255; + uint8_t backgroundRGBA[4]; + prefs->getBackgroundAndForegroundColors()->getColorBackgroundVolumeView(backgroundRGBA); + backgroundRGBA[3] = 255; + const bool showCoordinates = m_browserTabContent->isVolumeMontageAxesCoordinatesDisplayed(); + + /* + * Determine a slice offset to selected slices is in + * the center of the montage + */ + const int32_t numSlicesViewed = (numCols * numRows); + const int32_t sliceOffset = ((numSlicesViewed / 2) + * sliceStep); + + sliceIndex += sliceOffset; + + /* + * Find first valid slice for montage + */ + while (sliceIndex >= 0) { + if (sliceIndex < maximumSliceIndex) { + break; + } + sliceIndex -= sliceStep; + } + + if (sliceIndex >= 0) { + for (int32_t i = 0; i < numRows; i++) { + for (int32_t j = 0; j < numCols; j++) { + if ((sliceIndex >= 0) + && (sliceIndex < maximumSliceIndex)) { + const int32_t vpX = (j * (vpSizeX + horizontalMargin)); + const int32_t vpY = ((numRows - i - 1) * (vpSizeY + verticalMargin)); + int32_t vp[4] = { + viewport[0] + vpX, + viewport[1] + vpY, + vpSizeX, + vpSizeY + }; + + if ((vp[2] <= 0) + || (vp[3] <= 0)) { + continue; + } + + const float sliceCoord = (sliceOrigin + + sliceThickness * sliceIndex); + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + break; + case VolumeSliceViewPlaneEnum::AXIAL: + sliceCoordinates[2] = sliceCoord; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + sliceCoordinates[1] = sliceCoord; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + sliceCoordinates[0] = sliceCoord; + break; + } + + drawVolumeSliceViewProjection(allSliceViewMode, + sliceDrawingType, + sliceProjectionType, + sliceViewPlane, + sliceCoordinates, + vp); + + if (showCoordinates) { + const AString coordText = (axisLetter + + "=" + + AString::number(sliceCoord, 'f', montageCoordPrecision)); + + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + annotationText.setFontPercentViewportSize(10.0f); + annotationText.setLineColor(CaretColorEnum::NONE); + annotationText.setTextColor(CaretColorEnum::CUSTOM); + annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); + annotationText.setCustomTextColor(foregroundRGBA); + annotationText.setCustomBackgroundColor(backgroundRGBA); + annotationText.setText(coordText); + m_fixedPipelineDrawing->drawTextAtViewportCoords((vpSizeX - 5), + 5.0, + annotationText); + } + } + sliceIndex -= sliceStep; + } + } + } + + /* + * Draw the axes labels for the montage view + */ + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + + if (m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed()) { + drawAxesCrosshairsOblique(sliceViewPlane, + sliceCoordinates, + false, + true); + } +} + +/** + * Draw a slice for either projection mode (oblique, orthogonal) + * + * @param allSliceViewMode + * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceViewPlane + * The plane for slice drawing. + * @param sliceCoordinates + * Coordinates of the selected slice. + * @param viewport + * The viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3], + const int32_t viewport[4]) +{ + bool twoDimSliceViewFlag = false; + if (m_modelVolume != NULL) { + twoDimSliceViewFlag = true; + } + else if (m_modelWholeBrain != NULL) { + /* nothing */ + } + else { + CaretAssertMessage(0, "Invalid model type."); + } + + if (twoDimSliceViewFlag) { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glViewport(viewport[0], + viewport[1], + viewport[2], + viewport[3]); + + /* + * Set the orthographic projection to fit the slice axis + */ + setOrthographicProjection(allSliceViewMode, + sliceViewPlane, + viewport); + } + + /* + * Create the plane equation for the slice + */ + Plane slicePlane; + createSlicePlaneEquation(sliceProjectionType, + sliceViewPlane, + sliceCoordinates, + slicePlane); + CaretAssert(slicePlane.isValidPlane()); + if (slicePlane.isValidPlane() == false) { + return; + } + + + if (twoDimSliceViewFlag) { + /* + * Set the viewing transformation (camera position) + */ + setVolumeSliceViewingAndModelingTransformations(sliceProjectionType, + sliceViewPlane, + slicePlane, + sliceCoordinates); + } + + SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); + SelectionItemVoxelEditing* voxelEditingID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); + + m_fixedPipelineDrawing->applyClippingPlanes(BrainOpenGLFixedPipeline::CLIPPING_DATA_TYPE_VOLUME, + StructureEnum::ALL); + + /* + * Check for a 'selection' type mode + */ + bool drawVolumeSlicesFlag = true; + m_identificationModeFlag = false; + switch (m_fixedPipelineDrawing->mode) { + case BrainOpenGLFixedPipeline::MODE_DRAWING: + break; + case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: + if (voxelID->isEnabledForSelection() + || voxelEditingID->isEnabledForSelection()) { + m_identificationModeFlag = true; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else { + /* + * Don't return. Allow other items (such as annotations) to be drawn. + */ + drawVolumeSlicesFlag = false; + } + break; + case BrainOpenGLFixedPipeline::MODE_PROJECTION: + return; + break; + } + + GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); + + if (drawVolumeSlicesFlag) { + /* + * Disable culling so that both sides of the triangles/quads are drawn. + */ + glDisable(GL_CULL_FACE); + + Matrix4x4 obliqueTransformationMatrix; + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: +// break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + /* + * Create the oblique slice transformation matrix + */ + createObliqueTransformationMatrix(sliceProjectionType, + sliceCoordinates, + obliqueTransformationMatrix); + + } + break; + } + drawObliqueSliceWithOutlines(sliceViewPlane, + sliceProjectionType, + obliqueTransformationMatrix); + } + + if ( ! m_identificationModeFlag) { + if (slicePlane.isValidPlane()) { + drawLayers(sliceDrawingType, + sliceProjectionType, + sliceViewPlane, + slicePlane, + sliceCoordinates); + } + } + + /* + * Draw model space annotaitons on the volume slice + */ + float sliceThickness = 1.0; + if ( ! m_volumeDrawInfo.empty()) { + if (m_volumeDrawInfo[0].volumeFile != NULL) { + float spaceX = 0.0, spaceY = 0.0, spaceZ = 0.0; + m_volumeDrawInfo[0].volumeFile->getVoxelSpacing(spaceX, spaceY, spaceZ); + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + CaretAssert(0); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + sliceThickness = spaceZ; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + sliceThickness = spaceY; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + sliceThickness = spaceX; + break; + } + } + } + const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, + m_fixedPipelineDrawing->mode, + BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, + m_fixedPipelineDrawing->m_windowIndex, + m_fixedPipelineDrawing->windowTabIndex, + SpacerTabIndex(), + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, + annotationModeFlag); + m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, + slicePlane, + sliceThickness); + + m_fixedPipelineDrawing->disableClippingPlanes(); + + + if (cullFaceOn) { + glEnable(GL_CULL_FACE); + } +} + +/** + * Create the equation for the slice plane + * + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceViewPlane + * View plane that is displayed. + * @param sliceCoordinates + * Slice coordinates + * @param planeOut + * OUTPUT plane of slice after transforms. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3], + Plane& planeOut) +{ + /* + * Default the slice normal vector to an orthogonal view + */ + float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + case VolumeSliceViewPlaneEnum::AXIAL: + sliceNormalVector[2] = 1.0; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + sliceNormalVector[1] = -1.0; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + sliceNormalVector[0] = -1.0; + break; + } + + switch (sliceProjectionType) { + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + /* + * Transform the slice normal vector by the oblique rotation + * matrix so that the normal vector points out of the slice + */ + const Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); + obliqueRotationMatrix.multiplyPoint3(sliceNormalVector); + MathFunctions::normalizeVector(sliceNormalVector); + } + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + break; + } + + Plane plane(sliceNormalVector, + sliceCoordinates); + planeOut = plane; + + m_lookAtCenter[0] = sliceCoordinates[0]; + m_lookAtCenter[1] = sliceCoordinates[1]; + m_lookAtCenter[2] = sliceCoordinates[2]; +} + +///** +// * Set the volume slice viewing transformation. This sets the position and +// * orientation of the camera. +// * +// * @param sliceProjectionType +// * Type of projection for the slice drawing (oblique, orthogonal) +// * @param sliceViewPlane +// * View plane that is displayed. +// * @param plane +// * Plane equation of selected slice. +// * @param sliceCoordinates +// * Coordinates of the selected slices. +// */ +//void +//BrainOpenGLVolumeTextureSliceDrawing::setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, +// const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, +// const Plane& plane, +// const float sliceCoordinates[3]) +//{ +// /* +// * Initialize the modelview matrix to the identity matrix +// * This places the camera at the origin, pointing down the +// * negative-Z axis with the up vector set to (0,1,0 => +// * positive-Y is up). +// */ +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// const float* userTranslation = m_browserTabContent->getTranslation(); +// +// /* +// * Move the camera with the user's translation +// */ +// float viewTranslationX = 0.0; +// float viewTranslationY = 0.0; +// float viewTranslationZ = 0.0; +// +// switch (sliceViewPlane) { +// case VolumeSliceViewPlaneEnum::ALL: +// case VolumeSliceViewPlaneEnum::AXIAL: +// viewTranslationX = sliceCoordinates[0] + userTranslation[0]; +// viewTranslationY = sliceCoordinates[1] + userTranslation[1]; +// break; +// case VolumeSliceViewPlaneEnum::CORONAL: +// viewTranslationX = sliceCoordinates[0] + userTranslation[0]; +// viewTranslationY = sliceCoordinates[2] + userTranslation[2]; +// break; +// case VolumeSliceViewPlaneEnum::PARASAGITTAL: +// viewTranslationX = -(sliceCoordinates[1] + userTranslation[1]); +// viewTranslationY = sliceCoordinates[2] + userTranslation[2]; +// break; +// } +// +// glTranslatef(viewTranslationX, +// viewTranslationY, +// viewTranslationZ); +// +// +// +// +// glGetDoublev(GL_MODELVIEW_MATRIX, +// m_viewingMatrix); +// +// /* +// * Since an orthographic projection is used, the camera only needs +// * to be a little bit from the center along the plane's normal vector. +// */ +// double planeNormal[3]; +// plane.getNormalVector(planeNormal); +// double cameraXYZ[3] = { +// m_lookAtCenter[0] + planeNormal[0] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, +// m_lookAtCenter[1] + planeNormal[1] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, +// m_lookAtCenter[2] + planeNormal[2] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, +// }; +// +// /* +// * Set the up vector which indices which way is up (screen Y) +// */ +// float up[3] = { 0.0, 0.0, 0.0 }; +// switch (sliceViewPlane) { +// case VolumeSliceViewPlaneEnum::ALL: +// case VolumeSliceViewPlaneEnum::AXIAL: +// up[1] = 1.0; +// break; +// case VolumeSliceViewPlaneEnum::CORONAL: +// up[2] = 1.0; +// break; +// case VolumeSliceViewPlaneEnum::PARASAGITTAL: +// up[2] = 1.0; +// break; +// } +// +// /* +// * For oblique viewing, the up vector needs to be rotated by the +// * oblique rotation matrix. +// */ +// switch (sliceProjectionType) { +// case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: +// m_browserTabContent->getObliqueVolumeRotationMatrix().multiplyPoint3(up); +// break; +// case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: +// break; +// } +// +// /* +// * Now set the camera to look at the selected coordinate (center) +// * with the camera offset a little bit from the center. +// * This allows the slice's voxels to be drawn in the actual coordinates. +// */ +// gluLookAt(cameraXYZ[0], cameraXYZ[1], cameraXYZ[2], +// m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2], +// up[0], up[1], up[2]); +//} + +/** + * Convert a Matrix4x4 to a glm::mat4 matrix + */ +static glm::mat4 +convertMatrix4x4toGlmMat4(const Matrix4x4& matrix) +{ + float m[16]; + matrix.getMatrixForOpenGL(m); + + glm::mat4 out(m[0], m[1], m[2], m[3], + m[4], m[5], m[6], m[7], + m[8], m[9], m[10], m[11], + m[12], m[13], m[14], m[15]); + return out; +} + +/** + * Convert a glm::mat4 matrix to an OpenGL matrix + */ +static void +mat4ToOpenGLMatrix(const glm::mat4& matrixIn, + float matrixOut[16]) +{ + int32_t indx = 0; + for (int32_t iRow = 0; iRow < 4; iRow++) { + for (int jCol = 0; jCol < 4; jCol++) { + matrixOut[indx] = matrixIn[iRow][jCol]; + indx++; + } + } +} + +/** + * Set the volume slice viewing transformation. This sets the position and + * orientation of the camera. + * + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceViewPlane + * View plane that is displayed. + * @param plane + * Plane equation of selected slice. + * @param sliceCoordinates + * Coordinates of the selected slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const Plane& plane, + const float sliceCoordinates[3]) +{ + + /* + * Move the camera with the user's translation + */ + const float* userTranslation = m_browserTabContent->getTranslation(); + glm::vec3 translation(0.0); + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + case VolumeSliceViewPlaneEnum::AXIAL: + translation[0] = sliceCoordinates[0] + userTranslation[0]; + translation[1] = sliceCoordinates[1] + userTranslation[1]; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + translation[0] = sliceCoordinates[0] + userTranslation[0]; + translation[1] = sliceCoordinates[2] + userTranslation[2]; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + translation[0] = -(sliceCoordinates[1] + userTranslation[1]); + translation[1] = sliceCoordinates[2] + userTranslation[2]; + break; + } + + /* + * Since an orthographic projection is used, the eye only needs + * to be a little bit from the center along the plane's normal vector. + */ + double planeNormal[3]; + plane.getNormalVector(planeNormal); + glm::vec3 eye(m_lookAtCenter[0] + planeNormal[0] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, + m_lookAtCenter[1] + planeNormal[1] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, + m_lookAtCenter[2] + planeNormal[2] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance); + + /* + * Set the up vector which indices which way is up (screen Y) + */ + glm::vec4 up(0.0, 0.0, 0.0, 1.0); + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + case VolumeSliceViewPlaneEnum::AXIAL: + up[1] = 1.0; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + up[2] = 1.0; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + up[2] = 1.0; + break; + } + + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + /* + * For oblique viewing, the up vector needs to be rotated by the + * oblique rotation matrix. + */ + const Matrix4x4 obMat = m_browserTabContent->getObliqueVolumeRotationMatrix(); + const glm::mat4 matrix = convertMatrix4x4toGlmMat4(obMat); + up = matrix * up; + + if (debugFlag) { + float upTemp[3] = { up[0], up[1], up[2] }; + m_browserTabContent->getObliqueVolumeRotationMatrix().multiplyPoint3(upTemp); + float upCopy[3] = { up[0], up[1], up[2] }; + const float dist = MathFunctions::distance3D(upTemp, upCopy); + if (dist >= 0.01) { + std::cout << "Up vectors different by distance: " << dist << std::endl; + } + } + } + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + break; + } + + /* + * Now set the camera to look at the selected coordinate (center) + * with the camera offset a little bit from the center. + * This allows the slice's voxels to be drawn in the actual coordinates. + */ +// gluLookAt(eye[0], eye[1], eye[2], +// m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2], +// up[0], up[1], up[2]); + glm::vec3 lookAt(m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2]); + glm::mat4 lookAtMatrix = glm::lookAt(eye, lookAt, glm::vec3(up)); + + glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0), translation); + + glm::mat4 projMatrix = translationMatrix * lookAtMatrix; + + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(glm::value_ptr(projMatrix)); +} + +/** + * Draw the layers type data. + * + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceViewPlane + * View plane that is displayed. + * @param slicePlane + * Plane of the slice. + * @param sliceCoordinates + * Coordinates of the selected slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const Plane& slicePlane, + const float sliceCoordinates[3]) +{ + bool drawCrosshairsFlag = true; + bool drawFibersFlag = true; + bool drawFociFlag = true; + bool drawOutlineFlag = true; + + if (m_modelWholeBrain != NULL) { + drawCrosshairsFlag = false; + drawFibersFlag = false; + drawFociFlag = false; + } + + if ( ! m_identificationModeFlag) { + if (slicePlane.isValidPlane()) { + /* + * Disable culling so that both sides of the triangles/quads are drawn. + */ + GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); + glDisable(GL_CULL_FACE); + + glPushMatrix(); + + GLboolean depthBufferEnabled = false; + glGetBooleanv(GL_DEPTH_TEST, + &depthBufferEnabled); + + /* + * Use some polygon offset that will adjust the depth values of the + * layers so that the layers depth values place the layers in front of + * the volume slice. + */ + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0.0, 1.0); + + if (drawOutlineFlag) { + BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(m_underlayVolume, + m_modelType, + sliceProjectionType, + sliceViewPlane, + sliceCoordinates, + slicePlane, + m_browserTabContent->getVolumeSurfaceOutlineSet(), + m_fixedPipelineDrawing, + true); + } + + if (drawFibersFlag) { + glDisable(GL_DEPTH_TEST); + m_fixedPipelineDrawing->drawFiberOrientations(&slicePlane, + StructureEnum::ALL); + m_fixedPipelineDrawing->drawFiberTrajectories(&slicePlane, + StructureEnum::ALL); + if (depthBufferEnabled) { + glEnable(GL_DEPTH_TEST); + } + else { + glDisable(GL_DEPTH_TEST); + } + } + if (drawFociFlag) { + glDisable(GL_DEPTH_TEST); + drawVolumeSliceFoci(slicePlane); + if (depthBufferEnabled) { + glEnable(GL_DEPTH_TEST); + } + else { + glDisable(GL_DEPTH_TEST); + } + } + + glDisable(GL_POLYGON_OFFSET_FILL); + + if (drawCrosshairsFlag) { + glPushMatrix(); + drawAxesCrosshairs(sliceProjectionType, + sliceDrawingType, + sliceViewPlane, + sliceCoordinates); + glPopMatrix(); + if (depthBufferEnabled) { + glEnable(GL_DEPTH_TEST); + } + else { + glDisable(GL_DEPTH_TEST); + } + } + + glPopMatrix(); + + if (cullFaceOn) { + glEnable(GL_CULL_FACE); + } + } + } +} + +/** + * Draw foci on volume slice. + * + * @param plane + * Plane of the volume slice on which surface outlines are drawn. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceFoci(const Plane& plane) +{ + SelectionItemFocusVolume* idFocus = m_brain->getSelectionManager()->getVolumeFocusIdentification(); + + /* + * Check for a 'selection' type mode + */ + bool isSelect = false; + switch (m_fixedPipelineDrawing->mode) { + case BrainOpenGLFixedPipeline::MODE_DRAWING: + break; + case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: + if (idFocus->isEnabledForSelection()) { + isSelect = true; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else { + return; + } + break; + case BrainOpenGLFixedPipeline::MODE_PROJECTION: + return; + break; + } + + VolumeMappableInterface* underlayVolume = m_volumeDrawInfo[0].volumeFile; + float minVoxelSpacing; + float maxVoxelSpacing; + if ( ! getMinMaxVoxelSpacing(underlayVolume, minVoxelSpacing, maxVoxelSpacing)) { + return; + } + + const float sliceThickness = maxVoxelSpacing; + const float halfSliceThickness = sliceThickness * 0.5; + + + const DisplayPropertiesFoci* fociDisplayProperties = m_brain->getDisplayPropertiesFoci(); + const DisplayGroupEnum::Enum displayGroup = fociDisplayProperties->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); + + if (fociDisplayProperties->isDisplayed(displayGroup, + m_fixedPipelineDrawing->windowTabIndex) == false) { + return; + } + const float focusDiameter = fociDisplayProperties->getFociSize(displayGroup, + m_fixedPipelineDrawing->windowTabIndex); + const FeatureColoringTypeEnum::Enum fociColoringType = fociDisplayProperties->getColoringType(displayGroup, + m_fixedPipelineDrawing->windowTabIndex); + + const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, + m_fixedPipelineDrawing->windowTabIndex); + float caretColorRGBA[4]; + CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); + + bool drawAsSpheres = false; + switch (fociDisplayProperties->getDrawingType(displayGroup, + m_fixedPipelineDrawing->windowTabIndex)) { + case FociDrawingTypeEnum::DRAW_AS_SPHERES: + drawAsSpheres = true; + break; + case FociDrawingTypeEnum::DRAW_AS_SQUARES: + break; + } + + /* + * Process each foci file + */ + const int32_t numberOfFociFiles = m_brain->getNumberOfFociFiles(); + for (int32_t iFile = 0; iFile < numberOfFociFiles; iFile++) { + FociFile* fociFile = m_brain->getFociFile(iFile); + + const GroupAndNameHierarchyModel* classAndNameSelection = fociFile->getGroupAndNameHierarchyModel(); + if (classAndNameSelection->isSelected(displayGroup, + m_fixedPipelineDrawing->windowTabIndex) == false) { + continue; + } + + const GiftiLabelTable* classColorTable = fociFile->getClassColorTable(); + const GiftiLabelTable* nameColorTable = fociFile->getNameColorTable(); + + const int32_t numFoci = fociFile->getNumberOfFoci(); + + for (int32_t j = 0; j < numFoci; j++) { + Focus* focus = fociFile->getFocus(j); + + const GroupAndNameHierarchyItem* groupNameItem = focus->getGroupNameSelectionItem(); + if (groupNameItem != NULL) { + if (groupNameItem->isSelected(displayGroup, + m_fixedPipelineDrawing->windowTabIndex) == false) { + continue; + } + } + + float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; + switch (fociColoringType) { + case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_CLASS: + if (focus->isClassRgbaValid() == false) { + const GiftiLabel* colorLabel = classColorTable->getLabelBestMatching(focus->getClassName()); + if (colorLabel != NULL) { + colorLabel->getColor(rgba); + focus->setClassRgba(rgba); + } + else { + focus->setClassRgba(rgba); + } + } + focus->getClassRgba(rgba); + break; + case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_STANDARD_COLOR: + rgba[0] = caretColorRGBA[0]; + rgba[1] = caretColorRGBA[1]; + rgba[2] = caretColorRGBA[2]; + rgba[3] = caretColorRGBA[3]; + break; + case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME: + if (focus->isNameRgbaValid() == false) { + const GiftiLabel* colorLabel = nameColorTable->getLabelBestMatching(focus->getName()); + if (colorLabel != NULL) { + colorLabel->getColor(rgba); + focus->setNameRgba(rgba); + } + else { + focus->setNameRgba(rgba); + } + } + focus->getNameRgba(rgba); + break; + } + + const int32_t numProjections = focus->getNumberOfProjections(); + for (int32_t k = 0; k < numProjections; k++) { + const SurfaceProjectedItem* spi = focus->getProjection(k); + if (spi->isVolumeXYZValid()) { + float xyz[3]; + spi->getVolumeXYZ(xyz); + + bool drawIt = false; + if (plane.absoluteDistanceToPlane(xyz) < halfSliceThickness) { + drawIt = true; + } + + if (drawIt) { + glPushMatrix(); + glTranslatef(xyz[0], xyz[1], xyz[2]); + if (isSelect) { + uint8_t idRGBA[4]; + m_fixedPipelineDrawing->colorIdentification->addItem(idRGBA, + SelectionItemDataTypeEnum::FOCUS_VOLUME, + iFile, // file index + j, // focus index + k);// projection index + idRGBA[3] = 255; + if (drawAsSpheres) { + m_fixedPipelineDrawing->drawSphereWithDiameter(idRGBA, + focusDiameter); + } + else { + glColor4ubv(idRGBA); + drawSquare(focusDiameter); + } + } + else { + if (drawAsSpheres) { + m_fixedPipelineDrawing->drawSphereWithDiameter(rgba, + focusDiameter); + } + else { + glColor3fv(rgba); + drawSquare(focusDiameter); + } + } + glPopMatrix(); + } + } + } + } + } + + if (isSelect) { + int32_t fociFileIndex = -1; + int32_t focusIndex = -1; + int32_t focusProjectionIndex = -1; + float depth = -1.0; + m_fixedPipelineDrawing->getIndexFromColorSelection(SelectionItemDataTypeEnum::FOCUS_VOLUME, + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + fociFileIndex, + focusIndex, + focusProjectionIndex, + depth); + if (fociFileIndex >= 0) { + if (idFocus->isOtherScreenDepthCloserToViewer(depth)) { + Focus* focus = m_brain->getFociFile(fociFileIndex)->getFocus(focusIndex); + idFocus->setBrain(m_brain); + idFocus->setFocus(focus); + idFocus->setFociFile(m_brain->getFociFile(fociFileIndex)); + idFocus->setFocusIndex(focusIndex); + idFocus->setFocusProjectionIndex(focusProjectionIndex); + idFocus->setVolumeFile(underlayVolume); + idFocus->setScreenDepth(depth); + float xyz[3]; + const SurfaceProjectedItem* spi = focus->getProjection(focusProjectionIndex); + spi->getVolumeXYZ(xyz); + m_fixedPipelineDrawing->setSelectedItemScreenXYZ(idFocus, xyz); + CaretLogFine("Selected Volume Focus Identification Symbol: " + QString::number(focusIndex)); + } + } + } +} + +/** + * Draw the axes crosshairs. + * + * @param sliceProjectionType + * Type of projection for the slice drawing (oblique, orthogonal) + * @param sliceDrawingType + * Type of slice drawing (montage, single) + * @param sliceViewPlane + * View plane that is displayed. + * @param sliceCoordinates + * Coordinates of the selected slices. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3]) +{ + const bool drawCrosshairsFlag = m_browserTabContent->isVolumeAxesCrosshairsDisplayed(); + bool drawCrosshairLabelsFlag = m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed(); + + switch (sliceDrawingType) { + case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: + drawCrosshairLabelsFlag = false; + break; + case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: + break; + } + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: +// break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + glPushMatrix(); + glLoadIdentity(); + drawAxesCrosshairsOblique(sliceViewPlane, + sliceCoordinates, + drawCrosshairsFlag, + drawCrosshairLabelsFlag); + glPopMatrix(); + } + break; + } +} + +/** + * Draw the axes crosshairs for an orthogonal slice. + * + * @param sliceViewPlane + * The slice plane view. + * @param sliceCoordinatesIn + * Coordinates of the selected slices. + * @param drawCrosshairsFlag + * If true, draw the crosshairs. + * @param drawCrosshairLabelsFlag + * If true, draw the crosshair labels. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinatesIn[3], + const bool drawCrosshairsFlag, + const bool drawCrosshairLabelsFlag) +{ + const float gapPercentViewportHeight = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); + const float gapMM = GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(gapPercentViewportHeight); + + const std::array sliceCoordinates = { sliceCoordinatesIn[0], sliceCoordinatesIn[1], sliceCoordinatesIn[2] }; + GLboolean depthEnabled = GL_FALSE; + glGetBooleanv(GL_DEPTH_TEST, + &depthEnabled); + glDisable(GL_DEPTH_TEST); + + const float bigValue = 10000.0 + gapMM; + + std::array horizontalAxisPosStartXYZ = sliceCoordinates; + + float trans[3]; + m_browserTabContent->getTranslation(trans); + + std::array horizTrans = { trans[0], trans[1], trans[2] }; + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + break; + case VolumeSliceViewPlaneEnum::AXIAL: + break; + case VolumeSliceViewPlaneEnum::CORONAL: + horizontalAxisPosStartXYZ[0] = sliceCoordinates[0]; + horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; + horizontalAxisPosStartXYZ[2] = sliceCoordinates[1]; + + horizTrans[0] = trans[0]; + horizTrans[1] = trans[2]; + horizTrans[2] = trans[1]; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + horizontalAxisPosStartXYZ[0] = -sliceCoordinates[1]; + horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; + horizontalAxisPosStartXYZ[2] = sliceCoordinates[0]; + + horizTrans[0] = -trans[1]; + horizTrans[1] = trans[2]; + horizTrans[2] = trans[0]; + break; + } + + std::array horizontalAxisPosEndXYZ = horizontalAxisPosStartXYZ; + std::array verticalAxisPosStartXYZ = horizontalAxisPosStartXYZ; + std::array verticalAxisPosEndXYZ = horizontalAxisPosStartXYZ; + + std::array horizontalAxisNegStartXYZ = horizontalAxisPosStartXYZ; + std::array horizontalAxisNegEndXYZ = horizontalAxisPosEndXYZ; + std::array verticalAxisNegStartXYZ = verticalAxisPosStartXYZ; + std::array verticalAxisNegEndXYZ = verticalAxisPosEndXYZ; + + std::array vertTrans = horizTrans; + + float axialRGBA[4]; + getAxesColor(VolumeSliceViewPlaneEnum::AXIAL, + axialRGBA); + + float coronalRGBA[4]; + getAxesColor(VolumeSliceViewPlaneEnum::CORONAL, + coronalRGBA); + + float paraRGBA[4]; + getAxesColor(VolumeSliceViewPlaneEnum::PARASAGITTAL, + paraRGBA); + + AString horizontalLeftText = ""; + AString horizontalRightText = ""; + AString verticalBottomText = ""; + AString verticalTopText = ""; + + float* horizontalAxisRGBA = axialRGBA; + float* verticalAxisRGBA = axialRGBA; + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + break; + case VolumeSliceViewPlaneEnum::AXIAL: + horizontalLeftText = "L"; + horizontalRightText = "R"; + horizontalAxisRGBA = coronalRGBA; + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; + + verticalBottomText = "P"; + verticalTopText = "A"; + verticalAxisRGBA = paraRGBA; + verticalAxisPosStartXYZ[1] += gapMM; + verticalAxisPosEndXYZ[1] += bigValue; + verticalAxisNegStartXYZ[1] -= gapMM; + verticalAxisNegEndXYZ[1] -= bigValue; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + horizontalLeftText = "L"; + horizontalRightText = "R"; + horizontalAxisRGBA = axialRGBA; + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; + + verticalBottomText = "I"; + verticalTopText = "S"; + verticalAxisRGBA = paraRGBA; + verticalAxisPosStartXYZ[1] += gapMM; + verticalAxisPosEndXYZ[1] += bigValue; + verticalAxisNegStartXYZ[1] -= gapMM; + verticalAxisNegEndXYZ[1] -= bigValue; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + horizontalLeftText = "A"; + horizontalRightText = "P"; + horizontalAxisRGBA = axialRGBA; + horizontalAxisPosStartXYZ[0] += gapMM; + horizontalAxisPosEndXYZ[0] += bigValue; + horizontalAxisNegStartXYZ[0] -= gapMM; + horizontalAxisNegEndXYZ[0] -= bigValue; + + verticalBottomText = "I"; + verticalTopText = "S"; + verticalAxisRGBA = coronalRGBA; + verticalAxisPosStartXYZ[1] += gapMM; + verticalAxisPosEndXYZ[1] += bigValue; + verticalAxisNegStartXYZ[1] -= gapMM; + verticalAxisNegEndXYZ[1] -= bigValue; + break; + } + + /* + * Offset text labels be a percentage of viewort width/height + */ + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + const int textOffsetX = viewport[2] * 0.01f; + const int textOffsetY = viewport[3] * 0.01f; + const int textLeftWindowXY[2] = { + textOffsetX, + (viewport[3] / 2) + }; + const int textRightWindowXY[2] = { + viewport[2] - textOffsetX, + (viewport[3] / 2) + }; + const int textBottomWindowXY[2] = { + viewport[2] / 2, + textOffsetY + }; + const int textTopWindowXY[2] = { + (viewport[2] / 2), + viewport[3] - textOffsetY + }; + + /* + * Crosshairs + */ + if (drawCrosshairsFlag) { + glPushMatrix(); + glTranslatef(horizTrans[0], horizTrans[1], horizTrans[2]); + std::unique_ptr horizHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); + horizHairPrimitive->addVertex(&horizontalAxisPosStartXYZ[0], horizontalAxisRGBA); + horizHairPrimitive->addVertex(&horizontalAxisPosEndXYZ[0], horizontalAxisRGBA); + horizHairPrimitive->addVertex(&horizontalAxisNegStartXYZ[0], horizontalAxisRGBA); + horizHairPrimitive->addVertex(&horizontalAxisNegEndXYZ[0], horizontalAxisRGBA); + horizHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); + GraphicsEngineDataOpenGL::draw(horizHairPrimitive.get()); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(vertTrans[0], vertTrans[1], vertTrans[2]); + std::unique_ptr vertHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); + vertHairPrimitive->addVertex(&verticalAxisPosStartXYZ[0], verticalAxisRGBA); + vertHairPrimitive->addVertex(&verticalAxisPosEndXYZ[0], verticalAxisRGBA); + vertHairPrimitive->addVertex(&verticalAxisNegStartXYZ[0], verticalAxisRGBA); + vertHairPrimitive->addVertex(&verticalAxisNegEndXYZ[0], verticalAxisRGBA); + vertHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); + GraphicsEngineDataOpenGL::draw(vertHairPrimitive.get()); + glPopMatrix(); + } + + if (drawCrosshairLabelsFlag) { + const AnnotationTextFontPointSizeEnum::Enum fontSize = AnnotationTextFontPointSizeEnum::SIZE18; + + const int textCenter[2] = { + textLeftWindowXY[0], + textLeftWindowXY[1] + }; + const int halfFontSize = AnnotationTextFontPointSizeEnum::toSizeNumeric(fontSize) / 2; + + uint8_t backgroundRGBA[4] = { + m_fixedPipelineDrawing->m_backgroundColorByte[0], + m_fixedPipelineDrawing->m_backgroundColorByte[1], + m_fixedPipelineDrawing->m_backgroundColorByte[2], + m_fixedPipelineDrawing->m_backgroundColorByte[3] + }; + + GLint savedViewport[4]; + glGetIntegerv(GL_VIEWPORT, savedViewport); + + int vpLeftX = savedViewport[0] + textCenter[0] - halfFontSize; + int vpRightX = savedViewport[0] + textCenter[0] + halfFontSize; + int vpBottomY = savedViewport[1] + textCenter[1] - halfFontSize; + int vpTopY = savedViewport[1] + textCenter[1] + halfFontSize; + MathFunctions::limitRange(vpLeftX, + savedViewport[0], + savedViewport[0] + savedViewport[2]); + MathFunctions::limitRange(vpRightX, + savedViewport[0], + savedViewport[0] + savedViewport[2]); + MathFunctions::limitRange(vpBottomY, + savedViewport[1], + savedViewport[1] + savedViewport[3]); + MathFunctions::limitRange(vpTopY, + savedViewport[1], + savedViewport[1] + savedViewport[3]); + + const int vpSizeX = vpRightX - vpLeftX; + const int vpSizeY = vpTopY - vpBottomY; + glViewport(vpLeftX, vpBottomY, vpSizeX, vpSizeY); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + std::vector rgba; + std::vector coords, normals; + + coords.push_back(-1.0); + coords.push_back(-1.0); + coords.push_back( 0.0); + normals.push_back(0.0); + normals.push_back(0.0); + normals.push_back(1.0); + rgba.push_back(backgroundRGBA[0]); + rgba.push_back(backgroundRGBA[1]); + rgba.push_back(backgroundRGBA[2]); + rgba.push_back(backgroundRGBA[3]); + + coords.push_back( 1.0); + coords.push_back(-1.0); + coords.push_back( 0.0); + normals.push_back(0.0); + normals.push_back(0.0); + normals.push_back(1.0); + rgba.push_back(backgroundRGBA[0]); + rgba.push_back(backgroundRGBA[1]); + rgba.push_back(backgroundRGBA[2]); + rgba.push_back(backgroundRGBA[3]); + + coords.push_back( 1.0); + coords.push_back( 1.0); + coords.push_back( 0.0); + normals.push_back(0.0); + normals.push_back(0.0); + normals.push_back(1.0); + rgba.push_back(backgroundRGBA[0]); + rgba.push_back(backgroundRGBA[1]); + rgba.push_back(backgroundRGBA[2]); + rgba.push_back(backgroundRGBA[3]); + + coords.push_back(-1.0); + coords.push_back( 1.0); + coords.push_back( 0.0); + normals.push_back(0.0); + normals.push_back(0.0); + normals.push_back(1.0); + rgba.push_back(backgroundRGBA[0]); + rgba.push_back(backgroundRGBA[1]); + rgba.push_back(backgroundRGBA[2]); + rgba.push_back(backgroundRGBA[3]); + + + BrainOpenGLPrimitiveDrawing::drawQuads(coords, + normals, + rgba); + + glPopMatrix(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + glViewport(savedViewport[0], + savedViewport[1], + savedViewport[2], + savedViewport[3]); + + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setBoldStyleEnabled(true); + annotationText.setFontPercentViewportSize(5.0f); + annotationText.setTextColor(CaretColorEnum::CUSTOM); + annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); + annotationText.setCustomTextColor(horizontalAxisRGBA); + annotationText.setCustomBackgroundColor(backgroundRGBA); + + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + annotationText.setText(horizontalLeftText); + m_fixedPipelineDrawing->drawTextAtViewportCoords(textLeftWindowXY[0], + textLeftWindowXY[1], + annotationText); + + annotationText.setText(horizontalRightText); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + m_fixedPipelineDrawing->drawTextAtViewportCoords(textRightWindowXY[0], + textRightWindowXY[1], + annotationText); + + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + annotationText.setCustomTextColor(verticalAxisRGBA); + annotationText.setText(verticalBottomText); + m_fixedPipelineDrawing->drawTextAtViewportCoords(textBottomWindowXY[0], + textBottomWindowXY[1], + annotationText); + + annotationText.setText(verticalTopText); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + annotationText.getCoordinate()->setXYZ(textTopWindowXY[0], textTopWindowXY[1], 0.0); + m_fixedPipelineDrawing->drawTextAtViewportCoords(textTopWindowXY[0], + textTopWindowXY[1], + annotationText); + } + + if (depthEnabled) { + glEnable(GL_DEPTH_TEST); + } +} + +/** + * Get the RGBA coloring for a slice view plane. + * + * @param sliceViewPlane + * The slice view plane. + * @param rgbaOut + * Output colors ranging 0.0 to 1.0 + */ +void +BrainOpenGLVolumeTextureSliceDrawing::getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + float rgbaOut[4]) const +{ + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + CaretAssert(0); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + rgbaOut[0] = 0.0; + rgbaOut[1] = 0.0; + rgbaOut[2] = 1.0; + rgbaOut[3] = 1.0; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + rgbaOut[0] = 0.0; + rgbaOut[1] = 1.0; + rgbaOut[2] = 0.0; + rgbaOut[3] = 1.0; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + rgbaOut[0] = 1.0; + rgbaOut[1] = 0.0; + rgbaOut[2] = 0.0; + rgbaOut[3] = 1.0; + break; + } +} + +/** + * Draw a one millimeter square facing the user. + * NOTE: This method will alter the current + * modelviewing matrices so caller may need + * to enclose the call to this method within + * glPushMatrix() and glPopMatrix(). + * + * @param size + * Size of square. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawSquare(const float size) +{ + const float length = size * 0.5; + + /* + * Draw both front and back side since in some instances, + * such as surface montage, we are viweing from the far + * side (from back of monitor) + */ + glBegin(GL_QUADS); + glNormal3f(0.0, 0.0, 1.0); + glVertex3f(-length, -length, 0.0); + glVertex3f( length, -length, 0.0); + glVertex3f( length, length, 0.0); + glVertex3f(-length, length, 0.0); + glNormal3f(0.0, 0.0, -1.0); + glVertex3f(-length, -length, 0.0); + glVertex3f(-length, length, 0.0); + glVertex3f( length, length, 0.0); + glVertex3f( length, -length, 0.0); + glEnd(); +} + +/** + * Get the minimum and maximum distance between adjacent voxels in all + * slices planes. Output spacing value are always non-negative even if + * a right-to-left orientation. + * + * @param volume + * Volume for which min/max spacing is requested. + * @param minSpacingOut + * Output minimum spacing. + * @param maxSpacingOut + * Output maximum spacing. + * @return + * True if min and max spacing are greater than zero. + */ +bool +BrainOpenGLVolumeTextureSliceDrawing::getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, + float& minSpacingOut, + float& maxSpacingOut) const +{ + CaretAssert(volume); + + float originX, originY, originZ; + float x1, y1, z1; + volume->indexToSpace(0, 0, 0, originX, originY, originZ); + volume->indexToSpace(1, 1, 1, x1, y1, z1); + const float dx = std::fabs(x1 - originX); + const float dy = std::fabs(y1 - originY); + const float dz = std::fabs(z1 - originZ); + + minSpacingOut = std::min(std::min(dx, dy), dz); + maxSpacingOut = std::max(std::max(dx, dy), dz); + + if ((minSpacingOut > 0.0) + && (maxSpacingOut > 0.0)) { + return true; + } + return false; +} + +/** + * Draw orientation axes + * + * @param viewport + * The viewport region for the orientation axes. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawOrientationAxes(const int viewport[4]) +{ + const bool drawCylindersFlag = m_browserTabContent->isVolumeAxesCrosshairsDisplayed(); + const bool drawLabelsFlag = m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed(); + + /* + * Set the viewport + */ + glViewport(viewport[0], + viewport[1], + viewport[2], + viewport[3]); + const double viewportWidth = viewport[2]; + const double viewportHeight = viewport[3]; + + /* + * Determine bounds for orthographic projection + */ + const double maxCoord = 100.0; + const double minCoord = -maxCoord; + double left = 0.0; + double right = 0.0; + double top = 0.0; + double bottom = 0.0; + const double nearDepth = -1000.0; + const double farDepth = 1000.0; + if (viewportHeight > viewportWidth) { + left = minCoord; + right = maxCoord; + const double aspectRatio = (viewportHeight + / viewportWidth); + top = maxCoord * aspectRatio; + bottom = minCoord * aspectRatio; + } + else { + const double aspectRatio = (viewportWidth + / viewportHeight); + top = maxCoord; + bottom = minCoord; + left = minCoord * aspectRatio; + right = maxCoord * aspectRatio; + } + + /* + * Set the orthographic projection + */ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); +// glLoadIdentity(); +// glOrtho(left, right, +// bottom, top, +// nearDepth, farDepth); + glm::mat4 orthoMatrix = glm::ortho(left, right, + bottom, top, + nearDepth, farDepth); + glLoadMatrixf(glm::value_ptr(orthoMatrix)); + + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + { + /* + * Set the viewing transformation, places 'eye' so that it looks + * at the 'model' which is, in this case, the axes + */ + const glm::vec3 eyeXYZ(0.0, 0.0, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance); + const glm::vec3 lookAtXYZ(0.0, 0.0, 0.0); + const glm::vec3 upVector(0.0, 1.0, 0.0); + glm::mat4 lookAtMatrix = glm::lookAt(eyeXYZ, + lookAtXYZ, + upVector); + + /* + * Set the modeling transformation + */ + const Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); + const glm::mat4 obliqueMat4 = convertMatrix4x4toGlmMat4(obliqueRotationMatrix); + const glm::mat4 modelMatrix = lookAtMatrix * obliqueMat4; + glLoadMatrixf(glm::value_ptr(modelMatrix)); + + + /* + * Disable depth buffer. Otherwise, when volume slices are drawn + * black regions of the slices may set depth buffer and the occlude + * the axes from display. + */ + GLboolean depthBufferEnabled = false; + glGetBooleanv(GL_DEPTH_TEST, + &depthBufferEnabled); + glDisable(GL_DEPTH_TEST); + const float red[4] = { + 1.0, 0.0, 0.0, 1.0 + }; + const float green[4] = { + 0.0, 1.0, 0.0, 1.0 + }; + const float blue[4] = { + 0.0, 0.0, 1.0, 1.0 + }; + + const double axisMaxCoord = maxCoord * 0.8; + const double axisMinCoord = -axisMaxCoord; + const double textMaxCoord = maxCoord * 0.9; + const double textMinCoord = -textMaxCoord; + + + const float axialPlaneMin[3] = { 0.0, 0.0, (float)axisMinCoord }; + const float axialPlaneMax[3] = { 0.0, 0.0, (float)axisMaxCoord }; + const double axialTextMin[3] = { 0.0, 0.0, (float)textMinCoord }; + const double axialTextMax[3] = { 0.0, 0.0, (float)textMaxCoord }; + + const float coronalPlaneMin[3] = { (float)axisMinCoord, 0.0, 0.0 }; + const float coronalPlaneMax[3] = { (float)axisMaxCoord, 0.0, 0.0 }; + const double coronalTextMin[3] = { (float)textMinCoord, 0.0, 0.0 }; + const double coronalTextMax[3] = { (float)textMaxCoord, 0.0, 0.0 }; + + const float paraPlaneMin[3] = { 0.0, (float)axisMinCoord, 0.0 }; + const float paraPlaneMax[3] = { 0.0, (float)axisMaxCoord, 0.0 }; + const double paraTextMin[3] = { 0.0, (float)textMinCoord, 0.0 }; + const double paraTextMax[3] = { 0.0, (float)textMaxCoord, 0.0 }; + + /* + * Set radius as percentage of viewport height + */ + float axesCrosshairRadius = 1.0; + if (viewportHeight > 0) { + const float percentageRadius = 0.005f; + axesCrosshairRadius = percentageRadius * viewportHeight; + } + + if (drawCylindersFlag) { + m_fixedPipelineDrawing->drawCylinder(blue, + axialPlaneMin, + axialPlaneMax, + axesCrosshairRadius * 0.5f); + } + + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + annotationText.setFontPercentViewportSize(5.0f); + annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); + annotationText.setTextColor(CaretColorEnum::CUSTOM); + + if (drawLabelsFlag) { + annotationText.setCustomTextColor(blue); + annotationText.setText("I"); + m_fixedPipelineDrawing->drawTextAtModelCoords(axialTextMin, + annotationText); + annotationText.setText("S"); + m_fixedPipelineDrawing->drawTextAtModelCoords(axialTextMax, + annotationText); + } + + + if (drawCylindersFlag) { + m_fixedPipelineDrawing->drawCylinder(green, + coronalPlaneMin, + coronalPlaneMax, + axesCrosshairRadius * 0.5f); + } + + if (drawLabelsFlag) { + annotationText.setCustomTextColor(green); + annotationText.setText("L"); + m_fixedPipelineDrawing->drawTextAtModelCoords(coronalTextMin, + annotationText); + annotationText.setText("R"); + m_fixedPipelineDrawing->drawTextAtModelCoords(coronalTextMax, + annotationText); + } + + + if (drawCylindersFlag) { + m_fixedPipelineDrawing->drawCylinder(red, + paraPlaneMin, + paraPlaneMax, + axesCrosshairRadius * 0.5f); + } + + if (drawLabelsFlag) { + annotationText.setCustomTextColor(red); + annotationText.setText("P"); + m_fixedPipelineDrawing->drawTextAtModelCoords(paraTextMin, + annotationText); + + annotationText.setText("A"); + m_fixedPipelineDrawing->drawTextAtModelCoords(paraTextMax, + annotationText); + } + } + glPopMatrix(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + +} + +/** + * Set the orthographic projection. + * + * @param allSliceViewMode + * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) + * @param sliceViewPlane + * View plane that is displayed. + * @param viewport + * The viewport. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::setOrthographicProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const int viewport[4]) +{ + const bool useOrthosDrawingProjectionFlag = false; /* does not work as expected when oblique */ + if (useOrthosDrawingProjectionFlag) { + /* + * Determine model size in screen Y when viewed + */ + BoundingBox boundingBox; + m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); + + const double zoomFactor = m_browserTabContent->getScaling(); + BrainOpenGLVolumeSliceDrawing::setOrthographicProjection(allSliceViewMode, + sliceViewPlane, + boundingBox, + zoomFactor, + viewport, + m_orthographicBounds); + + return; + } + + /* + * Determine model size in screen Y when viewed + */ + BoundingBox boundingBox; + m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); + + /* + * Set top and bottom to the min/max coordinate + * that runs vertically on the screen + */ + double modelTop = 200.0; + double modelBottom = -200.0; + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + CaretAssertMessage(0, "Should never get here"); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + modelTop = boundingBox.getMaxY(); + modelBottom = boundingBox.getMinY(); + break; + case VolumeSliceViewPlaneEnum::CORONAL: + modelTop = boundingBox.getMaxZ(); + modelBottom = boundingBox.getMinZ(); + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + modelTop = boundingBox.getMaxZ(); + modelBottom = boundingBox.getMinZ(); + break; + } + + switch (allSliceViewMode) { + case BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES: + { + /* + * Parasagittal and Coronal Views have Brain's Z-axis in Screen Y + * Axial View has Brain's Y-axis in Screen Y + * So, use maximum of Brain's Y- and Z-axes for sizing height of slice + * so that voxels are same size for each slice in each axis view + */ + const float maxRangeYZ = std::max(boundingBox.getDifferenceY(), + boundingBox.getDifferenceZ()); + const float range = modelTop - modelBottom; + if (maxRangeYZ > range) { + const float diff = maxRangeYZ - range; + const float halfDiff = diff / 2.0; + modelTop += halfDiff; + modelBottom -= halfDiff; + } + } + break; + case BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO: + break; + } + + /* + * Scale ratio makes region slightly larger than model + */ + const double zoom = m_browserTabContent->getScaling(); + double scaleRatio = (1.0 / 0.98); + if (zoom > 0.0) { + scaleRatio /= zoom; + } + modelTop *= scaleRatio; + modelBottom *= scaleRatio; + + /* + * Determine aspect ratio of viewport + */ + const double viewportWidth = viewport[2]; + const double viewportHeight = viewport[3]; + const double aspectRatio = (viewportWidth + / viewportHeight); + + /* + * Set bounds of orthographic projection + */ + const double halfModelY = ((modelTop - modelBottom) / 2.0); + const double orthoBottom = modelBottom; + const double orthoTop = modelTop; + const double orthoRight = halfModelY * aspectRatio; + const double orthoLeft = -halfModelY * aspectRatio; + const double nearDepth = -1000.0; + const double farDepth = 1000.0; + m_orthographicBounds[0] = orthoLeft; + m_orthographicBounds[1] = orthoRight; + m_orthographicBounds[2] = orthoBottom; + m_orthographicBounds[3] = orthoTop; + m_orthographicBounds[4] = nearDepth; + m_orthographicBounds[5] = farDepth; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(m_orthographicBounds[0], + m_orthographicBounds[1], + m_orthographicBounds[2], + m_orthographicBounds[3], + m_orthographicBounds[4], + m_orthographicBounds[5]); + glMatrixMode(GL_MODELVIEW); +} + +/** + * Get the maximum bounds that enclose the volumes and the minimum + * voxel spacing from the volumes. + * + * @param boundsOut + * Bounds of the volumes. + * @param spacingOut + * Minimum voxel spacing from the volumes. Always positive values (even if + * volumes is oriented right to left). + * + */ +bool +BrainOpenGLVolumeTextureSliceDrawing::getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], + float spacingOut[3]) +{ + const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); + if (numberOfVolumesToDraw <= 0) { + return false; + } + + /* + * Find maximum extent of all voxels and smallest voxel + * size in each dimension. + */ + float minVoxelX = std::numeric_limits::max(); + float maxVoxelX = -std::numeric_limits::max(); + float minVoxelY = std::numeric_limits::max(); + float maxVoxelY = -std::numeric_limits::max(); + float minVoxelZ = std::numeric_limits::max(); + float maxVoxelZ = -std::numeric_limits::max(); + float voxelStepX = std::numeric_limits::max(); + float voxelStepY = std::numeric_limits::max(); + float voxelStepZ = std::numeric_limits::max(); + for (int32_t i = 0; i < numberOfVolumesToDraw; i++) { + const VolumeMappableInterface* volumeFile = m_volumeDrawInfo[i].volumeFile; + int64_t dimI, dimJ, dimK, numMaps, numComponents; + volumeFile->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); + + float originX, originY, originZ; + float x1, y1, z1; + float lastX, lastY, lastZ; + volumeFile->indexToSpace(0, 0, 0, originX, originY, originZ); + volumeFile->indexToSpace(1, 1, 1, x1, y1, z1); + volumeFile->indexToSpace(dimI - 1, dimJ - 1, dimK - 1, lastX, lastY, lastZ); + const float dx = x1 - originX; + const float dy = y1 - originY; + const float dz = z1 - originZ; + voxelStepX = std::min(voxelStepX, std::fabs(dx)); + voxelStepY = std::min(voxelStepY, std::fabs(dy)); + voxelStepZ = std::min(voxelStepZ, std::fabs(dz)); + + minVoxelX = std::min(minVoxelX, std::min(originX, lastX)); + maxVoxelX = std::max(maxVoxelX, std::max(originX, lastX)); + minVoxelY = std::min(minVoxelY, std::min(originY, lastY)); + maxVoxelY = std::max(maxVoxelY, std::max(originY, lastY)); + minVoxelZ = std::min(minVoxelZ, std::min(originZ, lastZ)); + maxVoxelZ = std::max(maxVoxelZ, std::max(originZ, lastZ)); + } + + boundsOut[0] = minVoxelX; + boundsOut[1] = maxVoxelX; + boundsOut[2] = minVoxelY; + boundsOut[3] = maxVoxelY; + boundsOut[4] = minVoxelZ; + boundsOut[5] = maxVoxelZ; + + spacingOut[0] = voxelStepX; + spacingOut[1] = voxelStepY; + spacingOut[2] = voxelStepZ; + + /* + * Two dimensions: single slice + * Three dimensions: multiple slices + */ + int32_t validDimCount = 0; + if (maxVoxelX > minVoxelX) validDimCount++; + if (maxVoxelY > minVoxelY) validDimCount++; + if (maxVoxelZ > minVoxelZ) validDimCount++; + + bool valid = false; + if ((validDimCount >= 2) + && (voxelStepX > 0.0) + && (voxelStepY > 0.0) + && (voxelStepZ > 0.0)) { + valid = true; + } + + return valid; +} + +/** + * Create the oblique transformation matrix. + * + * @parm sliceProjectionType + * The slice projection type + * @param sliceCoordinates + * Slice that is being drawn. + * @param obliqueTransformationMatrixOut + * OUTPUT transformation matrix for oblique viewing. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::createObliqueTransformationMatrix(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const float sliceCoordinates[3], + Matrix4x4& obliqueTransformationMatrixOut) +{ + /* + * Initialize the oblique transformation matrix + */ + obliqueTransformationMatrixOut.identity(); + + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + /* + * Get the oblique rotation matrix + */ + Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); + + /* + * Create the transformation matrix + */ + obliqueTransformationMatrixOut.postmultiply(obliqueRotationMatrix); + + } + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + break; + } + + /* + * Translate to selected coordinate + */ + obliqueTransformationMatrixOut.translate(sliceCoordinates[0], + sliceCoordinates[1], + sliceCoordinates[2]); +} + +/* ======================================================================= */ + +/** + * Get the texture coordinates for an XYZ-coordinate + * + * @param volumeMappableInterface + * The volume file + * @param xyz + * The XYZ coordinate + * @param maxStr + * The maximum texture str coordinate + * @param strOut + * Output texture str coordinate + * @return + * True if output coordinate is valid, else false. + */ +bool +BrainOpenGLVolumeTextureSliceDrawing::getTextureCoordinates(const VolumeMappableInterface* volumeMappableInterface, + const std::array& xyz, + const std::array& maxStr, + std::array& strOut) const +{ + std::vector dims(5); + volumeMappableInterface->getDimensions(dims); + +// int64_t smallCornerIJK[3] = { 0, 0, 0}; +// float smallCornerXYZ[3] = { 0.0, 0.0, 0.0 }; +// volumeMappableInterface->indexToSpace(smallCornerIJK, smallCornerXYZ); +// +// int64_t bigCornerIJK[3] = { dims[0] - 1, dims[1] - 1, dims[2] - 1 }; +// float bigCornerXYZ[3] = { 0.0, 0.0, 0.0 }; +// volumeMappableInterface->indexToSpace(bigCornerIJK, bigCornerXYZ); +// +// /* +// * Coordinates from volume are at CENTER of the voxel +// * so increase size of volume so that range is from +// * outside edge to outside edge of the volume. +// */ +// float voxelOneXYZ[3]; +// volumeMappableInterface->indexToSpace(0, 0, 0, voxelOneXYZ); +// float voxelTwoXYZ[3]; +// volumeMappableInterface->indexToSpace(1, 1, 1, voxelTwoXYZ); +// const float halfVoxelSizeXYZ[3] { +// (voxelTwoXYZ[0] - voxelOneXYZ[0]) / 2.0f, +// (voxelTwoXYZ[1] - voxelOneXYZ[1]) / 2.0f, +// (voxelTwoXYZ[2] - voxelOneXYZ[2]) / 2.0f, +// }; +// for (int32_t i = 0; i < 3; i++) { +// smallCornerXYZ[i] -= halfVoxelSizeXYZ[i]; +// bigCornerXYZ[i] += halfVoxelSizeXYZ[i]; +// } +// +// const float rangeXYZ[3] = { +// (bigCornerXYZ[0] - smallCornerXYZ[0]), +// (bigCornerXYZ[1] - smallCornerXYZ[1]), +// (bigCornerXYZ[2] - smallCornerXYZ[2]) +// }; +// +// const float normalizedOffset[3] = { +// (xyz[0] - smallCornerXYZ[0]) / rangeXYZ[0], +// (xyz[1] - smallCornerXYZ[1]) / rangeXYZ[1], +// (xyz[2] - smallCornerXYZ[2]) / rangeXYZ[2], +// }; +// +// strOut[0] = normalizedOffset[0] * maxStr[0]; +// strOut[1] = normalizedOffset[1] * maxStr[1]; +// strOut[2] = normalizedOffset[2] * maxStr[2]; + + { + const VolumeSpace& volumeSpace = volumeMappableInterface->getVolumeSpace(); + std::array ijk; + volumeSpace.spaceToIndex(xyz.data(), ijk.data()); + + const std::array normalizedIJK { + (ijk[0] / dims[0]), + (ijk[1] / dims[1]), + (ijk[2] / dims[2]) + }; + std::array str { + (normalizedIJK[0] * maxStr[0]), + (normalizedIJK[1] * maxStr[1]), + (normalizedIJK[2] * maxStr[2]) + }; + + strOut = str; + } + + return true; +} + +/** + * Create RGBA coloring for volume's texture + * + * @param volumeMappableInterface + * The volume file + * @param displayGroup + * Display group for current tab + * @param tabIndex + * Index of tab + * @param allowNonPowerOfTwoTextureFlag + * Allow non power-of-two texture + * @param identificationTextureFlag + * True if creating texture for voxel identification + * @param rgbaColorsOut + * Output containing RGBA coloring + * @param textureDimsOut + * Output with dimensions for texture + * @param maxStrOut + * Output with maximum Texture str coordinates + * @return + * True if output rgba coloring is valid, else false. + */ +bool +BrainOpenGLVolumeTextureSliceDrawing::createVolumeTexture(const VolumeMappableInterface* volumeMappableInterface, + const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex, + const bool allowNonPowerOfTwoTextureFlag, + const bool identificationTextureFlag, + std::vector& rgbaColorsOut, + std::array& textureDimsOut, + std::array& maxStrOut) const +{ + maxStrOut.fill(0.0); + + std::vector dims(5); + volumeMappableInterface->getDimensions(dims); + textureDimsOut.fill(256); + const int64_t dimLargest = *std::max_element(dims.begin(), dims.begin() + 3); + if (allowNonPowerOfTwoTextureFlag) { + + } + else { + if (dimLargest > 512) { + const CaretMappableDataFile* mapFile = dynamic_cast(volumeMappableInterface); + const QString filename((mapFile != NULL) + ? mapFile->getFileNameNoPath() + : "no file name available"); + const QString msg("Dimensions too large for volume texture support. Dimensions=" + + AString::fromNumbers(&dims[0], 3, ",") + + " for volume " + + filename); + CaretLogSevere(msg); + return false; + } + else if (dimLargest > 256) { + textureDimsOut.fill(512); + } + } + + const int64_t mapIndex(0); + const int64_t numberOfSlices = dims[2]; + const int64_t numberOfRows = dims[1]; + const int64_t numberOfColumns = dims[0]; + const int64_t numSliceBytes = (numberOfRows * numberOfColumns * 4); + + if (allowNonPowerOfTwoTextureFlag) { + textureDimsOut[0] = numberOfColumns; + textureDimsOut[1] = numberOfRows; + textureDimsOut[2] = numberOfSlices; + } + const int64_t textureBytes = (textureDimsOut[0] * textureDimsOut[1] * textureDimsOut[2] * 4); + + rgbaColorsOut.clear(); + rgbaColorsOut.resize(textureBytes, 0); + + if (identificationTextureFlag) { + uint32_t offsetID = 0; + for (int64_t k = 0; k < numberOfSlices; k++) { + for (int32_t j = 0; j < numberOfRows; j++) { + for (int32_t i = 0; i < numberOfColumns; i++) { + const int32_t textureOffset = ((k * textureDimsOut[0] * textureDimsOut[1]) + + (j * textureDimsOut[0]) + i) * 4; + CaretAssertVectorIndex(rgbaColorsOut, (textureOffset + 3)); + + /* + * An offset is used and encoded into the R, G, and B bytes. + * While we could use IJK, we cannot if a dimension is + * greater than 255. With the offset, number of voxels + * must only be less than 255**3. + */ + const uint8_t offsetRed = static_cast((offsetID >> 16) & 0xff); + const uint8_t offsetGreen = static_cast((offsetID >> 8) & 0xff); + const uint8_t offsetBlue = static_cast((offsetID) & 0xff); + rgbaColorsOut[textureOffset] = offsetRed; + rgbaColorsOut[textureOffset+1] = offsetGreen; + rgbaColorsOut[textureOffset+2] = offsetBlue; + rgbaColorsOut[textureOffset+3] = 255; + + offsetID++; + } + } + } + } + else { + /* + * When non power-of-two textures are NOT allowed (OpenGL < 2.0) + * To avoid resampling of the voxel data, the texture has larger dimensions + * and the volume's voxels are placed in the bottom left corner of the texture + * and extra texture texel's are zeros. + */ + std::vector rgbaSlice(numSliceBytes); + for (int64_t k = 0; k < numberOfSlices; k++) { + int64_t firstVoxelIJK[3] = { 0, 0, k }; + int64_t rowStepIJK[3] = { 0, 1, 0 }; + int64_t columnStepIJK[3] = { 1, 0, 0 }; + + std::fill(rgbaSlice.begin(), rgbaSlice.end(), 0); + volumeMappableInterface->getVoxelColorsForSliceInMap(mapIndex, + firstVoxelIJK, + rowStepIJK, + columnStepIJK, + numberOfRows, + numberOfColumns, + displayGroup, + tabIndex, + &rgbaSlice[0]); + + for (int32_t j = 0; j < numberOfRows; j++) { + for (int32_t i = 0; i < numberOfColumns; i++) { + const int32_t sliceOffset = ((j * numberOfColumns) + i) * 4; + const int32_t textureOffset = ((k * textureDimsOut[0] * textureDimsOut[1]) + + (j * textureDimsOut[0]) + i) * 4; + for (int32_t m = 0; m < 4; m++) { + CaretAssertVectorIndex(rgbaColorsOut, (textureOffset + 3)); + CaretAssertVectorIndex(rgbaSlice, sliceOffset + m); + rgbaColorsOut[textureOffset + m] = rgbaSlice[sliceOffset + m]; + } + } + } + } + } + + maxStrOut[0] = static_cast(dims[0]) / static_cast(textureDimsOut[0]); + maxStrOut[1] = static_cast(dims[1]) / static_cast(textureDimsOut[1]); + maxStrOut[2] = static_cast(dims[2]) / static_cast(textureDimsOut[2]); + if (debugFlag) std::cout << "max STR: " << AString::fromNumbers(maxStrOut.data(), 3, ",") << std::endl; + + return true; + +} + +/** + * Create a volume's texture + * + * @param volumeMappableInterface + * The volume file + * @param identificationTextureFlag + * True if creating texture for voxel identification + * @param displayGroup + * Display group for current tab + * @param maxStrOut + * Output with maximum Texture str coordinates + * @return + * Valid texture ID (greater than zero) if texture was created, else 0. + */ +GLuint +BrainOpenGLVolumeTextureSliceDrawing::createTextureName(const VolumeMappableInterface* volumeMappableInterface, + const bool identificationTextureFlag, + const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex, + std::array& maxStrOut) const +{ + const CaretMappableDataFile* mapFile = dynamic_cast(volumeMappableInterface); + CaretAssert(mapFile); + + const VolumeFile* volumeFile = dynamic_cast(volumeMappableInterface); + const CiftiMappableDataFile* ciftiFile = dynamic_cast(volumeMappableInterface); + + std::vector rgbaColors; + std::array textureDims; + + /* + * OpenGL 2.0 or later supports non-power-of-two texture dimensions + */ + const bool allowNonPowerOfTwoTextureFlag(true); + if (volumeFile != NULL) { + if ( ! createVolumeTexture(volumeFile, + displayGroup, + tabIndex, + allowNonPowerOfTwoTextureFlag, + identificationTextureFlag, + rgbaColors, + textureDims, + maxStrOut)) { + return 0; + } + } + else if (ciftiFile != NULL) { + if ( ! createVolumeTexture(ciftiFile, + displayGroup, + tabIndex, + allowNonPowerOfTwoTextureFlag, + identificationTextureFlag, + rgbaColors, + textureDims, + maxStrOut)) { + return 0; + } + } + else { + CaretAssert(0); + } + + GLint64 maxTextureSize(0); + glGetInteger64v(GL_MAX_3D_TEXTURE_SIZE, + &maxTextureSize); + if (maxTextureSize > 0) { + for (int32_t i = 0; i < static_cast(textureDims.size()); i++) { + if (textureDims[i] > maxTextureSize) { + CaretLogSevere("Texture maximum dimension is " + + AString::number(maxTextureSize) + + ". Volume " + + mapFile->getFileNameNoPath() + + " dimensions = (" + + AString::fromNumbers(textureDims.data(), 3, ", ") + + ")"); + return 0; + } + } + } + GLuint textureName(0); + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + + glGenTextures(1, &textureName); + glBindTexture(GL_TEXTURE_3D, textureName); + + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + + /* + * Always clamp to border. If no texels (voxels) are available, pixel + * maps to area outside of the volume, the border color is used. + */ + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + + const bool enableMipMapsFlag(false); + if (enableMipMapsFlag) { + /* + * Generate mip-maps + * However does not improve quality or remove aliasing in oblique views (rotation + * around multiple axes) + */ + glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE); + } + + /* + * Compression works but appears lossy for palette mapped data + * but may be okay for label mapped data + */ + m_fixedPipelineDrawing->testForOpenGLError("Before glTexImage3D"); + glTexImage3D(GL_TEXTURE_3D, + 0, + GL_RGBA, //GL_COMPRESSED_RGBA, //GL_RGBA, + textureDims[0], + textureDims[1], + textureDims[2], + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + &rgbaColors[0]); + m_fixedPipelineDrawing->testForOpenGLError("After glTexImage3D"); + + glBindTexture(GL_TEXTURE_3D, 0); + glPopClientAttrib(); + + return textureName; +} + +/** + * Draw an oblique slice with support for outlining labels and thresholded palette data. + * + * @param sliceViewPlane + * The plane for slice drawing. + * @param sliceProjectionType + * The slice projection type + * @param transformationMatrix + * The for oblique viewing. + */ +void +BrainOpenGLVolumeTextureSliceDrawing::drawObliqueSliceWithOutlines(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + Matrix4x4& transformationMatrix) +{ + /* + * When performing voxel identification for editing voxels, + * we need to draw EVERY voxel since the user may click + * regions where the voxels are "off". + */ + float voxelEditingValue = 1.0; + VolumeFile* voxelEditingVolumeFile = NULL; + if (m_identificationModeFlag) { + SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); + if (voxelEditID->isEnabledForSelection()) { + voxelEditingVolumeFile = voxelEditID->getVolumeFileForEditing(); + if (voxelEditingVolumeFile != NULL) { + if (voxelEditingVolumeFile->isMappedWithLabelTable()) { + if (voxelEditingVolumeFile->getNumberOfMaps() > 0) { + voxelEditingValue = voxelEditingVolumeFile->getMapLabelTable(0)->getUnassignedLabelKey(); + } + } + } + } + } + + const bool obliqueSliceModeThreeDimFlag = false; + + const int32_t numVolumes = static_cast(m_volumeDrawInfo.size()); + + /* + * Get the maximum bounds of the voxels from all slices + * and the smallest voxel spacing + */ + float voxelBounds[6]; + float voxelSpacing[3]; + if ( ! getVoxelCoordinateBoundsAndSpacing(voxelBounds, + voxelSpacing)) { + return; + } + float voxelSize = std::min(voxelSpacing[0], + std::min(voxelSpacing[1], + voxelSpacing[2])); + + /* + * Use a larger voxel size for the 3D view in volume slice viewing + * since it draws all three slices and this takes time + */ + if (obliqueSliceModeThreeDimFlag) { + voxelSize *= 3.0; + } + + /* + * Look at point is in center of volume + */ + float translation[3]; + m_browserTabContent->getTranslation(translation); + float viewOffsetX = 0.0; + float viewOffsetY = 0.0; + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + CaretAssert(0); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + viewOffsetX = (m_lookAtCenter[0] + translation[0]); + viewOffsetY = (m_lookAtCenter[1] + translation[1]); + break; + case VolumeSliceViewPlaneEnum::CORONAL: + viewOffsetX = (m_lookAtCenter[0] + translation[0]); + viewOffsetY = (m_lookAtCenter[2] + translation[2]); + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + viewOffsetX = (m_lookAtCenter[1] + translation[1]); + viewOffsetY = (m_lookAtCenter[2] + translation[2]); + break; + } + + float minScreenX = m_orthographicBounds[0] - viewOffsetX; + float maxScreenX = m_orthographicBounds[1] - viewOffsetX; + float minScreenY = m_orthographicBounds[2] - viewOffsetY; + float maxScreenY = m_orthographicBounds[3] - viewOffsetY; + + + /* + * Get origin voxel IJK + */ + const float zeroXYZ[3] = { 0.0, 0.0, 0.0 }; + int64_t originIJK[3]; + m_volumeDrawInfo[0].volumeFile->enclosingVoxel(zeroXYZ[0], zeroXYZ[1], zeroXYZ[2], + originIJK[0], originIJK[1], originIJK[2]); + + + /* + * Get XYZ center of origin Voxel + */ + float originVoxelXYZ[3]; + m_volumeDrawInfo[0].volumeFile->indexToSpace(originIJK, originVoxelXYZ); + float actualOrigin[3]; + m_volumeDrawInfo[0].volumeFile->indexToSpace(originIJK, actualOrigin); + + /* + * Set the corners of the screen for the respective view + */ + std::array bottomLeft; + std::array bottomRight; + std::array topRight; + std::array topLeft; + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + CaretAssert(0); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + bottomLeft[0] = minScreenX; + bottomLeft[1] = minScreenY; + bottomLeft[2] = 0.0; + bottomRight[0] = maxScreenX; + bottomRight[1] = minScreenY; + bottomRight[2] = 0.0; + topRight[0] = maxScreenX; + topRight[1] = maxScreenY; + topRight[2] = 0.0; + topLeft[0] = minScreenX; + topLeft[1] = maxScreenY; + topLeft[2] = 0.0; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + bottomLeft[0] = minScreenX; + bottomLeft[1] = 0.0; + bottomLeft[2] = minScreenY; + bottomRight[0] = maxScreenX; + bottomRight[1] = 0.0; + bottomRight[2] = minScreenY; + topRight[0] = maxScreenX; + topRight[1] = 0.0; + topRight[2] = maxScreenY; + topLeft[0] = minScreenX; + topLeft[1] = 0.0; + topLeft[2] = maxScreenY; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + bottomLeft[0] = 0.0; + bottomLeft[1] = minScreenX; + bottomLeft[2] = minScreenY; + bottomRight[0] = 0.0; + bottomRight[1] = maxScreenX; + bottomRight[2] = minScreenY; + topRight[0] = 0.0; + topRight[1] = maxScreenX; + topRight[2] = maxScreenY; + topLeft[0] = 0.0; + topLeft[1] = minScreenX; + topLeft[2] = maxScreenY; + break; + } + + + /* + * Transform the corners of the screen into model coordinates + */ + transformationMatrix.multiplyPoint3(bottomLeft.data()); + transformationMatrix.multiplyPoint3(bottomRight.data()); + transformationMatrix.multiplyPoint3(topRight.data()); + transformationMatrix.multiplyPoint3(topLeft.data()); + + if (debugFlag) { + const double bottomDist = MathFunctions::distance3D(bottomLeft.data(), bottomRight.data()); + const double topDist = MathFunctions::distance3D(topLeft.data(), topRight.data()); + const double bottomVoxels = bottomDist / voxelSize; + const double topVoxels = topDist / voxelSize; + const AString msg = ("Bottom Dist: " + + AString::number(bottomDist) + + " voxel size: " + + AString::number(bottomVoxels) + + " Top Dist: " + + AString::number(bottomDist) + + " voxel size: " + + AString::number(topVoxels)); + std::cout << qPrintable(msg) << std::endl; + } + + if (debugFlag) { + m_fixedPipelineDrawing->setLineWidth(3.0); + glColor3f(1.0, 0.0, 0.0); + glBegin(GL_LINE_LOOP); + glVertex3fv(bottomLeft.data()); + glVertex3fv(bottomRight.data()); + glVertex3fv(topRight.data()); + glVertex3fv(topLeft.data()); + glEnd(); + } + + /* + * Unit vector and distance in model coords along left side of screen + */ + double bottomLeftToTopLeftUnitVector[3] = { + topLeft[0] - bottomLeft[0], + topLeft[1] - bottomLeft[1], + topLeft[2] - bottomLeft[2], + }; + MathFunctions::normalizeVector(bottomLeftToTopLeftUnitVector); + const double bottomLeftToTopLeftDistance = MathFunctions::distance3D(bottomLeft.data(), + topLeft.data()); + + /* + * Unit vector and distance in model coords along right side of screen + */ + double bottomRightToTopRightUnitVector[3] = { + topRight[0] - bottomRight[0], + topRight[1] - bottomRight[1], + topRight[2] - bottomRight[2] + }; + MathFunctions::normalizeVector(bottomRightToTopRightUnitVector); + const double bottomRightToTopRightDistance = MathFunctions::distance3D(bottomRight.data(), + topRight.data()); + + if ((bottomLeftToTopLeftDistance > 0) + && (bottomRightToTopRightDistance > 0)) { + glPushAttrib(GL_COLOR_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if (m_modelWholeBrain != NULL) { + glAlphaFunc(GL_GEQUAL, 0.95); + glEnable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); + } + else { + glDisable(GL_DEPTH_TEST); + } + + bool firstFlag(true); + for (int32_t iVol = 0; iVol < numVolumes; iVol++) { + const BrainOpenGLFixedPipeline::VolumeDrawInfo& vdi = m_volumeDrawInfo[iVol]; + VolumeMappableInterface* volumeInterface = vdi.volumeFile; + if (volumeInterface != NULL) { + if (debugFlag) { + //std::cout << "Vol: " << iVol << ": " << vf->getFileNameNoPath() << std::endl; + } + + if (firstFlag) { + /* + * Using GL_ONE prevents an edge artifact + * (narrow line on texture edges). + */ + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + firstFlag = false; + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + std::array maxStr = { 1.0, 1.0, 1.0 }; + GLuint textureID = 0; + + if (m_identificationModeFlag) { + auto idIter = s_identificationTextureInfo.find(volumeInterface); + if (idIter != s_identificationTextureInfo.end()) { + TextureInfo textureInfo = idIter->second; + textureID = textureInfo.m_textureID; + maxStr = textureInfo.m_maxSTR; + } + } + else { + auto idIter = s_volumeTextureInfo.find(volumeInterface); + if (idIter != s_volumeTextureInfo.end()) { + TextureInfo textureInfo = idIter->second; + textureID = textureInfo.m_textureID; + maxStr = textureInfo.m_maxSTR; + } + } + + if (textureID == 0) { + m_fixedPipelineDrawing->testForOpenGLError("Before creating texture"); + textureID = createTextureName(volumeInterface, + m_identificationModeFlag, + m_displayGroup, + m_tabIndex, + maxStr); + m_fixedPipelineDrawing->testForOpenGLError("After creating texture"); + if (textureID != 0) { + TextureInfo textureInfo; + textureInfo.m_textureID = textureID; + textureInfo.m_maxSTR = maxStr; + + if (m_identificationModeFlag) { + s_identificationTextureInfo.insert(std::make_pair(volumeInterface, textureInfo)); + } + else { + s_volumeTextureInfo.insert(std::make_pair(volumeInterface, textureInfo)); + } + + /* 1.0 is highest priority texture so that texture is resident */ + const GLclampf priority(1.0); + glPrioritizeTextures(1, &textureID, &priority); + + if (debugFlag) std::cout << "Created texture: " << textureID << std::endl; + + if (debugFlag) { + std::vector dims; + volumeInterface->getDimensions(dims); + if (dims.size() >= 3) { + const int64_t maxI((dims[0] > 1) ? dims[0] - 1 : 0); + const int64_t maxJ((dims[1] > 1) ? dims[1] - 1 : 0); + const int64_t maxK((dims[2] > 1) ? dims[2] - 1 : 0); + int64_t corners[8][3] = { + { 0, 0, 0 }, + { maxI, 0, 0 }, + { maxI, maxJ, 0 }, + { 0, maxJ, 0}, + { 0, 0, maxK }, + { maxI, 0, maxK }, + { maxI, maxJ, maxK }, + { 0, maxJ, maxK} + }; + for (int32_t m = 0; m < 8; m++) { + const int64_t i(corners[m][0]); + const int64_t j(corners[m][1]); + const int64_t k(corners[m][2]); + if (volumeInterface->indexValid(i, j, k)) { + float x, y, z; + volumeInterface->indexToSpace(i, j, k, x, y, z); + std::cout << ("IJK = (" + + AString::number(i) + + "," + + AString::number(j) + + "," + + AString::number(k) + + ")") << std::endl; + std::cout << (" XYZ = (" + + AString::number(x) + + ", " + + AString::number(y) + + ", " + + AString::number(z) + + ")") << std::endl; + + std::array str; + std::array xyz { x, y, z }; + getTextureCoordinates(volumeInterface, xyz, maxStr, str); + std::cout << (" STR = (" + + AString::number(str[0]) + + ", " + + AString::number(str[1]) + + ", " + + AString::number(str[2]) + + ")") << std::endl; + } + } + } + } + } + else { + if (debugFlag) std::cout << "Failed to create texture ID" << std::endl; + } + } + + if (textureID > 0) { + std::array textureBottomLeft; + getTextureCoordinates(volumeInterface, bottomLeft, maxStr, textureBottomLeft); + std::array textureBottomRight; + getTextureCoordinates(volumeInterface, bottomRight, maxStr, textureBottomRight); + std::array textureTopLeft; + getTextureCoordinates(volumeInterface, topLeft, maxStr, textureTopLeft); + std::array textureTopRight; + getTextureCoordinates(volumeInterface, topRight, maxStr, textureTopRight); + + if (debugFlag) { + std::cout << "Bottom Left RST: " << AString::fromNumbers(textureBottomLeft.data(), 3, ", ") << std::endl; + std::cout << "Bottom Right RST: " << AString::fromNumbers(textureBottomRight.data(), 3, ", ") << std::endl; + std::cout << "Top Right RST: " << AString::fromNumbers(textureTopRight.data(), 3, ", ") << std::endl; + std::cout << "Top Left RST: " << AString::fromNumbers(textureTopLeft.data(), 3, ", ") << std::endl; + std::cout << std::endl; + } + + glDisable(GL_CULL_FACE); + m_fixedPipelineDrawing->testForOpenGLError("Before drawing with texture"); + glEnable(GL_TEXTURE_3D); + glBindTexture(GL_TEXTURE_3D, textureID); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + CaretMappableDataFile* mapFile = dynamic_cast(volumeInterface); + CaretAssert(mapFile); + + /* + * Setup pixel to texel filtering + */ + setupTextureFiltering(mapFile, sliceProjectionType); + + glBegin(GL_QUADS); + glColor4f(0.0, 0.0, 1.0, 0.0); + glTexCoord3fv(textureBottomLeft.data()); + glVertex3fv(bottomLeft.data()); + glTexCoord3fv(textureBottomRight.data()); + glVertex3fv(bottomRight.data()); + glTexCoord3fv(textureTopRight.data()); + glVertex3fv(topRight.data()); + glTexCoord3fv(textureTopLeft.data()); + glVertex3fv(topLeft.data()); + glEnd(); + + glBindTexture(GL_TEXTURE_3D, 0); + glDisable(GL_TEXTURE_3D); + m_fixedPipelineDrawing->testForOpenGLError("After drawing with texture"); + + + if (m_identificationModeFlag) { + processTextureVoxelIdentification(volumeInterface); + + /* + * Exit loop so that only underlay volume is used for identification + */ + iVol = numVolumes; + } + } + } + } + + glPopAttrib(); + } +} + +/** + * Process identification from the texture volume + */ +void +BrainOpenGLVolumeTextureSliceDrawing::processTextureVoxelIdentification(VolumeMappableInterface* volumeMappableInterface) +{ + /* + * Saves glPixelStore parameters + */ + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + + /* + * Determine item picked by examination of color in back buffer + * + * QOpenGLWidget Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation). This is + * probably why calls to glReadBuffer() always cause an + * OpenGL error. + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* do not call glReadBuffer() */ +#else + glReadBuffer(GL_BACK); +#endif + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + uint8_t pixels[4]; + glReadPixels((int)m_fixedPipelineDrawing->mouseX, + (int)m_fixedPipelineDrawing->mouseY, + 1, + 1, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixels); + + CaretLogFine("ID color RGBA " + + QString::number(pixels[0]) + ", " + + QString::number(pixels[1]) + ", " + + QString::number(pixels[2]) + ", " + + QString::number(pixels[3])); + + if (debugFlag) std::cout << "Pixel ID: " << AString::fromNumbers(pixels, 4, ",") << std::endl; + + uint32_t alphaInt(pixels[3]); + if (alphaInt == 255) { + uint32_t redInt(pixels[0]); + uint32_t greenInt(pixels[1]); + uint32_t blueInt(pixels[2]); + uint32_t offset = ((redInt << 16) + + (greenInt << 8) + + (blueInt)); + if (debugFlag) std::cout << " Offset: " << offset << std::endl; + + std::vector dims; + volumeMappableInterface->getDimensions(dims); + const int64_t sliceSize = dims[0] * dims[1]; + const int64_t sliceK = offset / sliceSize; + const int64_t sliceOffset = offset % sliceSize; + const int64_t sliceJ = sliceOffset / dims[0]; + const int64_t sliceI = sliceOffset % dims[0]; + if (debugFlag) std::cout << " Voxel IJK: " << sliceI << ", " << sliceJ << ", " << sliceK << std::endl; + + const int64_t voxelIndices[3] { + sliceI, + sliceJ, + sliceK + }; + + /* + * Get depth from depth buffer + */ + glPixelStorei(GL_PACK_ALIGNMENT, 4); + float depth(0.0); + glReadPixels(m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + 1, + 1, + GL_DEPTH_COMPONENT, + GL_FLOAT, + &depth); + + SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); + if (voxelID->isEnabledForSelection()) { + if (voxelID->isOtherScreenDepthCloserToViewer(depth)) { + voxelID->setVoxelIdentification(m_brain, + volumeMappableInterface, + voxelIndices, + depth); + + float voxelCoordinates[3]; + volumeMappableInterface->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], + voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); + + m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelID, + voxelCoordinates); + CaretLogFinest("Selected Voxel (3D): " + AString::fromNumbers(voxelIndices, 3, ",")); + } + } + + SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); + if (voxelEditID->isEnabledForSelection()) { + if (voxelEditID->getVolumeFileForEditing() == volumeMappableInterface) { + if (voxelEditID->isOtherScreenDepthCloserToViewer(depth)) { + voxelEditID->setVoxelIdentification(m_brain, + volumeMappableInterface, + voxelIndices, + depth); + const float floatDiffXYZ[3] = { 1.0, 1.0, 1.0 }; + voxelEditID->setVoxelDiffXYZ(floatDiffXYZ); + + float voxelCoordinates[3]; + volumeMappableInterface->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], + voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); + + m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelEditID, + voxelCoordinates); + CaretLogFinest("Selected Voxel Editing (3D): Indices (" + + AString::fromNumbers(voxelIndices, 3, ",") + + ") Diff XYZ (" + + AString::fromNumbers(floatDiffXYZ, 3, ",") + + ")"); + } + } + } + } + + glPopClientAttrib(); + +} + + +/** + * Set the texture filtering that controls mapping of texels to pixels + * + * @param mapFile + * File is is being drawn + * @param sliceProjectionType + * Type of projection + */ +void +BrainOpenGLVolumeTextureSliceDrawing::setupTextureFiltering(const CaretMappableDataFile* mapFile, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType) +{ + if (mapFile->isMappedWithPalette()) { + + switch (sliceProjectionType) { + case caret::VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + /* + * This combination MIN=Linear, MAG=Nearest + * seems to produce voxel drawing that is + * nearly identical to cubic interpolation when zoomed in so + * that the voxels are large. The difference is when the slices + * are rotated; In cubic interpolation, the "scan lines" are + * horizontal (left to right on the screen) but with texture, + * the "scan lines" follow the volume rotation. + * + * From the OpenGL documentation (man page) + * + * GL_TEXTURE_MIN_FILTER - The texture minifying function is used + * whenever the pixel being textured maps to an area greater than one + * texture element. + * GL_NEAREST - Returns the value of the texture element that is + * nearest (in Manhattan distance) to the center of + * the pixel being textured. + * GL_LINEAR - Returns the weighted average of the four texture + * elements that are closest to the center of the + * pixel being textured. + * + * Pixel area is GREATER THAN texel area so ZOOMED OUT + * + * Thus, Pixel contains more than one texel + */ + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + /* + * GL_TEXTURE_MAG_FILTER - The texture magnification function + * is used when the pixel being textured maps to an area less than or + * equal to one texture element. + * GL_NEAREST - Returns the value of the texture element that is + * nearest (in Manhattan distance) to the center of + * the pixel being textured. + * GL_LINEAR Returns the weighted average of the four texture + * elements that are closest to the center of the + * pixel being textured. + * + * Pixel area is LESS THAN Texel area so ZOOMED IN + * + * Thus, pixel may be inside a texel + * + * If GL_LINEAR is used the voxel "blockiness" is smoothed out + */ + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + } + break; + case caret::VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + { + /* + * No interpolation for orthogonal slice viewing + */ + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + break; + } + + /* + * Option to smooth voxels that removes all "blocki-ness" + */ + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DELELOPER_FLAG_VOXEL_SMOOTH)) { + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + GLfloat borderColor[4] = { 0.0, 0.0, 0.0, 0.0 }; + glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, borderColor); + } + else { + /* + * No interpolation for Label or RGBA data + */ + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } +} + diff --git a/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.h b/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.h new file mode 100644 index 0000000000000000000000000000000000000000..3f9a3df11ddf1ed6e152ebd78929f71c5e8670f0 --- /dev/null +++ b/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.h @@ -0,0 +1,249 @@ +#ifndef __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_H__ +#define __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "BrainOpenGLFixedPipeline.h" +#include "BrainOpenGLVolumeSliceDrawing.h" +#include "CaretObject.h" +#include "DisplayGroupEnum.h" +#include "ModelTypeEnum.h" +#include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" +#include "VolumeSliceProjectionTypeEnum.h" +#include "VolumeSliceDrawingTypeEnum.h" +#include "VolumeSliceViewAllPlanesLayoutEnum.h" +#include "VolumeSliceViewPlaneEnum.h" + +namespace caret { + + class Brain; + class BrowserTabContent; + class CiftiMappableDataFile; + class Matrix4x4; + class ModelVolume; + class ModelWholeBrain; + class Plane; + class VolumeMappableInterface; + + class BrainOpenGLVolumeTextureSliceDrawing : public CaretObject { + + public: + BrainOpenGLVolumeTextureSliceDrawing(); + + virtual ~BrainOpenGLVolumeTextureSliceDrawing(); + + void draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, + BrowserTabContent* browserTabContent, + std::vector& volumeDrawInfo, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, + const int32_t viewport[4]); + + // ADD_NEW_METHODS_HERE + + private: + BrainOpenGLVolumeTextureSliceDrawing(const BrainOpenGLVolumeTextureSliceDrawing&); + + BrainOpenGLVolumeTextureSliceDrawing& operator=(const BrainOpenGLVolumeTextureSliceDrawing&); + + void drawPrivate(BrainOpenGLFixedPipeline* fixedPipelineDrawing, + BrowserTabContent* browserTabContent, + std::vector& volumeDrawInfo, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, + const int32_t viewport[4]); + + void drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const int32_t viewport[4]); + + void drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + const int32_t viewport[4]); + + void drawVolumeSliceViewType(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const int32_t viewport[4]); + + void drawVolumeSliceViewTypeMontage(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const int32_t viewport[4]); + + void drawVolumeSliceViewProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3], + const int32_t viewport[4]); + + void drawObliqueSlice(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + Matrix4x4& transformationMatrix, + const Plane& plane); + + void drawObliqueSliceWithOutlines(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + Matrix4x4& transformationMatrix); + + void createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3], + Plane& planeOut); + + void drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3], + const bool drawCrosshairsFlag, + const bool drawCrosshairLabelsFlag); + + void setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const Plane& plane, + const float sliceCoordinates[3]); + + void getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + float rgbaOut[4]) const; + + void drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const Plane& slicePlane, + const float sliceCoordinates[3]); + + void drawVolumeSliceFoci(const Plane& plane); + + void drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinates[3]); + + bool getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, + float& minSpacingOut, + float& maxSpacingOut) const; + + void drawSquare(const float size); + + void drawOrientationAxes(const int viewport[4]); + + void setOrthographicProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const int viewport[4]); + + bool getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], + float spacingOut[3]); + + void createObliqueTransformationMatrix(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const float sliceCoordinates[3], + Matrix4x4& obliqueTransformationMatrixOut); + + bool getVolumeDrawingViewDependentCulling(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float selectedSliceCoordinate, + const VolumeMappableInterface* volumeFile, + int64_t culledFirstVoxelIJKOut[3], + int64_t culledLastVoxelIJKOut[3], + float voxelDeltaXYZOut[3]); + + bool getTextureCoordinates(const VolumeMappableInterface* volumeMappableInterface, + const std::array& xyz, + const std::array& maxStr, + std::array& strOut) const; + + bool createVolumeTexture(const VolumeMappableInterface* volumeFile, + const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex, + const bool allowNonPowerOfTwoTextureFlag, + const bool identificationTextureFlag, + std::vector& rgbaColorsOut, + std::array& textureDimsOut, + std::array& maxStrOut) const; + + GLuint createTextureName(const VolumeMappableInterface* volumeMappableInterface, + const bool identificationTextureFlag, + const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex, + std::array& maxStrOut) const; + + void setupTextureFiltering(const CaretMappableDataFile* mapFile, + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType); + + void processTextureVoxelIdentification(VolumeMappableInterface* volumeMappableInterface); + + struct TextureInfo { + GLuint m_textureID; + std::array m_maxSTR; + }; + + /* + * These items will eventually be moved into the volume and cifti files + */ + static std::map s_volumeTextureInfo; + static std::map s_identificationTextureInfo; + + ModelVolume* m_modelVolume; + + ModelWholeBrain* m_modelWholeBrain; + + ModelTypeEnum::Enum m_modelType; + + VolumeMappableInterface* m_underlayVolume; + + Brain* m_brain; + + std::vector> m_ciftiMappableFileData; + + BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; + + std::vector m_volumeDrawInfo; + + BrowserTabContent* m_browserTabContent; + + DisplayGroupEnum::Enum m_displayGroup; + + int32_t m_tabIndex; + + double m_lookAtCenter[3]; + +// double m_viewingMatrix[16]; + + double m_orthographicBounds[6]; + + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum m_obliqueSliceMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF; + + bool m_identificationModeFlag; + + // ADD_NEW_MEMBERS_HERE + }; + +#ifdef __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ + std::map BrainOpenGLVolumeTextureSliceDrawing::s_volumeTextureInfo; + std::map BrainOpenGLVolumeTextureSliceDrawing::s_identificationTextureInfo; + +#endif // __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ + +} // namespace +#endif //__BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_H__ diff --git a/src/Brain/BrainStructure.cxx b/src/Brain/BrainStructure.cxx index 59165150b4a76802e36529dcabc5c9f96359f997..33409222acfd771a78a97e06ebaf214519d7177d 100644 --- a/src/Brain/BrainStructure.cxx +++ b/src/Brain/BrainStructure.cxx @@ -45,6 +45,7 @@ #include "SelectionManager.h" #include "LabelFile.h" #include "MathFunctions.h" +#include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "ModelSurface.h" #include "OverlaySet.h" @@ -249,6 +250,15 @@ BrainStructure::addMetricFile(MetricFile* metricFile, if (addFileToBrainStructure) { m_metricFiles.push_back(metricFile); + + /* + * Enable dynamic connectivity using preferences + */ + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + MetricDynamicConnectivityFile* metricDynConn = metricFile->getMetricDynamicConnectivityFile(); + if (metricDynConn != NULL) { + metricDynConn->setEnabledAsLayer(prefs->isDynamicConnectivityDefaultedOn()); + } } } @@ -1136,9 +1146,15 @@ BrainStructure::getAllDataFiles(std::vector& allDataFilesOut) co allDataFilesOut.insert(allDataFilesOut.end(), m_labelFiles.begin(), m_labelFiles.end()); - allDataFilesOut.insert(allDataFilesOut.end(), - m_metricFiles.begin(), - m_metricFiles.end()); + for (auto mf : m_metricFiles) { + allDataFilesOut.push_back(mf); + MetricDynamicConnectivityFile* dynFile = mf->getMetricDynamicConnectivityFile(); + if (dynFile != NULL) { + if (dynFile->isDataValid()) { + allDataFilesOut.push_back(dynFile); + } + } + } allDataFilesOut.insert(allDataFilesOut.end(), m_rgbaFiles.begin(), m_rgbaFiles.end()); @@ -1526,3 +1542,24 @@ BrainStructure::restoreFromScene(const SceneAttributes* sceneAttributes, } +/** + * Match surface sizes to the primary anatomical surface + * + * @param matchStatus + * The match status + */ +void +BrainStructure::matchSurfacesToPrimaryAnatomical(const bool matchStatus) +{ + const Surface* primaryAnatomical = getPrimaryAnatomicalSurface(); + if (primaryAnatomical == NULL) { + return; + } + + for (auto s : m_surfaces) { + if (s != primaryAnatomical) { + s->matchToAnatomicalSurface(primaryAnatomical, + matchStatus); + } + } +} diff --git a/src/Brain/BrainStructure.h b/src/Brain/BrainStructure.h index 1a9f7f5818fc10389daf7321c249a4667753d48e..a6578ece265cd61a6c0dc15809a71cec6d1882e0 100644 --- a/src/Brain/BrainStructure.h +++ b/src/Brain/BrainStructure.h @@ -166,6 +166,8 @@ namespace caret { void initializeOverlays(); + void matchSurfacesToPrimaryAnatomical(const bool matchStatus); + private: const Surface* getPrimaryAnatomicalSurfacePrivate() const; diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 554163132099bec9dad0887ea20f077d0afeb254..b578eee2e01dc8a83abab372c46e528e5ebd5d8b 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -53,6 +53,7 @@ #include "DisplayPropertiesBorders.h" #include "DisplayPropertiesFoci.h" #include "EventAnnotationColorBarGet.h" +#include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" #include "EventCaretMappableDataFileMapsViewedInOverlays.h" #include "EventIdentificationHighlightLocation.h" #include "EventModelGetAll.h" @@ -62,6 +63,7 @@ #include "LabelFile.h" #include "MathFunctions.h" #include "Matrix4x4.h" +#include "MetricDynamicConnectivityFile.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "ModelSurface.h" @@ -87,6 +89,7 @@ #include "ViewingTransformations.h" #include "ViewingTransformationsCerebellum.h" #include "ViewingTransformationsVolume.h" +#include "VolumeDynamicConnectivityFile.h" #include "VolumeSliceSettings.h" #include "VolumeSurfaceOutlineModel.h" #include "VolumeSurfaceOutlineSetModel.h" @@ -100,7 +103,7 @@ using namespace caret; * Number for this tab. */ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) -: CaretObject() +: TabContentBase() { isExecutingConstructor = true; @@ -229,7 +232,6 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS); - isExecutingConstructor = false; /* @@ -1843,6 +1845,81 @@ BrowserTabContent::getSurfaceStructuresDisplayed() return structuresOut; } +/** + * Get data files and their map indices in all displayed overlays. + * + * @param fileAndMapsEvent + * File and maps event to which files and maps are added. + */ +void +BrowserTabContent::getFilesAndMapIndicesInOverlays(EventCaretMappableDataFilesAndMapsInDisplayedOverlays* fileAndMapsEvent) +{ + Model* model = getModelForDisplay(); + if (model == NULL) { + return; + } + + const int32_t tabIndex = getTabNumber(); + + switch (model->getModelType()) { + case ModelTypeEnum::MODEL_TYPE_INVALID: + case ModelTypeEnum::MODEL_TYPE_CHART: + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + { + ModelChartTwo* chartTwoModel = getDisplayedChartTwoModel(); + CaretAssert(chartTwoModel); + ChartTwoOverlaySet* chartOverlaySet = chartTwoModel->getChartTwoOverlaySet(tabIndex); + const int32_t numOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + ChartTwoOverlay* overlay = chartOverlaySet->getOverlay(i); + if (overlay->isEnabled()) { + CaretMappableDataFile* overlayDataFile = NULL; + ChartTwoOverlay::SelectedIndexType indexType; + int32_t mapIndex(0); + overlay->getSelectionData(overlayDataFile, + indexType, + mapIndex); + + if (overlayDataFile != NULL) { + if (mapIndex >= 0) { + fileAndMapsEvent->addChartFileAndMap(overlayDataFile, + mapIndex); + } + } + } + } + } + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + { + OverlaySet* overlaySet = model->getOverlaySet(tabIndex); + const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + Overlay* overlay = overlaySet->getOverlay(i); + if (overlay->isEnabled()) { + CaretMappableDataFile* overlayDataFile = NULL; + int32_t mapIndex; + overlay->getSelectionData(overlayDataFile, + mapIndex); + + if (overlayDataFile != NULL) { + if (mapIndex >= 0) { + fileAndMapsEvent->addBrainordinateFileAndMap(overlayDataFile, + mapIndex); + } + } + } + } + } + break; + } + +} + /** * Get the data files displayed in this tab. * @param displayedDataFilesOut @@ -1989,14 +2066,82 @@ BrowserTabContent::getFilesDisplayedInTab(std::vector& displayed mapIndex); if (overlayDataFile != NULL) { - /* - * Dense dynamic is encapsulated within its parent data-series - * file so include both files. - */ - if (overlayDataFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { - CiftiConnectivityMatrixDenseDynamicFile* dynFile = dynamic_cast(overlayDataFile); - CaretAssert(dynFile); - displayedDataFiles.insert(dynFile->getParentBrainordinateDataSeriesFile()); + switch (overlayDataFile->getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + { + CiftiConnectivityMatrixDenseDynamicFile* dynFile = dynamic_cast(overlayDataFile); + CaretAssert(dynFile); + displayedDataFiles.insert(dynFile->getParentBrainordinateDataSeriesFile()); + } + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + { + MetricDynamicConnectivityFile* metricDynFile = dynamic_cast(overlayDataFile); + CaretAssert(metricDynFile); + displayedDataFiles.insert(metricDynFile); + } + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + { + VolumeDynamicConnectivityFile* volDynFile = dynamic_cast(overlayDataFile); + CaretAssert(volDynFile); + displayedDataFiles.insert(volDynFile->getParentVolumeFile()); + } + break; } displayedDataFiles.insert(overlayDataFile); @@ -2374,12 +2519,120 @@ BrowserTabContent::ventralView() } /** - * Apply mouse rotation to the displayed model. + * Apply volume slice increment while dragging mouse * + * @param viewportContent + * Content of viewport * @param mousePressX * X coordinate of where mouse was pressed. * @param mousePressY + * Y coordinate of where mouse was pressed. + * @param mouseDY + * Change in mouse Y coordinate. + */ +void +BrowserTabContent::applyMouseVolumeSliceIncrement(BrainOpenGLViewportContent* viewportContent, + const int32_t mousePressX, + const int32_t mousePressY, + const int32_t mouseDY) +{ + bool incrementFlag(false); + if (isVolumeSlicesDisplayed()) { + switch (getSliceProjectionType()) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + incrementFlag = true; + break; + } + } + + if ( ! incrementFlag) { + return; + } + if (mouseDY == 0) { + return; + } + + /* + * Prevents "too fast" scrolling. + * If set to a very large number, it will result in the + * slice increment becoming one + */ + int32_t slowDownIncrementer = 3; + + int32_t sliceDelta = mouseDY; + if (sliceDelta > 1) { + sliceDelta /= slowDownIncrementer; + if (sliceDelta == 0) { + sliceDelta = 1; + } + } + else if (sliceDelta < -1) { + sliceDelta /= slowDownIncrementer; + if (sliceDelta == 0) { + sliceDelta = -1; + } + } + + const int32_t tabIndex = viewportContent->getTabIndex(); + VolumeMappableInterface* underlayVolume(NULL); + ModelVolume* volumeModel = getDisplayedVolumeModel(); + if (volumeModel != NULL) { + underlayVolume = volumeModel->getUnderlayVolumeFile(tabIndex); + } + + VolumeSliceViewPlaneEnum::Enum sliceViewPlane = getSliceViewPlane(); + if (sliceViewPlane == VolumeSliceViewPlaneEnum::ALL) { + int viewport[4]; + viewportContent->getModelViewport(viewport); + int sliceViewport[4] = { + viewport[0], + viewport[1], + viewport[2], + viewport[3] + }; + sliceViewPlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, + getSlicePlanesAllViewLayout(), + mousePressX, + mousePressY, + sliceViewport); + } + + /* + * Note: Functions that set slice indices will prevent + * invalid slice indices + */ + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + break; + case VolumeSliceViewPlaneEnum::AXIAL: + setSliceIndexAxial(underlayVolume, + (getSliceIndexAxial(underlayVolume) + sliceDelta)); + break; + case VolumeSliceViewPlaneEnum::CORONAL: + setSliceIndexCoronal(underlayVolume, + (getSliceIndexCoronal(underlayVolume) + sliceDelta)); + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + setSliceIndexParasagittal(underlayVolume, + (getSliceIndexParasagittal(underlayVolume) + sliceDelta)); + break; + } + + updateYokedModelBrowserTabs(); +} + + +/** + * Apply mouse rotation to the displayed model. + * + * @param viewportContent + * Content of viewport + * @param mousePressX * X coordinate of where mouse was pressed. + * @param mousePressY + * Y coordinate of where mouse was pressed. * @param mouseX * X coordinate of mouse. * @param mouseY @@ -2401,146 +2654,153 @@ BrowserTabContent::applyMouseRotation(BrainOpenGLViewportContent* viewportConten if (isVolumeSlicesDisplayed()) { switch (getSliceProjectionType()) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: - { - int viewport[4]; - viewportContent->getModelViewport(viewport); - VolumeSliceViewPlaneEnum::Enum slicePlane = this->getSliceViewPlane(); - int sliceViewport[4] = { - viewport[0], - viewport[1], - viewport[2], - viewport[3] - }; - if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { - slicePlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, - getSlicePlanesAllViewLayout(), - mousePressX, - mousePressY, - sliceViewport); - } - - Matrix4x4 rotationMatrix = getObliqueVolumeRotationMatrix(); - - if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { + if (viewportContent == NULL) { + /* + * When no viewport content is available, apply 'ALL' rotation + */ + Matrix4x4 rotationMatrix = getObliqueVolumeRotationMatrix(); rotationMatrix.rotateX(-mouseDeltaY); rotationMatrix.rotateY(mouseDeltaX); + setObliqueVolumeRotationMatrix(rotationMatrix); } else { - if ((mouseDeltaX != 0) - || (mouseDeltaY != 0)) { - - const int previousMouseX = mouseX - mouseDeltaX; - const int previousMouseY = mouseY - mouseDeltaY; - - /* - * Need to account for the quadrants!!!! - */ - const float viewportCenter[3] = { - (float)(sliceViewport[0] + sliceViewport[2] / 2), - ((float)sliceViewport[1] + sliceViewport[3] / 2), - 0.0 - }; - - const float oldPos[3] = { - (float)previousMouseX, - (float)previousMouseY, - 0.0 - }; - - const float newPos[3] = { - (float)mouseX, - (float)mouseY, - 0.0 - }; - - /* - * Compute normal vector from viewport center to - * old mouse position to new mouse position. - * If normal-Z is positive, mouse has been moved - * in a counter clockwise motion relative to center. - * If normal-Z is negative, mouse has moved clockwise. - */ - float normalDirection[3]; - MathFunctions::normalVectorDirection(viewportCenter, - oldPos, - newPos, - normalDirection); - bool isClockwise = false; - bool isCounterClockwise = false; - if (normalDirection[2] > 0.0) { - isCounterClockwise = true; - } - else if (normalDirection[2] < 0.0) { - isClockwise = true; - } - - if (isClockwise - || isCounterClockwise) { - float mouseDelta = std::sqrt(static_cast((mouseDeltaX * mouseDeltaX) - + (mouseDeltaY * mouseDeltaY))); + int viewport[4]; + viewportContent->getModelViewport(viewport); + VolumeSliceViewPlaneEnum::Enum slicePlane = this->getSliceViewPlane(); + int sliceViewport[4] = { + viewport[0], + viewport[1], + viewport[2], + viewport[3] + }; + if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { + slicePlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, + getSlicePlanesAllViewLayout(), + mousePressX, + mousePressY, + sliceViewport); + } + + Matrix4x4 rotationMatrix = getObliqueVolumeRotationMatrix(); + + if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { + rotationMatrix.rotateX(-mouseDeltaY); + rotationMatrix.rotateY(mouseDeltaX); + } + else { + if ((mouseDeltaX != 0) + || (mouseDeltaY != 0)) { -// /* -// * Rotation needs to be oppposite for newer -// * oblique slice drawing for volumes that -// * do not have a voxel corresponding to -// * the origin. -// */ -// mouseDelta = -mouseDelta; + const int previousMouseX = mouseX - mouseDeltaX; + const int previousMouseY = mouseY - mouseDeltaY; - switch (slicePlane) { - case VolumeSliceViewPlaneEnum::ALL: - { - CaretAssert(0); - } - break; - case VolumeSliceViewPlaneEnum::AXIAL: - { - Matrix4x4 rotation; - if (isClockwise) { - rotation.rotateZ(mouseDelta); - } - else if (isCounterClockwise) { - rotation.rotateZ(-mouseDelta); - } - rotationMatrix.premultiply(rotation); - } - break; - case VolumeSliceViewPlaneEnum::CORONAL: - { - Matrix4x4 rotation; - if (isClockwise) { - rotation.rotateY(-mouseDelta); + /* + * Need to account for the quadrants!!!! + */ + const float viewportCenter[3] = { + (float)(sliceViewport[0] + sliceViewport[2] / 2), + ((float)sliceViewport[1] + sliceViewport[3] / 2), + 0.0 + }; + + const float oldPos[3] = { + (float)previousMouseX, + (float)previousMouseY, + 0.0 + }; + + const float newPos[3] = { + (float)mouseX, + (float)mouseY, + 0.0 + }; + + /* + * Compute normal vector from viewport center to + * old mouse position to new mouse position. + * If normal-Z is positive, mouse has been moved + * in a counter clockwise motion relative to center. + * If normal-Z is negative, mouse has moved clockwise. + */ + float normalDirection[3]; + MathFunctions::normalVectorDirection(viewportCenter, + oldPos, + newPos, + normalDirection); + bool isClockwise = false; + bool isCounterClockwise = false; + if (normalDirection[2] > 0.0) { + isCounterClockwise = true; + } + else if (normalDirection[2] < 0.0) { + isClockwise = true; + } + + if (isClockwise + || isCounterClockwise) { + float mouseDelta = std::sqrt(static_cast((mouseDeltaX * mouseDeltaX) + + (mouseDeltaY * mouseDeltaY))); + + // /* + // * Rotation needs to be oppposite for newer + // * oblique slice drawing for volumes that + // * do not have a voxel corresponding to + // * the origin. + // */ + // mouseDelta = -mouseDelta; + + switch (slicePlane) { + case VolumeSliceViewPlaneEnum::ALL: + { + CaretAssert(0); } - else if (isCounterClockwise) { - rotation.rotateY(mouseDelta); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + { + Matrix4x4 rotation; + if (isClockwise) { + rotation.rotateZ(mouseDelta); + } + else if (isCounterClockwise) { + rotation.rotateZ(-mouseDelta); + } + rotationMatrix.premultiply(rotation); } - rotationMatrix.premultiply(rotation); - } - break; - case VolumeSliceViewPlaneEnum::PARASAGITTAL: - { - Matrix4x4 rotation; - if (isClockwise) { - rotation.rotateX(-mouseDelta); + break; + case VolumeSliceViewPlaneEnum::CORONAL: + { + Matrix4x4 rotation; + if (isClockwise) { + rotation.rotateY(-mouseDelta); + } + else if (isCounterClockwise) { + rotation.rotateY(mouseDelta); + } + rotationMatrix.premultiply(rotation); } - else if (isCounterClockwise) { - rotation.rotateX(mouseDelta); + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + { + Matrix4x4 rotation; + if (isClockwise) { + rotation.rotateX(-mouseDelta); + } + else if (isCounterClockwise) { + rotation.rotateX(mouseDelta); + } + rotationMatrix.premultiply(rotation); } - rotationMatrix.premultiply(rotation); + break; } - break; } } } + + setObliqueVolumeRotationMatrix(rotationMatrix); } - - setObliqueVolumeRotationMatrix(rotationMatrix); - } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; - /* Orthogonal olume slices are not rotated */ - break; } } else if (isChartOneDisplayed() @@ -4543,7 +4803,9 @@ BrowserTabContent::setBrainModelYokingGroup(const YokingGroupEnum::Enum brainMod *m_flatSurfaceViewingTransformation = *btc->m_flatSurfaceViewingTransformation; *m_cerebellumViewingTransformation = *btc->m_cerebellumViewingTransformation; *m_volumeSliceViewingTransformation = *btc->m_volumeSliceViewingTransformation; + const VolumeSliceViewPlaneEnum::Enum slicePlane = m_volumeSliceSettings->getSliceViewPlane(); *m_volumeSliceSettings = *btc->m_volumeSliceSettings; + m_volumeSliceSettings->setSliceViewPlane(slicePlane); // do not yoke the slice plane *m_obliqueVolumeRotationMatrix = *btc->m_obliqueVolumeRotationMatrix; *m_clippingPlaneGroup = *btc->m_clippingPlaneGroup; m_identificationUpdatesVolumeSlices = btc->m_identificationUpdatesVolumeSlices; @@ -4646,7 +4908,9 @@ BrowserTabContent::updateBrainModelYokedBrowserTabs() *btc->m_flatSurfaceViewingTransformation = *m_flatSurfaceViewingTransformation; *btc->m_cerebellumViewingTransformation = *m_cerebellumViewingTransformation; *btc->m_volumeSliceViewingTransformation = *m_volumeSliceViewingTransformation; + const VolumeSliceViewPlaneEnum::Enum slicePlane = btc->m_volumeSliceSettings->getSliceViewPlane(); *btc->m_volumeSliceSettings = *m_volumeSliceSettings; + btc->m_volumeSliceSettings->setSliceViewPlane(slicePlane); // do not yoke the slice plane *btc->m_obliqueVolumeRotationMatrix = *m_obliqueVolumeRotationMatrix; *btc->m_clippingPlaneGroup = *m_clippingPlaneGroup; btc->m_identificationUpdatesVolumeSlices = m_identificationUpdatesVolumeSlices; diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 78f2cda174d495e88785fab16eda0aff876bf965..d9babb5bf90e650d6ccd4e772fd4703d4ff08722 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -31,6 +31,7 @@ #include "ProjectionViewTypeEnum.h" #include "SceneableInterface.h" #include "StructureEnum.h" +#include "TabContentBase.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" @@ -47,6 +48,7 @@ namespace caret { class ChartTwoMatrixDisplayProperties; class ChartTwoOverlaySet; class ClippingPlaneGroup; + class EventCaretMappableDataFilesAndMapsInDisplayedOverlays; class Matrix4x4; class ModelChart; class ModelChartTwo; @@ -70,7 +72,7 @@ namespace caret { class WholeBrainSurfaceSettings; /// Maintains content in a brower's tab - class BrowserTabContent : public CaretObject, public EventListenerInterface, public SceneableInterface { + class BrowserTabContent : public TabContentBase, public EventListenerInterface, public SceneableInterface { public: BrowserTabContent(const int32_t tabNumber); @@ -85,7 +87,7 @@ namespace caret { virtual AString toString() const; - AString getTabName() const; + AString getTabName() const override; AString getUserTabName() const; @@ -151,6 +153,8 @@ namespace caret { void getFilesDisplayedInTab(std::vector& displayedDataFilesOut); + void getFilesAndMapIndicesInOverlays(EventCaretMappableDataFilesAndMapsInDisplayedOverlays* fileAndMapsEvent); + void update(const std::vector models); bool isChartOneModelValid() const; @@ -259,6 +263,11 @@ namespace caret { void ventralView(); + void applyMouseVolumeSliceIncrement(BrainOpenGLViewportContent* viewportContent, + const int32_t mousePressX, + const int32_t mousePressY, + const int32_t mouseDY); + void applyMouseRotation(BrainOpenGLViewportContent* viewportContent, const int32_t mousePressX, const int32_t mousePressY, @@ -428,6 +437,10 @@ namespace caret { void setWholeBrainCerebellumSeparation(const float separation); + ViewingTransformations* getViewingTransformation(); + + const ViewingTransformations* getViewingTransformation() const; + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); @@ -459,17 +472,13 @@ namespace caret { // const int32_t mousePressY, // int sliceViewportOut[4]) const; - ViewingTransformations* getViewingTransformation(); - - const ViewingTransformations* getViewingTransformation() const; - void updateBrainModelYokedBrowserTabs(); void updateYokedModelBrowserTabs(); AString getDefaultName() const; - AString getTabNamePrefix() const; + AString getTabNamePrefix() const override; /** Number of this tab */ int32_t m_tabNumber; diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx index dd63f173444655d842a9e5a2f6ade96ad259cd7a..8c097401fd7b463cd6c92ad19856772eb39905f8 100644 --- a/src/Brain/BrowserWindowContent.cxx +++ b/src/Brain/BrowserWindowContent.cxx @@ -58,7 +58,7 @@ m_windowIndex(windowIndex) m_sceneAssistant->add("m_windowAspectLockedRatio", &m_windowAspectLockedRatio); m_sceneAssistant->add("m_allTabsInWindowAspectRatioLocked", &m_allTabsInWindowAspectRatioLocked); m_sceneAssistant->add("m_tileTabsEnabled", &m_tileTabsEnabled); - m_sceneAssistant->add("m_tileTabsConfigurationMode", + m_sceneAssistant->add("m_tileTabsConfigurationMode", &m_tileTabsConfigurationMode); m_sceneAssistant->add("m_sceneGraphicsWidth", &m_sceneGraphicsWidth); m_sceneAssistant->add("m_sceneGraphicsHeight", &m_sceneGraphicsHeight); @@ -108,7 +108,7 @@ BrowserWindowContent::reset() m_tileTabsEnabled = false; m_sceneGraphicsHeight = 0; m_sceneGraphicsWidth = 0; - m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; m_automaticTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); /* sets rows/columns/factors to defaults */ m_customTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); @@ -222,10 +222,10 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() TileTabsConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: configMode = m_automaticTileTabsConfiguration.get(); break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: configMode = m_customTileTabsConfiguration.get(); break; } @@ -245,10 +245,10 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() const TileTabsConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: configMode = m_automaticTileTabsConfiguration.get(); break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: configMode = m_customTileTabsConfiguration.get(); break; } @@ -296,7 +296,7 @@ BrowserWindowContent::getCustomTileTabsConfiguration() const /** * @return The tile tabs configuration mode. */ -TileTabsConfigurationModeEnum::Enum +TileTabsGridModeEnum::Enum BrowserWindowContent::getTileTabsConfigurationMode() const { return m_tileTabsConfigurationMode; @@ -309,7 +309,7 @@ BrowserWindowContent::getTileTabsConfigurationMode() const * New value for configuration mode. */ void -BrowserWindowContent::setTileTabsConfigurationMode(const TileTabsConfigurationModeEnum::Enum configMode) +BrowserWindowContent::setTileTabsConfigurationMode(const TileTabsGridModeEnum::Enum configMode) { m_tileTabsConfigurationMode = configMode; } @@ -426,19 +426,25 @@ BrowserWindowContent::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - if (m_tileTabsEnabled) { - sceneClass->addString("m_customTileTabsConfiguration", - m_customTileTabsConfiguration->encodeInXML()); - - /* - * Write the tile tabs configuration a second time using - * the old name 'm_sceneTileTabsConfiguration'. This will - * allow the previous version of Workbench to display - * tile tabs correctly. - */ - sceneClass->addString("m_sceneTileTabsConfiguration", - m_customTileTabsConfiguration->encodeInXML()); - } + sceneClass->addString("m_customTileTabsConfigurationLatest", + m_customTileTabsConfiguration->encodeInXML()); + + /* + * Add a tile tabs version one so older versions of wb_view + * may still load the scene correctly + */ + sceneClass->addString("m_customTileTabsConfiguration", + m_customTileTabsConfiguration->encodeVersionInXML(1)); + + /* + * Write the tile tabs configuration a second time using + * the old name 'm_sceneTileTabsConfiguration'. This will + * allow the previous version of Workbench to display + * tile tabs correctly. + */ + sceneClass->addString("m_sceneTileTabsConfiguration", + m_customTileTabsConfiguration->encodeVersionInXML(1)); + sceneClass->addChild(new SceneIntegerArray("m_sceneTabIndices", m_sceneTabIndices)); @@ -480,18 +486,33 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, sceneTabIndicesArray->integerVectorValues(m_sceneTabIndices); } - AString tileTabsConfig = sceneClass->getStringValue("m_customTileTabsConfiguration"); + /* + * Try restoring newest tile tabs configuration + */ + AString tileTabsConfig = sceneClass->getStringValue("m_customTileTabsConfigurationLatest"); + if ( ! tileTabsConfig.isEmpty()) { + /* Since latest was found, restore, but do not use, older configuration to prevent 'not found' warning */ + sceneClass->getStringValue("m_customTileTabsConfiguration"); + } + if (tileTabsConfig.isEmpty()) { + /* Try version one */ + tileTabsConfig = sceneClass->getStringValue("m_customTileTabsConfiguration"); + } if (tileTabsConfig.isEmpty()) { /* Restore an old name for custom configuration */ tileTabsConfig = sceneClass->getStringValue("m_tileTabsConfiguration"); } if ( ! tileTabsConfig.isEmpty()) { - const bool valid = m_customTileTabsConfiguration->decodeFromXML(tileTabsConfig); + AString errorMessage; + const bool valid = m_customTileTabsConfiguration->decodeFromXML(tileTabsConfig, + errorMessage); if ( ! valid) { - sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration from BrowserWindowContent: \"" + sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + + errorMessage + + "\" from BrowserWindowContent: \"" + tileTabsConfig + "\""); - m_customTileTabsConfiguration.reset(); + m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); } /* @@ -508,12 +529,16 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, */ const AString stringTileTabsConfig = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! stringTileTabsConfig.isEmpty()) { - const bool valid = m_customTileTabsConfiguration->decodeFromXML(stringTileTabsConfig); + AString errorMessage; + const bool valid = m_customTileTabsConfiguration->decodeFromXML(stringTileTabsConfig, + errorMessage); if ( ! valid) { - sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration from BrowserWindowContent: \"" + sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + + errorMessage + + "\" from BrowserWindowContent: \"" + stringTileTabsConfig + "\""); - m_customTileTabsConfiguration.reset(); + m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); } } } @@ -523,10 +548,10 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, if (oldTileTabsAutoPrimitive != NULL) { const bool autoModeSelected = oldTileTabsAutoPrimitive->booleanValue(); if (autoModeSelected) { - m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; } else { - m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::CUSTOM; + m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; } } @@ -536,10 +561,10 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, * If tile tabs was enabled, use CUSTOM, otherwise AUTOMATIC */ if (m_tileTabsEnabled) { - m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::CUSTOM; + m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; } else { - m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; } } @@ -594,7 +619,17 @@ BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttribute const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! tileTabsConfigString.isEmpty()) { - m_customTileTabsConfiguration->decodeFromXML(tileTabsConfigString); + AString errorMessage; + const bool valid = m_customTileTabsConfiguration->decodeFromXML(tileTabsConfigString, + errorMessage); + if ( ! valid) { + sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + + errorMessage + + "\" from OLD BrowserWindowContent: \"" + + tileTabsConfigString + + "\""); + m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); + } } const SceneClass* toolbarClass = browserClass->getClass("m_toolbar"); @@ -615,10 +650,10 @@ BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttribute * If tile tabs was enabled, use CUSTOM, otherwise AUTOMATIC */ if (m_tileTabsEnabled) { - m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::CUSTOM; + m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; } else { - m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; } } diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h index 9b4c5763a3a3bdbaf01bec20894a4cf961eb0fab..06567a3a74e73fa3c89652090142acba55871566 100644 --- a/src/Brain/BrowserWindowContent.h +++ b/src/Brain/BrowserWindowContent.h @@ -28,7 +28,7 @@ #include "CaretObject.h" #include "SceneableInterface.h" -#include "TileTabsConfigurationModeEnum.h" +#include "TileTabsGridModeEnum.h" namespace caret { class SceneClassAssistant; @@ -77,9 +77,9 @@ namespace caret { const TileTabsConfiguration* getCustomTileTabsConfiguration() const; - TileTabsConfigurationModeEnum::Enum getTileTabsConfigurationMode() const; + TileTabsGridModeEnum::Enum getTileTabsConfigurationMode() const; - void setTileTabsConfigurationMode(const TileTabsConfigurationModeEnum::Enum configMode); + void setTileTabsConfigurationMode(const TileTabsGridModeEnum::Enum configMode); int32_t getSceneGraphicsWidth() const; @@ -142,7 +142,7 @@ namespace caret { bool m_tileTabsEnabled = false; - TileTabsConfigurationModeEnum::Enum m_tileTabsConfigurationMode = TileTabsConfigurationModeEnum::AUTOMATIC; + TileTabsGridModeEnum::Enum m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; int32_t m_sceneGraphicsWidth = 0; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 84b6f094785beb9b7fff7dec324c75203237f69a..9e40d104d9c7fc5bb1e7ed505545195466a2f366 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -48,6 +48,7 @@ BrainOpenGLTextRenderInterface.h BrainOpenGLViewportContent.h BrainOpenGLVolumeObliqueSliceDrawing.h BrainOpenGLVolumeSliceDrawing.h +BrainOpenGLVolumeTextureSliceDrawing.h BrainOpenGLWindowContent.h BrainStructure.h BrainStructureNodeAttributes.h @@ -60,6 +61,7 @@ ChartingDataManager.h CiftiConnectivityMatrixDataFileManager.h CiftiFiberTrajectoryManager.h ClippingPlaneGroup.h +DataToolTipsManager.h DisplayProperties.h DisplayPropertiesAnnotation.h DisplayPropertiesAnnotationTextSubstitution.h @@ -80,8 +82,8 @@ EventBrainStructureGetAll.h EventBrowserTabGet.h EventBrowserTabGetAll.h EventBrowserTabGetAllViewed.h -EventBrowserTabNew.h EventBrowserWindowContent.h +EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h EventChartOverlayValidate.h EventDataFileAdd.h EventDataFileDelete.h @@ -97,6 +99,8 @@ EventModelSurfaceGet.h EventNodeDataFilesGet.h EventNodeIdentificationColorsGetFromCharts.h EventOverlayValidate.h +EventSceneActive.h +EventSpacerTabGet.h EventSpecFileReadDataFiles.h EventSurfacesGet.h FeatureColoringTypeEnum.h @@ -123,6 +127,11 @@ ModelSurfaceSelector.h ModelTypeEnum.h ModelVolume.h ModelWholeBrain.h +MovieRecorder.h +MovieRecorderCaptureRegionTypeEnum.h +MovieRecorderModeEnum.h +MovieRecorderVideoFormatTypeEnum.h +MovieRecorderVideoResolutionTypeEnum.h Overlay.h OverlaySet.h OverlaySetArray.h @@ -152,6 +161,7 @@ SelectionItemVoxelEditing.h SelectionItemVoxelIdentificationSymbol.h SelectionManager.h SessionManager.h +SpacerTabContent.h Surface.h SurfaceDrawingTypeEnum.h SurfaceMontageConfigurationAbstract.h @@ -163,15 +173,18 @@ SurfaceMontageLayoutOrientationEnum.h SurfaceMontageViewport.h SurfaceNodeColoring.h SurfaceSelectionModel.h +TabContentBase.h +UserInputModeEnum.h ViewingTransformations.h ViewingTransformationsCerebellum.h ViewingTransformationsVolume.h VolumeSliceDrawingTypeEnum.h VolumeSliceInterpolationEdgeEffectsMaskingEnum.h VolumeSliceSettings.h -VolumeSliceViewAllPlanesLayoutEnum.h VolumeSurfaceOutlineColorOrTabModel.h VolumeSurfaceOutlineModel.h +VolumeSurfaceOutlineModelCacheKey.h +VolumeSurfaceOutlineModelCacheValue.h VolumeSurfaceOutlineSetModel.h WholeBrainSurfaceSettings.h WholeBrainVoxelDrawingMode.h @@ -197,6 +210,7 @@ BrainOpenGLTextRenderInterface.cxx BrainOpenGLViewportContent.cxx BrainOpenGLVolumeObliqueSliceDrawing.cxx BrainOpenGLVolumeSliceDrawing.cxx +BrainOpenGLVolumeTextureSliceDrawing.cxx BrainOpenGLWindowContent.cxx BrainStructure.cxx BrainStructureNodeAttributes.cxx @@ -209,6 +223,7 @@ ChartingDataManager.cxx CiftiConnectivityMatrixDataFileManager.cxx CiftiFiberTrajectoryManager.cxx ClippingPlaneGroup.cxx +DataToolTipsManager.cxx DisplayProperties.cxx DisplayPropertiesAnnotation.cxx DisplayPropertiesAnnotationTextSubstitution.cxx @@ -228,8 +243,8 @@ EventBrainStructureGetAll.cxx EventBrowserTabGet.cxx EventBrowserTabGetAll.cxx EventBrowserTabGetAllViewed.cxx -EventBrowserTabNew.cxx EventBrowserWindowContent.cxx +EventCaretMappableDataFilesAndMapsInDisplayedOverlays.cxx EventChartOverlayValidate.cxx EventDataFileAdd.cxx EventDataFileDelete.cxx @@ -245,6 +260,8 @@ EventModelSurfaceGet.cxx EventNodeDataFilesGet.cxx EventNodeIdentificationColorsGetFromCharts.cxx EventOverlayValidate.cxx +EventSceneActive.cxx +EventSpacerTabGet.cxx EventSpecFileReadDataFiles.cxx EventSurfacesGet.cxx FeatureColoringTypeEnum.cxx @@ -270,6 +287,11 @@ ModelSurfaceSelector.cxx ModelTypeEnum.cxx ModelVolume.cxx ModelWholeBrain.cxx +MovieRecorder.cxx +MovieRecorderCaptureRegionTypeEnum.cxx +MovieRecorderModeEnum.cxx +MovieRecorderVideoFormatTypeEnum.cxx +MovieRecorderVideoResolutionTypeEnum.cxx Overlay.cxx OverlaySet.cxx OverlaySetArray.cxx @@ -299,6 +321,7 @@ SelectionItemVoxelIdentificationSymbol.cxx SelectionItemVoxelEditing.cxx SelectionManager.cxx SessionManager.cxx +SpacerTabContent.cxx Surface.cxx SurfaceDrawingTypeEnum.cxx SurfaceMontageConfigurationAbstract.cxx @@ -310,15 +333,18 @@ SurfaceMontageLayoutOrientationEnum.cxx SurfaceMontageViewport.cxx SurfaceNodeColoring.cxx SurfaceSelectionModel.cxx +TabContentBase.cxx +UserInputModeEnum.cxx ViewingTransformations.cxx ViewingTransformationsCerebellum.cxx ViewingTransformationsVolume.cxx VolumeSliceDrawingTypeEnum.cxx VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx VolumeSliceSettings.cxx -VolumeSliceViewAllPlanesLayoutEnum.cxx VolumeSurfaceOutlineColorOrTabModel.cxx VolumeSurfaceOutlineModel.cxx +VolumeSurfaceOutlineModelCacheKey.cxx +VolumeSurfaceOutlineModelCacheValue.cxx VolumeSurfaceOutlineSetModel.cxx WholeBrainSurfaceSettings.cxx WholeBrainVoxelDrawingMode.cxx diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index dc5602ba4ed66ae9212976524c1f0874d0e036e5..ff59dbf9556e85de3b31f41b8039e4bf64dd4d4f 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -739,6 +739,28 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma * and dimensions must also match */ useIt = true; + + /* + * If file is a scalar data series, and the same scalar data series file + * is enabled in a "higher" chart overlay, do not show the file in this + * overlay. Updated to only hide this file in disabled overlays. + */ + const bool enableSdsFilterFlag(false); + if (enableSdsFilterFlag) { + if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + if ( ! isEnabled()) { + for (int32_t io = 0; io < m_overlayIndex; io++) { + const ChartTwoOverlay* otherOverlay = m_parentChartTwoOverlaySet->getOverlay(io); + CaretAssert(otherOverlay); + if (otherOverlay->isEnabled()) { + if (otherOverlay->getSelectedMapFile() == mapFile) { + useIt = false; + } + } + } + } + } + } } } } @@ -1010,10 +1032,21 @@ ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); CaretAssert(chartDelegate); matrixChart = chartDelegate->getMatrixCharting(); -// ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); -// CaretAssert(matrixChart); -// matrixChart->setSelectedRowColumnIndex(m_parentChartTwoOverlaySet->m_tabIndex, -// selectedMapIndex); + + if (m_selectedMapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + ChartableTwoFileLineSeriesChart* lineChart = chartDelegate->getLineSeriesCharting(); + if (lineChart != NULL) { + switch (lineChart->getLineSeriesContentType()) { + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: + lineSeriesChart = lineChart; + break; + } + } + } } break; } @@ -1125,6 +1158,8 @@ ChartTwoOverlay::isAllMapsSupported() const break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -1139,6 +1174,8 @@ ChartTwoOverlay::isAllMapsSupported() const break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } } } diff --git a/src/Brain/DataToolTipsManager.cxx b/src/Brain/DataToolTipsManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..247bcc092710229f57a7d8fa29e6037c528e5de2 --- /dev/null +++ b/src/Brain/DataToolTipsManager.cxx @@ -0,0 +1,349 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __DATA_TOOL_TIPS_MANAGER_DECLARE__ +#include "DataToolTipsManager.h" +#undef __DATA_TOOL_TIPS_MANAGER_DECLARE__ + +#include "Brain.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "EventManager.h" +#include "IdentificationStringBuilder.h" +#include "IdentificationTextGenerator.h" +#include "Overlay.h" +#include "OverlaySet.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" +#include "SelectionManager.h" + +using namespace caret; + +/** + * \class caret::DataToolTipsManager + * \brief Manages Data ToolTips. + * \ingroup Brain + */ + +/** + * Constructor. + * + * @param enabledStatus + * Enabled status for data tool tips + */ +DataToolTipsManager::DataToolTipsManager(const bool enabledStatus) +: CaretObject() +{ + m_enabledFlag = enabledStatus; + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + + /*EventManager::get()->addEventListener(this, EventTypeEnum::);*/ +} + +/** + * Destructor. + */ +DataToolTipsManager::~DataToolTipsManager() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Get text for the tooltip. + * + * @param brain + * The Brain. + * @param browserTab + * Browser tab in which tooltip is displayed + * @param selectionManager + * The selection manager. + */ +AString +DataToolTipsManager::getToolTip(const Brain* brain, + const BrowserTabContent* browserTab, + const SelectionManager* selectionManager) const +{ + CaretAssert(brain); + CaretAssert(browserTab); + CaretAssert(selectionManager); + + IdentificationTextGenerator itg; + const AString text = itg.createToolTipText(brain, + browserTab, + selectionManager, + this); + + return text; +} + +/** + * @return Is tips enabled? + */ +bool +DataToolTipsManager::isEnabled() const +{ + return m_enabledFlag; +} + +/** + * Set status for tips enabled + * + * @param status + * New status. + */ +void +DataToolTipsManager::setEnabled(const bool status) +{ + m_enabledFlag = status; +} + +/** + * @return Is show primary anatomical surface enabled? + */ +bool +DataToolTipsManager::isShowSurfacePrimaryAnatomical() const +{ + return m_showSurfacePrimaryAnatomicalFlag; +} + +/** + * Set status for primary anatomical surface enabled + * + * @param status + * New status. + */ +void +DataToolTipsManager::setShowSurfacePrimaryAnatomical(const bool status) +{ + m_showSurfacePrimaryAnatomicalFlag = status; +} + +/** + * @return Is show viewed surface enabled? + */ +bool +DataToolTipsManager::isShowSurfaceViewed() const +{ + return m_showSurfaceViewedFlag; +} + +/** + * Set status for viewed surface enabled + * + * @param status + * New status. + */ +void +DataToolTipsManager::setShowSurfaceViewed(const bool status) +{ + m_showSurfaceViewedFlag = status; +} + +/** + * @return Is show volume underlayenabled? + */ +bool +DataToolTipsManager::isShowVolumeUnderlay() const +{ + return m_showVolumeUnderlayFlag; +} + +/** + * Set status for volume underlay enabled + * + * @param status + * New status. + */ +void +DataToolTipsManager::setShowVolumeUnderlay(const bool status) +{ + m_showVolumeUnderlayFlag = status; +} + + +/** + * @return Is show top enabled layer enabled? + */ +bool +DataToolTipsManager::isShowTopEnabledLayer() const +{ + return m_showTopEnabledLayerFlag; +} + +/** + * Set status for top layer enabled + * + * @param status + * New status. + */ +void +DataToolTipsManager::setShowTopEnabledLayer(const bool status) +{ + m_showTopEnabledLayerFlag = status; +} + +/** + * @return Is show border enabled? + */ +bool +DataToolTipsManager::isShowBorder() const +{ + return m_showBorderFlag; +} + +/** + * Set status for show border + * + * @param status + * New status. + */ +void +DataToolTipsManager::setShowBorder(const bool status) +{ + m_showBorderFlag = status; +} + +/** + * @return Is show focus enabled? + */ +bool +DataToolTipsManager::isShowFocus() const +{ + return m_showFocusFlag; +} + +/** + * Set status for show focus + * + * @param status + * New status. + */ +void +DataToolTipsManager::setShowFocus(const bool status) +{ + m_showFocusFlag = status; +} + +/** + * @return Is show chart enabled? + */ +bool +DataToolTipsManager::isShowChart() const +{ + return m_showChartFlag; +} + +/** + * Set status for show chart + * + * @param status + * New status. + */ +void +DataToolTipsManager::setShowChart(const bool status) +{ + m_showChartFlag = status; +} + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +DataToolTipsManager::toString() const +{ + return "DataToolTipsManager"; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +DataToolTipsManager::receiveEvent(Event* /*event*/) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +DataToolTipsManager::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "DataToolTipsManager", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +DataToolTipsManager::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Brain/DataToolTipsManager.h b/src/Brain/DataToolTipsManager.h new file mode 100644 index 0000000000000000000000000000000000000000..8b5b00c869c7446b06032e68a0ae7ce0dc6007e1 --- /dev/null +++ b/src/Brain/DataToolTipsManager.h @@ -0,0 +1,144 @@ +#ifndef __DATA_TOOL_TIPS_MANAGER_H__ +#define __DATA_TOOL_TIPS_MANAGER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "EventListenerInterface.h" +#include "SceneableInterface.h" + + +namespace caret { + class Brain; + class BrowserTabContent; + class SceneClassAssistant; + class SelectionItemSurfaceNode; + class SelectionItemVoxel; + class SelectionManager; + + class DataToolTipsManager : public CaretObject, public EventListenerInterface, public SceneableInterface { + + public: + DataToolTipsManager(const bool enabledStatus); + + virtual ~DataToolTipsManager(); + + DataToolTipsManager(const DataToolTipsManager&) = delete; + + DataToolTipsManager& operator=(const DataToolTipsManager&) = delete; + + AString getToolTip(const Brain* brain, + const BrowserTabContent* browserTab, + const SelectionManager* selectionManager) const; + + bool isEnabled() const; + + void setEnabled(const bool status); + + bool isShowSurfacePrimaryAnatomical() const; + + void setShowSurfacePrimaryAnatomical(const bool status); + + bool isShowSurfaceViewed() const; + + void setShowSurfaceViewed(const bool status); + + bool isShowVolumeUnderlay() const; + + void setShowVolumeUnderlay(const bool status); + + bool isShowTopEnabledLayer() const; + + void setShowTopEnabledLayer(const bool status); + + bool isShowBorder() const; + + void setShowBorder(const bool status); + + bool isShowFocus() const; + + void setShowFocus(const bool status); + + bool isShowChart() const; + + void setShowChart(const bool status); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void receiveEvent(Event* event); + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + std::unique_ptr m_sceneAssistant; + + bool m_enabledFlag = true; + + bool m_showSurfacePrimaryAnatomicalFlag = true; + + bool m_showSurfaceViewedFlag = true; + + bool m_showVolumeUnderlayFlag = true; + + bool m_showTopEnabledLayerFlag = true; + + bool m_showBorderFlag = true; + + bool m_showFocusFlag = true; + + bool m_showChartFlag = true; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __DATA_TOOL_TIPS_MANAGER_DECLARE__ + // +#endif // __DATA_TOOL_TIPS_MANAGER_DECLARE__ + +} // namespace +#endif //__DATA_TOOL_TIPS_MANAGER_H__ diff --git a/src/Brain/DisplayPropertiesAnnotation.cxx b/src/Brain/DisplayPropertiesAnnotation.cxx index 71389ade536183a8adaec87c9e1f66efd26bbafa..a0161e89cd9cf5aa3e9d702924491ab5c2caf57f 100644 --- a/src/Brain/DisplayPropertiesAnnotation.cxx +++ b/src/Brain/DisplayPropertiesAnnotation.cxx @@ -89,6 +89,8 @@ DisplayPropertiesAnnotation::updateForNewAnnotation(const Annotation* annotation switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -415,6 +417,9 @@ DisplayPropertiesAnnotation::restoreVersionOne(const SceneClass* sceneClass) case AnnotationCoordinateSpaceEnum::CHART: CaretAssertMessage(0, "This should never happen as CHART SPACE was never available in a version one scene"); break; + case AnnotationCoordinateSpaceEnum::SPACER: + CaretAssertMessage(0, "This should never happen as SPACER TAB SPACE was never available in a version one scene"); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (stereoAnnDisplay != NULL) { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { diff --git a/src/Brain/DisplayPropertiesVolume.cxx b/src/Brain/DisplayPropertiesVolume.cxx index 77392ff7afbdedeef0adb615d90867dad4974bd2..4a98a66c923d891e4b5408ff803a54375d980d99 100644 --- a/src/Brain/DisplayPropertiesVolume.cxx +++ b/src/Brain/DisplayPropertiesVolume.cxx @@ -25,6 +25,7 @@ #include "SceneAttributes.h" #include "SceneClass.h" +#include "SceneClassAssistant.h" using namespace caret; @@ -42,6 +43,9 @@ using namespace caret; DisplayPropertiesVolume::DisplayPropertiesVolume() : DisplayProperties() { + m_opacity = 1.0f; + m_sceneAssistant->add("m_opacity", + &m_opacity); } /** @@ -58,6 +62,7 @@ DisplayPropertiesVolume::~DisplayPropertiesVolume() void DisplayPropertiesVolume::reset() { + m_opacity = 1.0f; } /** @@ -83,6 +88,27 @@ DisplayPropertiesVolume::copyDisplayProperties(const int32_t /*sourceTabIndex*/, { } +/** + * @return The overall surface opacity. + */ +float +DisplayPropertiesVolume::getOpacity() const +{ + return m_opacity; +} + +/** + * Set the overall surface opacity. + * + * @param opacity + * New value for opacity. + */ +void +DisplayPropertiesVolume::setOpacity(const float opacity) +{ + m_opacity = opacity; +} + /** * Create a scene for an instance of a class. * @@ -103,6 +129,8 @@ DisplayPropertiesVolume::saveToScene(const SceneAttributes* sceneAttributes, "DisplayPropertiesVolume", 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; @@ -133,6 +161,9 @@ DisplayPropertiesVolume::restoreFromScene(const SceneAttributes* sceneAttributes return; } + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; diff --git a/src/Brain/DisplayPropertiesVolume.h b/src/Brain/DisplayPropertiesVolume.h index 1dae14a9be5f9bd70b21b8baad40f66ca2e3d79b..fe3f213ecbbf7184fd8f4579d8b5899134687b0e 100644 --- a/src/Brain/DisplayPropertiesVolume.h +++ b/src/Brain/DisplayPropertiesVolume.h @@ -38,6 +38,10 @@ namespace caret { void update(); + float getOpacity() const; + + void setOpacity(const float opacity); + virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); @@ -52,6 +56,7 @@ namespace caret { DisplayPropertiesVolume& operator=(const DisplayPropertiesVolume&); + float m_opacity = 1.0f; }; #ifdef __DISPLAY_PROPERTIES_VOLUME_DECLARE__ diff --git a/src/Brain/DummyFontTextRenderer.cxx b/src/Brain/DummyFontTextRenderer.cxx index 886686e480d7ca4d6052ed4278133b4f4e9780f9..b5a1ccbd21000cdc3e2b4db268f8a093d7a88dd9 100644 --- a/src/Brain/DummyFontTextRenderer.cxx +++ b/src/Brain/DummyFontTextRenderer.cxx @@ -116,6 +116,7 @@ DummyFontTextRenderer::drawTextAtViewportCoords(const double /*viewportX*/, /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. + * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * @@ -127,9 +128,11 @@ DummyFontTextRenderer::drawTextAtViewportCoords(const double /*viewportX*/, * Model Z-coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ void -DummyFontTextRenderer::drawTextAtModelCoords(const double /*modelX*/, +DummyFontTextRenderer::drawTextAtModelCoordsFacingUser(const double /*modelX*/, const double /*modelY*/, const double /*modelZ*/, const AnnotationText& /*annotationText*/, @@ -138,6 +141,71 @@ DummyFontTextRenderer::drawTextAtModelCoords(const double /*modelX*/, } +/** + * Draw text in model space using the current model transformations. + * + * Depth testing is ENABLED when drawing text with this method. + * + * @param annotationText + * Annotation text and attributes. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * If positive, use it to override width/height of viewport. + * @param normalVector + * Normal vector of text. + * @param flags + * Drawing flags. + */ +void +DummyFontTextRenderer::drawTextInModelSpace(const AnnotationText& /* annotationText */, + const float /*modelSpaceScaling*/, + const float /*heightOrWidthForPercentageSizeText*/, + const float* /*normalVector[3]*/, + const DrawingFlags& /* flags */) +{ + +} + +/** + * Get the bounds of text drawn in model space using the current model transformations. + * + * @param annotationText + * Text that is to be drawn. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * Size of region used when converting percentage size to a fixed size + * @param flags + * Drawing flags. + * @param bottomLeftOut + * The bottom left corner of the text bounds. + * @param bottomRightOut + * The bottom right corner of the text bounds. + * @param topRightOut + * The top right corner of the text bounds. + * @param topLeftOut + * The top left corner of the text bounds. + * @param underlineStartOut + * Starting coordinate for drawing text underline. + * @param underlineEndOut + * Ending coordinate for drawing text underline. + */ +void +DummyFontTextRenderer::getBoundsForTextInModelSpace(const AnnotationText& /*annotationText*/, + const float /*modelSpaceScaling*/, + const float /*heightOrWidthForPercentageSizeText*/, + const DrawingFlags& /*flags*/, + double* /*bottomLeftOut[3]*/, + double* /*bottomRightOut[3]*/, + double* /*topRightOut[3]*/, + double* /*topLeftOut[3]*/, + double* /*underlineStartOut[3]*/, + double* /*underlineEndOut[3]*/) +{ + +} + /** * Get the bounds of text (in pixels) using the given text * attributes. diff --git a/src/Brain/DummyFontTextRenderer.h b/src/Brain/DummyFontTextRenderer.h index 6bfe16db248e0635b52768389687a8831cb7b17d..61c114028f34421085e18e856a4e9864663a2ddd 100644 --- a/src/Brain/DummyFontTextRenderer.h +++ b/src/Brain/DummyFontTextRenderer.h @@ -48,12 +48,18 @@ namespace caret { const AnnotationText& annotationText, const DrawingFlags& flags) override; - virtual void drawTextAtModelCoords(const double modelX, + virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const DrawingFlags& flags) override; + virtual void drawTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const float normalVector[3], + const DrawingFlags& flags) override; + virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportWidth, @@ -61,6 +67,17 @@ namespace caret { double& widthOut, double& heightOut) override; + virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const DrawingFlags& flags, + double bottomLeftOut[3], + double bottomRightOut[3], + double topRightOut[3], + double topLeftOut[3], + double underlineStartOut[3], + double underlineEndOut[3]) override; + virtual void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, diff --git a/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.cxx b/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e4ecd5e5755063514865fa5d828f3848a5bf0397 --- /dev/null +++ b/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.cxx @@ -0,0 +1,181 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ +#include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" +#undef __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ + +#include "CaretAssert.h" +#include "CaretMappableDataFile.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventCaretMappableDataFilesAndMapsInDisplayedOverlays + * \brief Get caret mappable files and their map indices in displayed overlays + * \ingroup Brain + */ + +/** + * Constructor. + */ +EventCaretMappableDataFilesAndMapsInDisplayedOverlays::EventCaretMappableDataFilesAndMapsInDisplayedOverlays() +: Event(EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS) +{ + +} + +/** + * Destructor. + */ +EventCaretMappableDataFilesAndMapsInDisplayedOverlays::~EventCaretMappableDataFilesAndMapsInDisplayedOverlays() +{ +} + +/** + * Add file and map displayed in an chart overlay. + * + * @param mapFile + * File to add. + * @param mapIndex + * Index of selected map. + */ +void +EventCaretMappableDataFilesAndMapsInDisplayedOverlays::addChartFileAndMap(CaretMappableDataFile* mapFile, + const int32_t mapIndex) +{ + { + auto iter = m_mapFilesAndIndices.find(mapFile); + if (iter != m_mapFilesAndIndices.end()) { + iter->second.insert(mapIndex); + } + else { + std::set indicesSet; + indicesSet.insert(mapIndex); + m_mapFilesAndIndices.insert(std::make_pair(mapFile, + indicesSet)); + } + } + + auto iter = m_chartMapFilesAndIndices.find(mapFile); + if (iter != m_chartMapFilesAndIndices.end()) { + iter->second.insert(mapIndex); + } + else { + std::set indicesSet; + indicesSet.insert(mapIndex); + m_chartMapFilesAndIndices.insert(std::make_pair(mapFile, + indicesSet)); + } +} + +/** + * Add file and map displayed in an brainordinate (surface/volume) overlay. + * + * @param mapFile + * File to add. + * @param mapIndex + * Index of selected map. + */ +void +EventCaretMappableDataFilesAndMapsInDisplayedOverlays::addBrainordinateFileAndMap(CaretMappableDataFile* mapFile, + const int32_t mapIndex) +{ + { + auto iter = m_mapFilesAndIndices.find(mapFile); + if (iter != m_mapFilesAndIndices.end()) { + iter->second.insert(mapIndex); + } + else { + std::set indicesSet; + indicesSet.insert(mapIndex); + m_mapFilesAndIndices.insert(std::make_pair(mapFile, + indicesSet)); + } + } + + auto iter = m_surfaceVolumeMapFilesAndIndices.find(mapFile); + if (iter != m_surfaceVolumeMapFilesAndIndices.end()) { + iter->second.insert(mapIndex); + } + else { + std::set indicesSet; + indicesSet.insert(mapIndex); + m_surfaceVolumeMapFilesAndIndices.insert(std::make_pair(mapFile, + indicesSet)); + } +} + +/** + * @return Files and maps selected in overlays for both brainordinates + * (surfaces and volumes) and charts. + */ +std::vector +EventCaretMappableDataFilesAndMapsInDisplayedOverlays::getFilesAndMaps() const +{ + std::vector infoOut; + + for (auto iter : m_surfaceVolumeMapFilesAndIndices) { + infoOut.push_back(FileInfo(OverlayType::BRAINORDINATE, + iter.first, + iter.second)); + } + for (auto iter : m_chartMapFilesAndIndices) { + infoOut.push_back(FileInfo(OverlayType::CHART, + iter.first, + iter.second)); + } + + return infoOut; +} + + +/** + * @return Map containing with each pair a map file and map indices selected for the file. + */ +std::map> +EventCaretMappableDataFilesAndMapsInDisplayedOverlays::getMapFilesAndIndices() const +{ + return m_mapFilesAndIndices; +} + +/** + * Constructor. + * + * @param overlayType + * Type of overlay + * @param mapFile + * Map file in the overlay(s) + * @param mapIndices + * Indices of maps selected in overlays + */ +EventCaretMappableDataFilesAndMapsInDisplayedOverlays::FileInfo::FileInfo(OverlayType overlayType, + CaretMappableDataFile* mapFile, + const std::set& mapIndices) +: m_overlayType(overlayType), +m_mapFile(mapFile), +m_mapIndices(mapIndices) +{ +} + diff --git a/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h b/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h new file mode 100644 index 0000000000000000000000000000000000000000..b1af03efda58d2f285c853a68139904e70277f31 --- /dev/null +++ b/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h @@ -0,0 +1,94 @@ +#ifndef __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_H__ +#define __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include + +#include "Event.h" + + + +namespace caret { + + class CaretMappableDataFile; + + class EventCaretMappableDataFilesAndMapsInDisplayedOverlays : public Event { + + public: + enum class OverlayType { + BRAINORDINATE, + CHART + }; + + class FileInfo { + public: + FileInfo(OverlayType overlayType, + CaretMappableDataFile* mapFile, + const std::set& mapIndices); + + const OverlayType m_overlayType; + + CaretMappableDataFile* m_mapFile; + + const std::set m_mapIndices; + }; + + EventCaretMappableDataFilesAndMapsInDisplayedOverlays(); + + virtual ~EventCaretMappableDataFilesAndMapsInDisplayedOverlays(); + + EventCaretMappableDataFilesAndMapsInDisplayedOverlays(const EventCaretMappableDataFilesAndMapsInDisplayedOverlays&) = delete; + + EventCaretMappableDataFilesAndMapsInDisplayedOverlays& operator=(const EventCaretMappableDataFilesAndMapsInDisplayedOverlays&) = delete; + + void addBrainordinateFileAndMap(CaretMappableDataFile* mapFile, + const int32_t mapIndex); + + void addChartFileAndMap(CaretMappableDataFile* mapFile, + const int32_t mapIndex); + + std::map> getMapFilesAndIndices() const; + + std::vector getFilesAndMaps() const; + + // ADD_NEW_METHODS_HERE + + private: + std::map> m_mapFilesAndIndices; + + std::map> m_surfaceVolumeMapFilesAndIndices; + + std::map> m_chartMapFilesAndIndices; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ + // +#endif // __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ + +} // namespace +#endif //__EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_H__ diff --git a/src/Brain/EventSceneActive.cxx b/src/Brain/EventSceneActive.cxx new file mode 100644 index 0000000000000000000000000000000000000000..16472b7e9e146ad3d304a72ac90e884d75a58a94 --- /dev/null +++ b/src/Brain/EventSceneActive.cxx @@ -0,0 +1,91 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_SCENE_ACTIVE_DECLARE__ +#include "EventSceneActive.h" +#undef __EVENT_SCENE_ACTIVE_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventSceneActive + * \brief Event to get/set the active scene + * \ingroup Brain + * + * Event to get/set the active scene. + * The "active scene" is the scene that was last loaded + * or created. If a spec file is loaded or the scene file + * containing the scene is closed, the "active scene" + * becomes invalid. + */ + +/** + * Constructor. + * + * @param mode + * The mode of this event + */ +EventSceneActive::EventSceneActive(const Mode mode) +: Event(EventTypeEnum::EVENT_SCENE_ACTIVE), +m_mode(mode) +{ + +} + +/** + * Destructor. + */ +EventSceneActive::~EventSceneActive() +{ +} + +/** + * @return The mode. + */ +EventSceneActive::Mode +EventSceneActive::getMode() const +{ + return m_mode; +} +/** + * @return The scene + */ +Scene* +EventSceneActive::getScene() const +{ + return m_scene; +} + +/** + * Set the scene + * New value for active scene. + */ +void +EventSceneActive::setScene(Scene* scene) +{ + m_scene = scene; +} + diff --git a/src/Brain/EventSceneActive.h b/src/Brain/EventSceneActive.h new file mode 100644 index 0000000000000000000000000000000000000000..5532f0ae81c4f3f1a0ebcc06da4b53079ee13f61 --- /dev/null +++ b/src/Brain/EventSceneActive.h @@ -0,0 +1,78 @@ +#ifndef __EVENT_SCENE_ACTIVE_H__ +#define __EVENT_SCENE_ACTIVE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class Scene; + + class EventSceneActive : public Event { + + public: + /** The mode of the event */ + enum Mode { + /** Get the active scene */ + MODE_GET, + /** Set the active scene */ + MODE_SET + }; + + EventSceneActive(const Mode mode); + + virtual ~EventSceneActive(); + + Mode getMode() const; + + Scene* getScene() const; + + void setScene(Scene* scene); + + EventSceneActive(const EventSceneActive&) = delete; + + EventSceneActive& operator=(const EventSceneActive&) = delete; + + + // ADD_NEW_METHODS_HERE + + private: + const Mode m_mode; + + Scene* m_scene = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_SCENE_ACTIVE_DECLARE__ + // +#endif // __EVENT_SCENE_ACTIVE_DECLARE__ + +} // namespace +#endif //__EVENT_SCENE_ACTIVE_H__ diff --git a/src/Brain/EventSpacerTabGet.cxx b/src/Brain/EventSpacerTabGet.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9081a16e7f9ca4e7cb042108757c1b7131643b66 --- /dev/null +++ b/src/Brain/EventSpacerTabGet.cxx @@ -0,0 +1,116 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_SPACER_TAB_GET_DECLARE__ +#include "EventSpacerTabGet.h" +#undef __EVENT_SPACER_TAB_GET_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventSpacerTabGet + * \brief Event for getting a spacer tag. + * \ingroup Brain + */ + +/** + * Constructor. + * + * @param windowIndex + * Index of the window + * @param rowIndex + * Index of the row + * @param columnIndex + * Index of the column + */ +EventSpacerTabGet::EventSpacerTabGet(const int32_t windowIndex, + const int32_t rowIndex, + const int32_t columnIndex) +: Event(EventTypeEnum::EVENT_SPACER_TAB_GET), +m_windowIndex(windowIndex), +m_rowIndex(rowIndex), +m_columnIndex(columnIndex), +m_spacerTabContent(NULL) +{ + +} + +/** + * Destructor. + */ +EventSpacerTabGet::~EventSpacerTabGet() +{ +} + +/** + * @return The window index. + */ +int32_t +EventSpacerTabGet::getWindowIndex() const +{ + return m_windowIndex; +} + +/** + * @return The row index. + */ +int32_t +EventSpacerTabGet::getRowIndex() const +{ + return m_rowIndex; +} + +/** + * @return The column index. + */ +int32_t +EventSpacerTabGet::getColumnIndex() const +{ + return m_columnIndex; +} + +/** + * @return The spacer tab. + */ +SpacerTabContent* +EventSpacerTabGet::getSpacerTabContent() +{ + return m_spacerTabContent; +} + +/** + * Set the spacer tab content. + * + * @param spacerTabContent + * New value for the spacer tab content. + */ +void +EventSpacerTabGet::setSpacerTabContent(SpacerTabContent* spacerTabContent) +{ + m_spacerTabContent = spacerTabContent; +} + + diff --git a/src/Brain/EventSpacerTabGet.h b/src/Brain/EventSpacerTabGet.h new file mode 100644 index 0000000000000000000000000000000000000000..d75b52befe2c16762631ec328757338918599be4 --- /dev/null +++ b/src/Brain/EventSpacerTabGet.h @@ -0,0 +1,76 @@ +#ifndef __EVENT_SPACER_TAB_GET_H__ +#define __EVENT_SPACER_TAB_GET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class SpacerTabContent; + + class EventSpacerTabGet : public Event { + + public: + EventSpacerTabGet(const int32_t windowIndex, + const int32_t rowIndex, + const int32_t columnIndex); + + virtual ~EventSpacerTabGet(); + + EventSpacerTabGet(const EventSpacerTabGet&) = delete; + + EventSpacerTabGet& operator=(const EventSpacerTabGet&) = delete; + + int32_t getWindowIndex() const; + + int32_t getRowIndex() const; + + int32_t getColumnIndex() const; + + SpacerTabContent* getSpacerTabContent(); + + void setSpacerTabContent(SpacerTabContent* spacerTabContent); + + // ADD_NEW_METHODS_HERE + + private: + const int32_t m_windowIndex; + const int32_t m_rowIndex; + const int32_t m_columnIndex; + + SpacerTabContent* m_spacerTabContent = NULL; + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_SPACER_TAB_GET_DECLARE__ + // +#endif // __EVENT_SPACER_TAB_GET_DECLARE__ + +} // namespace +#endif //__EVENT_SPACER_TAB_GET_H__ diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 01481d25aad3720aa04c8411422b10b373459675..3b64a324b33be1eb9350f92c6f5c2badea9e7e0f 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -63,6 +63,8 @@ ** ****************************************************************************/ +#ifdef HAVE_FREETYPE + #define __FTGL_FONT_TEXT_RENDERER_DECLARE__ #include "FtglFontTextRenderer.h" #undef __FTGL_FONT_TEXT_RENDERER_DECLARE__ @@ -75,21 +77,23 @@ #include #include +#include "AnnotationCoordinate.h" #include "AnnotationPointSizeText.h" #include "BrainOpenGL.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" +#include "GraphicsEngineDataOpenGL.h" #include "GraphicsOpenGLError.h" +#include "GraphicsPrimitiveV3f.h" +#include "GraphicsPrimitiveV3fN3f.h" #include "GraphicsShape.h" #include "GraphicsUtilitiesOpenGL.h" #include "MathFunctions.h" #include "Matrix4x4.h" -#ifdef HAVE_FREETYPE #include using namespace FTGL; -#endif // HAVE_FREETYPE using namespace caret; @@ -122,7 +126,6 @@ FtglFontTextRenderer::FtglFontTextRenderer() : BrainOpenGLTextRenderInterface() { m_defaultFont = NULL; -#ifdef HAVE_FREETYPE AnnotationPointSizeText defaultAnnotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); defaultAnnotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE14); defaultAnnotationText.setFont(AnnotationTextFontNameEnum::VERA); @@ -130,8 +133,8 @@ FtglFontTextRenderer::FtglFontTextRenderer() defaultAnnotationText.setBoldStyleEnabled(false); defaultAnnotationText.setUnderlineStyleEnabled(false); m_defaultFont = getFont(defaultAnnotationText, + FtglFontTypeEnum::TEXTURE, true); -#endif // HAVE_FREETYPE m_depthTestingStatus = DEPTH_TEST_NO; BrainOpenGL::getMinMaxLineWidth(m_lineWidthMinimum, m_lineWidthMaximum); @@ -142,7 +145,6 @@ FtglFontTextRenderer::FtglFontTextRenderer() */ FtglFontTextRenderer::~FtglFontTextRenderer() { -#ifdef HAVE_FREETYPE for (FONT_MAP_ITERATOR iter = m_fontNameToFontMap.begin(); iter != m_fontNameToFontMap.end(); iter++) { @@ -155,7 +157,6 @@ FtglFontTextRenderer::~FtglFontTextRenderer() * in m_fontNameToFontMap. Doing so would cause * a double delete. */ -#endif // HAVE_FREETYPE } /** @@ -173,6 +174,10 @@ FtglFontTextRenderer::isValid() const * * @param annotationText * Annotation Text that is to be drawn. + * @param ftglFontType + * Type of font. + * @param heightOrWidthForPercentageSizeText + * If positive, use it to override width/height of viewport. * @param creatingDefaultFontFlag * True if creating the default font. * @return @@ -181,15 +186,18 @@ FtglFontTextRenderer::isValid() const */ FTFont* FtglFontTextRenderer::getFont(const AnnotationText& annotationText, + const FtglFontTypeEnum ftglFontType, + const float heightOrWidthForPercentageSizeText, const bool creatingDefaultFontFlag) { -#ifdef HAVE_FREETYPE int32_t viewportWidth = m_viewportWidth; int32_t viewportHeight = m_viewportHeight; switch (annotationText.getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -207,8 +215,29 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, case AnnotationCoordinateSpaceEnum::WINDOW: break; } - const AString fontName = annotationText.getFontRenderingEncodedName(viewportWidth, - viewportHeight); + + if (heightOrWidthForPercentageSizeText > 0.0) { + viewportHeight = heightOrWidthForPercentageSizeText; + viewportWidth = heightOrWidthForPercentageSizeText; + } + + bool tooSmallTextHeightValidFlag = false; + AString fontTypeString; + switch (ftglFontType) { + case FtglFontTypeEnum::POLYGON: + fontTypeString = "Polygon_"; + /* Polygon text is never too small */ + tooSmallTextHeightValidFlag = false; + break; + case FtglFontTypeEnum::TEXTURE: + fontTypeString = "Texture_"; + tooSmallTextHeightValidFlag = true; + break; + } + + const AString fontName = (fontTypeString + + annotationText.getFontRenderingEncodedName(viewportWidth, + viewportHeight)); /* * Has the font already has been created? @@ -222,7 +251,8 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, * Set font "too small" status */ const bool tooSmallFlag = (fontData->m_font->FaceSize() <= AnnotationText::getTooSmallTextHeight()); - annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); + annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag + && tooSmallTextHeightValidFlag); return fontData->m_font; } @@ -231,6 +261,7 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, * Create and save the font */ FontData* fontData = new FontData(annotationText, + ftglFontType, viewportWidth, viewportHeight); if (fontData->m_valid) { @@ -246,8 +277,9 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, * Set font "too small" status */ const bool tooSmallFlag = (fontData->m_font->FaceSize() <= AnnotationText::getTooSmallTextHeight()); - annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); - + annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag + && tooSmallTextHeightValidFlag); + return fontData->m_font; } else { @@ -282,11 +314,32 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, */ annotationText.setFontTooSmallWhenLastDrawn(false); return m_defaultFont; - -#else // HAVE_FREETYPE - CaretLogSevere("Trying to use FTGL Font rendering but FTGL is not valid."); - return NULL; -#endif // HAVE_FREETYPE +} + + +/* + * Get the font with the given font attributes. + * If the font is not created, return the default font. + * + * @param annotationText + * Annotation Text that is to be drawn. + * @param ftglFontType + * Type of font. + * @param creatingDefaultFontFlag + * True if creating the default font. + * @return + * The FTGL font. If there are errors this value will + * be NULL. + */ +FTFont* +FtglFontTextRenderer::getFont(const AnnotationText& annotationText, + const FtglFontTypeEnum ftglFontType, + const bool creatingDefaultFontFlag) +{ + return getFont(annotationText, + ftglFontType, + -1.0, // negative indicates invalid height for percentage text + creatingDefaultFontFlag); } /** @@ -325,16 +378,13 @@ void FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText& annotationText, const TextStringGroup& textStringGroup) { -#ifdef HAVE_FREETYPE FTFont* font = getFont(annotationText, + FtglFontTypeEnum::TEXTURE, false); if (! font) { return; } -// const bool tooSmallFlag = (font->FaceSize() <= s_tooSmallFontSize); -// annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); - if (annotationText.getText().isEmpty()) { return; } @@ -479,25 +529,23 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText glPopMatrix(); } - - if (ts->m_outlineThickness > 0.0) { - glPushMatrix(); - glTranslated(ts->m_viewportX - rotationPointXYZ[0], ts->m_viewportY - rotationPointXYZ[1], 0.0); - - uint8_t foregroundRgba[4]; - annotationText.getLineColorRGBA(foregroundRgba); - drawOutline(ts->m_stringGlyphsMinX, - ts->m_stringGlyphsMaxX, - ts->m_stringGlyphsMinY, - ts->m_stringGlyphsMaxY, - z, - ts->m_outlineThickness, - foregroundRgba); - - glPopMatrix(); - } } + glLoadIdentity(); + + uint8_t foregroundRgba[4]; + annotationText.getLineColorRGBA(foregroundRgba); + if (foregroundRgba[3] > 0) { + GraphicsPrimitiveV3f primitive(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, + foregroundRgba); + primitive.addVertex(topLeft); + primitive.addVertex(bottomLeft); + primitive.addVertex(bottomRight); + primitive.addVertex(topRight); + primitive.setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, + annotationText.getLineWidthPercentage()); + GraphicsEngineDataOpenGL::draw(&primitive); + } glPopMatrix(); BrainOpenGL::testForOpenGLError("At end of " @@ -506,10 +554,6 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText + annotationText.getText()); restoreStateOfOpenGL(); - -#else // HAVE_FREETYPE - CaretLogSevere("Trying to use FTGL Font rendering but it cannot be used due to FreeType not found."); -#endif // HAVE_FREETYPE } /** @@ -539,6 +583,8 @@ FtglFontTextRenderer::drawUnderline(const double lineStartX, /* * Need to enable anti-aliasing for smooth lines */ + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_ENABLE_BIT); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -556,9 +602,7 @@ FtglFontTextRenderer::drawUnderline(const double lineStartX, foregroundRgba, GraphicsPrimitive::LineWidthType::PIXELS, underlineThickness); - - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); + glPopAttrib(); } /** @@ -591,6 +635,8 @@ FtglFontTextRenderer::drawOutline(const double minX, /* * Need to enable anti-aliasing for smooth lines */ + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_ENABLE_BIT); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -600,19 +646,17 @@ FtglFontTextRenderer::drawOutline(const double minX, float bottomRight[3] = { (float)maxX, (float)minY, (float)z }; float topRight[3] = { (float)maxX, (float)maxY, (float)z }; float topLeft[3] = { (float)minX, (float)maxY, (float)z }; - expandBox(bottomLeft, bottomRight, topRight, topLeft, - outlineThickness, outlineThickness); + MathFunctions::expandBox(bottomLeft, bottomRight, topRight, topLeft, + outlineThickness, outlineThickness); GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRgba, GraphicsPrimitive::LineWidthType::PIXELS, outlineThickness); - - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); + glPopAttrib(); } /** - * Expand a box by given amounts in X and Y. + * Draw an outline for 3D using the given coordinates. * * @param bottomLeft * Bottom left corner of annotation. @@ -622,45 +666,33 @@ FtglFontTextRenderer::drawOutline(const double minX, * Top right corner of annotation. * @param topLeft * Top left corner of annotation. - * @param extraSpaceX - * Extra space to add in X. - * @param extraSpaceY - * Extra space to add in Y. + * @param outlineThickness + * Thickness of outline + * @param foregroundRGBA + * Color for drawing outline. */ void -FtglFontTextRenderer::expandBox(float bottomLeft[3], - float bottomRight[3], - float topRight[3], - float topLeft[3], - const float extraSpaceX, - const float extraSpaceY) +FtglFontTextRenderer::drawOutline3D(float bottomLeft[3], + float bottomRight[3], + float topRight[3], + float topLeft[3], + const double outlineThickness, + uint8_t foregroundRgba[4]) { - float widthVector[3]; - MathFunctions::subtractVectors(topRight, topLeft, widthVector); - MathFunctions::normalizeVector(widthVector); - - float heightVector[3]; - MathFunctions::subtractVectors(topLeft, bottomLeft, heightVector); - MathFunctions::normalizeVector(heightVector); - - const float widthSpacingX = extraSpaceX * widthVector[0]; - const float widthSpacingY = extraSpaceY * widthVector[1]; - - const float heightSpacingX = extraSpaceX * heightVector[0]; - const float heightSpacingY = extraSpaceY * heightVector[1]; - - - topLeft[0] += (-widthSpacingX + heightSpacingX); - topLeft[1] += (-widthSpacingY + heightSpacingY); - - topRight[0] += (widthSpacingX + heightSpacingX); - topRight[1] += (widthSpacingY + heightSpacingY); - - bottomLeft[0] += (-widthSpacingX - heightSpacingX); - bottomLeft[1] += (-widthSpacingY - heightSpacingY); + /* + * Need to enable anti-aliasing for smooth lines + */ + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_ENABLE_BIT); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - bottomRight[0] += (widthSpacingX - heightSpacingX); - bottomRight[1] += (widthSpacingY - heightSpacingY); + GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, + foregroundRgba, + GraphicsPrimitive::LineWidthType::PIXELS, outlineThickness); + glPopAttrib(); } /** @@ -752,14 +784,13 @@ FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depth return; } - FTFont* font = getFont(annotationText, false); + FTFont* font = getFont(annotationText, + FtglFontTypeEnum::TEXTURE, + false); if ( ! font) { return; } -// const bool tooSmallFlag = (font->FaceSize() < s_tooSmallFontSize); -// annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); - m_depthTestingStatus = depthTesting; if (annotationText.getLineWidthPercentage() <= 0.0f) { @@ -826,7 +857,9 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann m_viewportWidth = viewportWidth; m_viewportHeight = viewportHeight; - FTFont* font = getFont(annotationText, false); + FTFont* font = getFont(annotationText, + FtglFontTypeEnum::TEXTURE, + false); if ( ! font) { return; } @@ -941,7 +974,9 @@ FtglFontTextRenderer::getBoundsWithoutMarginForTextAtViewportCoords(const Annota m_viewportWidth = viewportWidth; m_viewportHeight = viewportHeight; - FTFont* font = getFont(annotationText, false); + FTFont* font = getFont(annotationText, + FtglFontTypeEnum::TEXTURE, + false); if ( ! font) { return; } @@ -1140,6 +1175,7 @@ FtglFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotatio /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. + * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * @@ -1151,13 +1187,15 @@ FtglFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotatio * Model Z-coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ void -FtglFontTextRenderer::drawTextAtModelCoords(const double modelX, - const double modelY, - const double modelZ, - const AnnotationText& annotationText, - const DrawingFlags& flags) +FtglFontTextRenderer::drawTextAtModelCoordsFacingUser(const double modelX, + const double modelY, + const double modelZ, + const AnnotationText& annotationText, + const DrawingFlags& flags) { setViewportHeight(); @@ -1209,6 +1247,316 @@ FtglFontTextRenderer::drawTextAtModelCoords(const double modelX, } } +/** + * Get the bounds of text drawn in model space using the current model transformations. + * + * @param annotationText + * Text that is to be drawn. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * Size of region used when converting percentage size to a fixed size + * @param flags + * Drawing flags. + * @param bottomLeftOut + * The bottom left corner of the text bounds. + * @param bottomRightOut + * The bottom right corner of the text bounds. + * @param topRightOut + * The top right corner of the text bounds. + * @param topLeftOut + * The top left corner of the text bounds. + * @param underlineStartOut + * Starting coordinate for drawing text underline. + * @param underlineEndOut + * Ending coordinate for drawing text underline. + */ +void +FtglFontTextRenderer::getBoundsForTextInModelSpace(const AnnotationText& annotationText, + const float /*modelSpaceScaling*/, + const float heightOrWidthForPercentageSizeText, + const DrawingFlags& flags, + double bottomLeftOut[3], + double bottomRightOut[3], + double topRightOut[3], + double topLeftOut[3], + double underlineStartOut[3], + double underlineEndOut[3]) +{ + std::fill(bottomLeftOut, bottomLeftOut + 3, 0.0f); + std::fill(bottomRightOut, bottomRightOut + 3, 0.0f); + std::fill(topRightOut, topRightOut + 3, 0.0f); + std::fill(topLeftOut, topLeftOut + 3, 0.0f); + + FTFont* font = getFont(annotationText, + FtglFontTypeEnum::POLYGON, + heightOrWidthForPercentageSizeText, + false); + if (! font) { + return; + } + + + + + const float lineThicknessForViewportHeight(getLineThicknessPixelsInModelSpace(annotationText.getLineWidthPercentage(), + heightOrWidthForPercentageSizeText, + 0.0)); + + TextStringGroup textStringGroup(annotationText, + flags, + font, + 0.0, + 0.0, + 0.0, + annotationText.getRotationAngle(), + lineThicknessForViewportHeight); + + double rotationPointXYZ[3]; + textStringGroup.getViewportBounds(s_textMarginSize, + bottomLeftOut, + bottomRightOut, + topRightOut, + topLeftOut, + rotationPointXYZ); + + underlineStartOut[0] = bottomLeftOut[0]; + underlineStartOut[1] = bottomLeftOut[1]; + underlineStartOut[2] = bottomLeftOut[2]; + underlineEndOut[0] = bottomRightOut[0]; + underlineEndOut[1] = bottomRightOut[1]; + underlineEndOut[2] = bottomRightOut[2]; +} + +/** + * Get the line thickness for model space. + * + * @param lineWidthPercentage + * The line width percentage. + * @param heightOrWidthForPercentageSizeText + * The height/width of region (surface) for percentage size text. + * @param modelSpaceScaling + * Scaling in model space. + */ +float +FtglFontTextRenderer::getLineThicknessPixelsInModelSpace(const float lineWidthPercentage, + const float heightOrWidthForPercentageSizeText, + const float modelSpaceScaling) const +{ + float lineThicknessPercentage = std::max(0.01f, + (lineWidthPercentage / 100.f)); + float lineThicknessPixels = (heightOrWidthForPercentageSizeText + * lineThicknessPercentage); + lineThicknessPixels *= modelSpaceScaling; + + return lineThicknessPixels; +} + + +/** + * Draw text in model space using the current model transformations. + * + * Depth testing is ENABLED when drawing text with this method. + * + * @param annotationText + * Annotation text and attributes. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * If positive, use it to override width/height of viewport. + * @param normalVector + * Normal vector of text. + * @param flags + * Drawing flags. + */ +void +FtglFontTextRenderer::drawTextInModelSpace(const AnnotationText& annotationText, + const float /*modelSpaceScaling*/, + const float heightOrWidthForPercentageSizeText, + const float* /*normalVector[3]*/, + const DrawingFlags& flags) +{ + FTFont* font = getFont(annotationText, + FtglFontTypeEnum::POLYGON, + heightOrWidthForPercentageSizeText, + false); + if (! font) { + return; + } + + const bool drawCrossFlag = false; + if (drawCrossFlag) { + const float a(100.0f); + glLineWidth(3.0); + glBegin(GL_LINES); + glVertex3f(-a, 0, 0); + glVertex3f( a, 0, 0); + glVertex3f(0, -a, 0); + glVertex3f(0, a, 0); + glVertex3f(0, 0,-a); + glVertex3f(0, 0, a); + glEnd(); + } + AString text = (flags.isDrawSubstitutedText() + ? annotationText.getTextWithSubstitutionsApplied() + : annotationText.getText()); + if (text.isEmpty()) { + return; + } + + const float lineThicknessForViewportHeight(getLineThicknessPixelsInModelSpace(annotationText.getLineWidthPercentage(), + heightOrWidthForPercentageSizeText, + 0.0)); + TextStringGroup tsg(annotationText, + flags, + font, + 0.0, + 0.0, + 0.0, + annotationText.getRotationAngle(), + lineThicknessForViewportHeight); + drawTextInModelSpaceInternal(annotationText, + tsg, + heightOrWidthForPercentageSizeText); +} + +/** + * Draw the text piceces at their assigned model space. + * + * @param annotationText + * Annotation text and attributes. + * @param textStringGroup + * Text broken up into characters with positions + * @param heightOrWidthForPercentageSizeText + * If positive, use it to override width/height of viewport. + * + */ +void +FtglFontTextRenderer::drawTextInModelSpaceInternal(const AnnotationText& annotationText, + const TextStringGroup& textStringGroup, + const float heightOrWidthForPercentageSizeText) +{ + FTFont* font = getFont(annotationText, + FtglFontTypeEnum::POLYGON, + heightOrWidthForPercentageSizeText, + false); + if (! font) { + return; + } + + if (annotationText.getText().isEmpty()) { + return; + } + + saveStateOfOpenGL(); + + BrainOpenGL::testForOpenGLError("At beginning of " + "FtglFontTextRenderer::drawTextInModelSpaceInternal " + "while drawing text: " + + annotationText.getText()); + + glEnable(GL_DEPTH_TEST); + + + const double underlineOffsetY = (textStringGroup.m_underlineThickness / 2.0); + + double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3], rotationPointXYZ[3]; + textStringGroup.getViewportBounds(s_textMarginSize, + bottomLeft, bottomRight, topRight, topLeft, rotationPointXYZ); + rotationPointXYZ[2] = 0.0; + + glPushMatrix(); + + applyBackgroundColoring(textStringGroup); + + applyTextColoring(annotationText); + + const float rotationAngle = annotationText.getRotationAngle(); + glTranslated(rotationPointXYZ[0], rotationPointXYZ[1], rotationPointXYZ[2]); + glRotated(rotationAngle, 0.0, 0.0, -1.0); + + glPolygonOffset(-1.0, -1.0); + glEnable(GL_POLYGON_OFFSET_FILL); + for (std::vector::const_iterator iter = textStringGroup.m_textStrings.begin(); + iter != textStringGroup.m_textStrings.end(); + iter++) { + const TextString* ts = *iter; + + double x = ts->m_viewportX; + double y = ts->m_viewportY; + double z = ts->m_viewportZ; + + applyTextColoring(annotationText); + + for (std::vector::const_iterator charIter = ts->m_characters.begin(); + charIter != ts->m_characters.end(); + charIter++) { + const TextCharacter* tc = *charIter; + x += tc->m_offsetX; + y += tc->m_offsetY; + z += tc->m_offsetZ; + + const double offsetX = x - rotationPointXYZ[0]; + const double offsetY = y - rotationPointXYZ[1]; + const double offsetZ = z - rotationPointXYZ[2]; + + glPushMatrix(); + glTranslated(offsetX, + offsetY, + offsetZ); + font->Render(&tc->m_character, + 1); + glPopMatrix(); + } + + if (ts->m_underlineThickness > 0.0) { + glPushMatrix(); + glTranslated(ts->m_viewportX - rotationPointXYZ[0], ts->m_viewportY - rotationPointXYZ[1], 0.0); + + const double underlineY = ts->m_stringGlyphsMinY + underlineOffsetY; + uint8_t foregroundRgba[4]; + annotationText.getTextColorRGBA(foregroundRgba); + drawUnderline(ts->m_stringGlyphsMinX, + ts->m_stringGlyphsMaxX, + underlineY, + z, + ts->m_underlineThickness, + foregroundRgba); + + glPopMatrix(); + } + } + + if (annotationText.getLineColor() != CaretColorEnum::NONE) { + glPushMatrix(); + + uint8_t foregroundRgba[4]; + annotationText.getLineColorRGBA(foregroundRgba); + + const float thickness = ((annotationText.getLineWidthPercentage() / 100.0) + * heightOrWidthForPercentageSizeText); + GraphicsShape::drawOutlineRectangleVerticesAtInside(bottomLeft, + bottomRight, + topRight, + topLeft, + thickness, + foregroundRgba); + + glPopMatrix(); + } + + glDisable(GL_POLYGON_OFFSET_FILL); + glPopMatrix(); + + BrainOpenGL::testForOpenGLError("At end of " + "FtglFontTextRenderer::drawTextInModelSpaceInternal " + "while drawing text: " + + annotationText.getText()); + + restoreStateOfOpenGL(); +} + + /** * Save the state of OpenGL. * Copied from Qt's qgl.cpp, qt_save_gl_state(). @@ -1273,13 +1621,14 @@ FtglFontTextRenderer::FontData::FontData() * Height of the viewport in which text is drawn. */ FtglFontTextRenderer::FontData::FontData(const AnnotationText& annotationText, + const FtglFontTypeEnum ftglFontType, const int32_t viewportWidth, const int32_t viewportHeight) +: m_ftglFontType(ftglFontType) { m_valid = false; m_font = NULL; -#ifdef HAVE_FREETYPE const AnnotationTextFontNameEnum::Enum fontName = annotationText.getFont(); AString fontFileName = AnnotationTextFontNameEnum::getResourceFontFileName(fontName); @@ -1312,8 +1661,16 @@ FtglFontTextRenderer::FontData::FontData(const AnnotationText& annotationText, /* * Create the FTGL font. */ - m_font = new FTTextureFont((const unsigned char*)m_fontData.data(), - numBytes); + switch (m_ftglFontType) { + case FtglFontTypeEnum::POLYGON: + m_font = new FTGLPolygonFont((const unsigned char*)m_fontData.data(), + numBytes); + break; + case FtglFontTypeEnum::TEXTURE: + m_font = new FTTextureFont((const unsigned char*)m_fontData.data(), + numBytes); + break; + } CaretAssert(m_font); @@ -1369,7 +1726,6 @@ FtglFontTextRenderer::FontData::FontData(const AnnotationText& annotationText, m_font = NULL; } } -#endif // HAVE_FREETYPE } /** @@ -1377,12 +1733,10 @@ FtglFontTextRenderer::FontData::FontData(const AnnotationText& annotationText, */ FtglFontTextRenderer::FontData::~FontData() { -#ifdef HAVE_FREETYPE if (m_font != NULL) { delete m_font; m_font = NULL; } -#endif // HAVE_FREETYPE } /** @@ -1488,7 +1842,9 @@ FtglFontTextRenderer::TextCharacter::print(const AString& offsetString) * * @param textString * The text string. - * @parm orientation + * @param textDrawingSpace + * Text drawn in space. + * @param orientation * Orientation of the text string. * @param underlineThickness * Thickness of underline for the text. @@ -1498,11 +1854,13 @@ FtglFontTextRenderer::TextCharacter::print(const AString& offsetString) * Font for drawing the text string. */ FtglFontTextRenderer::TextString::TextString(const QString& textString, + const TextDrawingSpace textDrawingSpace, const AnnotationTextOrientationEnum::Enum orientation, const double underlineThickness, const double outlineThickness, FTFont* font) -: m_underlineThickness(underlineThickness), +: m_textDrawingSpace(textDrawingSpace), +m_underlineThickness(underlineThickness), m_outlineThickness(outlineThickness), m_viewportX(0.0), m_viewportY(0.0), @@ -1512,7 +1870,6 @@ m_stringGlyphsMaxX(0.0), m_stringGlyphsMinY(0.0), m_stringGlyphsMaxY(0.0) { -#ifdef HAVE_FREETYPE /* * Split the string into individual characters. */ @@ -1572,7 +1929,6 @@ m_stringGlyphsMaxY(0.0) * Set the bounds of the characters in this string. */ setGlyphBounds(); -#endif // HAVE_FREETYPE } /** @@ -1610,7 +1966,7 @@ FtglFontTextRenderer::TextString::initializeTextCharacterOffsets(const Annotatio double stringMinX = std::numeric_limits::max(); double stringMaxX = -std::numeric_limits::max(); - const float verticalSpacing = s_textMarginSize * 2.0; + //const float verticalSpacing = s_textMarginSize * 2.0; /* * For each character, set its offset from the previous character @@ -1629,7 +1985,16 @@ FtglFontTextRenderer::TextString::initializeTextCharacterOffsets(const Annotatio if (stackedTextFlag) { double offsetY1 = prevChar->m_glyphMinY; - double offsetY2 = -verticalSpacing; + double offsetY2 = 0.0; + switch (m_textDrawingSpace) { + case TextDrawingSpace::MODEL: + offsetY2 = prevChar->m_glyphMaxY - prevChar->m_glyphMinY; + offsetY2 = -(s_modelSpaceMarginPercentage * offsetY2); + break; + case TextDrawingSpace::VIEWPORT: + offsetY2 = -(s_textMarginSize * 2.0); + break; + } double offsetY3 = -tc->m_glyphMaxY; offsetY = (offsetY1 + offsetY2 + offsetY3); @@ -1851,11 +2216,16 @@ m_underlineThickness(0.0), m_viewportBoundsMinX(0.0), m_viewportBoundsMaxX(0.0), m_viewportBoundsMinY(0.0), -m_viewportBoundsMaxY(0.0) +m_viewportBoundsMaxY(0.0), +m_textDrawingSpace(TextDrawingSpace::VIEWPORT) { -#ifdef HAVE_FREETYPE CaretAssert(font); + m_textDrawingSpace = TextDrawingSpace::VIEWPORT; + if (m_annotationText.isInSurfaceSpaceWithTangentOffset()) { + m_textDrawingSpace = TextDrawingSpace::MODEL; + } + if (annotationText.getText().isEmpty()) { m_viewportBoundsMinX = m_viewportX; m_viewportBoundsMaxX = m_viewportY; @@ -1898,6 +2268,7 @@ m_viewportBoundsMaxY(0.0) for (int32_t i = 0; i < textListSize; i++) { TextString* ts = new TextString(textList.at(i), + m_textDrawingSpace, annotationText.getOrientation(), m_underlineThickness, outlineThickness, @@ -1915,7 +2286,6 @@ m_viewportBoundsMaxY(0.0) * Alignment moves text so bounds need to be updated */ updateTextBounds(); -#endif // HAVE_FREETYPE } /** @@ -2047,14 +2417,23 @@ FtglFontTextRenderer::TextStringGroup::getViewportBounds(const double margin, * Margin is NOT included when rotation point is computed * as it will move the rotation point to the wrong position. */ - bottomLeftOut[0] -= margin; - bottomLeftOut[1] -= margin; - bottomRightOut[0] += margin; - bottomRightOut[1] -= margin; - topRightOut[0] += margin; - topRightOut[1] += margin; - topLeftOut[0] -= margin; - topLeftOut[1] += margin; + double boundsMargin = 0.0; + switch (m_textDrawingSpace) { + case TextDrawingSpace::MODEL: + boundsMargin = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(margin); + break; + case TextDrawingSpace::VIEWPORT: + boundsMargin = margin; + break; + } + bottomLeftOut[0] -= boundsMargin; + bottomLeftOut[1] -= boundsMargin; + bottomRightOut[0] += boundsMargin; + bottomRightOut[1] -= boundsMargin; + topRightOut[0] += boundsMargin; + topRightOut[1] += boundsMargin; + topLeftOut[0] -= boundsMargin; + topLeftOut[1] += boundsMargin; matrix.multiplyPoint3(bottomLeftOut); matrix.multiplyPoint3(bottomRightOut); @@ -2089,7 +2468,16 @@ FtglFontTextRenderer::TextStringGroup::initializeTextPositions() * Move coordinate DOWN for next ROW of text */ const double offsetY1 = prevTextString->m_stringGlyphsMinY; - const double offsetY2 = -(s_textMarginSize * 2.0); + double offsetY2 = 0.0; + switch (m_textDrawingSpace) { + case TextDrawingSpace::MODEL: + offsetY2 = -(prevTextString->m_stringGlyphsMaxY - prevTextString->m_stringGlyphsMinY); + offsetY2 = s_modelSpaceMarginPercentage * offsetY2; + break; + case TextDrawingSpace::VIEWPORT: + offsetY2 = -(s_textMarginSize * 2.0); + break; + } const double offsetY3 = -textString->m_stringGlyphsMaxY; const double offsetY4 = 0.0; const double offsetY = (offsetY1 + offsetY2 + offsetY3 + offsetY4); @@ -2103,7 +2491,16 @@ FtglFontTextRenderer::TextStringGroup::initializeTextPositions() * Move coordinate RIGHT for next COLUMN of text */ const double offsetX1 = prevTextString->m_stringGlyphsMaxX; - const double offsetX2 = s_textMarginSize; + double offsetX2 = 0.0; + switch (m_textDrawingSpace) { + case TextDrawingSpace::MODEL: + offsetX2 = (prevTextString->m_stringGlyphsMaxX - prevTextString->m_stringGlyphsMinX); + offsetX2 = s_modelSpaceMarginPercentage * offsetX2; + break; + case TextDrawingSpace::VIEWPORT: + offsetX2 = s_textMarginSize; + break; + } const double offsetX3 = -textString->m_stringGlyphsMinX; const double offsetX = (offsetX1 + offsetX2 + offsetX3); @@ -2293,3 +2690,5 @@ FtglFontTextRenderer::TextStringGroup::applyAlignmentsToTextStrings() break; } } + +#endif // HAVE_FREETYPE diff --git a/src/Brain/FtglFontTextRenderer.h b/src/Brain/FtglFontTextRenderer.h index c24a8ed4ac765a0c58398dd79655019be25d8ff4..c89a6d11a5243b8f33dcb519338aabfb4dd394c2 100644 --- a/src/Brain/FtglFontTextRenderer.h +++ b/src/Brain/FtglFontTextRenderer.h @@ -1,6 +1,9 @@ + #ifndef __FTGL_FONT_TEXT_RENDERER_H__ #define __FTGL_FONT_TEXT_RENDERER_H__ +#ifdef HAVE_FREETYPE + /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine @@ -52,12 +55,18 @@ namespace caret { const AnnotationText& annotationText, const DrawingFlags& flags) override; - virtual void drawTextAtModelCoords(const double modelX, + virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const DrawingFlags& flags) override; + virtual void drawTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const float normalVector[3], + const DrawingFlags& flags) override; + virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportWidth, @@ -66,6 +75,17 @@ namespace caret { double& heightOut) override; + virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const DrawingFlags& flags, + double bottomLeftOut[3], + double bottomRightOut[3], + double topRightOut[3], + double topLeftOut[3], + double underlineStartOut[3], + double underlineEndOut[3]) override; + virtual void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, @@ -98,6 +118,11 @@ namespace caret { DEPTH_TEST_YES }; + enum class FtglFontTypeEnum { + POLYGON, + TEXTURE + }; + FtglFontTextRenderer(const FtglFontTextRenderer&); FtglFontTextRenderer& operator=(const FtglFontTextRenderer&); @@ -110,6 +135,12 @@ namespace caret { const DrawingFlags& flags); FTFont* getFont(const AnnotationText& annotationText, + const FtglFontTypeEnum ftglFontType, + const bool creatingDefaultFontFlag); + + FTFont* getFont(const AnnotationText& annotationText, + const FtglFontTypeEnum ftglFontType, + const float heightOrWidthForPercentageSizeText, const bool creatingDefaultFontFlag); void drawUnderline(const double lineStartX, @@ -127,21 +158,25 @@ namespace caret { const double outlineThickness, uint8_t foregroundRgba[4]); - static void expandBox(float bottomLeft[3], - float bottomRight[3], - float topRight[3], - float topLeft[3], - const float extraSpaceX, - const float extraSpaceY); + void drawOutline3D(float bottomLeft[3], + float bottomRight[3], + float topRight[3], + float topLeft[3], + const double outlineThickness, + uint8_t foregroundRgba[4]); double getLineWidthFromPercentageHeight(const double percentageHeight) const; + float getLineThicknessPixelsInModelSpace(const float lineWidthPercentage, + const float heightOrWidthForPercentageSizeText, + const float modelSpaceScaling) const; class FontData { public: FontData(); FontData(const AnnotationText& annotationText, + const FtglFontTypeEnum ftglFontType, const int32_t viewportWidth, const int32_t viewportHeight); @@ -149,6 +184,8 @@ namespace caret { void initialize(const AString& fontFileName); + FtglFontTypeEnum m_ftglFontType = FtglFontTypeEnum::TEXTURE; + QByteArray m_fontData; FTFont* m_font; @@ -156,7 +193,19 @@ namespace caret { bool m_valid; }; - + /** + * Drawing space of text + */ + enum class TextDrawingSpace { + /** + * Drawn in model space coordinates + */ + MODEL, + /** + * Drawn in viewport coordinates + */ + VIEWPORT + }; /** * A text character @@ -201,6 +250,7 @@ namespace caret { class TextString { public: TextString(const QString& textString, + const TextDrawingSpace textDrawingSpace, const AnnotationTextOrientationEnum::Enum orientation, const double underlineThickness, const double outlineThickness, @@ -217,6 +267,7 @@ namespace caret { double& viewportMinY, double& viewportMaxY) const; + const TextDrawingSpace m_textDrawingSpace; const double m_underlineThickness; const double m_outlineThickness; @@ -288,6 +339,7 @@ namespace caret { double m_viewportBoundsMinY; double m_viewportBoundsMaxY; + TextDrawingSpace m_textDrawingSpace; private: void applyAlignmentsToHorizontalTextStrings(); void applyAlignmentsToStackedTextStrings(); @@ -300,6 +352,10 @@ namespace caret { void drawTextAtViewportCoordinatesInternal(const AnnotationText& annotationText, const TextStringGroup& textStringGroup); + void drawTextInModelSpaceInternal(const AnnotationText& annotationText, + const TextStringGroup& textStringGroup, + const float heightOrWidthForPercentageSizeText); + void applyTextColoring(const AnnotationText& annotationText); void applyBackgroundColoring(const TextStringGroup& textStringGroup); @@ -351,11 +407,16 @@ namespace caret { float m_lineWidthMaximum = 5.0f; static const double s_textMarginSize; + static const double s_modelSpaceMarginPercentage; }; #ifdef __FTGL_FONT_TEXT_RENDERER_DECLARE__ const double FtglFontTextRenderer::s_textMarginSize = 3.0; + const double FtglFontTextRenderer::s_modelSpaceMarginPercentage = 0.2; #endif // __FTGL_FONT_TEXT_RENDERER_DECLARE__ } // namespace + +#endif // HAVE_FREETYPE + #endif //__FTGL_FONT_TEXT_RENDERER_H__ diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index d8343cccd579894248e0ebea6c3f33b2ed7c6260..fe5ec45c7f2cf6c2a6d21b8e108352530775eea0 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -41,15 +41,19 @@ #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiMappableDataFile.h" #include "CaretVolumeExtension.h" +#include "DataToolTipsManager.h" #include "EventBrowserTabGetAll.h" #include "EventManager.h" #include "FileInformation.h" #include "FociFile.h" #include "Focus.h" #include "GiftiLabel.h" +#include "GraphicsPrimitive.h" +#include "GraphicsPrimitiveV3f.h" #include "Histogram.h" #include "ImageFile.h" #include "MapFileDataSelector.h" +#include "MetricDynamicConnectivityFile.h" #include "OverlaySet.h" #include "SelectionItemBorderSurface.h" #include "SelectionItemChartDataSeries.h" @@ -70,6 +74,7 @@ #include "LabelFile.h" #include "MetricFile.h" #include "Surface.h" +#include "VolumeDynamicConnectivityFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" @@ -126,17 +131,19 @@ IdentificationTextGenerator::createIdentificationText(const SelectionManager* id surfaceID); this->generateSurfaceBorderIdentifcationText(idText, - idManager->getSurfaceBorderIdentification()); + idManager->getSurfaceBorderIdentification(), + false); this->generateSurfaceFociIdentifcationText(idText, - idManager->getSurfaceFocusIdentification()); + idManager->getSurfaceFocusIdentification(), + false); this->generateVolumeFociIdentifcationText(idText, idManager->getVolumeFocusIdentification()); this->generateVolumeIdentificationText(idText, brain, - idManager->getVoxelIdentification()); + idManager->getVoxelIdentification()); this->generateChartDataSeriesIdentificationText(idText, idManager->getChartDataSeriesIdentification()); @@ -168,6 +175,64 @@ IdentificationTextGenerator::createIdentificationText(const SelectionManager* id return idText.toString(); } +/** + * Get text for the tooltip for a selected node. + * + * @param brain + * The Brain. + * @param browserTab + * Browser tab in which tooltip is displayed + * @param selectionManager + * The selection manager. + * @param dataToolTipsManager + * The data tooltips manager + * @param idText + * String builder for identification text. + */ +AString +IdentificationTextGenerator::createToolTipText(const Brain* brain, + const BrowserTabContent* browserTab, + const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager) const +{ + CaretAssert(brain); + CaretAssert(browserTab); + CaretAssert(selectionManager); + CaretAssert(dataToolTipsManager); + + const SelectionItemSurfaceNode* selectedNode = selectionManager->getSurfaceNodeIdentification(); + const SelectionItemVoxel* selectedVoxel = selectionManager->getVoxelIdentification(); + + IdentificationStringBuilder idText; + + if (selectedNode->isValid()) { + generateSurfaceToolTip(brain, + browserTab, + selectionManager, + dataToolTipsManager, + idText); + } + else if (selectedVoxel->isValid()) { + generateVolumeToolTip(browserTab, + selectionManager, + dataToolTipsManager, + idText); + } + else { + generateChartToolTip(selectionManager, + dataToolTipsManager, + idText); + } + + AString text; + if (idText.length() > 0) { + text = idText.toStringWithHtmlBodyForToolTip(); + } + + return text; +} + + /** * Generate identification text for volume voxel identification. * @@ -213,6 +278,13 @@ IdentificationTextGenerator::generateVolumeIdentificationText(IdentificationStri for (int32_t i = 0; i < numVolumeFiles; i++) { const VolumeFile* vf = brain->getVolumeFile(i); volumeInterfaces.push_back(vf); + + const VolumeDynamicConnectivityFile* volDynConnFile = vf->getVolumeDynamicConnectivityFile(); + if (volDynConnFile != NULL) { + if (volDynConnFile->isDataValid()) { + volumeInterfaces.push_back(volDynConnFile); + } + } } /* @@ -320,6 +392,10 @@ IdentificationTextGenerator::generateVolumeIdentificationText(IdentificationStri } } + if (dynamic_cast(volumeFile) != NULL) { + boldText.insert(0, + (DataFileTypeEnum::toOverlayTypeName(DataFileTypeEnum::VOLUME_DYNAMIC) + " ")); + } idText.addLine(true, boldText, text); @@ -385,6 +461,8 @@ IdentificationTextGenerator::generateVolumeIdentificationText(IdentificationStri break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -400,6 +478,8 @@ IdentificationTextGenerator::generateVolumeIdentificationText(IdentificationStri break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } if (limitMapIndicesFlag) { getMapIndicesOfFileUsedInOverlays(ciftiFile, @@ -537,6 +617,8 @@ IdentificationTextGenerator::generateSurfaceIdentificationText(IdentificationStr break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -552,6 +634,8 @@ IdentificationTextGenerator::generateSurfaceIdentificationText(IdentificationStr break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } if (limitMapIndicesFlag) { getMapIndicesOfFileUsedInOverlays(cmdf, @@ -575,7 +659,7 @@ IdentificationTextGenerator::generateSurfaceIdentificationText(IdentificationStr const int32_t numLabelFiles = brainStructure->getNumberOfLabelFiles(); for (int32_t i = 0; i < numLabelFiles; i++) { const LabelFile* lf = brainStructure->getLabelFile(i); - AString boldText = "LABEL " + lf->getFileNameNoPath() + ":"; + AString boldText = "LABEL " + lf->getFileNameNoPath(); AString text; const int numMaps = lf->getNumberOfMaps(); for (int32_t j = 0; j < numMaps; j++) { @@ -588,19 +672,34 @@ IdentificationTextGenerator::generateSurfaceIdentificationText(IdentificationStr idText.addLine(true, boldText, text); } + std::vector metricDynConFiles; const int32_t numMetricFiles = brainStructure->getNumberOfMetricFiles(); for (int32_t i = 0; i < numMetricFiles; i++) { const MetricFile* mf = brainStructure->getMetricFile(i); - AString boldText = "METRIC " + mf->getFileNameNoPath() + ":"; + AString boldText = "METRIC " + mf->getFileNameNoPath(); AString text; const int numMaps = mf->getNumberOfMaps(); for (int32_t j = 0; j < numMaps; j++) { text += (" " + AString::number(mf->getValue(nodeNumber, j))); } idText.addLine(true, boldText, text); + + const MetricDynamicConnectivityFile* mdcf = mf->getMetricDynamicConnectivityFile(); + if (mdcf != NULL) { + if (mdcf->isDataValid()) { + if (mdcf->isEnabledAsLayer()) { + AString boldText = "METRIC DYNAMIC " + mdcf->getFileNameNoPath(); + AString text; + const int numMaps = mdcf->getNumberOfMaps(); + for (int32_t j = 0; j < numMaps; j++) { + text += (" " + AString::number(mdcf->getValue(nodeNumber, j))); + } + idText.addLine(true, boldText, text); + } + } + } } } - } /** @@ -811,16 +910,39 @@ IdentificationTextGenerator::generateChartTwoLineSeriesIdentificationText(Identi const MapFileDataSelector* mapFileDataSelector = cartesianData->getMapFileDataSelector(); CaretAssert(mapFileDataSelector); - const int32_t primitiveIndex = idChartTwoLineSeries->getLineSegmentIndex(); + int32_t primitiveIndex = idChartTwoLineSeries->getLineSegmentIndex(); AString boldText("Line Chart"); idText.addLine(false, boldText, mapFile->getFileNameNoPath()); - idText.addLine(true, - "Line Segment Index", - (AString::number(primitiveIndex))); + cartesianData->getGraphicsPrimitive(); + const GraphicsPrimitive* primitive = cartesianData->getGraphicsPrimitive(); + CaretAssert(primitive); + + if (primitiveIndex >= 1) { + float xyz1[3]; + primitive->getVertexFloatXYZ(primitiveIndex - 1, + xyz1); + float xyz2[3]; + primitive->getVertexFloatXYZ(primitiveIndex, + xyz2); + idText.addLine(true, + "XY Start", + AString::fromNumbers(xyz1, 2, ", ")); + idText.addLine(true, + "XY End ", + AString::fromNumbers(xyz2, 2, ", ")); + } + else { + float xyz[3]; + primitive->getVertexFloatXYZ(primitiveIndex, + xyz); + idText.addLine(true, + "XY", + AString::fromNumbers(xyz, 2, ", ")); + } generateMapFileSelectorText(idText, mapFileDataSelector); @@ -1046,7 +1168,7 @@ IdentificationTextGenerator::generateMapFileSelectorText(IdentificationStringBui mapFileName); idText.addLine(true, "Column Index", - AString::number(columnIndex)); + AString::number(columnIndex + 1)); } break; case MapFileDataSelector::DataSelectionType::ROW_DATA: @@ -1063,7 +1185,7 @@ IdentificationTextGenerator::generateMapFileSelectorText(IdentificationStringBui mapFileName); idText.addLine(true, "Row Index", - AString::number(rowIndex)); + AString::number(rowIndex + 1)); } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: @@ -1146,10 +1268,13 @@ IdentificationTextGenerator::generateChartTimeSeriesIdentificationText(Identific * String builder for identification text. * @param idSurfaceBorder * Information for surface border ID. + * @param toolTipFlag + * True if this is for tooltip. */ void IdentificationTextGenerator::generateSurfaceBorderIdentifcationText(IdentificationStringBuilder& idText, - const SelectionItemBorderSurface* idSurfaceBorder) const + const SelectionItemBorderSurface* idSurfaceBorder, + const bool toolTipFlag) const { if (idSurfaceBorder->isValid()) { const Border* border = idSurfaceBorder->getBorder(); @@ -1157,23 +1282,36 @@ IdentificationTextGenerator::generateSurfaceBorderIdentifcationText(Identificati float xyz[3]; spi->getProjectedPosition(*idSurfaceBorder->getSurface(), xyz, false); - AString boldText = ("BORDER " - + StructureEnum::toGuiName(spi->getStructure()) - + " Name: " - + border->getName()); - if (border->getClassName().isEmpty() == false) { - boldText += (" ClassName: " - + border->getClassName() - + ": "); + if (toolTipFlag) { + bool indentFlag = false; + idText.addLine(indentFlag, + "Border", + border->getName()); + indentFlag = true; + idText.addLine(indentFlag, + "XYZ", + AString::fromNumbers(xyz, 3, ",")); + } + else { + AString boldText = ("BORDER " + + StructureEnum::toGuiName(spi->getStructure()) + + " Name: " + + border->getName()); + if (border->getClassName().isEmpty() == false) { + boldText += (" ClassName: " + + border->getClassName() + + ": "); + } + + const AString text = ("(" + + AString::number(idSurfaceBorder->getBorderIndex()) + + "," + + AString::number(idSurfaceBorder->getBorderPointIndex()) + + ") (" + + AString::fromNumbers(xyz, 3, ",") + + ")"); + idText.addLine(false, boldText, text); } - const AString text = ("(" - + AString::number(idSurfaceBorder->getBorderIndex()) - + "," - + AString::number(idSurfaceBorder->getBorderPointIndex()) - + ") (" - + AString::fromNumbers(xyz, 3, ",") - + ")"); - idText.addLine(false, boldText, text); } } @@ -1183,121 +1321,139 @@ IdentificationTextGenerator::generateSurfaceBorderIdentifcationText(Identificati * String builder for identification text. * @param idSurfaceFocus * Information for surface focus ID. - */void + * @param toolTipFlag + * True if this is for tooltip. + */ +void IdentificationTextGenerator::generateSurfaceFociIdentifcationText(IdentificationStringBuilder& idText, - const SelectionItemFocusSurface* idSurfaceFocus) const + const SelectionItemFocusSurface* idSurfaceFocus, + const bool toolTipFlag) const { if (idSurfaceFocus->isValid()) { const Focus* focus = idSurfaceFocus->getFocus(); - idText.addLine(false, - "FOCUS", - focus->getName()); - - idText.addLine(true, - "Index", - AString::number(idSurfaceFocus->getFocusIndex())); - const int32_t projectionIndex = idSurfaceFocus->getFocusProjectionIndex(); const SurfaceProjectedItem* spi = focus->getProjection(projectionIndex); - float xyzProj[3]; - spi->getProjectedPosition(*idSurfaceFocus->getSurface(), xyzProj, false); float xyzStereo[3]; spi->getStereotaxicXYZ(xyzStereo); - - idText.addLine(true, - "Structure", - StructureEnum::toGuiName(spi->getStructure())); - - if (spi->isStereotaxicXYZValid()) { - idText.addLine(true, - "XYZ (Stereotaxic)", - xyzStereo, - 3, - true); + if (toolTipFlag) { + bool indentFlag = false; + idText.addLine(indentFlag, + "Focus", + focus->getName()); + indentFlag = true; + idText.addLine(indentFlag, + "XYZ", + (spi->isStereotaxicXYZValid() + ? AString::fromNumbers(xyzStereo, 3, ",") + : "Invalid")); } else { + idText.addLine(false, + "FOCUS", + focus->getName()); + idText.addLine(true, - "XYZ (Stereotaxic)", - "Invalid"); - } - - bool projValid = false; - AString xyzProjName = "XYZ (Projected)"; - if (spi->getBarycentricProjection()->isValid()) { - xyzProjName = "XYZ (Projected to Triangle)"; - projValid = true; - } - else if (spi->getVanEssenProjection()->isValid()) { - xyzProjName = "XYZ (Projected to Edge)"; - projValid = true; - } - if (projValid) { - idText.addLine(true, - xyzProjName, - xyzProj, - 3, - true); - } - else { + "Index", + AString::number(idSurfaceFocus->getFocusIndex())); + + float xyzProj[3]; + spi->getProjectedPosition(*idSurfaceFocus->getSurface(), xyzProj, false); + idText.addLine(true, - xyzProjName, - "Invalid"); - } - - const int32_t numberOfProjections = focus->getNumberOfProjections(); - for (int32_t i = 0; i < numberOfProjections; i++) { - if (i != projectionIndex) { - const SurfaceProjectedItem* proj = focus->getProjection(i); - AString projTypeName = ""; - if (proj->getBarycentricProjection()->isValid()) { - projTypeName = "Triangle"; - - } - else if (proj->getVanEssenProjection()->isValid()) { - projTypeName = "Edge"; - } - if (projTypeName.isEmpty() == false) { - const AString txt = (StructureEnum::toGuiName(proj->getStructure()) - + " (" - + projTypeName - + ")"); - - idText.addLine(true, - "Ambiguous Projection", - txt); + "Structure", + StructureEnum::toGuiName(spi->getStructure())); + + if (spi->isStereotaxicXYZValid()) { + idText.addLine(true, + "XYZ (Stereotaxic)", + xyzStereo, + 3, + true); + } + else { + idText.addLine(true, + "XYZ (Stereotaxic)", + "Invalid"); + } + + bool projValid = false; + AString xyzProjName = "XYZ (Projected)"; + if (spi->getBarycentricProjection()->isValid()) { + xyzProjName = "XYZ (Projected to Triangle)"; + projValid = true; + } + else if (spi->getVanEssenProjection()->isValid()) { + xyzProjName = "XYZ (Projected to Edge)"; + projValid = true; + } + if (projValid) { + idText.addLine(true, + xyzProjName, + xyzProj, + 3, + true); + } + else { + idText.addLine(true, + xyzProjName, + "Invalid"); + } + + const int32_t numberOfProjections = focus->getNumberOfProjections(); + for (int32_t i = 0; i < numberOfProjections; i++) { + if (i != projectionIndex) { + const SurfaceProjectedItem* proj = focus->getProjection(i); + AString projTypeName = ""; + if (proj->getBarycentricProjection()->isValid()) { + projTypeName = "Triangle"; + + } + else if (proj->getVanEssenProjection()->isValid()) { + projTypeName = "Edge"; + } + if (projTypeName.isEmpty() == false) { + const AString txt = (StructureEnum::toGuiName(proj->getStructure()) + + " (" + + projTypeName + + ")"); + + idText.addLine(true, + "Ambiguous Projection", + txt); + } } } + + idText.addLine(true, + "Area", + focus->getArea()); + + idText.addLine(true, + "Class Name", + focus->getClassName()); + + idText.addLine(true, + "Comment", + focus->getComment()); + + idText.addLine(true, + "Extent", + focus->getExtent(), + true); + + idText.addLine(true, + "Geography", + focus->getGeography()); + + idText.addLine(true, + "Region of Interest", + focus->getRegionOfInterest()); + + idText.addLine(true, + "Statistic", + focus->getStatistic()); + } - - idText.addLine(true, - "Area", - focus->getArea()); - - idText.addLine(true, - "Class Name", - focus->getClassName()); - - idText.addLine(true, - "Comment", - focus->getComment()); - - idText.addLine(true, - "Extent", - focus->getExtent(), - true); - - idText.addLine(true, - "Geography", - focus->getGeography()); - - idText.addLine(true, - "Region of Interest", - focus->getRegionOfInterest()); - - idText.addLine(true, - "Statistic", - focus->getStatistic()); - } } @@ -1413,6 +1569,309 @@ IdentificationTextGenerator::generateImageIdentificationText(IdentificationStrin } } +/** + * Get text for the tooltip for a selected node. + * + * @param brain + * The Brain. + * @param browserTab + * Browser tab in which tooltip is displayed + * @param selectionManager + * The selection manager. + * @param dataToolTipsManager + * The data tooltips manager + * @param idText + * String builder for identification text. + */ +void +IdentificationTextGenerator::generateSurfaceToolTip(const Brain* brain, + const BrowserTabContent* browserTab, + const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager, + IdentificationStringBuilder& idText) const +{ + const SelectionItemSurfaceNode* nodeSelection = selectionManager->getSurfaceNodeIdentification(); + CaretAssert(nodeSelection); + if (nodeSelection->isValid()) { + const Surface* surface = nodeSelection->getSurface(); + CaretAssert(surface); + int32_t surfaceNumberOfNodes = surface->getNumberOfNodes(); + int32_t surfaceNodeIndex = nodeSelection->getNodeNumber(); + StructureEnum::Enum surfaceStructure = surface->getStructure(); + + bool indentFlag = false; + if ((surfaceStructure != StructureEnum::INVALID) + && (surfaceNumberOfNodes > 0) + && (surfaceNodeIndex >= 0)) { + + bool addVertexFlag(false); + bool showSurfaceFlag = dataToolTipsManager->isShowSurfaceViewed(); + if (dataToolTipsManager->isShowSurfacePrimaryAnatomical()) { + const Surface* anatSurface = brain->getPrimaryAnatomicalSurfaceForStructure(surfaceStructure); + if (anatSurface != NULL) { + if (anatSurface->getNumberOfNodes() == surfaceNumberOfNodes) { + float xyz[3]; + anatSurface->getCoordinate(surfaceNodeIndex, + xyz); + idText.addLine(indentFlag, + "Vertex", + AString::number(surfaceNodeIndex)); + indentFlag = true; + addVertexFlag = false; + + idText.addLine(indentFlag, + "Anatomy Surface", + AString::fromNumbers(xyz, 3, ", ", 'f', 2)); + if (surface == anatSurface) { + showSurfaceFlag = false; + } + } + } + } + + if (showSurfaceFlag) { + float xyz[3]; + surface->getCoordinate(surfaceNodeIndex, + xyz); + if (addVertexFlag) { + idText.addLine(indentFlag, + "Vertex", + AString::number(surfaceNodeIndex)); + indentFlag = true; + } + + idText.addLine(indentFlag, + (SurfaceTypeEnum::toGuiName(surface->getSurfaceType()) + + " Surface"), + AString::fromNumbers(xyz, 3, ", ")); + } + + if (dataToolTipsManager->isShowTopEnabledLayer()) { + OverlaySet* overlaySet = const_cast(browserTab->getOverlaySet()); + CaretAssert(overlaySet); + Overlay* overlay = getTopEnabledOverlay(overlaySet); + if (overlay != NULL) { + CaretMappableDataFile* mapFile(NULL); + int32_t mapIndex(-1); + overlay->getSelectionData(mapFile, + mapIndex); + if ((mapFile != NULL) + && (mapIndex >= 0)) { + std::vector mapIndices { mapIndex }; + AString textValue; + mapFile->getSurfaceNodeIdentificationForMaps(mapIndices, + surfaceStructure, + surfaceNodeIndex, + surfaceNumberOfNodes, + textValue); + if ( ! textValue.isEmpty()) { + idText.addLine(indentFlag, + "Top Enabled Layer", + textValue); + } + } + } + } + } + } + + if (dataToolTipsManager->isShowBorder()) { + const SelectionItemBorderSurface* borderSelection = selectionManager->getSurfaceBorderIdentification(); + CaretAssert(borderSelection); + if (borderSelection->isValid()) { + generateSurfaceBorderIdentifcationText(idText, + borderSelection, + true); + +// const BorderFile* borderFile = borderSelection->getBorderFile(); +// const int32_t borderIndex = borderSelection->getBorderIndex(); +// if ((borderFile != NULL) +// && (borderIndex >= 0)) { +// const Border* border = borderFile->getBorder(borderIndex); +// if (border != NULL) { +// text.appendWithNewLine("Border: " +// + border->getName()); +// } +// } + } + } + + if (dataToolTipsManager->isShowFocus()) { + const SelectionItemFocusSurface* focusSelection = selectionManager->getSurfaceFocusIdentification(); + CaretAssert(focusSelection); + if (focusSelection->isValid()) { + generateSurfaceFociIdentifcationText(idText, + focusSelection, + true); + + +// const FociFile* fociFile = focusSelection->getFociFile(); +// const int32_t focusIndex = focusSelection->getFocusIndex(); +// if ((fociFile != NULL) +// && (focusIndex >= 0)) { +// const Focus* focus = fociFile->getFocus(focusIndex); +// if (focus != NULL) { +// text.appendWithNewLine("Focus: " +// + focus->getName()); +// } +// } + } + } +} + +/** + * Get text for the tooltip for a selected node. + * + * @param browserTab + * Browser tab in which tooltip is displayed + * @param selectionManager + * The selection manager. + * @param dataToolTipsManager + * The data tooltips manager + * @param idText + * String builder for identification text. + */ +void +IdentificationTextGenerator::generateVolumeToolTip(const BrowserTabContent* browserTab, + const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager, + IdentificationStringBuilder& idText) const +{ + const SelectionItemVoxel* voxelSelection = selectionManager->getVoxelIdentification(); + + OverlaySet* overlaySet = const_cast(browserTab->getOverlaySet()); + CaretAssert(overlaySet); + + double selectionXYZ[3]; + voxelSelection->getModelXYZ(selectionXYZ); + float xyz[3] { + static_cast(selectionXYZ[0]), + static_cast(selectionXYZ[1]), + static_cast(selectionXYZ[2]) + }; + + bool indentFlag = false; + if (dataToolTipsManager->isShowVolumeUnderlay()) { + Overlay* volumeUnderlay = overlaySet->getUnderlayContainingVolume(); + if (volumeUnderlay != NULL) { + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex(-1); + volumeUnderlay->getSelectionData(mapFile, + mapIndex); + + VolumeMappableInterface* underlayVolumeInterface = NULL; + if (mapFile != NULL) { + underlayVolumeInterface = dynamic_cast(mapFile); + CaretAssert(underlayVolumeInterface == overlaySet->getUnderlayVolume()); + } + + if (underlayVolumeInterface != NULL) { + /* + * Update IJK and XYZ since selection XYZ may be + * a different volume file. + */ + int64_t selectionIJK[3]; + voxelSelection->getVoxelIJK(selectionIJK); + int64_t ijk[3] { selectionIJK[0], selectionIJK[1], selectionIJK[2] }; + + + bool validFlag(false); + const float value = underlayVolumeInterface->getVoxelValue(xyz[0], xyz[1], xyz[2], + &validFlag, + mapIndex); + if (validFlag) { + underlayVolumeInterface->enclosingVoxel(xyz[0], xyz[1], xyz[2], + ijk[0], ijk[1], ijk[2]); + underlayVolumeInterface->indexToSpace(ijk, xyz); + idText.addLine(indentFlag, + "Underlay Value", + AString::number(value, 'f')); + indentFlag = true; + idText.addLine(indentFlag, + "IJK: ", + AString::fromNumbers(ijk, 3, ", ")); + idText.addLine(indentFlag, + "XYZ", + AString::fromNumbers(xyz, 3, ", ", 'f', 1)); + } + } + } + } + + if (dataToolTipsManager->isShowTopEnabledLayer()) { + Overlay* overlay = getTopEnabledOverlay(overlaySet); + if (overlay != NULL) { + CaretMappableDataFile* mapFile(NULL); + int32_t mapIndex(-1); + overlay->getSelectionData(mapFile, + mapIndex); + if ((mapFile != NULL) + && (mapIndex >= 0)) { + std::vector mapIndices { mapIndex }; + AString textValue; + int64_t ijk[3]; + mapFile->getVolumeVoxelIdentificationForMaps(mapIndices, + xyz, + ijk, + textValue); + if ( ! textValue.isEmpty()) { + idText.addLine(indentFlag, + ("Top Enabled Layer: " + + textValue)); + } + } + } + } +} + +/** + * @return Get the top-most enabled overlay. NULL if no overlays enabled + * + * @param overlaySet + * Overlay set for overlay. + */ +Overlay* +IdentificationTextGenerator::getTopEnabledOverlay(OverlaySet* overlaySet) const +{ + CaretAssert(overlaySet); + const int32_t numberOfOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numberOfOverlays; i++) { + Overlay* overlay = overlaySet->getOverlay(i); + CaretAssert(overlay); + if (overlay->isEnabled()) { + return overlay; + } + } + return NULL; +} + +/** + * Get text for the tooltip for a selected node. + * + * @param selectionManager + * The selection manager. + * @param dataToolTipsManager + * The data tooltips manager + * @param idText + * String builder for identification text. + */ +void +IdentificationTextGenerator::generateChartToolTip(const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager, + IdentificationStringBuilder& idText) const +{ + if (dataToolTipsManager->isShowChart()) { + this->generateChartTwoHistogramIdentificationText(idText, + selectionManager->getChartTwoHistogramIdentification()); + + this->generateChartTwoLineSeriesIdentificationText(idText, + selectionManager->getChartTwoLineSeriesIdentification()); + + this->generateChartTwoMatrixIdentificationText(idText, + selectionManager->getChartTwoMatrixIdentification()); + } +} + /** diff --git a/src/Brain/IdentificationTextGenerator.h b/src/Brain/IdentificationTextGenerator.h index 4fa605adde97d3b0d0afd5e093019421e265069d..df3320e58d45c9e5a6e5515210fbcc54b134e1f7 100644 --- a/src/Brain/IdentificationTextGenerator.h +++ b/src/Brain/IdentificationTextGenerator.h @@ -30,7 +30,10 @@ namespace caret { class BrowserTabContent; class CaretMappableDataFile; class ChartDataSource; + class DataToolTipsManager; class MapFileDataSelector; + class Overlay; + class OverlaySet; class SelectionItemBorderSurface; class SelectionItemChartDataSeries; class SelectionItemChartFrequencySeries; @@ -58,6 +61,11 @@ namespace caret { AString createIdentificationText(const SelectionManager* idManager, const Brain* brain) const; + AString createToolTipText(const Brain* brain, + const BrowserTabContent* browserTab, + const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager) const; + private: IdentificationTextGenerator(const IdentificationTextGenerator&); @@ -67,11 +75,28 @@ namespace caret { virtual AString toString() const; private: + void generateSurfaceToolTip(const Brain* brain, + const BrowserTabContent* browserTab, + const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager, + IdentificationStringBuilder& idText) const; + + void generateVolumeToolTip(const BrowserTabContent* browserTab, + const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager, + IdentificationStringBuilder& idText) const; + + void generateChartToolTip(const SelectionManager* selectionManager, + const DataToolTipsManager* dataToolTipsManager, + IdentificationStringBuilder& idText) const; + void generateSurfaceBorderIdentifcationText(IdentificationStringBuilder& idText, - const SelectionItemBorderSurface* idSurfaceBorder) const; + const SelectionItemBorderSurface* idSurfaceBorder, + const bool toolTipFlag) const; void generateSurfaceFociIdentifcationText(IdentificationStringBuilder& idText, - const SelectionItemFocusSurface* idSurfaceFocus) const; + const SelectionItemFocusSurface* idSurfaceFocus, + const bool toolTipFlag) const; void generateVolumeFociIdentifcationText(IdentificationStringBuilder& idText, const SelectionItemFocusVolume* idVolumeFocus) const; @@ -120,6 +145,10 @@ namespace caret { void generateMapFileSelectorText(IdentificationStringBuilder& idText, const MapFileDataSelector* mapFileDataSelector) const; + + Overlay* getTopEnabledOverlay(OverlaySet* overlaySet) const; + + friend class DataToolTipsManager; }; #ifdef __IDENTIFICATION_TEXT_GENERATOR_DECLARE__ diff --git a/src/Brain/MovieRecorder.cxx b/src/Brain/MovieRecorder.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bb525685374945a370b9c6c1464b4671eb957a83 --- /dev/null +++ b/src/Brain/MovieRecorder.cxx @@ -0,0 +1,782 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __MOVIE_RECORDER_DECLARE__ +#include "MovieRecorder.h" +#undef __MOVIE_RECORDER_DECLARE__ + +#include +#include +#include +#include + +#include + +#include "Brain.h" +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "DataFileException.h" +#include "FileInformation.h" +#include "MovieRecorderVideoFormatTypeEnum.h" +#include "ImageFile.h" +#include "TextFile.h" + +using namespace caret; + + + +/** + * \class caret::MovieRecorder + * \brief Records images and creates movie file from images + * \ingroup Brain + */ + +/** + * Constructor. + */ +MovieRecorder::MovieRecorder() +: CaretObject() +{ + const QString tempSubDir("WbViewMovie"); + QDir tempDir(QDir::temp()); + /* + * "CD" will fail if temporary subdirectory does not exist + */ + if ( ! tempDir.cd(tempSubDir)) { + /* + * Try to create subdirectory + */ + if (tempDir.mkdir(tempSubDir)) { + /* + * Go to temp subdirectory + */ + tempDir.cd(tempSubDir); + } + } + m_temporaryImagesDirectory = tempDir.absolutePath(); + + m_tempImageFileNamePrefix = "movie"; + m_tempImageFileNameSuffix = ".png"; + removeTemporaryImages(); +} + +/** + * Destructor. + */ +MovieRecorder::~MovieRecorder() +{ + removeTemporaryImages(); +} + +/** + * Add an image to the movie, typically used during automatic mode recording + * + * @param image + * Image that is added + */ +void +MovieRecorder::addImageToMovie(const QImage* image) +{ + if (image == NULL) { + CaretLogSevere("Attempting to add NULL image to movie"); + return; + } + + if (getNumberOfFrames() <= 0) { + std::cout << "Temporary Directory for movie images: " + << std::endl + << " " << m_temporaryImagesDirectory << std::endl << std::flush; + } + + CaretAssert(m_tempImageSequenceNumberOfDigits > 0); + + /* + * First image starts at 1 and is padded with zeros on the left + */ + const int32_t imageIndexInt = getNumberOfFrames() + 1; + const QString imageIndex = QString::number(imageIndexInt).rightJustified(m_tempImageSequenceNumberOfDigits, '0'); + const QString imageFileName(m_temporaryImagesDirectory + + "/" + + m_tempImageFileNamePrefix + + imageIndex + + m_tempImageFileNameSuffix); + + switch (m_imageWriteMode) { + case ImageWriteMode::IMMEDITATE: + if (image->save(imageFileName)) { + if (m_imageFileNames.empty()) { + m_firstImageWidth = image->width(); + m_firstImageHeight = image->height(); + } + + if ((image->width() == m_firstImageWidth) + && (image->height() == m_firstImageHeight)) { + m_imageFileNames.push_back(imageFileName); + } + else { + CaretLogSevere("Attempting to create movie with images that are different sizes. " + "First image width=" + QString::number(m_firstImageWidth) + + ", height=" + QString::number(m_firstImageHeight) + + " Image number=" + QString::number(imageIndexInt) + + ", width=" + QString::number(image->width()) + + ", height=" + QString::number(image->height())); + } + } + else { + CaretLogSevere("Saving temporary image failed: " + + imageFileName); + } + break; + case ImageWriteMode::PARALLEL: + { + ImageWriter* iw = new ImageWriter(image, imageFileName); + m_imageWriters.push_back(iw); + QFuture f = QtConcurrent::run(iw, &ImageWriter::writeImage); + m_imageWriteResultFutures.push_back(f); + m_imageFileNames.push_back(imageFileName); + } + break; + } +} + +/** + * Add copies of an image to the movie for the given number of copies. + * Typically used during manual mode recording. + * + * @param image + * Image that is added + * @param numberOfCopies + * Number of copies for the image. + */ +void +MovieRecorder::addImageToMovieWithCopies(const QImage* image, + const int32_t numberOfCopies) +{ + for (int32_t i = 0; i < numberOfCopies; i++) { + addImageToMovie(image); + } +} + +/** + * @return True if all images were written succussfully + * if parallel image file writing is enabled. Returns + * true if image writing mode is immediate. + */ +bool +MovieRecorder::waitForImagesToFinishWriting() +{ + bool allValid(true); + + switch (m_imageWriteMode) { + case ImageWriteMode::IMMEDITATE: + break; + case ImageWriteMode::PARALLEL: + { + for (auto f : m_imageWriteResultFutures) { + f.waitForFinished(); + } + } + break; + } + + return allValid; +} + +/** + * Remove all images and starting a new movie + */ +void +MovieRecorder::removeTemporaryImages() +{ + waitForImagesToFinishWriting(); + m_imageWriteResultFutures.clear(); + + for (auto iw : m_imageWriters) { + delete iw; + } + m_imageWriters.clear(); + + const QString nameFilter(m_tempImageFileNamePrefix + + "*" + + m_tempImageFileNameSuffix); + QStringList allNameFilters; + allNameFilters.append(nameFilter); + QDir dir(m_temporaryImagesDirectory); + QFileInfoList fileInfoList = dir.entryInfoList(allNameFilters, + QDir::Files, + QDir::Name); + QListIterator iter(fileInfoList); + while (iter.hasNext()) { + QFile file(iter.next().absoluteFilePath()); + if (file.exists()) { + file.remove(); + } + } + + m_imageFileNames.clear(); + m_firstImageWidth = -1; + m_firstImageHeight = -1; +} + + +/** + * @return The recording mode + */ +MovieRecorderModeEnum::Enum +MovieRecorder::getRecordingMode() const +{ + return m_recordingMode; +} + +/** + * Set the recording mode + * + * @param recordingMode + * New recording mode + */ +void +MovieRecorder::setRecordingMode(const MovieRecorderModeEnum::Enum recordingMode) +{ + m_recordingMode = recordingMode; +} + +/** + * @return Index of window that is recorded + */ +int32_t +MovieRecorder::getRecordingWindowIndex() const +{ + return m_windowIndex; +} + +/** + * Set index of window that is recorded + * + * @param windowIndex + * Index of window + */ +void +MovieRecorder::setRecordingWindowIndex(const int32_t windowIndex) +{ + m_windowIndex = windowIndex; +} + +/** + * @return Video resolution type + */ +MovieRecorderVideoResolutionTypeEnum::Enum +MovieRecorder::getVideoResolutionType() const +{ + return m_resolutionType; +} + +/** + * Set the video resolution type + * + * @param resolutionType + * New resolution type + */ +void +MovieRecorder::setVideoResolutionType(const MovieRecorderVideoResolutionTypeEnum::Enum resolutionType) +{ + m_resolutionType = resolutionType; +} + +/** + * Get the video width and height + * + * @param widthOut + * Output width + * @param heightOut + * Output height + */ +void +MovieRecorder::getVideoWidthAndHeight(int32_t& widthOut, + int32_t& heightOut) const +{ + widthOut = 100; + heightOut = 100; + + const MovieRecorderVideoResolutionTypeEnum::Enum dimType = getVideoResolutionType(); + if (dimType == MovieRecorderVideoResolutionTypeEnum::CUSTOM) { + getCustomWidthAndHeight(widthOut, + heightOut); + } + else { + MovieRecorderVideoResolutionTypeEnum::getWidthAndHeight(dimType, + widthOut, + heightOut); + } +} + +/** + * Get the custom width and height + * + * @param widthOut + * Output width + * @param heightOut + * Output height + */ +void +MovieRecorder::getCustomWidthAndHeight(int32_t& widthOut, + int32_t& heightOut) const +{ + widthOut = m_customWidth; + heightOut = m_customHeight; +} + +/** + * Set the custom width and height + * + * @param width + * New width + * @param height + * New height + */ +void +MovieRecorder::setCustomWidthAndHeight(const int32_t width, + const int32_t height) +{ + m_customWidth = width; + m_customHeight = height; +} + +/** + * @return The capture region type + */ +MovieRecorderCaptureRegionTypeEnum::Enum +MovieRecorder::getCaptureRegionType() const +{ + return m_captureRegionType; +} + +/** + * Set the capture region type + * + * @param captureRegionType + * New capture region type + */ +void +MovieRecorder::setCaptureRegionType(const MovieRecorderCaptureRegionTypeEnum::Enum captureRegionType) +{ + m_captureRegionType = captureRegionType; +} + +/** + * @return Name of movie file + */ +AString +MovieRecorder::getMovieFileName() const +{ + return m_movieFileName; +} + +/** + * Set name of movie file + * + * @param filename + * New name for movie file + */ +void +MovieRecorder::setMovieFileName(const AString& filename) +{ + m_movieFileName = filename; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +MovieRecorder::toString() const +{ + return "MovieRecorder"; +} + +/** + * @return The frame rate (number of frames per second) + */ +float +MovieRecorder::getFramesRate() const +{ + return m_frameRate; +} + +/** + * Set the frame rate (number of frames per second) + * + * @param frameRate + * New frame rate + */ +void +MovieRecorder::setFramesRate(const float frameRate) +{ + m_frameRate = frameRate; +} + +/** + * @return True if temporary images should be removed + * after creation of a movie + */ +bool +MovieRecorder::isRemoveTemporaryImagesAfterMovieCreation() const +{ + return m_removeTemporaryImagesAfterMovieCreationFlag; +} + +/** + * Set temporary images should be removed after creation of a movie + * + * @param status + * New status + */ +void +MovieRecorder::setRemoveTemporaryImagesAfterMovieCreation(const bool status) +{ + m_removeTemporaryImagesAfterMovieCreationFlag = status; +} + +/** + * @return Number of frames (images) that have been recorded + */ +int32_t +MovieRecorder::getNumberOfFrames() const +{ + return m_imageFileNames.size(); +} + +/** + * Create the movie using images captured thus far + * + * @param filename + * File name for movie. + * @param errorMessageOut + * Contains information if movie creation failed + * @return + * True if successful, else false + */ +bool +MovieRecorder::createMovie(const AString& filename, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + if ( ! waitForImagesToFinishWriting()) { + errorMessageOut = "There was a problem writing the image files."; + return false; + } + + m_movieFileName = filename; + + if (m_movieFileName.isEmpty()) { + errorMessageOut = "Movie file name is invalid or empty"; + return false; + } + + FileInformation fileInfo(m_movieFileName); + if (fileInfo.exists()) { + errorMessageOut = ("Movie file exists, delete or change name: " + + m_movieFileName); + return false; + } + + if (m_imageFileNames.empty()) { + errorMessageOut.appendWithNewLine("No images have been recorded for the movie."); + } + if (m_movieFileName.isEmpty()) { + errorMessageOut.appendWithNewLine("Movie file name is empty."); + } + + if ( ! errorMessageOut.isEmpty()) { + return false; + } + + const AString sequenceDigitsPattern("%0" + + AString::number(m_tempImageSequenceNumberOfDigits) + + "d"); + + const AString imagesRegularExpressionMatch(m_temporaryImagesDirectory + + "/" + + m_tempImageFileNamePrefix + + sequenceDigitsPattern + + m_tempImageFileNameSuffix); + QString workbenchHomeDir = SystemUtilities::getWorkbenchHome(); + + /* Qt after 5.? const QString ffmpegDir = qEnvironmentVariable("WORKBENCH_FFMPEG_DIR"); */ + const QString ffmpegDir = qgetenv("WORKBENCH_FFMPEG_DIR").constData(); + if ( ! ffmpegDir.isEmpty()) { + workbenchHomeDir = ffmpegDir; + } + + const bool qProcessPipeFlag(false); + const QString textFileName(m_temporaryImagesDirectory + + "/" + + "images.txt"); + + const QString programName(workbenchHomeDir + + "/ffmpeg"); + FileInformation ffmpegInfo(programName); + if ( ! ffmpegInfo.exists()) { + errorMessageOut = ("Invalid path for ffmpeg: " + + programName + + "\n WORKBENCH_FFMPEG_DIR can be set to directory containing ffmpeg."); + return false; + } + + QStringList arguments; + arguments.append("-threads"); + arguments.append("4"); + arguments.append("-framerate"); + arguments.append(AString::number(m_frameRate)); + if (qProcessPipeFlag) { + /* list of images in file */ + arguments.append("-f"); + arguments.append("concat"); +// arguments.append("-safe"); +// arguments.append("0"); + arguments.append("-i"); + arguments.append(textFileName); + } + else { + arguments.append("-i"); + arguments.append(imagesRegularExpressionMatch); + } + arguments.append("-q:v"); + arguments.append("1"); + arguments.append(m_movieFileName); + + bool successFlag(false); + if (qProcessPipeFlag) { + successFlag = createMovieWithQProcessPipe(programName, + arguments, + textFileName, + errorMessageOut); + } + else { + const bool useQProcessFlag(true); + if (useQProcessFlag) { + successFlag = createMovieWithQProcess(programName, + arguments, + errorMessageOut); + } + else { + successFlag = createMovieWithSystemCommand(programName, + arguments, + errorMessageOut); + } + } + + if (successFlag) { + if (m_removeTemporaryImagesAfterMovieCreationFlag) { + removeTemporaryImages(); + } + } + + return successFlag; +} + +/** + * Create the movie by using Qt's QProcess and using a + * pipe to send the images to ffmpeg + * + * @param programName + * Name of program + * @param arguments + * Arguments to program + * @param errorMessageOut + * Output containing error message + * @return + * True if movie was created or false if there was an error + */ +bool +MovieRecorder::createMovieWithQProcessPipe(const QString& programName, + const QStringList& arguments, + const QString& textFileName, + QString& errorMessageOut) +{ + /* + * https://trac.ffmpeg.org/wiki/Concatenate + * https://trac.ffmpeg.org/wiki/Slideshow + */ + bool successFlag(false); + + TextFile textFile; + try { + for (const auto name : m_imageFileNames) { + textFile.addLine("file " + + name); + } + textFile.writeFile(textFileName); + } + catch (const DataFileException& dfe) { + errorMessageOut = ("Error creating text file containing image names: " + + dfe.whatString()); + return false; + } + + QProcess process; + process.start(programName, + arguments); + process.closeWriteChannel(); + + const int noTimeout(-1); + const bool finishedFlag = process.waitForFinished(noTimeout); + if (finishedFlag) { + if (process.exitStatus() == QProcess::NormalExit) { + const int resultCode = process.exitCode(); + if (resultCode == 0) { + successFlag = true; + } + else { + QByteArray results = process.readAllStandardError(); + errorMessageOut = QString(results); + } + } + else if (process.exitStatus() == QProcess::CrashExit) { + errorMessageOut = "Running ffmpeg crashed"; + } + } + else { + errorMessageOut = "Creating movie was terminated for unknown reason"; + } + + return successFlag; +} + +/** + * Create the movie by using Qt's QProcess + * + * @param programName + * Name of program + * @param arguments + * Arguments to program + * @param errorMessageOut + * Output containing error message + * @return + * True if movie was created or false if there was an error + */ +bool +MovieRecorder::createMovieWithQProcess(const QString& programName, + const QStringList& arguments, + QString& errorMessageOut) +{ + bool successFlag(false); + + QProcess process; + process.start(programName, + arguments); + process.closeWriteChannel(); + + const int noTimeout(-1); + const bool finishedFlag = process.waitForFinished(noTimeout); + if (finishedFlag) { + if (process.exitStatus() == QProcess::NormalExit) { + const int resultCode = process.exitCode(); + if (resultCode == 0) { + successFlag = true; + } + else { + QByteArray results = process.readAllStandardError(); + errorMessageOut = QString(results); + } + } + else if (process.exitStatus() == QProcess::CrashExit) { + errorMessageOut = "Running ffmpeg crashed"; + } + } + else { + errorMessageOut = "Creating movie was terminated for unknown reason"; + } + + return successFlag; +} + +/** + * Create the movie by using the system command + * + * @param programName + * Name of program + * @param arguments + * Arguments to program + * @param errorMessageOut + * Output containing error message + * @return + * True if movie was created or false if there was an error + */ +bool +MovieRecorder::createMovieWithSystemCommand(const QString& programName, + const QStringList& arguments, + QString& errorMessageOut) +{ + const AString commandString(programName + + " " + + arguments.join(" ")); + const int result = system(commandString.toLatin1().constData()); + + bool successFlag(false); + if (result == 0) { + successFlag = true; + } + else { + errorMessageOut = ("Running ffmpeg failed with code=" + + AString::number(result)); + } + return successFlag; +} + + +/** + * Constructor for image writer + * + * @param image + * The image file + * @param filename + * Name of file + */ +MovieRecorder::ImageWriter::ImageWriter(const QImage* image, + const QString& filename) +: m_image(new QImage(*image)), +m_filename(filename) +{ + CaretAssert(m_image); + +} + +/** + * Destructor + */ +MovieRecorder::ImageWriter::~ImageWriter() +{ +} + +/** + * Write the image + * + * @return True if written, false if error. + */ +bool +MovieRecorder::ImageWriter::writeImage() +{ + CaretAssert(m_image); + return m_image->save(m_filename); +} + + diff --git a/src/Brain/MovieRecorder.h b/src/Brain/MovieRecorder.h new file mode 100644 index 0000000000000000000000000000000000000000..96df94bbca3e261d2b20ed453a31bab1968b2971 --- /dev/null +++ b/src/Brain/MovieRecorder.h @@ -0,0 +1,188 @@ +#ifndef __MOVIE_RECORDER_H__ +#define __MOVIE_RECORDER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +#include "CaretObject.h" +#include "MovieRecorderCaptureRegionTypeEnum.h" +#include "MovieRecorderModeEnum.h" +#include "MovieRecorderVideoResolutionTypeEnum.h" + +class QImage; +class QStringList; + +namespace caret { + class MovieRecorder : public CaretObject { + + public: + + MovieRecorder(); + + virtual ~MovieRecorder(); + + MovieRecorder(const MovieRecorder&) = delete; + + MovieRecorder& operator=(const MovieRecorder&) = delete; + + MovieRecorderModeEnum::Enum getRecordingMode() const; + + void addImageToMovie(const QImage* image); + + void addImageToMovieWithCopies(const QImage* image, + const int32_t numberOfCopies); + + void setRecordingMode(const MovieRecorderModeEnum::Enum recordingMode); + + int32_t getRecordingWindowIndex() const; + + void setRecordingWindowIndex(const int32_t windowIndex); + + MovieRecorderVideoResolutionTypeEnum::Enum getVideoResolutionType() const; + + void setVideoResolutionType(const MovieRecorderVideoResolutionTypeEnum::Enum resolutionType); + + void getVideoWidthAndHeight(int32_t& widthOut, + int32_t& heightOut) const; + + void getCustomWidthAndHeight(int32_t& widthOut, + int32_t& heightOut) const; + + void setCustomWidthAndHeight(const int32_t width, + const int32_t height); + + MovieRecorderCaptureRegionTypeEnum::Enum getCaptureRegionType() const; + + void setCaptureRegionType(const MovieRecorderCaptureRegionTypeEnum::Enum captureRegionType); + + AString getMovieFileName() const; + + void setMovieFileName(const AString& filename); + + int32_t getNumberOfFrames() const; + + float getFramesRate() const; + + void setFramesRate(const float frameRate); + + bool isRemoveTemporaryImagesAfterMovieCreation() const; + + void setRemoveTemporaryImagesAfterMovieCreation(const bool status); + + void removeTemporaryImages(); + + bool createMovie(const AString& filename, + AString& errorMessageOut); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + enum class ImageWriteMode { + IMMEDITATE, + PARALLEL + }; + + /** + * Used to write images in separate thread + */ + class ImageWriter { + public: + ImageWriter(const QImage* image, + const QString& filename); + + ~ImageWriter(); + + bool writeImage(); + private: + std::unique_ptr m_image; + + const QString m_filename; + }; + + // ADD_NEW_MEMBERS_HERE + + bool createMovieWithSystemCommand(const QString& programName, + const QStringList& arguments, + QString& errorMessageOut); + + bool createMovieWithQProcess(const QString& programName, + const QStringList& arguments, + QString& errorMessageOut); + + bool createMovieWithQProcessPipe(const QString& programName, + const QStringList& arguments, + const QString& textFileName, + QString& errorMessageOut); + + bool waitForImagesToFinishWriting(); + + MovieRecorderModeEnum::Enum m_recordingMode = MovieRecorderModeEnum::MANUAL; + + MovieRecorderVideoResolutionTypeEnum::Enum m_resolutionType = MovieRecorderVideoResolutionTypeEnum::SD_640_480; + + MovieRecorderCaptureRegionTypeEnum::Enum m_captureRegionType = MovieRecorderCaptureRegionTypeEnum::GRAPHICS; + + int32_t m_windowIndex = 0; + + int32_t m_customWidth = 640; + + int32_t m_customHeight = 480; + + std::vector m_imageFileNames; + + std::vector> m_imageWriteResultFutures; + + std::vector m_imageWriters; + + ImageWriteMode m_imageWriteMode = ImageWriteMode::PARALLEL; + + mutable AString m_movieFileName; + + std::vector m_imageFrameFileNames; + + float m_frameRate = 30.0f; + + AString m_temporaryImagesDirectory; + + AString m_tempImageFileNamePrefix; + + AString m_tempImageFileNameSuffix; + + bool m_removeTemporaryImagesAfterMovieCreationFlag = true; + + const int32_t m_tempImageSequenceNumberOfDigits = 6; + + int32_t m_firstImageWidth = -1; + int32_t m_firstImageHeight = -1; + }; + +#ifdef __MOVIE_RECORDER_DECLARE__ +#endif // __MOVIE_RECORDER_DECLARE__ + +} // namespace +#endif //__MOVIE_RECORDER_H__ diff --git a/src/Brain/MovieRecorderCaptureRegionTypeEnum.cxx b/src/Brain/MovieRecorderCaptureRegionTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..50b1f4d1d18cac0c8a958e255b69c4dd56299eb3 --- /dev/null +++ b/src/Brain/MovieRecorderCaptureRegionTypeEnum.cxx @@ -0,0 +1,375 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ +#include "MovieRecorderCaptureRegionTypeEnum.h" +#undef __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::MovieRecorderCaptureRegionTypeEnum + * \brief + * + * + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_movieRecorderCaptureRegionTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void movieRecorderCaptureRegionTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "MovieRecorderCaptureRegionTypeEnum.h" + * + * Instatiate: + * m_movieRecorderCaptureRegionTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_movieRecorderCaptureRegionTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_movieRecorderCaptureRegionTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(movieRecorderCaptureRegionTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_movieRecorderCaptureRegionTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const MovieRecorderCaptureRegionTypeEnum::Enum VARIABLE = m_movieRecorderCaptureRegionTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +MovieRecorderCaptureRegionTypeEnum::MovieRecorderCaptureRegionTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +MovieRecorderCaptureRegionTypeEnum::~MovieRecorderCaptureRegionTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +MovieRecorderCaptureRegionTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(MovieRecorderCaptureRegionTypeEnum(GRAPHICS, + "GRAPHICS", + "Graphics")); + + enumData.push_back(MovieRecorderCaptureRegionTypeEnum(WINDOW, + "WINDOW", + "Window")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const MovieRecorderCaptureRegionTypeEnum* +MovieRecorderCaptureRegionTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const MovieRecorderCaptureRegionTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderCaptureRegionTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderCaptureRegionTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderCaptureRegionTypeEnum::Enum +MovieRecorderCaptureRegionTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderCaptureRegionTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderCaptureRegionTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderCaptureRegionTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderCaptureRegionTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderCaptureRegionTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderCaptureRegionTypeEnum::Enum +MovieRecorderCaptureRegionTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderCaptureRegionTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderCaptureRegionTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderCaptureRegionTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +MovieRecorderCaptureRegionTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const MovieRecorderCaptureRegionTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +MovieRecorderCaptureRegionTypeEnum::Enum +MovieRecorderCaptureRegionTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderCaptureRegionTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderCaptureRegionTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderCaptureRegionTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +MovieRecorderCaptureRegionTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderCaptureRegionTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(MovieRecorderCaptureRegionTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderCaptureRegionTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(MovieRecorderCaptureRegionTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Brain/MovieRecorderCaptureRegionTypeEnum.h b/src/Brain/MovieRecorderCaptureRegionTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..7b479bc280115dd23c12bd2fb352735ff18a32eb --- /dev/null +++ b/src/Brain/MovieRecorderCaptureRegionTypeEnum.h @@ -0,0 +1,104 @@ +#ifndef __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_H__ +#define __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class MovieRecorderCaptureRegionTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** */ + GRAPHICS, + /** */ + WINDOW + }; + + + ~MovieRecorderCaptureRegionTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + MovieRecorderCaptureRegionTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const MovieRecorderCaptureRegionTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ +std::vector MovieRecorderCaptureRegionTypeEnum::enumData; +bool MovieRecorderCaptureRegionTypeEnum::initializedFlag = false; +int32_t MovieRecorderCaptureRegionTypeEnum::integerCodeCounter = 0; +#endif // __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_H__ diff --git a/src/Brain/MovieRecorderModeEnum.cxx b/src/Brain/MovieRecorderModeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9e5410f9772769620ffd43691210cbdac9282cd8 --- /dev/null +++ b/src/Brain/MovieRecorderModeEnum.cxx @@ -0,0 +1,372 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __MOVIE_RECORDER_MODE_ENUM_DECLARE__ +#include "MovieRecorderModeEnum.h" +#undef __MOVIE_RECORDER_MODE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::MovieRecorderModeEnum + * \brief Mode for video recording + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_movieRecorderModeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void movieRecorderModeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "MovieRecorderModeEnum.h" + * + * Instatiate: + * m_movieRecorderModeEnumComboBox = new EnumComboBoxTemplate(this); + * m_movieRecorderModeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_movieRecorderModeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(movieRecorderModeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_movieRecorderModeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const MovieRecorderModeEnum::Enum VARIABLE = m_movieRecorderModeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +MovieRecorderModeEnum::MovieRecorderModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +MovieRecorderModeEnum::~MovieRecorderModeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +MovieRecorderModeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(MovieRecorderModeEnum(AUTOMATIC, + "AUTOMATIC", + "Automatic")); + + enumData.push_back(MovieRecorderModeEnum(MANUAL, + "MANUAL", + "Manual")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const MovieRecorderModeEnum* +MovieRecorderModeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const MovieRecorderModeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderModeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderModeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderModeEnum::Enum +MovieRecorderModeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderModeEnum::MANUAL; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderModeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderModeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderModeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderModeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderModeEnum::Enum +MovieRecorderModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderModeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderModeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +MovieRecorderModeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const MovieRecorderModeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +MovieRecorderModeEnum::Enum +MovieRecorderModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderModeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderModeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +MovieRecorderModeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderModeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(MovieRecorderModeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(MovieRecorderModeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Brain/MovieRecorderModeEnum.h b/src/Brain/MovieRecorderModeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..d36302511986abb7b78c623ef5bfc76e62dfc9fb --- /dev/null +++ b/src/Brain/MovieRecorderModeEnum.h @@ -0,0 +1,104 @@ +#ifndef __MOVIE_RECORDER_MODE_ENUM_H__ +#define __MOVIE_RECORDER_MODE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class MovieRecorderModeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Automatic*/ + AUTOMATIC, + /** Manual */ + MANUAL + }; + + + ~MovieRecorderModeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + MovieRecorderModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const MovieRecorderModeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __MOVIE_RECORDER_MODE_ENUM_DECLARE__ +std::vector MovieRecorderModeEnum::enumData; +bool MovieRecorderModeEnum::initializedFlag = false; +int32_t MovieRecorderModeEnum::integerCodeCounter = 0; +#endif // __MOVIE_RECORDER_MODE_ENUM_DECLARE__ + +} // namespace +#endif //__MOVIE_RECORDER_MODE_ENUM_H__ diff --git a/src/Brain/MovieRecorderVideoFormatTypeEnum.cxx b/src/Brain/MovieRecorderVideoFormatTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a3d842efc44be01e041cfa889f0ca80019480f3f --- /dev/null +++ b/src/Brain/MovieRecorderVideoFormatTypeEnum.cxx @@ -0,0 +1,410 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ +#include "MovieRecorderVideoFormatTypeEnum.h" +#undef __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::MovieRecorderVideoFormatTypeEnum + * \brief Format for video recording + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_movieRecorderVideoFormatTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void movieRecorderVideoFormatTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "MovieRecorderVideoFormatTypeEnum.h" + * + * Instatiate: + * m_movieRecorderVideoFormatTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_movieRecorderVideoFormatTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_movieRecorderVideoFormatTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(movieRecorderVideoFormatTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_movieRecorderVideoFormatTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const MovieRecorderVideoFormatTypeEnum::Enum VARIABLE = m_movieRecorderVideoFormatTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * @param guiName + * User-friendly name for use in user-interface. + * @param filenameExtensionNoDot + * Extension for file without a dot + * @param fileDialogFilter + * Filter for use in file dialogs + */ +MovieRecorderVideoFormatTypeEnum::MovieRecorderVideoFormatTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName, + const AString& filenameExtensionNoDot, + const AString& fileDialogFilter) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; + this->filenameExtensionNoDot = filenameExtensionNoDot; + this->fileDialogFilter = fileDialogFilter; +} + +/** + * Destructor. + */ +MovieRecorderVideoFormatTypeEnum::~MovieRecorderVideoFormatTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +MovieRecorderVideoFormatTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(MovieRecorderVideoFormatTypeEnum(AVI, + "AVI", + "Avi", + "avi", + "AVI (*.avi)")); + + enumData.push_back(MovieRecorderVideoFormatTypeEnum(MPEG, + "MPEG", + "Mpeg", + "mpg", + "MPEG (*.mpg)")); + + enumData.push_back(MovieRecorderVideoFormatTypeEnum(MPEG_4, + "MPEG_4", + "Mpeg 4", + "mp4", + "MPEG 4 (*.mp4)")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const MovieRecorderVideoFormatTypeEnum* +MovieRecorderVideoFormatTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const MovieRecorderVideoFormatTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderVideoFormatTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderVideoFormatTypeEnum::Enum +MovieRecorderVideoFormatTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderVideoFormatTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderVideoFormatTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderVideoFormatTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderVideoFormatTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderVideoFormatTypeEnum::Enum +MovieRecorderVideoFormatTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderVideoFormatTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderVideoFormatTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderVideoFormatTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +MovieRecorderVideoFormatTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +MovieRecorderVideoFormatTypeEnum::Enum +MovieRecorderVideoFormatTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderVideoFormatTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderVideoFormatTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderVideoFormatTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +MovieRecorderVideoFormatTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderVideoFormatTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(MovieRecorderVideoFormatTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderVideoFormatTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(MovieRecorderVideoFormatTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + +/** + * Get the filename extension for the video format + */ +AString +MovieRecorderVideoFormatTypeEnum::toFileNameExtensionNoDot(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); + return enumInstance->filenameExtensionNoDot; +} + +/** + * Get the file dialog filter for the video format + */ +AString +MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); + return enumInstance->fileDialogFilter; +} diff --git a/src/Brain/MovieRecorderVideoFormatTypeEnum.h b/src/Brain/MovieRecorderVideoFormatTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..6849812db8d586701476b2e7a1f973f69455ab70 --- /dev/null +++ b/src/Brain/MovieRecorderVideoFormatTypeEnum.h @@ -0,0 +1,116 @@ +#ifndef __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_H__ +#define __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class MovieRecorderVideoFormatTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** AVI video */ + AVI, + /** MPEG */ + MPEG, + /** MPEG-4 video */ + MPEG_4 + }; + + + ~MovieRecorderVideoFormatTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + + static AString toFileNameExtensionNoDot(Enum enumValue); + + static AString toFileDialogFilter(Enum enumValue); + +private: + MovieRecorderVideoFormatTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName, + const AString& filenameExtensionNoDot, + const AString& fileDialogFilter); + + static const MovieRecorderVideoFormatTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; + + AString filenameExtensionNoDot; + + AString fileDialogFilter; +}; + +#ifdef __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ +std::vector MovieRecorderVideoFormatTypeEnum::enumData; +bool MovieRecorderVideoFormatTypeEnum::initializedFlag = false; +int32_t MovieRecorderVideoFormatTypeEnum::integerCodeCounter = 0; +#endif // __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_H__ diff --git a/src/Brain/MovieRecorderVideoResolutionTypeEnum.cxx b/src/Brain/MovieRecorderVideoResolutionTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dd3da8740291a890eda77e40ff945aa386b7bdd6 --- /dev/null +++ b/src/Brain/MovieRecorderVideoResolutionTypeEnum.cxx @@ -0,0 +1,423 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ +#include "MovieRecorderVideoResolutionTypeEnum.h" +#undef __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::MovieRecorderVideoResolutionTypeEnum + * \brief Resolutions for movie recording + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_MovieRecorderVideoResolutionTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void MovieRecorderVideoResolutionTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "MovieRecorderVideoResolutionTypeEnum.h" + * + * Instatiate: + * m_MovieRecorderVideoResolutionTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_MovieRecorderVideoResolutionTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_MovieRecorderVideoResolutionTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(MovieRecorderVideoResolutionTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_MovieRecorderVideoResolutionTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const MovieRecorderVideoResolutionTypeEnum::Enum VARIABLE = m_MovieRecorderVideoResolutionTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +MovieRecorderVideoResolutionTypeEnum::MovieRecorderVideoResolutionTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +MovieRecorderVideoResolutionTypeEnum::~MovieRecorderVideoResolutionTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +MovieRecorderVideoResolutionTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(MovieRecorderVideoResolutionTypeEnum(CUSTOM, + "CUSTOM", + "Custom")); + + enumData.push_back(MovieRecorderVideoResolutionTypeEnum(UHD_3840_2160, + "UHD_3840_2160", + "UHD (3840x2160)")); + + enumData.push_back(MovieRecorderVideoResolutionTypeEnum(FULL_HD_1920_1080, + "FULL_HD_1920_1080", + "Full HD (1920x1080)")); + + enumData.push_back(MovieRecorderVideoResolutionTypeEnum(HD_1280_720, + "HD_1280_720", + "HD Ready (1280x720)")); + + enumData.push_back(MovieRecorderVideoResolutionTypeEnum(SD_640_480, + "SD_640_480", + "SD (640x480)")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const MovieRecorderVideoResolutionTypeEnum* +MovieRecorderVideoResolutionTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const MovieRecorderVideoResolutionTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderVideoResolutionTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderVideoResolutionTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderVideoResolutionTypeEnum::Enum +MovieRecorderVideoResolutionTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderVideoResolutionTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderVideoResolutionTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderVideoResolutionTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MovieRecorderVideoResolutionTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MovieRecorderVideoResolutionTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MovieRecorderVideoResolutionTypeEnum::Enum +MovieRecorderVideoResolutionTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderVideoResolutionTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderVideoResolutionTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderVideoResolutionTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +MovieRecorderVideoResolutionTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const MovieRecorderVideoResolutionTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +MovieRecorderVideoResolutionTypeEnum::Enum +MovieRecorderVideoResolutionTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MovieRecorderVideoResolutionTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MovieRecorderVideoResolutionTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderVideoResolutionTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +MovieRecorderVideoResolutionTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderVideoResolutionTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(MovieRecorderVideoResolutionTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MovieRecorderVideoResolutionTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(MovieRecorderVideoResolutionTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + +/** + * Get the width and height for given enumerated value. Output will be zeros + * for custom. + * + * @param enumValue + * Enumerated value. + * @param widthOut + * Output containing width + * @param heightOut + * Output containing height + */ +void +MovieRecorderVideoResolutionTypeEnum::getWidthAndHeight(const Enum enumValue, + int32_t& widthOut, + int32_t& heightOut) +{ + switch (enumValue) { + case CUSTOM: + break; + case FULL_HD_1920_1080: + widthOut = 1920; + heightOut = 1080; + break; + case HD_1280_720: + widthOut = 1280; + heightOut = 720; + break; + case SD_640_480: + widthOut = 640; + heightOut = 480; + break; + case UHD_3840_2160: + widthOut = 3840; + heightOut = 2160; + break; + } +} + diff --git a/src/Brain/MovieRecorderVideoResolutionTypeEnum.h b/src/Brain/MovieRecorderVideoResolutionTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..fc6ddd55c9458708aa29d219e17b2c9bca50ea97 --- /dev/null +++ b/src/Brain/MovieRecorderVideoResolutionTypeEnum.h @@ -0,0 +1,114 @@ +#ifndef __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_H__ +#define __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class MovieRecorderVideoResolutionTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Custom */ + CUSTOM, + /** UHD */ + UHD_3840_2160, + /** Full HD */ + FULL_HD_1920_1080, + /** HD Ready */ + HD_1280_720, + /** SD */ + SD_640_480 + }; + + + ~MovieRecorderVideoResolutionTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + + static void getWidthAndHeight(const Enum enumValue, + int32_t& widthOut, + int32_t& heightOut); + +private: + MovieRecorderVideoResolutionTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const MovieRecorderVideoResolutionTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ +std::vector MovieRecorderVideoResolutionTypeEnum::enumData; +bool MovieRecorderVideoResolutionTypeEnum::initializedFlag = false; +int32_t MovieRecorderVideoResolutionTypeEnum::integerCodeCounter = 0; +#endif // __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_H__ diff --git a/src/Brain/Overlay.cxx b/src/Brain/Overlay.cxx index 2144afe1098991b12e16acb1aeb298b7a9076c17..fdf86cc0b04b35f361ce8fda37fdd50b70668d93 100644 --- a/src/Brain/Overlay.cxx +++ b/src/Brain/Overlay.cxx @@ -34,12 +34,14 @@ #include "EventManager.h" #include "EventOverlayValidate.h" #include "LabelFile.h" +#include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "PlainTextStringBuilder.h" #include "RgbaFile.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "Surface.h" +#include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" using namespace caret; @@ -385,10 +387,82 @@ Overlay::getSelectionData(std::vector& mapFilesOut, } if (useIt) { - if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { - CiftiConnectivityMatrixDenseDynamicFile* dynConnFile = dynamic_cast(mapFile); - CaretAssert(dynConnFile); - useIt = dynConnFile->isEnabledAsLayer(); + switch (mapFile->getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + { + CiftiConnectivityMatrixDenseDynamicFile* dynConnFile = dynamic_cast(mapFile); + CaretAssert(dynConnFile); + useIt = dynConnFile->isEnabledAsLayer(); + } + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + { + MetricDynamicConnectivityFile* metricDynFile = dynamic_cast(mapFile); + CaretAssert(metricDynFile); + useIt = metricDynFile->isEnabledAsLayer(); + } + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + { + VolumeDynamicConnectivityFile* volDynFile = dynamic_cast(mapFile); + CaretAssert(volDynFile); + useIt = volDynFile->isEnabledAsLayer(); + } + break; } } diff --git a/src/Brain/OverlaySet.cxx b/src/Brain/OverlaySet.cxx index 052a9dec08a73dc6e9eb54c0a3c8127ac8bb77cd..30e152cdd4c859296df8f65d9371eac5e36b1094 100644 --- a/src/Brain/OverlaySet.cxx +++ b/src/Brain/OverlaySet.cxx @@ -173,28 +173,84 @@ OverlaySet::getUnderlay() * @return Returns the bottom-most overlay that is set a a volume file. * Will return NULL if no, enabled overlays are set to a volume file. */ -VolumeMappableInterface* -OverlaySet::getUnderlayVolume() +Overlay* +OverlaySet::getUnderlayContainingVolume() { - VolumeMappableInterface* vf = NULL; + Overlay* underlayOut(NULL); - for (int32_t i = (getNumberOfDisplayedOverlays() - 1); i >= 0; i--) { + const int32_t numOverlays = getNumberOfDisplayedOverlays(); + for (int32_t i = (numOverlays - 1); i >= 0; i--) { if (m_overlays[i]->isEnabled()) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex; + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); + m_overlays[i]->getSelectionData(mapFile, + mapIndex); + + if (mapFile != NULL) { + if (mapFile->isVolumeMappable()) { + const VolumeMappableInterface* vf = dynamic_cast(mapFile); + if (vf != NULL) { + underlayOut = m_overlays[i]; + break; + } + } + } + } + } + + if (underlayOut == NULL) { + /* + * If we are here, either there are no volume files or + * no overlays are enabled containing a volume file. + * So, find the lowest layer than contains a volume file, + * even if the layer is disabled. + */ + for (int32_t i = 0; i < numOverlays; i++) { + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex; + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->isVolumeMappable()) { - vf = dynamic_cast(mapFile); + const VolumeMappableInterface* vf = dynamic_cast(mapFile); if (vf != NULL) { + underlayOut = m_overlays[i]; break; } } } } } + + return underlayOut; +} + +/* + * Get the bottom-most overlay that is a volume file for the given + * browser tab and return its volume file. + * @param browserTabContent + * Content of browser tab. + * @return Returns the bottom-most overlay that is set a a volume file. + * Will return NULL if no, enabled overlays are set to a volume file. + */ +VolumeMappableInterface* +OverlaySet::getUnderlayVolume() +{ + VolumeMappableInterface* vf = NULL; + + Overlay* underlay = getUnderlayContainingVolume(); + if (underlay != NULL) { + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex; + underlay->getSelectionData(mapFile, mapIndex); + if (mapFile != NULL) { + vf = dynamic_cast(mapFile); + } + } + return vf; } diff --git a/src/Brain/OverlaySet.h b/src/Brain/OverlaySet.h index 0fa269756fa64f7334eff7cfc8c36264323e7a9c..bd3a57fd3c8da71c3f5871fccaa511f856949df3 100644 --- a/src/Brain/OverlaySet.h +++ b/src/Brain/OverlaySet.h @@ -58,6 +58,8 @@ namespace caret { VolumeMappableInterface* getUnderlayVolume(); + Overlay* getUnderlayContainingVolume(); + Overlay* getOverlay(const int32_t overlayNumber); const Overlay* getOverlay(const int32_t overlayNumber) const; diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index d1cc889e333a2cc233990f7b46c71fd388fb8646..7907d2eadd22c547599ce42e95119c4977c864c4 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -32,9 +32,11 @@ #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" +#include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryManager.h" +#include "DataToolTipsManager.h" #include "ElapsedTimer.h" #include "EventManager.h" #include "EventBrowserTabDelete.h" @@ -42,6 +44,7 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventBrowserTabNew.h" +#include "EventBrowserTabNewClone.h" #include "EventBrowserWindowContent.h" #include "EventCaretPreferencesGet.h" #include "EventModelAdd.h" @@ -49,15 +52,18 @@ #include "EventModelGetAll.h" #include "EventModelGetAllDisplayed.h" #include "EventProgressUpdate.h" +#include "EventSpacerTabGet.h" #include "ImageCaptureSettings.h" #include "LogManager.h" #include "MapYokingGroupEnum.h" #include "ModelWholeBrain.h" +#include "MovieRecorder.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "ScenePrimitiveArray.h" +#include "SpacerTabContent.h" #include "VolumeSurfaceOutlineSetModel.h" @@ -76,6 +82,7 @@ SessionManager::SessionManager() m_ciftiConnectivityMatrixDataFileManager = new CiftiConnectivityMatrixDataFileManager(); m_ciftiFiberTrajectoryManager = new CiftiFiberTrajectoryManager(); + m_dataToolTipsManager.reset(new DataToolTipsManager(m_caretPreferences->isShowDataToolTipsEnabled())); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_browserTabs[i] = NULL; @@ -91,15 +98,18 @@ SessionManager::SessionManager() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_PREFERENCES_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_ADD); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SPACER_TAB_GET); Brain* brain = new Brain(m_caretPreferences); m_brains.push_back(brain); + m_movieRecorder.reset(new MovieRecorder()); } /** @@ -119,6 +129,8 @@ SessionManager::~SessionManager() } } + clearSpacerTabs(); + std::for_each(m_browserWindowContent.begin(), m_browserWindowContent.end(), [](BrowserWindowContent* bwc) { if (bwc != NULL) delete bwc; } ); @@ -260,6 +272,18 @@ SessionManager::getBrain(const int32_t brainIndex) const return m_brains[brainIndex]; } +/** + * Clear all of the spacer tabs + */ +void +SessionManager::clearSpacerTabs() +{ + for (auto st : m_spacerTabsMap) { + delete st.second; + } + m_spacerTabsMap.clear(); +} + /** * Get a description of this object's content. * @return String describing this object's content. @@ -297,8 +321,41 @@ SessionManager::receiveEvent(Event* event) break; } } - if (createdTab == false) { - tabEvent->setErrorMessage("Workbench is exhausted. It cannot create any more tabs."); + if ( ! createdTab) { + tabEvent->setErrorMessage("Workbench is unable to create tabs, all tabs are in use."); + } + } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE) { + EventBrowserTabNewClone* cloneTabEvent = dynamic_cast(event); + CaretAssert(cloneTabEvent); + + cloneTabEvent->setEventProcessed(); + + const int32_t cloneTabIndex = cloneTabEvent->getIndexOfBrowserTabThatWasCloned(); + if ((cloneTabIndex < 0) + || (cloneTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { + cloneTabEvent->setErrorMessage("Invalid tab for cloning index=" + AString::number(cloneTabIndex)); + return; + } + + int32_t newTabIndex(-1); + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + if (m_browserTabs[i] == NULL) { + newTabIndex = i; + break; + } + } + if (newTabIndex >= 0) { + CaretAssertArrayIndex(m_browserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, cloneTabIndex); + CaretAssertArrayIndex(m_browserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, newTabIndex); + m_browserTabs[newTabIndex] = new BrowserTabContent(newTabIndex); + m_browserTabs[newTabIndex]->update(m_models); + m_browserTabs[newTabIndex]->cloneBrowserTabContent(m_browserTabs[cloneTabIndex]); + cloneTabEvent->setNewBrowserTab(m_browserTabs[newTabIndex], + newTabIndex); + } + else { + cloneTabEvent->setErrorMessage("Workbench is unable to create tabs, all tabs are in use."); } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { @@ -443,6 +500,35 @@ SessionManager::receiveEvent(Event* event) getDisplayedModelsEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_SPACER_TAB_GET) { + EventSpacerTabGet* spacerTabEvent = dynamic_cast(event); + CaretAssert(spacerTabEvent); + + SpacerTabContent* spacerTabContent = NULL; + + SpacerTabIndex spacerTabIndex(spacerTabEvent->getWindowIndex(), + spacerTabEvent->getRowIndex(), + spacerTabEvent->getColumnIndex()); + auto iter = m_spacerTabsMap.find(spacerTabIndex); + if (iter != m_spacerTabsMap.end()) { + spacerTabContent = iter->second; + CaretLogFiner("Found Spacer Tab Content: " + + spacerTabContent->getTabName()); + } + else { + spacerTabContent = new SpacerTabContent(spacerTabEvent->getWindowIndex(), + spacerTabEvent->getRowIndex(), + spacerTabEvent->getColumnIndex()); + m_spacerTabsMap.insert(std::make_pair(spacerTabIndex, + spacerTabContent)); + CaretLogFiner("Created Spacer Tab Content: " + + spacerTabContent->getTabName()); + } + + CaretAssert(spacerTabContent); + spacerTabEvent->setSpacerTabContent(spacerTabContent); + spacerTabEvent->setEventProcessed(); + } } /** @@ -590,6 +676,9 @@ SessionManager::saveToScene(const SceneAttributes* sceneAttributes, sceneClass->addChild(colorHelper.saveToScene(sceneAttributes, "backgroundAndForegroundColors")); + sceneClass->addClass(savePreferencesToScene(sceneAttributes, + "ScenePreferenceDataValues")); + return sceneClass; } @@ -607,12 +696,13 @@ SessionManager::saveToScene(const SceneAttributes* sceneAttributes, */ void SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) + const SceneClass* sceneClass) { /* * Default to user preferences for colors */ m_caretPreferences->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); + m_caretPreferences->invalidateSceneDataValues(); if (sceneClass == NULL) { return; @@ -800,6 +890,11 @@ SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, } } + /* + * Remove all spacer tabs + */ + clearSpacerTabs(); + /* * Restore tabs */ @@ -902,6 +997,9 @@ SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, } } + restorePreferencesFromScene(sceneAttributes, + sceneClass->getClass("ScenePreferenceDataValues")); + m_imageCaptureDialogSettings->restoreFromScene(sceneAttributes, sceneClass->getClass("m_imageCaptureDialogSettings")); @@ -919,6 +1017,72 @@ SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, } } +/** + * Save items in preferences to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name for the scene class + * + * @return Pointer to scene class containing preferences + */ +SceneClass* +SessionManager::savePreferencesToScene(const SceneAttributes* /*sceneAttributes*/, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ScenePreferences", + 1); + std::vector sceneDataValues = m_caretPreferences->getPreferenceSceneDataValues(); + for (auto scv : sceneDataValues) { + if (scv->isSavedToScenes()) { + sceneClass->addString(scv->getName(), + scv->getPreferenceValue().toString()); + } + } + + return sceneClass; +} + +/** + * Restore items in preferences from the scene + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass containing the preference items. + */ +void +SessionManager::restorePreferencesFromScene(const SceneAttributes* /*sceneAttributes*/, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + const QString invalidValueName("InVaLiDvAlUe"); + m_caretPreferences->invalidateSceneDataValues(); + + std::vector sceneDataValues = m_caretPreferences->getPreferenceSceneDataValues(); + for (auto scv : sceneDataValues) { + if (scv->isSavedToScenes()) { + const QString name = scv->getName(); + const QString value = sceneClass->getStringValue(scv->getName(), + invalidValueName); + if (value != invalidValueName) { + scv->setSceneValue(QVariant(value)); + } + } + } +} + /** * Reset the first brain and remove all other brains. */ @@ -938,6 +1102,8 @@ SessionManager::resetBrains(const bool keepSceneFiles) } } + clearSpacerTabs(); + if (numBrains > 1) { m_brains.resize(1); } @@ -979,6 +1145,24 @@ SessionManager::getCiftiFiberTrajectoryManager() const return m_ciftiFiberTrajectoryManager; } +/** + * @return The data tool tips manager + */ +DataToolTipsManager* +SessionManager::getDataToolTipsManager() +{ + return m_dataToolTipsManager.get(); +} + +/** + * @return The data tool tips manager (const method) + */ +const DataToolTipsManager* +SessionManager::getDataToolTipsManager() const +{ + return m_dataToolTipsManager.get(); +} + /** * @return Image capture settings for image capture dialog. */ @@ -997,4 +1181,21 @@ SessionManager::getImageCaptureDialogSettings() const return m_imageCaptureDialogSettings; } +/** + * @return The movie recorder + */ +MovieRecorder* +SessionManager::getMovieRecorder() +{ + return m_movieRecorder.get(); +} + +/** + * @return The movie recorder (const method) + */ +const MovieRecorder* +SessionManager::getMovieRecorder() const +{ + return m_movieRecorder.get(); +} diff --git a/src/Brain/SessionManager.h b/src/Brain/SessionManager.h index 9590293272177760b37c8ba0e39e62efc45f0550..319985f1a17cb0b8a5543fe1117eac1c3ca3b883 100644 --- a/src/Brain/SessionManager.h +++ b/src/Brain/SessionManager.h @@ -22,12 +22,15 @@ /*LICENSE_END*/ #include +#include +#include #include "ApplicationTypeEnum.h" #include "BrainConstants.h" #include "CaretObject.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" +#include "SpacerTabIndex.h" namespace caret { @@ -37,8 +40,11 @@ namespace caret { class CaretPreferences; class CiftiConnectivityMatrixDataFileManager; class CiftiFiberTrajectoryManager; + class DataToolTipsManager; class ImageCaptureSettings; class Model; + class MovieRecorder; + class SpacerTabContent; /// Manages a Caret session which contains 'global' brain data. class SessionManager : public CaretObject, public EventListenerInterface, public SceneableInterface { @@ -68,10 +74,18 @@ namespace caret { const CiftiFiberTrajectoryManager* getCiftiFiberTrajectoryManager() const; + DataToolTipsManager* getDataToolTipsManager(); + + const DataToolTipsManager* getDataToolTipsManager() const; + ImageCaptureSettings* getImageCaptureDialogSettings(); const ImageCaptureSettings* getImageCaptureDialogSettings() const; + MovieRecorder* getMovieRecorder(); + + const MovieRecorder* getMovieRecorder() const; + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); @@ -94,6 +108,14 @@ namespace caret { void resetBrains(const bool keepSceneFiles); + void clearSpacerTabs(); + + SceneClass* savePreferencesToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + void restorePreferencesFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + /** The session manager */ static SessionManager* s_singletonSessionManager; @@ -118,9 +140,16 @@ namespace caret { /** Loads fiber trajectory data */ CiftiFiberTrajectoryManager* m_ciftiFiberTrajectoryManager; + /** Data Tool Tips Manager */ + std::unique_ptr m_dataToolTipsManager; + /** Settings for image capture dialog */ ImageCaptureSettings* m_imageCaptureDialogSettings; + /** Map to spacer tabs where key is window index, row index, column index */ + std::map m_spacerTabsMap; + + std::unique_ptr m_movieRecorder; }; #ifdef __SESSION_MANAGER_DECLARE__ diff --git a/src/Brain/SpacerTabContent.cxx b/src/Brain/SpacerTabContent.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1d7efb7adc14913eb7b9a97c9f2627db962473da --- /dev/null +++ b/src/Brain/SpacerTabContent.cxx @@ -0,0 +1,123 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SPACER_TAB_CONTENT_DECLARE__ +#include "SpacerTabContent.h" +#undef __SPACER_TAB_CONTENT_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SpacerTabContent + * \brief Content of a tile tabs 'spacer' + * \ingroup Brain + */ + +/** + * Constructor. + * + * @param windowIndex + * Index of the window. + * @param rowIndex + * Index of the row. + * @param columnIndex + * Index of the column. + */ +SpacerTabContent::SpacerTabContent(const int32_t windowIndex, + const int32_t rowIndex, + const int32_t columnIndex) +: TabContentBase(), +m_key(windowIndex, + rowIndex, + columnIndex) +{ +} + +/** + * Destructor. + */ +SpacerTabContent::~SpacerTabContent() +{ +} + +/** + * @return Name of the tab. + */ +AString +SpacerTabContent::getTabName() const +{ + AString s("Spacer " + + getTabNamePrefix()); + + return s; +} + +/** + * @return Prefix name of the tab. + */ +AString +SpacerTabContent::getTabNamePrefix() const +{ + AString s("%1, %2"); + s = s.arg(m_key.m_rowIndex).arg(m_key.m_columnIndex); + + return s; +} + +/** + * @return The spacer tab index. + */ +SpacerTabIndex +SpacerTabContent::getSpacerTabIndex() const +{ + return m_key; +} + +/** + * @return The Window index + */ +int32_t +SpacerTabContent::getWindowIndex() const +{ + return m_key.m_windowIndex; +} + +/** + * @return The row index + */ +int32_t +SpacerTabContent::getRowIndex() const +{ + return m_key.m_rowIndex; +} + +/** + * @return The column index + */ +int32_t +SpacerTabContent::getColumnIndex() const +{ + return m_key.m_columnIndex; +} + diff --git a/src/Brain/SpacerTabContent.h b/src/Brain/SpacerTabContent.h new file mode 100644 index 0000000000000000000000000000000000000000..5f4faf8baf5654050d36d2c6368dafd234fa5edd --- /dev/null +++ b/src/Brain/SpacerTabContent.h @@ -0,0 +1,74 @@ +#ifndef __SPACER_TAB_CONTENT_H__ +#define __SPACER_TAB_CONTENT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "SpacerTabIndex.h" +#include "TabContentBase.h" + + + +namespace caret { + + class SpacerTabContent : public TabContentBase { + + public: + SpacerTabContent(const int32_t windowIndex, + const int32_t rowIndex, + const int32_t columnIndex); + + virtual ~SpacerTabContent(); + + SpacerTabContent(const SpacerTabContent&) = delete; + + SpacerTabContent& operator=(const SpacerTabContent&) = delete; + + virtual AString getTabName() const override; + + virtual AString getTabNamePrefix() const override; + + SpacerTabIndex getSpacerTabIndex() const; + + int32_t getWindowIndex() const; + + int32_t getRowIndex() const; + + int32_t getColumnIndex() const; + + // ADD_NEW_METHODS_HERE + + private: + SpacerTabIndex m_key; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SPACER_TAB_CONTENT_DECLARE__ + // +#endif // __SPACER_TAB_CONTENT_DECLARE__ + +} // namespace +#endif //__SPACER_TAB_CONTENT_H__ diff --git a/src/Brain/SurfaceNodeColoring.cxx b/src/Brain/SurfaceNodeColoring.cxx index db8dc967ca3499bbaed4510c90f022c9ff6b0a5f..41912950bf65c23f151e773d8a4f53b4c4431812 100644 --- a/src/Brain/SurfaceNodeColoring.cxx +++ b/src/Brain/SurfaceNodeColoring.cxx @@ -467,7 +467,8 @@ SurfaceNodeColoring::colorSurfaceNodes(const DisplayPropertiesLabels* displayPro overlayRGBV); break; case DataFileTypeEnum::METRIC: - isColoringValid = this->assignMetricColoring(brainStructure, + case DataFileTypeEnum::METRIC_DYNAMIC: // same as metric + isColoringValid = this->assignMetricColoring(brainStructure, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, @@ -490,6 +491,8 @@ SurfaceNodeColoring::colorSurfaceNodes(const DisplayPropertiesLabels* displayPro break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; case DataFileTypeEnum::UNKNOWN: break; } diff --git a/src/Brain/SurfaceSelectionModel.cxx b/src/Brain/SurfaceSelectionModel.cxx index 57add87cab283aecf0e6b36aad060bc50a5d81d9..7d3aeb3677efba3a2ca0d257ccf58c37bb75bfe9 100644 --- a/src/Brain/SurfaceSelectionModel.cxx +++ b/src/Brain/SurfaceSelectionModel.cxx @@ -389,10 +389,8 @@ SurfaceSelectionModel::saveToScene(const SceneAttributes* /*sceneAttributes*/, Surface* surface = getSurface(); if (surface != NULL) { - sceneClass->addString("m_selectedSurfaceFullPath", - surface->getFileName()); - sceneClass->addString("m_selectedSurface", - surface->getFileNameNoPath()); + sceneClass->addPathName("m_selectedSurfacePathName", + surface->getFileName()); } return sceneClass; @@ -420,41 +418,56 @@ SurfaceSelectionModel::restoreFromScene(const SceneAttributes* /*sceneAttributes std::vector allSurfaces = getAvailableSurfaces(); - const AString& surfaceFileNameFullPath = sceneClass->getStringValue("m_selectedSurfaceFullPath", - ""); /* - * For full path, find the best match using the right-most characters that - * will contain any relative path. When scene files are moved to different - * computers the full path may change the parts of the path nearest the - * name of the file will match. + * Element "m_selectedSurfacePathName" replaces older elements + * and fixes problem with absolute paths in the scene file */ + const AString surfacePathName = sceneClass->getPathNameValue("m_selectedSurfacePathName"); Surface* pathNameMatchSurface = NULL; - int32_t pathNameMatchLength = 0; - if ( ! surfaceFileNameFullPath.isEmpty()) { + Surface* nameMatchSurface = NULL; + if ( ! surfacePathName.isEmpty()) { for (auto surface : allSurfaces) { - const AString name = surface->getFileName(); - const int32_t numMatch = name.countMatchingCharactersFromEnd(surfaceFileNameFullPath); - if (numMatch > pathNameMatchLength) { - pathNameMatchLength = numMatch; + if (surface->getFileName() == surfacePathName) { pathNameMatchSurface = surface; + break; } } } - - /* - * Match name of file with NO path - * Always restore this so that the object is marked as restored - * (within the 'get' method). Otherwise if compiled debug, this - * object will get logged as 'not restored'. - */ - Surface* nameMatchSurface = NULL; - const AString& surfaceFileName = sceneClass->getStringValue("m_selectedSurface", - ""); - if ( ! surfaceFileName.isEmpty()) { - for (auto surface : allSurfaces) { - if (surface->getFileNameNoPath() == surfaceFileName) { - nameMatchSurface = surface; - break; + else { + /* + * For full path, find the best match using the right-most characters that + * will contain any relative path. When scene files are moved to different + * computers the full path may change the parts of the path nearest the + * name of the file will match. + */ + const AString surfaceFileNameFullPath = sceneClass->getStringValue("m_selectedSurfaceFullPath", + ""); + int32_t pathNameMatchLength = 0; + if ( ! surfaceFileNameFullPath.isEmpty()) { + for (auto surface : allSurfaces) { + const AString name = surface->getFileName(); + const int32_t numMatch = name.countMatchingCharactersFromEnd(surfaceFileNameFullPath); + if (numMatch > pathNameMatchLength) { + pathNameMatchLength = numMatch; + pathNameMatchSurface = surface; + } + } + } + + /* + * Match name of file with NO path + * Always restore this so that the object is marked as restored + * (within the 'get' method). Otherwise if compiled debug, this + * object will get logged as 'not restored'. + */ + const AString surfaceFileName = sceneClass->getStringValue("m_selectedSurface", + ""); + if ( ! surfaceFileName.isEmpty()) { + for (auto surface : allSurfaces) { + if (surface->getFileNameNoPath() == surfaceFileName) { + nameMatchSurface = surface; + break; + } } } } diff --git a/src/Brain/TabContentBase.cxx b/src/Brain/TabContentBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0763f3e31acdbeb91e6ab30a41789a7404f56829 --- /dev/null +++ b/src/Brain/TabContentBase.cxx @@ -0,0 +1,64 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __TAB_CONTENT_BASE_DECLARE__ +#include "TabContentBase.h" +#undef __TAB_CONTENT_BASE_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::TabContentBase + * \brief + * \ingroup Brain + * + * + */ + +/** + * Constructor. + */ +TabContentBase::TabContentBase() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +TabContentBase::~TabContentBase() +{ +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +TabContentBase::toString() const +{ + return "TabContentBase"; +} + diff --git a/src/Brain/TabContentBase.h b/src/Brain/TabContentBase.h new file mode 100644 index 0000000000000000000000000000000000000000..ae4f203790b4b3e95c919ed24d4db9840b18610f --- /dev/null +++ b/src/Brain/TabContentBase.h @@ -0,0 +1,63 @@ +#ifndef __TAB_CONTENT_BASE_H__ +#define __TAB_CONTENT_BASE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class TabContentBase : public CaretObject { + + public: + TabContentBase(); + + virtual ~TabContentBase(); + + TabContentBase(const TabContentBase&) = delete; + + TabContentBase& operator=(const TabContentBase&) = delete; + + virtual AString getTabName() const = 0; + + virtual AString getTabNamePrefix() const = 0; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __TAB_CONTENT_BASE_DECLARE__ + // +#endif // __TAB_CONTENT_BASE_DECLARE__ + +} // namespace +#endif //__TAB_CONTENT_BASE_H__ diff --git a/src/Brain/UserInputModeEnum.cxx b/src/Brain/UserInputModeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9a9749feae58e26d5e37c76bae7c72a9d665e00d --- /dev/null +++ b/src/Brain/UserInputModeEnum.cxx @@ -0,0 +1,393 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __USER_INPUT_MODE_ENUM_DECLARE__ +#include "UserInputModeEnum.h" +#undef __USER_INPUT_MODE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::UserInputModeEnum + * \brief User Input Modes for Browser Window + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_userInputModeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void userInputModeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "UserInputModeEnum.h" + * + * Instatiate: + * m_userInputModeEnumComboBox = new EnumComboBoxTemplate(this); + * m_userInputModeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_userInputModeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(userInputModeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_userInputModeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const UserInputModeEnum::Enum VARIABLE = m_userInputModeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +UserInputModeEnum::UserInputModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +UserInputModeEnum::~UserInputModeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +UserInputModeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(UserInputModeEnum(INVALID, + "INVALID", + "Invalid")); + + enumData.push_back(UserInputModeEnum(ANNOTATIONS, + "ANNOTATIONS", + "Annotations")); + + enumData.push_back(UserInputModeEnum(BORDERS, + "BORDERS", + "Borders")); + + enumData.push_back(UserInputModeEnum(FOCI, + "FOCI", + "Foci")); + + enumData.push_back(UserInputModeEnum(IMAGE, + "IMAGE", + "Image")); + + enumData.push_back(UserInputModeEnum(VIEW, + "VIEW", + "View")); + + enumData.push_back(UserInputModeEnum(VOLUME_EDIT, + "VOLUME_EDIT", + "Volume Edit")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const UserInputModeEnum* +UserInputModeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const UserInputModeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +UserInputModeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const UserInputModeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +UserInputModeEnum::Enum +UserInputModeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = UserInputModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const UserInputModeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type UserInputModeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +UserInputModeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const UserInputModeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +UserInputModeEnum::Enum +UserInputModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = UserInputModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const UserInputModeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type UserInputModeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +UserInputModeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const UserInputModeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +UserInputModeEnum::Enum +UserInputModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = UserInputModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const UserInputModeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type UserInputModeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +UserInputModeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +UserInputModeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(UserInputModeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +UserInputModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(UserInputModeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Brain/UserInputModeEnum.h b/src/Brain/UserInputModeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..564e4c488e6a1a730267fd742a96abcf73417545 --- /dev/null +++ b/src/Brain/UserInputModeEnum.h @@ -0,0 +1,114 @@ +#ifndef __USER_INPUT_MODE_ENUM_H__ +#define __USER_INPUT_MODE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class UserInputModeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Invalid */ + INVALID, + /** Annotations */ + ANNOTATIONS, + /** Borders */ + BORDERS, + /** Foci */ + FOCI, + /** Image */ + IMAGE, + /** View */ + VIEW, + /** Volume Edit */ + VOLUME_EDIT + }; + + + ~UserInputModeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + UserInputModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const UserInputModeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __USER_INPUT_MODE_ENUM_DECLARE__ +std::vector UserInputModeEnum::enumData; +bool UserInputModeEnum::initializedFlag = false; +int32_t UserInputModeEnum::integerCodeCounter = 0; +#endif // __USER_INPUT_MODE_ENUM_DECLARE__ + +} // namespace +#endif //__USER_INPUT_MODE_ENUM_H__ diff --git a/src/Brain/VolumeSliceSettings.cxx b/src/Brain/VolumeSliceSettings.cxx index a74ae6bb3e10630f0f276881ecf95ec07563e7b7..e43e307c1fdebb9a3d5b3d646d940fbd1437715a 100644 --- a/src/Brain/VolumeSliceSettings.cxx +++ b/src/Brain/VolumeSliceSettings.cxx @@ -23,12 +23,14 @@ #include "VolumeSliceSettings.h" #undef __VOLUME_SLICE_SETTINGS_DECLARE__ +#include "CaretPreferences.h" #include "DeveloperFlagsEnum.h" #include "CaretLogger.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SceneEnumeratedType.h" +#include "SessionManager.h" #include "VolumeFile.h" using namespace caret; @@ -49,8 +51,9 @@ const static VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum defaultVolumeS VolumeSliceSettings::VolumeSliceSettings() : CaretObject() { + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); m_sliceViewPlane = VolumeSliceViewPlaneEnum::AXIAL; - m_slicePlanesAllViewLayout = VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT; + m_slicePlanesAllViewLayout = prefs->getVolumeAllSlicePlanesLayout(); m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; m_volumeSliceInterpolationEdgeEffectsMaskingType = defaultVolumeSliceInterpolationEdgeMaskType; @@ -952,6 +955,14 @@ VolumeSliceSettings::restoreFromScene(const SceneAttributes* sceneAttributes, } } + /* + * For scenes before all view layout, use GRID so that the + * older scenes display correctly + */ + if (sceneClass->getObjectWithName("m_slicePlanesAllViewLayout") == NULL) { + m_slicePlanesAllViewLayout = VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT; + } + /* * Restoring scene initialize all members. * If this is not done, the slices will be reset diff --git a/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx b/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx index 08fc0c622cb9e3078838e762d514ae280abbf53a..d725d0138524db294f31feea2056839ef74ac9bb 100644 --- a/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx @@ -351,6 +351,20 @@ VolumeSurfaceOutlineColorOrTabModel::Item::~Item() } +/** + * Copy constructor. + * + * @param + * Item that is copied. + */ +VolumeSurfaceOutlineColorOrTabModel::Item::Item(const Item& item) +: SceneableInterface(item) +{ + m_color = item.m_color; + m_browserTabIndex = item.m_browserTabIndex; + m_itemType = item.m_itemType; +} + /** * Is this item equal to another item? * diff --git a/src/Brain/VolumeSurfaceOutlineColorOrTabModel.h b/src/Brain/VolumeSurfaceOutlineColorOrTabModel.h index 333256326140307533dda717e2e020eae998764f..7d116d7efb7344f5a0fd01b4a21307f7318fd446 100644 --- a/src/Brain/VolumeSurfaceOutlineColorOrTabModel.h +++ b/src/Brain/VolumeSurfaceOutlineColorOrTabModel.h @@ -49,6 +49,8 @@ namespace caret { Item(const int32_t browserTabIndex); + Item(const Item& item); + ~Item(); bool isValid() const; diff --git a/src/Brain/VolumeSurfaceOutlineModel.cxx b/src/Brain/VolumeSurfaceOutlineModel.cxx index 25dc6e9e50200f0d92307fcd9f62d9886f3ebf5d..b5956312c3208d9c81829b9ca96c72951b2b798b 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineModel.cxx @@ -23,15 +23,19 @@ #include "VolumeSurfaceOutlineModel.h" #undef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ +#include "EventManager.h" +#include "EventSurfaceColoringInvalidate.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SurfaceSelectionModel.h" #include "SurfaceTypeEnum.h" +#include "VolumeMappableInterface.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" +#include "VolumeSurfaceOutlineModelCacheValue.h" using namespace caret; - +static const bool debugFlag(false); /** * \class VolumeSurfaceOutlineSelection @@ -73,6 +77,8 @@ VolumeSurfaceOutlineModel::VolumeSurfaceOutlineModel() m_thicknessPercentageViewportHeight = -1.0f; m_sceneAssistant->add("m_thicknessPercentageViewportHeight", &m_thicknessPercentageViewportHeight); m_thicknessPercentageViewportHeight = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT; + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE); } /** @@ -80,10 +86,14 @@ VolumeSurfaceOutlineModel::VolumeSurfaceOutlineModel() */ VolumeSurfaceOutlineModel::~VolumeSurfaceOutlineModel() { + clearOutlineCache(); + delete m_surfaceSelectionModel; delete m_colorOrTabModel; delete m_sceneAssistant; + + EventManager::get()->removeAllEventsFromListener(this); } /** @@ -101,6 +111,28 @@ VolumeSurfaceOutlineModel::copyVolumeSurfaceOutlineModel(VolumeSurfaceOutlineMod VolumeSurfaceOutlineColorOrTabModel* colorTabToCopy = modelToCopy->getColorOrTabModel(); m_colorOrTabModel->copyVolumeSurfaceOutlineColorOrTabModel(colorTabToCopy); + + clearOutlineCache(); +} + +/** + * Receive an event. + * + * @param event + * The event that the receive can respond to. + */ +void +VolumeSurfaceOutlineModel::receiveEvent(Event* event) +{ + CaretAssert(event); + + if (event->getEventType() == EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE) { + EventSurfaceColoringInvalidate* colorEvent = dynamic_cast(event); + CaretAssert(colorEvent); + colorEvent->setEventProcessed(); + + clearOutlineCache(); + } } /** @@ -131,6 +163,10 @@ void VolumeSurfaceOutlineModel::setDisplayed(const bool displayed) { m_displayed = displayed; + + if ( ! m_displayed) { + clearOutlineCache(); + } } /** @@ -262,6 +298,171 @@ VolumeSurfaceOutlineModel::restoreFromScene(const SceneAttributes* sceneAttribut return; } + clearOutlineCache(); + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } + +/** + * Set the outline primitives for the given cache key + * + * @param key + * Key into the outline cache identifying axis and slice + * @param primitivesOut + * Input containing the primitives + */ +void +VolumeSurfaceOutlineModel::setOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, + const VolumeSurfaceOutlineModelCacheKey& key, + const std::vector& primitives) +{ + auto iter = m_outlineCache.find(key); + if (iter != m_outlineCache.end()) { + iter->second->setGraphicsPrimitive(primitives); + return; + } + + if (m_outlineCache.empty()) { + m_outlineCacheInfo.update(this, + underlayVolume); + } + + if (debugFlag) { + std::cout << "Adding " << key.toString() << std::endl; + } + VolumeSurfaceOutlineModelCacheValue* value = new VolumeSurfaceOutlineModelCacheValue(); + value->setGraphicsPrimitive(primitives); + m_outlineCache.insert(std::make_pair(key, value)); +} + + +/** + * Get the outline primitives for the given cache key + * + * @param underlayVolume + * The underlay volume + * @param key + * Key into the outline cache identifying axis and slice + * @param primitivesOut + * Output containing the primitives + * @return + * Truie if outline primitives valid, else false. + */ +bool +VolumeSurfaceOutlineModel::getOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, + const VolumeSurfaceOutlineModelCacheKey& key, + std::vector& primitivesOut) +{ + if ( ! m_outlineCacheInfo.isValid(this, + underlayVolume)) { + clearOutlineCache(); + } + + auto iter = m_outlineCache.find(key); + if (iter != m_outlineCache.end()) { + primitivesOut = iter->second->getGraphicsPrimitives(); + if (debugFlag) { + std::cout << "Found " << iter->first.toString() << std::endl; + } + return true; + } + + return false; +} + +/** + * Clear the outline cache + */ +void +VolumeSurfaceOutlineModel::clearOutlineCache() +{ + if (debugFlag) { + if ( ! m_outlineCache.empty()) { + std::cout << "Invalidating non-empty surface outline cache" << std::endl; + } + } + m_outlineCacheInfo.clear(); + + for (auto iter : m_outlineCache) { + delete iter.second; + } + m_outlineCache.clear(); +} + +/* ==========================================================================================*/ + +/** + * Constructor for outline cache + */ +VolumeSurfaceOutlineModel::OutlineCacheInfo::OutlineCacheInfo() +{ + clear(); +} + +/** + * Destructor + */ +VolumeSurfaceOutlineModel::OutlineCacheInfo::~OutlineCacheInfo() +{ + clear(); +} + +/** + * Clear the outline cache + */ +void +VolumeSurfaceOutlineModel::OutlineCacheInfo::clear() +{ + m_surface = NULL; + m_thicknessPercentageViewportHeight = -1.0; + m_colorItem.reset(); +} + +/** + * Is the outline cache valid? + * + * @param surfaceOutlineModel + * The parent surface outline model + * @param underlayVolume + * The underlay volume + * @return + * True if cache is valid, else false + */ +bool +VolumeSurfaceOutlineModel::OutlineCacheInfo::isValid(VolumeSurfaceOutlineModel* surfaceOutlineModel, + const VolumeMappableInterface* underlayVolume) +{ + bool validFlag(false); + if (m_surface != NULL) { + if ((m_surface == surfaceOutlineModel->getSurface()) + && (m_underlayVolume == underlayVolume) + && (m_thicknessPercentageViewportHeight == surfaceOutlineModel->getThicknessPercentageViewportHeight())) { + if (m_colorItem != NULL) { + if (m_colorItem->equals(*(surfaceOutlineModel->getColorOrTabModel()->getSelectedItem()))) { + validFlag = true; + } + } + } + } + + return validFlag; +} + +/** + * Update the cache info from the parent surface outline model + * + * @param surfaceOutlineModel + * The surface outline model + * @param underlayVolume + * The underlay volume + */ +void +VolumeSurfaceOutlineModel::OutlineCacheInfo::update(VolumeSurfaceOutlineModel* surfaceOutlineModel, + const VolumeMappableInterface* underlayVolume) +{ + m_underlayVolume = underlayVolume; + m_surface = surfaceOutlineModel->getSurface(); + m_thicknessPercentageViewportHeight = surfaceOutlineModel->getThicknessPercentageViewportHeight(); + m_colorItem.reset(new VolumeSurfaceOutlineColorOrTabModel::Item(*(surfaceOutlineModel->getColorOrTabModel()->getSelectedItem()))); +} diff --git a/src/Brain/VolumeSurfaceOutlineModel.h b/src/Brain/VolumeSurfaceOutlineModel.h index 64d7e47a3aa9bee0f3227c4f2916ccf5120143c0..3150529d5c709296a71b47f229aac6cab61350b4 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.h +++ b/src/Brain/VolumeSurfaceOutlineModel.h @@ -21,18 +21,25 @@ */ /*LICENSE_END*/ +#include + #include "CaretObject.h" +#include "EventListenerInterface.h" #include "SceneableInterface.h" +#include "VolumeSurfaceOutlineColorOrTabModel.h" +#include "VolumeSurfaceOutlineModelCacheKey.h" namespace caret { + class GraphicsPrimitive; class Surface; class SceneAttributes; class SceneClassAssistant; class SurfaceSelectionModel; - class VolumeSurfaceOutlineColorOrTabModel; + class VolumeMappableInterface; + class VolumeSurfaceOutlineModelCacheValue; - class VolumeSurfaceOutlineModel : public CaretObject, public SceneableInterface { + class VolumeSurfaceOutlineModel : public CaretObject, public EventListenerInterface, public SceneableInterface { public: VolumeSurfaceOutlineModel(); @@ -41,6 +48,8 @@ namespace caret { void copyVolumeSurfaceOutlineModel(VolumeSurfaceOutlineModel* modelToCopy); + virtual void receiveEvent(Event* event) override; + bool isDisplayed() const; void setDisplayed(const bool displayed); @@ -63,6 +72,14 @@ namespace caret { const VolumeSurfaceOutlineColorOrTabModel* getColorOrTabModel() const; + void setOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, + const VolumeSurfaceOutlineModelCacheKey& key, + const std::vector& primitives); + + bool getOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, + const VolumeSurfaceOutlineModelCacheKey& key, + std::vector& primitivesOut); + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); @@ -81,6 +98,8 @@ namespace caret { virtual AString toString() const; private: + void clearOutlineCache(); + bool m_displayed; float m_thicknessPixelsObsolete; @@ -92,6 +111,39 @@ namespace caret { VolumeSurfaceOutlineColorOrTabModel* m_colorOrTabModel; SceneClassAssistant* m_sceneAssistant; + + class OutlineCacheInfo { + public: + OutlineCacheInfo(); + + ~OutlineCacheInfo(); + + void clear(); + + bool isValid(VolumeSurfaceOutlineModel* surfaceOutlineModel, + const VolumeMappableInterface* underlayVolume); + + void update(VolumeSurfaceOutlineModel* surfaceOutlineModel, + const VolumeMappableInterface* underlayVolume); + + /** The underlay volume */ + const VolumeMappableInterface* m_underlayVolume; + + /** Thickness when first outline is added to outline cache */ + float m_thicknessPercentageViewportHeight = -1.0; + + /** Surface when first outline is added to outline cache */ + Surface* m_surface = NULL; + + /** Color Or Tab selection item when first outline is added to cache */ + std::unique_ptr m_colorItem; + }; + + /** info about outline cache that tracks validity of cache */ + OutlineCacheInfo m_outlineCacheInfo; + + /** Cache for volume surface outlines */ + std::map m_outlineCache; }; #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ diff --git a/src/Brain/VolumeSurfaceOutlineModelCacheKey.cxx b/src/Brain/VolumeSurfaceOutlineModelCacheKey.cxx new file mode 100644 index 0000000000000000000000000000000000000000..83d98bb57e4186b74b589965b193d1becd9f901d --- /dev/null +++ b/src/Brain/VolumeSurfaceOutlineModelCacheKey.cxx @@ -0,0 +1,314 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ +#include "VolumeSurfaceOutlineModelCacheKey.h" +#undef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "Plane.h" +#include "VolumeMappableInterface.h" + +using namespace caret; + + + +/** + * \class caret::VolumeSurfaceOutlineModelCacheKey + * \brief Key for a cached volume surface outline model + * \ingroup Brain + */ + +/** + * Constructor. + * + * @param underlayVolume + * The underlay volume + * @param sliceViewPlane + * The orthogonal slice view plane + * @param sliceCoordinate + * Coordinate of slice in orthogonal view plane + */ +VolumeSurfaceOutlineModelCacheKey::VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinate) +: CaretObject(), +m_mode(Mode::SLICE_VIEW_PLANE), +m_sliceViewPlane(sliceViewPlane) +{ + const float scaleFactor = computeScaleFactor(underlayVolume); + m_sliceCoordinateScaled = static_cast(sliceCoordinate * scaleFactor); + +// CaretAssert(underlayVolume); +// if (underlayVolume != NULL) { +// float voxelSizesMM[3]; +// underlayVolume->getVoxelSpacing(voxelSizesMM[0], +// voxelSizesMM[1], +// voxelSizesMM[2]); +// +// float voxelSize(0.0); +// switch (sliceViewPlane) { +// case VolumeSliceViewPlaneEnum::ALL: +// voxelSize = voxelSizesMM[2]; +// break; +// case VolumeSliceViewPlaneEnum::AXIAL: +// voxelSize = voxelSizesMM[2]; +// break; +// case VolumeSliceViewPlaneEnum::CORONAL: +// voxelSize = voxelSizesMM[1]; +// break; +// case VolumeSliceViewPlaneEnum::PARASAGITTAL: +// voxelSize = voxelSizesMM[0]; +// break; +// } +// +// if (voxelSize > 0.0) { +// /* +// * The coordinate for the slice is stored as an integer since +// * since integer comparison is precise oppposed to a float comparison +// * that requires some sort of tolerance. +// * +// * (1.0 / voxelSize) is used so that the scale factor will +// * be larger for small voxels and prevent an outline from +// * being used by adjacent volume slices +// */ +// const float scaleFactor = 10.0 * (1.0 / voxelSize); +// m_sliceCoordinateScaled = static_cast(std::round(sliceCoordinate * scaleFactor)); +// } +// } +} + +/** + * Constructor. + * + * @param underlayVolume + * The underlay volume + * @param sliceViewPlane + * The orthogonal slice view plane + * @param sliceCoordinate + * Coordinate of slice in orthogonal view plane + */ +VolumeSurfaceOutlineModelCacheKey::VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, + const Plane& plane) +: m_mode(Mode::PLANE_EQUATION) +{ + CaretAssert(underlayVolume); + if (underlayVolume != NULL) { + const float scaleFactor = computeScaleFactor(underlayVolume); + double a, b, c, d; + plane.getPlane(a, b, c, d); + m_planeEquationScaled[0] = scaleFactor * a; + m_planeEquationScaled[1] = scaleFactor * b; + m_planeEquationScaled[2] = scaleFactor * c; + m_planeEquationScaled[3] = scaleFactor * d; + } +} + +/** + * Compute the scale that is used to scale float values into integers + * + * @param underlayVolume + * The underlay volume whose voxel sizes are used to determine the scale factor + * @return The scale factor + */ +float +VolumeSurfaceOutlineModelCacheKey::computeScaleFactor(const VolumeMappableInterface* underlayVolume) const +{ + float scaleFactor(10.0); + + if (underlayVolume != NULL) { + float voxelSizesMM[3]; + underlayVolume->getVoxelSpacing(voxelSizesMM[0], + voxelSizesMM[1], + voxelSizesMM[2]); + const float voxelSize = std::min(std::min(voxelSizesMM[0], voxelSizesMM[1]), + voxelSizesMM[2]); + if (voxelSize > 0.0) { + /* + * The coordinate for the slice is stored as an integer since + * since integer comparison is precise oppposed to a float comparison + * that requires some sort of tolerance. + * + * (1.0 / voxelSize) is used so that the scale factor will + * be larger for small voxels and prevent an outline from + * being used by adjacent volume slices + */ + scaleFactor = 10.0 * (1.0 / voxelSize); + } + } + + return scaleFactor; +} + +/** + * Destructor. + */ +VolumeSurfaceOutlineModelCacheKey::~VolumeSurfaceOutlineModelCacheKey() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +VolumeSurfaceOutlineModelCacheKey::VolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj) +: CaretObject(obj) +{ + this->copyHelperVolumeSurfaceOutlineModelCacheKey(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +VolumeSurfaceOutlineModelCacheKey& +VolumeSurfaceOutlineModelCacheKey::operator=(const VolumeSurfaceOutlineModelCacheKey& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperVolumeSurfaceOutlineModelCacheKey(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +VolumeSurfaceOutlineModelCacheKey::copyHelperVolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj) +{ + m_mode = obj.m_mode; + m_sliceViewPlane = obj.m_sliceViewPlane; + m_sliceCoordinateScaled = obj.m_sliceCoordinateScaled; + m_planeEquationScaled = obj.m_planeEquationScaled; +} + +///** +// * Equality operator. +// * @param obj +// * Instance compared to this for equality. +// * @return +// * True if this instance and 'obj' instance are considered equal. +// */ +//bool +//VolumeSurfaceOutlineModelCacheKey::operator==(const VolumeSurfaceOutlineModelCacheKey& obj) const +//{ +// if (this == &obj) { +// return true; +// } +// +// /* perform equality testing HERE and return true if equal ! */ +// if ((m_sliceViewPlane == obj.m_sliceViewPlane) +// && (m_sliceCoordinateScaled == obj.m_sliceCoordinateScaled)) { +// return true; +// } +// +// return false; +//} + +/** + * Less than operator. + * + * @param obj + * Instance compared to this for equality. + * @return + * True if this instance and 'obj' instance are considered equal. + */ +bool +VolumeSurfaceOutlineModelCacheKey::operator<(const VolumeSurfaceOutlineModelCacheKey& obj) const +{ + if (this == &obj) { + return false; + } + + if (m_mode == obj.m_mode) { + switch (m_mode) { + case Mode::PLANE_EQUATION: + { + for (int32_t i = 0; i < static_cast(m_planeEquationScaled.size()); i++) { + if (m_planeEquationScaled[i] < obj.m_planeEquationScaled[i]) { + return true; + } + else if (m_planeEquationScaled[i] > obj.m_planeEquationScaled[i]) { + return false; + } + } + } + break; + case Mode::SLICE_VIEW_PLANE: + { + if (static_cast(m_sliceViewPlane) < static_cast(obj.m_sliceViewPlane)) { + return true; + } + else if (static_cast(m_sliceViewPlane) > static_cast(obj.m_sliceViewPlane)) { + return false; + } + + if (m_sliceCoordinateScaled < obj.m_sliceCoordinateScaled) { + return true; + } + } + break; + } + } + else { + if (static_cast(m_mode) < static_cast(obj.m_mode)) { + return true; + } + } + + + return false; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +VolumeSurfaceOutlineModelCacheKey::toString() const +{ + QString str; + switch (m_mode) { + case Mode::PLANE_EQUATION: + str = ("Plane Equation = " + + AString::fromNumbers(&m_planeEquationScaled[0], m_planeEquationScaled.size(), ",")); + break; + case Mode::SLICE_VIEW_PLANE: + str = ("Slice View Plane=" + + VolumeSliceViewPlaneEnum::toName(m_sliceViewPlane) + + ", " + + "ScaledCoordinate=" + + QString::number(m_sliceCoordinateScaled)); + break; + } + + return str; +} + diff --git a/src/Brain/VolumeSurfaceOutlineModelCacheKey.h b/src/Brain/VolumeSurfaceOutlineModelCacheKey.h new file mode 100644 index 0000000000000000000000000000000000000000..4ebbecdc1d767fd8deb4d92e1b3a9122d41ea754 --- /dev/null +++ b/src/Brain/VolumeSurfaceOutlineModelCacheKey.h @@ -0,0 +1,89 @@ +#ifndef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_H__ +#define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include "CaretObject.h" +#include "Plane.h" +#include "VolumeSliceViewPlaneEnum.h" + +namespace caret { + + class Plane; + + class VolumeMappableInterface; + + class VolumeSurfaceOutlineModelCacheKey : public CaretObject { + + public: + VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const float sliceCoordinate); + + VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, + const Plane& plane); + + virtual ~VolumeSurfaceOutlineModelCacheKey(); + + VolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj); + + VolumeSurfaceOutlineModelCacheKey& operator=(const VolumeSurfaceOutlineModelCacheKey& obj); + +// bool operator==(const VolumeSurfaceOutlineModelCacheKey& obj) const; + + bool operator<(const VolumeSurfaceOutlineModelCacheKey& obj) const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + enum class Mode { + PLANE_EQUATION, + SLICE_VIEW_PLANE + }; + + void copyHelperVolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj); + + float computeScaleFactor(const VolumeMappableInterface* underlayVolume) const; + + Mode m_mode; + + VolumeSliceViewPlaneEnum::Enum m_sliceViewPlane = VolumeSliceViewPlaneEnum::ALL; + + int64_t m_sliceCoordinateScaled = 100000; + + std::array m_planeEquationScaled; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ + // +#endif // __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ + +} // namespace +#endif //__VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_H__ diff --git a/src/Brain/VolumeSurfaceOutlineModelCacheValue.cxx b/src/Brain/VolumeSurfaceOutlineModelCacheValue.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d7af8a145a080fe0f3a419fa8282a5b94baeb85e --- /dev/null +++ b/src/Brain/VolumeSurfaceOutlineModelCacheValue.cxx @@ -0,0 +1,95 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ +#include "VolumeSurfaceOutlineModelCacheValue.h" +#undef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ + +#include "CaretAssert.h" +#include "GraphicsPrimitive.h" + +using namespace caret; + +/** + * \class caret::VolumeSurfaceOutlineModelCacheValue + * \brief Data for a cached surface outline model + * \ingroup Brain + */ + +/** + * Constructor. + */ +VolumeSurfaceOutlineModelCacheValue::VolumeSurfaceOutlineModelCacheValue() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +VolumeSurfaceOutlineModelCacheValue::~VolumeSurfaceOutlineModelCacheValue() +{ + deletePrimitives(); +} + +/** + * Delete the primitives. + */ +void +VolumeSurfaceOutlineModelCacheValue::deletePrimitives() +{ + for (auto p : m_contourLinePrimitives) { + delete p; + } + m_contourLinePrimitives.clear(); +} + +/** + * @return Reference to the graphics primitives; + */ +std::vector +VolumeSurfaceOutlineModelCacheValue::getGraphicsPrimitives() const +{ + return m_contourLinePrimitives; +} + +/** + * Set the primitives in this cache. Any current primitives are replaced and destroyed + */ +void +VolumeSurfaceOutlineModelCacheValue::setGraphicsPrimitive(const std::vector& primitives) +{ + deletePrimitives(); + + m_contourLinePrimitives = primitives; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +VolumeSurfaceOutlineModelCacheValue::toString() const +{ + return "VolumeSurfaceOutlineModelCacheValue"; +} + diff --git a/src/Brain/VolumeSurfaceOutlineModelCacheValue.h b/src/Brain/VolumeSurfaceOutlineModelCacheValue.h new file mode 100644 index 0000000000000000000000000000000000000000..755777478d8229c6fdb210692397cf7475e5b273 --- /dev/null +++ b/src/Brain/VolumeSurfaceOutlineModelCacheValue.h @@ -0,0 +1,68 @@ +#ifndef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_H__ +#define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + class GraphicsPrimitive; + + class VolumeSurfaceOutlineModelCacheValue : public CaretObject { + + public: + VolumeSurfaceOutlineModelCacheValue(); + + virtual ~VolumeSurfaceOutlineModelCacheValue(); + + VolumeSurfaceOutlineModelCacheValue(const VolumeSurfaceOutlineModelCacheValue&) = delete; + + VolumeSurfaceOutlineModelCacheValue& operator=(const VolumeSurfaceOutlineModelCacheValue&) = delete; + + void setGraphicsPrimitive(const std::vector& primitives); + + std::vector getGraphicsPrimitives() const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void deletePrimitives(); + + std::vector m_contourLinePrimitives; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ + // +#endif // __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ + +} // namespace +#endif //__VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78674261529332b04d3273000e61a1237e0b3b40..858a096cdebe011b3538c4217b50a5c7644d4627 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ # CMAKE_MINIMUM_REQUIRED (VERSION 2.8) +SET(WB_VERSION "1.4.0") # # Set to true for verbose output when debugging this file # @@ -185,6 +186,15 @@ ENDIF(OPENSSL_FOUND) # https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) # Modules List: http://doc.qt.io/qt-5/qtmodules.html # +SET(WB_WEBKIT_COMPONENTS "") +SET(WB_WEBKIT_LIBS "") +SET(HAVE_QT_WEBKIT False) +IF (HAVE_QT_WEBKIT) + ADD_DEFINITIONS(-DHAVE_WEBKIT) + SET (WB_WEBKIT_COMPONENTS "WebEngine WebEngineCore WebEngineWidgets") + SET (WB_WEBKIT_LIBS "Qt5::WebEngine Qt5::WebEngineCore Qt5::WebEngineWidgets") + +ENDIF (HAVE_QT_WEBKIT) SET(QT_RESULT "Not Found") SET(CARET_QT5_LINK "") IF (WORKBENCH_USE_QT5) @@ -197,7 +207,7 @@ IF (WORKBENCH_USE_QT5) SET(WB_QT_OPENGL_MODULE "OpenGL") ENDIF () - FIND_PACKAGE(Qt5 REQUIRED COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) + FIND_PACKAGE(Qt5 REQUIRED COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml ${WB_WEBKIT_COMPONENTS}) IF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) # # QGLWidget is deprecated in Qt 5 and is replaced with QOpenGLWidget @@ -245,6 +255,35 @@ ELSE (Qwt_FOUND) SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) +########################################################################################## +# +# glm Math Library is header filess only containing C++ templates and functions. +# Since there is no code to link, only need the path to the include files +# https://glm.g-truc.net/0.9.9/index.html +# +SET(GLMATH_RESULT "Not Found") +IF (NOT WIN32) + PKG_CHECK_MODULES(GLMath glm) +ENDIF (NOT WIN32) +IF (GLMath_FOUND) + SET(GLMATH_RESULT "Using OpenGL Math directory ${GLMath_INCLUDE_DIRS}") + INCLUDE_DIRECTORIES("${GLMath_INCLUDE_DIRS}") +ELSE (GLMath_FOUND) + SET(GLMATH_RESULT "In Workbench Source Code") + INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/GLMath") +ENDIF (GLMath_FOUND) + + +########################################################################################## +# +# Can Use OpenCL +# +SET(OPENCL_RESULT "Not found (OK, unused at this time)") +FIND_PACKAGE(OpenCL) +IF (OpenCL_FOUND) + SET(OPENCL_RESULT "Version: ${OpenCL_VERSION_STRING}") +ENDIF (OpenCL_FOUND) + ########################################################################################## # # Need OpenGL @@ -589,6 +628,8 @@ IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) MESSAGE(${MSG_MODE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "GLEW: " ${GLEW_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "GLMath: " ${GLMATH_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenCL: " ${OPENCL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenGL: " ${OPENGL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 7ea1038348afb77f6b4da48a6bd53936c33cf350..6cb8dacdf45cf1d4e2cca13cf1bc273014b2d649 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -27,6 +27,7 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartTwoDataCartesian.h" +#include "MapFileDataSelector.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -159,7 +160,7 @@ ChartTwoLineSeriesHistory::validateDefaultColor() { std::vector allEnums; CaretColorEnum::getColorAndOptionalEnums(allEnums, (CaretColorEnum::ColorOptions::OPTION_INCLUDE_CUSTOM_COLOR - || CaretColorEnum::CaretColorEnum::OPTION_INCLUDE_NONE_COLOR)); + | CaretColorEnum::CaretColorEnum::OPTION_INCLUDE_NONE_COLOR)); if (std::find(allEnums.begin(), allEnums.end(), m_defaultColor) == allEnums.end()) { @@ -371,6 +372,20 @@ void ChartTwoLineSeriesHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) { CaretAssert(historyItem); + + /* + * Do not add to history if new history item matches history + * item at front of the deque + */ + if ( ! m_chartHistory.empty()) { + const MapFileDataSelector* newFileMap = historyItem->getMapFileDataSelector(); + const MapFileDataSelector* frontFileMap = m_chartHistory.at(0)->getMapFileDataSelector(); + if (*newFileMap == *frontFileMap) { + delete historyItem; + return; + } + } + historyItem->setColor(m_defaultColor); historyItem->setLineWidth(m_defaultLineWidth); addHistoryItemNoDefaults(historyItem); @@ -416,6 +431,12 @@ ChartTwoLineSeriesHistory::getHistoryItem(const int32_t index) const return m_chartHistory[index]; } +/** + * Remove the history item at the given index + * + * @param index + * Index of the item. + */ void ChartTwoLineSeriesHistory::removeHistoryItem(const int32_t index) { @@ -424,6 +445,45 @@ ChartTwoLineSeriesHistory::removeHistoryItem(const int32_t index) m_chartHistory.erase(m_chartHistory.begin() + index); } +/** + * Move the history item down at the given index + * + * @param index + * Index of the item. + */ +void +ChartTwoLineSeriesHistory::moveDownHistoryItem(const int32_t index) +{ + if (getHistoryCount() <= 1) { + return; + } + + const int32_t lastIndex = getHistoryCount() - 1; + if (index < lastIndex) { + std::swap(m_chartHistory[index], + m_chartHistory[index + 1]); + } +} + +/** + * Move the history item up at the given index + * + * @param index + * Index of the item. + */ +void +ChartTwoLineSeriesHistory::moveUpHistoryItem(const int32_t index) +{ + if (getHistoryCount() <= 1) { + return; + } + + if (index > 0) { + std::swap(m_chartHistory[index - 1], + m_chartHistory[index]); + } +} + /** * @return Clear the history. */ diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index 24231f40013b0b707696c1828fc29aa8e89841ae..5fc50cd6f0b01ef955d9c98b4115fe2413f6602c 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -74,6 +74,10 @@ namespace caret { void removeHistoryItem(const int32_t index); + void moveDownHistoryItem(const int32_t index); + + void moveUpHistoryItem(const int32_t index); + void clearHistory(); bool getBounds(BoundingBox& boundingBoxOut) const; diff --git a/src/Charting/MapFileDataSelector.cxx b/src/Charting/MapFileDataSelector.cxx index 2f3db8d526ce5600c2898f50fadefc4c0ae503da..607baed617a99568a8590434a5d640749d4a2160 100644 --- a/src/Charting/MapFileDataSelector.cxx +++ b/src/Charting/MapFileDataSelector.cxx @@ -124,6 +124,74 @@ MapFileDataSelector::copyHelperMapFileDataSelector(const MapFileDataSelector& ob m_rowMapFileName = obj.m_rowMapFileName; } +/** + * Equality operator. + * + * @param obj + * Instance compared to 'this' instance. + * + * @return True if this and the compared instance are the same, else false. + */ +bool +MapFileDataSelector::operator==(const MapFileDataSelector& obj) const +{ + if (this == &obj) { + return true; + } + if (m_dataSelectionType != obj.m_dataSelectionType) { + return false; + } + + switch (m_dataSelectionType) { + case DataSelectionType::COLUMN_DATA: + if (m_columnIndex == obj.m_columnIndex) { + if ((m_columnMapFile == obj.m_columnMapFile) + || (m_columnMapFileName == obj.m_columnMapFileName)) { + return true; + } + } + break; + case DataSelectionType::INVALID: + break; + case DataSelectionType::ROW_DATA: + if (m_rowIndex == obj.m_rowIndex) { + if ((m_rowMapFile == obj.m_rowMapFile) + || (m_rowMapFileName == obj.m_rowMapFileName)) { + return true; + } + } + break; + case DataSelectionType::SURFACE_VERTEX: + if ((m_surfaceNumberOfVertices == obj.m_surfaceNumberOfVertices) + && (m_surfaceStructure == obj.m_surfaceStructure) + && (m_surfaceVertexIndex == obj.m_surfaceVertexIndex)) { + return true; + } + break; + case DataSelectionType::SURFACE_VERTICES_AVERAGE: + if ((m_surfaceNumberOfVertices == obj.m_surfaceNumberOfVertices) + && (m_surfaceStructure == obj.m_surfaceStructure)) { + if ( ! m_surfaceVertexAverageIndices.empty()) { + if (std::equal(m_surfaceVertexAverageIndices.begin(), + m_surfaceVertexAverageIndices.end(), + obj.m_surfaceVertexAverageIndices.begin())) { + return true; + } + } + } + break; + case DataSelectionType::VOLUME_XYZ: + if ((m_voxelXYZ[0] == obj.m_voxelXYZ[0]) + && (m_voxelXYZ[1] == obj.m_voxelXYZ[1]) + && (m_voxelXYZ[2] == obj.m_voxelXYZ[2])) { + return true; + } + break; + } + + return false; +} + /** * @return The data selection type. */ @@ -380,11 +448,11 @@ MapFileDataSelector::toString() const break; case DataSelectionType::COLUMN_DATA: s = ("Column " - + AString::number(m_columnIndex)); + + AString::number(m_columnIndex + 1)); break; case DataSelectionType::ROW_DATA: s = ("Row " - + AString::number(m_rowIndex)); + + AString::number(m_rowIndex + 1)); break; case DataSelectionType::SURFACE_VERTEX: s = ("Vertex " diff --git a/src/Charting/MapFileDataSelector.h b/src/Charting/MapFileDataSelector.h index c6ac3e95d3b1125b7c5b1ed76f15f619bfcf96e8..6307d03523d454fe888221cdb7a3886bf7f14fc9 100644 --- a/src/Charting/MapFileDataSelector.h +++ b/src/Charting/MapFileDataSelector.h @@ -54,6 +54,8 @@ namespace caret { MapFileDataSelector& operator=(const MapFileDataSelector& obj); + bool operator==(const MapFileDataSelector& obj) const; + DataSelectionType getDataSelectionType() const; static AString getDataSelectionTypeName(const DataSelectionType dataSelectionType); diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index dca8229c72594877d99138a15db0ae192716ade5..13663ed9b2580dd48072b411d1a53be898853608 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -39,7 +39,8 @@ namespace class CiftiOnDiskImpl : public CiftiFile::WriteImplInterface { mutable NiftiIO m_nifti;//because file objects aren't stateless (current position), so reading "changes" them - CiftiXML m_xml;//because we need to parse it to set up the dimensions anyway + vector m_matrixDims;//store the dimensions even if the xml is forgotten + CiftiXML m_xml;//we need to store the xml somewhere before it gets put into CiftiFile's copy public: CiftiOnDiskImpl(const QString& filename);//read-only CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, const CiftiVersion& version, const bool& swapEndian, @@ -52,6 +53,7 @@ namespace void setRow(const float* dataIn, const std::vector& indexSelect); void setColumn(const float* dataIn, const int64_t& index); void close(); + void dropXML() { m_xml = CiftiXML(); m_nifti.dropExtensions(); } }; class CiftiMemoryImpl : public CiftiFile::WriteImplInterface @@ -120,6 +122,8 @@ void CiftiFile::openFile(const QString& fileName) CaretPointer newRead(new CiftiOnDiskImpl(FileInformation(fileName).getAbsoluteFilePath()));//this constructor opens existing file read-only m_readingImpl = newRead;//it should be noted that if the constructor throws (if the file isn't readable), new guarantees the memory allocated for the object will be freed m_xml = newRead->getCiftiXML(); + newRead->dropXML();//save some memory, we don't need 2 copies of the xml - figure out if there is a better way to prevent copies + m_xmlBroken = false; m_dims = m_xml.getDimensions(); m_onDiskVersion = m_xml.getParsedVersion(); m_fileName = fileName; @@ -131,6 +135,7 @@ void CiftiFile::openURL(const QString& url, const QString& user, const QString& CaretPointer newRead(new CiftiXnatImpl(url, user, pass)); m_readingImpl = newRead; m_xml = newRead->getCiftiXML(); + m_xmlBroken = false; m_dims = m_xml.getDimensions(); m_fileName = url; } @@ -141,12 +146,14 @@ void CiftiFile::openURL(const QString& url) CaretPointer newRead(new CiftiXnatImpl(url)); m_readingImpl = newRead; m_xml = newRead->getCiftiXML(); + m_xmlBroken = false; m_dims = m_xml.getDimensions(); m_fileName = url; } void CiftiFile::setWritingFile(const QString& fileName, const CiftiVersion& writingVersion, const ENDIAN& endian) { + if (fileName != "" && m_xmlBroken) throw DataFileException("can't set cifti writing file when XML mappings have been forgotten"); m_writingFile = FileInformation(fileName).getAbsoluteFilePath();//always resolve paths as soon as they enter CiftiFile, in case some clown changes directory before writing data m_writingImpl.grabNew(NULL);//prevent writing to previous writing implementation, let the next set...() set up for writing m_onDiskVersion = writingVersion;//so that we can do on-disk writing with the old version @@ -175,6 +182,7 @@ void CiftiFile::setWritingDataTypeAndScaling(const int16_t& type, const double& void CiftiFile::writeFile(const QString& fileName, const CiftiVersion& writingVersion, const ENDIAN& endian) { if (m_readingImpl == NULL || m_dims.empty()) throw DataFileException("writeFile called on uninitialized CiftiFile"); + if (m_xmlBroken) throw DataFileException("can't write cifti file when XML mappings have been forgotten"); bool writeSwapped = shouldSwap(endian); FileInformation myInfo(fileName); QString canonicalFilename = myInfo.getCanonicalFilePath();//NOTE: returns EMPTY STRING for nonexistant file @@ -214,6 +222,7 @@ void CiftiFile::close() m_readingImpl.grabNew(NULL); m_dims.clear(); m_xml = CiftiXML(); + m_xmlBroken = false; m_writingFile = ""; m_fileName = ""; m_onDiskVersion = CiftiVersion();//for completeness, it gets reset on open anyway @@ -287,6 +296,7 @@ void CiftiFile::setCiftiXML(const CiftiXML& xml, const bool useOldMetadata) m_xml = xml; } m_dims = xmlDims; + m_xmlBroken = false; } void CiftiFile::setCiftiXML(const CiftiXMLOld& xml, const bool useOldMetadata) @@ -308,6 +318,18 @@ void CiftiFile::setCiftiXML(const CiftiXMLOld& xml, const bool useOldMetadata) setCiftiXML(tempXML, useOldMetadata); } +void CiftiFile::forgetMapping(const int& direction) +{ + if (direction >= m_xml.getNumberOfDimensions()) + { + CaretLogWarning("forgetMapping called on nonexistant dimension"); + return; + } + int64_t mapLength = m_xml.getDimensionLength(direction); + m_xml.setMap(direction, CiftiSeriesMap(mapLength));//keep the xml dimension length the same, because it is used in convertToInMemory + m_xmlBroken = true; +} + void CiftiFile::setRow(const float* dataIn, const vector& indexSelect) { verifyWriteImpl(); @@ -373,6 +395,7 @@ void CiftiFile::verifyWriteImpl() m_writingImpl.grabNew(new CiftiMemoryImpl(m_xml)); } } else {//NOTE: m_onDiskVersion gets set in setWritingFile + if (m_xmlBroken) throw DataFileException("can't write file when XML mappings have been forgotten"); if (m_readingImpl != NULL) { CiftiOnDiskImpl* testImpl = dynamic_cast(m_readingImpl.getPointer()); @@ -514,6 +537,7 @@ CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename) } } } + m_matrixDims = m_xml.getDimensions(); } namespace @@ -638,9 +662,9 @@ CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, c outExtension->m_bytes[i] = xmlBytes[i]; } outHeader.m_extensions.push_back(outExtension); - vector matrixDims = xml.getDimensions(); + m_matrixDims = xml.getDimensions(); vector niftiDims(4, 1);//the reserved space and time dims - niftiDims.insert(niftiDims.end(), matrixDims.begin(), matrixDims.end()); + niftiDims.insert(niftiDims.end(), m_matrixDims.begin(), m_matrixDims.end()); if (version.hasReversedFirstDims()) { vector headerDims = niftiDims; @@ -655,13 +679,16 @@ CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, c outHeader.setDimensions(niftiDims); m_nifti.writeNew(filename, outHeader, 2, true, swapEndian); } - m_xml = xml; + m_matrixDims = xml.getDimensions(); + //m_xml = xml;//a second copy of the being-written xml isn't needed, but might be okay + m_xml = CiftiXML();//use an empty one instead } void CiftiOnDiskImpl::close() { m_nifti.close();//lets this throw when there is a writing problem -}//don't bother resetting m_xml, this instance is about to be destroyed + dropXML(); +} void CiftiOnDiskImpl::getRow(float* dataOut, const vector& indexSelect, const bool& tolerateShortRead) const @@ -671,12 +698,12 @@ void CiftiOnDiskImpl::getRow(float* dataOut, const vector& indexSelect, void CiftiOnDiskImpl::getColumn(float* dataOut, const int64_t& index) const { - CaretAssert(m_xml.getNumberOfDimensions() == 2);//otherwise this shouldn't be called - CaretAssert(index >= 0 && index < m_xml.getDimensionLength(CiftiXML::ALONG_ROW)); + CaretAssert(m_matrixDims.size() == 2);//otherwise this shouldn't be called + CaretAssert(index >= 0 && index < m_matrixDims[0]); CaretLogFine("getColumn called on CiftiOnDiskImpl, this will be slow");//generate logging messages at a low priority vector indexSelect(2); indexSelect[0] = index; - int64_t colLength = m_xml.getDimensionLength(CiftiXML::ALONG_COLUMN); + int64_t colLength = m_matrixDims[1]; for (int64_t i = 0; i < colLength; ++i)//assume if they really want getColumn on disk, they don't want their pagecache obliterated, so read it 1 element at a time { indexSelect[1] = i; @@ -691,12 +718,12 @@ void CiftiOnDiskImpl::setRow(const float* dataIn, const vector& indexSe void CiftiOnDiskImpl::setColumn(const float* dataIn, const int64_t& index) { - CaretAssert(m_xml.getNumberOfDimensions() == 2);//otherwise this shouldn't be called - CaretAssert(index >= 0 && index < m_xml.getDimensionLength(CiftiXML::ALONG_ROW)); + CaretAssert(m_matrixDims.size() == 2);//otherwise this shouldn't be called + CaretAssert(index >= 0 && index < m_matrixDims[0]); CaretLogFine("setColumn called on CiftiOnDiskImpl, this will be slow");//generate logging messages at a low priority vector indexSelect(2); indexSelect[0] = index; - int64_t colLength = m_xml.getDimensionLength(CiftiXML::ALONG_COLUMN); + int64_t colLength = m_matrixDims[1]; for (int64_t i = 0; i < colLength; ++i)//don't do RMW, so write it 1 element at a time { indexSelect[1] = i; diff --git a/src/Cifti/CiftiFile.h b/src/Cifti/CiftiFile.h index 62119ff1366b0a8153d13d5c221fbc89574ca6b1..5d1907a051067f9b045d0800da5a10a896aa6693 100644 --- a/src/Cifti/CiftiFile.h +++ b/src/Cifti/CiftiFile.h @@ -50,6 +50,7 @@ namespace caret { m_endianPref = NATIVE; setWritingDataTypeNoScaling();//default argument is float32 + m_xmlBroken = false; } explicit CiftiFile(const QString &fileName);//calls openFile void openFile(const QString& fileName);//starts on-disk reading @@ -86,6 +87,8 @@ namespace caret void setRow(const float* dataIn, const int64_t& index);//backwards compatibility for old CiftiFile + void forgetMapping(const int& direction);//HACK: reduce memory usage by modifying the XML + class ReadImplInterface { public: @@ -114,6 +117,7 @@ namespace caret bool m_doWriteScaling; int16_t m_writingDataType; double m_minScalingVal, m_maxScalingVal; + bool m_xmlBroken;//sentinel for forgetMapping hack void verifyWriteImpl(); static void copyImplData(const ReadImplInterface* from, WriteImplInterface* to, const std::vector& dims); diff --git a/src/Cifti/QUICKSTART b/src/Cifti/QUICKSTART index 49e4c3f713a57e36ed9cb5c2919015aa7a90ffa0..a3e3e54f7d66dfaf2554923ff59b17a08db80367 100644 --- a/src/Cifti/QUICKSTART +++ b/src/Cifti/QUICKSTART @@ -1,6 +1,6 @@ The entry point for reading and writing Cifti data is the object CiftiFile. To get a handle to a Cifti File, use the following syntax: CiftiFile cf("testciftifile.dtseries.nii"), cf2;//starts on-disk reading, and makes an uninitialized second object -cf2.setWritingFile(testoutcifti.dtseries.nii");//prepare on-disk writing mode +cf2.setWritingFile("testoutcifti.dtseries.nii");//prepare on-disk writing mode //cf.convertToInMemory();//if you want to read entire file into memory now CiftiFile gives access to the file in two parts, the Cifti XML, and the Cifti Matrix data. To access the data use the following functions: diff --git a/src/Cifti/examples/datatype.cxx b/src/Cifti/examples/datatype.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b9c1124b92bcb2d5fd431ad4d487006cc2088224 --- /dev/null +++ b/src/Cifti/examples/datatype.cxx @@ -0,0 +1,63 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +/*LICENSE_END*/ + +#include "CaretException.h" +#include "CiftiFile.h" + +#include +#include + +using namespace std; +using namespace cifti; + +/**\file datatype.cxx +This program reads a Cifti file from argv[1], and writes it out to argv[2] using 8-bit unsigned integer and data scaling. +It uses a single CiftiFile object to do this, for simplicity - to see how to do something similar with two objects, +which is more relevant for how you would do processing on cifti files, see rewrite.cxx. + +\include datatype.cxx +*/ + +int main(int argc, char** argv) +{ + if (argc < 3) + { + cout << "usage: " << argv[0] << " " << endl; + cout << " rewrite the input cifti file to the output filename, using uint8 and data scaling." << endl; + return 1; + } + try + { + CiftiFile inputFile(argv[1]);//on-disk reading by default + inputFile.setWritingDataTypeAndScaling(NIFTI_TYPE_UINT8, -1.0, 6.0);//tells it to use this datatype to best represent this specified range of values [-1.0, 6.0] whenever this instance is written + inputFile.writeFile(argv[2]);//if the output filename is the same as the input filename, CiftiFile actually detects this and reads the input into memory first + //otherwise, it will read and write one row at a time, using very little memory + //inputFile.setWritingDataTypeNoScaling(NIFTI_TYPE_FLOAT32);//this is how you would revert back to writing as float32 without rescaling + } catch (CaretException& e) { + cerr << "Caught CaretException: " + e.whatString() << endl; + return 1; + } + return 0; +} diff --git a/src/Cifti/examples/rewrite.cxx b/src/Cifti/examples/rewrite.cxx index 55340f36739cfcf07aa5a18f95e532cb8fdff1c1..df0e637edc4ac930c4a250f7e44a7c252451afde 100644 --- a/src/Cifti/examples/rewrite.cxx +++ b/src/Cifti/examples/rewrite.cxx @@ -63,7 +63,7 @@ int main(int argc, char** argv) } outputFile.writeFile(argv[2]);//because we called setWritingFile with this filename (and default cifti version), this will return immediately //NOTE: if you call writeFile with a different writing version (takes its default from CiftiVersion constructor) than setWritingFile, it will rewrite the entire file after reading it into memory - } catch (CiftiException& e) { + } catch (CaretException& e) { cerr << "Caught CaretException: " + e.whatString() << endl; return 1; } diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index e0f29abfd9a383b14e717f7f37b9bb6e75c46846..96a126792b887957d83537a16710e1b000033343 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -24,6 +24,7 @@ #include "CommandOperationManager.h" #undef __COMMAND_OPERATION_MANAGER_DEFINE__ +#include "AlgorithmAnnotationResample.h" #include "AlgorithmBorderResample.h" #include "AlgorithmBorderToVertices.h" #include "AlgorithmCiftiAllLabelsToROIs.h" @@ -43,6 +44,7 @@ #include "AlgorithmCiftiFindClusters.h" #include "AlgorithmCiftiGradient.h" #include "AlgorithmCiftiLabelAdjacency.h" +#include "AlgorithmCiftiLabelModifyKeys.h" #include "AlgorithmCiftiLabelProbability.h" #include "AlgorithmCiftiLabelToBorder.h" #include "AlgorithmCiftiLabelToROI.h" @@ -122,6 +124,7 @@ #include "AlgorithmVolumeFillHoles.h" #include "AlgorithmVolumeFindClusters.h" #include "AlgorithmVolumeGradient.h" +#include "AlgorithmVolumeLabelModifyKeys.h" #include "AlgorithmVolumeLabelProbability.h" #include "AlgorithmVolumeLabelToROI.h" #include "AlgorithmVolumeLabelToSurfaceMapping.h" @@ -174,6 +177,7 @@ #include "OperationEstimateFiberBinghams.h" #include "OperationFileConvert.h" #include "OperationFileInformation.h" +#include "OperationFociCreate.h" #include "OperationFociGetProjectionVertex.h" #include "OperationFociListCoords.h" #include "OperationGiftiConvert.h" @@ -285,6 +289,7 @@ CommandOperationManager::deleteCommandOperationManager() */ CommandOperationManager::CommandOperationManager() { + this->commandOperations.push_back(new CommandParser(new AutoAlgorithmAnnotationResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmBorderResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmBorderToVertices())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiAllLabelsToROIs())); @@ -304,6 +309,7 @@ CommandOperationManager::CommandOperationManager() this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiFindClusters())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiGradient())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelAdjacency())); + this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelModifyKeys())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelProbability())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelToBorder())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelToROI())); @@ -384,6 +390,7 @@ CommandOperationManager::CommandOperationManager() this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeFillHoles())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeFindClusters())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeGradient())); + this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelModifyKeys())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelProbability())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelToROI())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelToSurfaceMapping())); @@ -431,6 +438,7 @@ CommandOperationManager::CommandOperationManager() this->commandOperations.push_back(new CommandParser(new AutoOperationEstimateFiberBinghams())); this->commandOperations.push_back(new CommandParser(new AutoOperationFileConvert())); this->commandOperations.push_back(new CommandParser(new AutoOperationFileInformation())); + this->commandOperations.push_back(new CommandParser(new AutoOperationFociCreate())); this->commandOperations.push_back(new CommandParser(new AutoOperationFociGetProjectionVertex())); this->commandOperations.push_back(new CommandParser(new AutoOperationFociListCoords())); this->commandOperations.push_back(new CommandParser(new AutoOperationGiftiConvert())); @@ -613,7 +621,7 @@ CommandOperationManager::runCommand(ProgramParameters& parameters) { printHelpInfo(); } else if (commandSwitch == "-arguments-help") { - printArgumentsHelp(myProgramName); + printArgumentsHelp(); } else if (commandSwitch == "-global-options") { printGlobalOptions(); } else if (commandSwitch == "-cifti-help") { @@ -991,18 +999,19 @@ void CommandOperationManager::printHelpInfo() cout << endl; } -void CommandOperationManager::printArgumentsHelp(const AString& programName) +void CommandOperationManager::printArgumentsHelp() { //guide for wrap, assuming 80 columns: | cout << " To get the help information on a subcommand, run it without any additional" << endl; - cout << " arguments. Options can occur in any position within the correct scope, and" << endl; - cout << " can have suboptions, which must occur within the scope of the option. The" << endl; - cout << " easiest way to get this right is to specify options and arguments in the" << endl; - cout << " order they are listed. As an example, consider this help information:" << endl; + cout << " arguments. Options can occur in any order, however suboptions and arguments" << endl; + cout << " to options must occur next to their parent option. The easiest way to get" << endl; + cout << " this right is to specify options and arguments in the order they are listed." << endl; + cout << " As an example, consider this abbreviated version of the -volume-math help" << endl; + cout << " information:" << endl; cout << endl;//guide for wrap, assuming 80 columns: | - cout << "$ " << programName << " -volume-math" << endl; + cout << "$ wb_command -volume-math" << endl; cout << "EVALUATE EXPRESSION ON VOLUME FILES" << endl; - cout << " " << programName << " -volume-math" << endl; + cout << " wb_command -volume-math" << endl; cout << " - the expression to evaluate, in quotes" << endl; cout << " - output - the output volume" << endl; cout << endl;//guide for wrap, assuming 80 columns: | @@ -1018,37 +1027,52 @@ void CommandOperationManager::printArgumentsHelp(const AString& programName) cout << endl;//guide for wrap, assuming 80 columns: | cout << " [-repeat] - reuse a single subvolume for each subvolume of calculation" << endl; cout << "..." << endl; + cout << " The following functions are supported:" << endl; + cout << "..." << endl; + cout << " abs: 1 argument, the absolute value of the argument" << endl; + cout << "..." << endl; + cout << endl;//guide for wrap, assuming 80 columns: | + cout << " '' represents a required input parameter (required parameters" << endl; + cout << " are marked with the < and > symbols), and ' - output' represents" << endl; + cout << " a required output filename (marked by the presence of the word 'output')." << endl; + cout << " '[-fixnan]' represents an option (marked with the [ and ] symbols), taking" << endl; + cout << " one required parameter '' (the indentation level indicates what" << endl; + cout << " parameters and suboptions are associated with a given option), and '[-var] -" << endl; + cout << " repeatable' denotes a repeatable option (marked by the presence of the word" << endl; + cout << " 'repeatable') with required parameters '' and '', and two" << endl; + cout << " suboptions: '[-subvolume]', which has a required parameter '', and" << endl; + cout << " '[-repeat]', which takes no parameters." << endl; cout << endl;//guide for wrap, assuming 80 columns: | - cout << " '' and '' denote mandatory parameters. '[-fixnan]'" << endl; - cout << " denotes an option taking one mandatory parameter '', and" << endl; - cout << " '[-var] - repeatable' denotes a repeatable option with mandatory parameters" << endl; - cout << " '' and '', and two suboptions: '[-subvolume]', which has a" << endl; - cout << " mandatory parameter '', and '[-repeat]', which takes no parameters." << endl; - cout << " Commands also provide additional help info below the section in the example." << endl; cout << " Each option starts a new scope, and all options and arguments end any scope" << endl; - cout << " that they are not valid in. For example, this command is correct:" << endl; + cout << " that they are not valid in. This means that for any option, you must" << endl; + cout << " specify all of its arguments and any desired suboptions before specifying" << endl; + cout << " any other option or argument on the same or a previous level. For example," << endl; + cout << " this annotated command is valid:" << endl; cout << endl;//guide for wrap, assuming 80 columns: | - cout << "$ " << programName << " -volume-math 'sin(x)' sin_x.nii.gz -fixnan 0 -var x x.nii.gz -subvolume 1" << endl; + cout << "$ wb_command -volume-math 'abs(x)' abs_x.nii.gz -fixnan 0 -var x x.nii.gz" << endl; + cout << "annotation: " << endl; cout << endl; - cout << " as is this one (though less intuitive):" << endl; + cout << " Here is another annotated command that results in the same output, but" << endl; + cout << " uses a different order of the options:" << endl; cout << endl; - cout << "$ " << programName << " -volume-math -fixnan 0 'sin(x)' -var x -subvolume 1 x.nii.gz sin_x.nii.gz" << endl; + cout << "$ wb_command -volume-math -fixnan 0 'abs(x)' -var x x.nii.gz abs_x.nii.gz" << endl; + cout << "annotation: " << endl; cout << endl;//guide for wrap, assuming 80 columns: | - cout << " while this one is not, because the -fixnan option ends the scope of the -var" << endl; - cout << " option before all of its mandatory arguments are given:" << endl; + cout << " This next command is invalid, because the -fixnan option ends the scope of" << endl; + cout << " the -var option before all of its required arguments are given:" << endl; cout << endl; - cout << "$ " << programName << " -volume-math 'sin(x)' sin_x.nii.gz -var x -fixnan 0 x.nii.gz -subvolume 1" << endl; + cout << "wrong: wb_command -volume-math 'abs(x)' abs_x.nii.gz -var x -fixnan 0 x.nii.gz" << endl; cout << endl; //guide for wrap, assuming 80 columns: | - cout << " and this one is incorrect because the -subvolume option occurs after the" << endl; - cout << " scope of the -var option has ended due to -fixnan:" << endl; + cout << " This command is invalid because the -subvolume option occurs after the" << endl; + cout << " scope of the -var option has ended due to the -fixnan option:" << endl; cout << endl; - cout << "$ " << programName << " -volume-math 'sin(x)' sin_x.nii.gz -var x x.nii.gz -fixnan 0 -subvolume 1" << endl; + cout << "wrong: wb_command -volume-math 'abs(x)' abs_x.nii.gz -var x x.nii.gz -fixnan 0 -subvolume 1" << endl; cout << endl;//guide for wrap, assuming 80 columns: | - cout << " and this one is similarly incorrect because the -subvolume option occurs" << endl; + cout << " This command is similarly invalid because the -subvolume option occurs" << endl; cout << " after the scope of the -var option has ended due to the volume-out argument:" << endl; cout << endl; - cout << "$ " << programName << " -volume-math 'sin(x)' -fixnan 0 -var x x.nii.gz sin_x.nii.gz -subvolume 1" << endl; + cout << "wrong: wb_command -volume-math 'abs(x)' -var x x.nii.gz abs_x.nii.gz -subvolume 1 -fixnan 0" << endl; cout << endl; } diff --git a/src/Commands/CommandOperationManager.h b/src/Commands/CommandOperationManager.h index b76f337517492611359b2a214e0793516496a7db..c0c11077779cb1adcdc59fbd440f768de9c87b0f 100644 --- a/src/Commands/CommandOperationManager.h +++ b/src/Commands/CommandOperationManager.h @@ -65,7 +65,7 @@ namespace caret { void printHelpInfo(); - void printArgumentsHelp(const AString& programName); + void printArgumentsHelp(); void printGlobalOptions(); diff --git a/src/Commands/CommandParser.cxx b/src/Commands/CommandParser.cxx index 2f0c4226a0e79b3d575589e5812a2322fe28570a..1486779ba58285a283a0e545bc8e2775e2ddbebd 100644 --- a/src/Commands/CommandParser.cxx +++ b/src/Commands/CommandParser.cxx @@ -21,6 +21,7 @@ #include "CommandParser.h" #include "AlgorithmException.h" +#include "AnnotationFile.h" #include "ApplicationInformation.h" #include "BorderFile.h" #include "CaretAssert.h" @@ -154,6 +155,30 @@ void CommandParser::parseComponent(ParameterComponent* myComponent, ProgramParam try { switch (myComponent->m_paramList[i]->getType()) { + case OperationParametersEnum::ANNOTATION: + { + CaretPointer myFile(new AnnotationFile()); + myFile->readFile(nextArg); + if (m_doProvenance) + { + const GiftiMetaData* md = myFile->getFileMetaData(); + if (md != NULL) + { + AString prov = md->get(PROVENANCE_NAME); + if (prov != "") + { + m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; + } + } + } + ((AnnotationParameter*)myComponent->m_paramList[i])->m_parameter = myFile; + if (debug) + { + cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; + cout << nextArg << endl; + } + break; + } case OperationParametersEnum::BOOL: { parameters.backup(); @@ -375,6 +400,7 @@ void CommandParser::parseComponent(ParameterComponent* myComponent, ProgramParam catch (const bad_alloc&) { switch (nextType) { + case OperationParametersEnum::ANNOTATION: case OperationParametersEnum::BORDER: case OperationParametersEnum::CIFTI: case OperationParametersEnum::FOCI: @@ -427,6 +453,12 @@ void CommandParser::parseComponent(ParameterComponent* myComponent, ProgramParam tempItem.m_param = myComponent->m_outputList[i]; switch (myComponent->m_outputList[i]->getType())//allocate outputs that only have in-memory implementations { + case OperationParametersEnum::ANNOTATION: + { + CaretPointer& myFile = ((AnnotationParameter*)(myComponent->m_outputList[i]))->m_parameter; + myFile.grabNew(new AnnotationFile()); + break; + } case OperationParametersEnum::BORDER: { CaretPointer& myFile = ((BorderParameter*)(myComponent->m_outputList[i]))->m_parameter; @@ -611,6 +643,15 @@ CommandParser::CompletionInfo CommandParser::completionComponent(ParameterCompon }//the above conditional does a continue unless we need to do completion now switch (myComponent->m_paramList[i]->getType()) { + case OperationParametersEnum::ANNOTATION: + if (ret.completionHints != "") ret.completionHints += " "; + if (useExtGlob) + { + ret.completionHints += "fileglob *.?(wb_)annot"; + } else { + ret.completionHints += "fileglob *.annot fileglob *.wb_annot"; + } + break; case OperationParametersEnum::BOOL: if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += "wordlist true\\ TRUE\\ false\\ FALSE"; diff --git a/src/Common/AString.cxx b/src/Common/AString.cxx index c97ea0bc8fbdf549f2baed9681a0eafe207f8914..b892ddba1df83357884e26a3cb226eb5fd69f636 100644 --- a/src/Common/AString.cxx +++ b/src/Common/AString.cxx @@ -178,19 +178,27 @@ AString::fromNumbers(const std::vector& v, const AString& separator) * The vector of values. * @param separator * Inserted between each pair of values. + * @param format + * e format as [-]9.9e[+|-]999 + * E format as [-]9.9E[+|-]999 + * f format as [-]9.9 + * g use e or f format, whichever is the most concise + * G use E or f format, whichever is the most concise + * @param precision + * Maximum number of digits following decimal. * @return * String containing the vector's values separated * by the separator. */ AString -AString::fromNumbers(const std::vector& v, const AString& separator) +AString::fromNumbers(const std::vector& v, const AString& separator, char format, const int32_t precision) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } - s += AString::number(v[i]); + s += AString::number(v[i], format, precision); } return s; } @@ -201,19 +209,27 @@ AString::fromNumbers(const std::vector& v, const AString& separator) * The vector of values. * @param separator * Inserted between each pair of values. + * @param format + * e format as [-]9.9e[+|-]999 + * E format as [-]9.9E[+|-]999 + * f format as [-]9.9 + * g use e or f format, whichever is the most concise + * G use E or f format, whichever is the most concise + * @param precision + * Maximum number of digits following decimal. * @return * String containing the vector's values separated * by the separator. */ AString -AString::fromNumbers(const std::vector& v, const AString& separator) +AString::fromNumbers(const std::vector& v, const AString& separator, char format, const int32_t precision) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } - s += AString::number(v[i]); + s += AString::number(v[i], format, precision); } return s; } @@ -226,19 +242,27 @@ AString::fromNumbers(const std::vector& v, const AString& separator) * Number of elements in the array. * @param separator * Inserted between each pair of values. + * @param format + * e format as [-]9.9e[+|-]999 + * E format as [-]9.9E[+|-]999 + * f format as [-]9.9 + * g use e or f format, whichever is the most concise + * G use E or f format, whichever is the most concise + * @param precision + * Maximum number of digits following decimal. * @return * String containing the array values separated * by the separator. */ AString -AString::fromNumbers(const float* array, const int64_t numberOfElements, const AString& separator) +AString::fromNumbers(const float* array, const int64_t numberOfElements, const AString& separator, char format, const int32_t precision) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } - s += AString::number(array[i]); + s += AString::number(array[i], format, precision); } return s; } @@ -360,21 +384,31 @@ AString::fromNumbers(const int64_t* array, * Number of elements in the array. * @param separator * Inserted between each pair of values. + * @param format + * e format as [-]9.9e[+|-]999 + * E format as [-]9.9E[+|-]999 + * f format as [-]9.9 + * g use e or f format, whichever is the most concise + * G use E or f format, whichever is the most concise + * @param precision + * Maximum number of digits following decimal. * @return * String containing the array values separated * by the separator. */ AString AString::fromNumbers(const double* array, - const int64_t numberOfElements, - const AString& separator) + const int64_t numberOfElements, + const AString& separator, + char format, + const int32_t precision) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } - s += AString::number(array[i]); + s += AString::number(array[i], format, precision); } return s; } @@ -426,19 +460,6 @@ AString::toNumbers(const AString& s, numbersOut.push_back(floatValue); } } - -// AString copy = s; -// QTextStream stream(©); -// -// AString numberString; -// bool valid = false; -// while (stream.atEnd() == false) { -// stream >> numberString; -// const float floatValue = numberString.toFloat(&valid); -// if (valid) { -// numbersOut.push_back(floatValue); -// } -// } } /** @@ -461,12 +482,30 @@ AString::toNumbers(const AString& s, AString copy = s; QTextStream stream(©); - AString numberString; - bool valid = false; + int intValue; while (stream.atEnd() == false) { - stream >> numberString; - const int32_t intValue = numberString.toInt(&valid); - if (valid) { + /* + * Try to read a int value from the current position + */ + stream >> intValue; + + /* + * If the text stream could not create an int from + * the current text position, the corrupt data flag + * will be set. + */ + if (stream.status() == QTextStream::ReadCorruptData) { + /* + * Reset the status of the string (to OK) and + * then read one character to remove the character + * from the stream since it was not the start + * of a number. + */ + stream.resetStatus(); + QChar oneChar; + stream >> oneChar; + } + else { numbersOut.push_back(intValue); } } diff --git a/src/Common/AString.h b/src/Common/AString.h index f7fdd49d2d66c367b01851b582bf093765366e35..b9313150177a20e71d6249fec72bebc1c159956b 100644 --- a/src/Common/AString.h +++ b/src/Common/AString.h @@ -118,14 +118,14 @@ namespace caret { static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator); - static AString fromNumbers(const std::vector& v, const AString& separator); - static AString fromNumbers(const std::vector& v, const AString& separator); - static AString fromNumbers(const float* array, const int64_t numberOfElements, const AString& separator); + static AString fromNumbers(const std::vector& v, const AString& separator, const char format = 'g', const int32_t precision = 6); + static AString fromNumbers(const std::vector& v, const AString& separator, const char format = 'g', const int32_t precision = 6); + static AString fromNumbers(const float* array, const int64_t numberOfElements, const AString& separator, char format = 'g', const int32_t precision = 6); static AString fromNumbers(const uint8_t* array,const int64_t numberOfElements, const AString& separator); static AString fromNumbers(const int8_t* array,const int64_t numberOfElements, const AString& separator); static AString fromNumbers(const int32_t* array,const int64_t numberOfElements, const AString& separator); static AString fromNumbers(const int64_t* array,const int64_t numberOfElements, const AString& separator); - static AString fromNumbers(const double* array, const int64_t numberOfElements, const AString& separator); + static AString fromNumbers(const double* array, const int64_t numberOfElements, const AString& separator, const char format = 'g', const int32_t precision = 6); static AString fromBool(const bool b); AString replaceHtmlSpecialCharactersWithEscapeCharacters() const; diff --git a/src/Common/ApplicationInformation.cxx.in b/src/Common/ApplicationInformation.cxx.in index 67e8be6fa290b56062e47aec74a75f69a534a695..701e15408ce12c6a381661e3a0d16be3a2c4a147 100644 --- a/src/Common/ApplicationInformation.cxx.in +++ b/src/Common/ApplicationInformation.cxx.in @@ -63,12 +63,9 @@ ApplicationInformation::ApplicationInformation() break; } /* - * When updating version, also update these - * items in Desktop/CMakeLists.txt: - * SET (MACOSX_BUNDLE_SHORT_VERSION_STRING 1.3.2) - * SET (MACOSX_BUNDLE_BUNDLE_VERSION 1.3.2) + * Version now gets set at the top of the main CMakeLists.txt only. */ - this->version = "1.3.2"; + this->version = "@VERSION@"; this->commit = "Commit: @COMMIT@"; this->commitDate = "Commit Date: @COMMIT_DATE@"; diff --git a/src/Common/BackgroundAndForegroundColors.cxx b/src/Common/BackgroundAndForegroundColors.cxx index 062196b0011b8f7d297d11a7ef734a9c3883a3d1..9df91a4ba07ccc6787c740a09ecbf1dcb7a9992b 100644 --- a/src/Common/BackgroundAndForegroundColors.cxx +++ b/src/Common/BackgroundAndForegroundColors.cxx @@ -78,6 +78,73 @@ BackgroundAndForegroundColors::operator=(const BackgroundAndForegroundColors& ob return *this; } +/** + * Equality operator + * + * @param obj + * Compare 'this' to 'obj' for equality + * @return + * True if 'this' is equal to 'obj', else false. + */ +bool +BackgroundAndForegroundColors::operator==(const BackgroundAndForegroundColors& obj) const +{ + bool equalFlag(true); + + for (int32_t i = 0; i < 3; i++) { + if (m_colorForegroundWindow[i] != obj.m_colorForegroundWindow[i]) { + equalFlag = false; + break; + } + if (m_colorBackgroundWindow[i] !=obj.m_colorBackgroundWindow[i]) { + equalFlag = false; + break; + } + if (m_colorForegroundAll[i] != obj.m_colorForegroundAll[i]) { + equalFlag = false; + break; + } + if (m_colorBackgroundAll[i] !=obj.m_colorBackgroundAll[i]) { + equalFlag = false; + break; + } + if (m_colorForegroundChart[i] != obj.m_colorForegroundChart[i]) { + equalFlag = false; + break; + } + if (m_colorBackgroundChart[i] != obj.m_colorBackgroundChart[i]) { + equalFlag = false; + break; + } + if (m_colorForegroundSurface[i] != obj.m_colorForegroundSurface[i]) { + equalFlag = false; + break; + } + if (m_colorBackgroundSurface[i] != obj.m_colorBackgroundSurface[i]) { + equalFlag = false; + break; + } + if (m_colorForegroundVolume[i] != obj.m_colorForegroundVolume[i]) { + equalFlag = false; + break; + } + if (m_colorBackgroundVolume[i] != obj.m_colorBackgroundVolume[i]) { + equalFlag = false; + break; + } + if (m_colorChartMatrixGridLines[i] != obj.m_colorChartMatrixGridLines[i]) { + equalFlag = false; + break; + } + if (m_colorChartHistogramThreshold[i] != obj.m_colorChartHistogramThreshold[i]) { + equalFlag = false; + break; + } + } + + return equalFlag; +} + /** * Helps with copying an object of this type. * @param obj @@ -87,6 +154,8 @@ void BackgroundAndForegroundColors::copyHelperBackgroundAndForegroundColors(const BackgroundAndForegroundColors& obj) { for (int32_t i = 0; i < 3; i++) { + m_colorForegroundWindow[i] = obj.m_colorForegroundWindow[i]; + m_colorBackgroundWindow[i] = obj.m_colorBackgroundWindow[i]; m_colorForegroundAll[i] = obj.m_colorForegroundAll[i]; m_colorBackgroundAll[i] = obj.m_colorBackgroundAll[i]; m_colorForegroundChart[i] = obj.m_colorForegroundChart[i]; @@ -114,6 +183,10 @@ BackgroundAndForegroundColors::reset() const uint8_t foreGreen = 255; const uint8_t foreBlue = 255; + setColor(m_colorForegroundWindow, foreRed, foreGreen, foreBlue); + + setColor(m_colorBackgroundWindow, backRed, backGreen, backBlue); + setColor(m_colorForegroundAll, foreRed, foreGreen, foreBlue); setColor(m_colorBackgroundAll, backRed, backGreen, backBlue); @@ -141,6 +214,64 @@ BackgroundAndForegroundColors::reset() setColor(m_colorChartHistogramThreshold, threshRed, threshGreen, threshBlue); } +/** + * Get the foreground color for the window. + * + * @param colorForeground + * RGB color components ranging [0, 255]. + */ +void +BackgroundAndForegroundColors::getColorForegroundWindow(uint8_t colorForeground[3]) const +{ + for (int32_t i = 0; i < 3; i++) { + colorForeground[i] = m_colorForegroundWindow[i]; + } +} + +/** + * Set the foreground color for the window. + * + * @param colorForeground + * RGB color components ranging [0, 255]. + */ +void +BackgroundAndForegroundColors::setColorForegroundWindow(const uint8_t colorForeground[3]) +{ + for (int32_t i = 0; i < 3; i++) { + m_colorForegroundWindow[i] = colorForeground[i]; + } +} + +/** + * Get the background color for the window. + * + * @param colorBackground + * RGB color components ranging [0, 255]. + */ +void +BackgroundAndForegroundColors::getColorBackgroundWindow(uint8_t colorBackground[3]) const +{ + for (int32_t i = 0; i < 3; i++) { + colorBackground[i] = m_colorBackgroundWindow[i]; + } +} + +/** + * Set the background color for the window. + * + * @param colorBackground + * RGB color components ranging [0, 255]. + */ +void +BackgroundAndForegroundColors::setColorBackgroundWindow(const uint8_t colorBackground[3]) +{ + for (int32_t i = 0; i < 3; i++) { + m_colorBackgroundWindow[i] = colorBackground[i]; + } +} + + + /** * Get the foreground color for viewing the ALL model. * diff --git a/src/Common/BackgroundAndForegroundColors.h b/src/Common/BackgroundAndForegroundColors.h index a772d6ad22e71fd304cf3e4c02c6d31c005165bf..eb123170b1a17e158c9ba6be38ee4166ef343af5 100644 --- a/src/Common/BackgroundAndForegroundColors.h +++ b/src/Common/BackgroundAndForegroundColors.h @@ -38,10 +38,21 @@ namespace caret { BackgroundAndForegroundColors& operator=(const BackgroundAndForegroundColors& obj); + bool operator==(const BackgroundAndForegroundColors& obj) const; + void reset(); // ADD_NEW_METHODS_HERE + void getColorBackgroundWindow(uint8_t colorBackground[3]) const; + + void setColorBackgroundWindow(const uint8_t colorBackground[3]); + + void getColorForegroundWindow(uint8_t colorForeground[3]) const; + + void setColorForegroundWindow(const uint8_t colorForeground[3]); + + void getColorForegroundAllView(uint8_t colorForeground[3]) const; void setColorForegroundAllView(const uint8_t colorForeground[3]); @@ -93,6 +104,10 @@ namespace caret { const uint8_t green, const uint8_t blue); + uint8_t m_colorBackgroundWindow[3]; + + uint8_t m_colorForegroundWindow[3]; + uint8_t m_colorForegroundAll[3]; uint8_t m_colorBackgroundAll[3]; diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index b828021da907250585a77310f84d640906b89b2c..f8d6d2db5679d10130570189ad50ea8dd0833d6b 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -14,6 +14,7 @@ SET(QT_USE_QTNETWORK TRUE) if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Gui_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Xml_INCLUDE_DIRS}) endif() @@ -76,11 +77,13 @@ CaretObjectTracksModification.h CaretOMP.h CaretPointer.h CaretPointLocator.h +CaretPreferenceDataValue.h CaretPreferences.h CaretTemporaryFile.h CaretUndoCommand.h CaretUndoStack.h CaretUnitsTypeEnum.h +ConnectivityCorrelation.h CubicSpline.h DataCompressZLib.h DataFile.h @@ -99,12 +102,15 @@ Event.h EventAlertUser.h EventBrowserTabDelete.h EventBrowserTabIndicesGetAll.h +EventBrowserTabNew.h +EventBrowserTabNewClone.h EventCaretPreferencesGet.h EventGetViewportSize.h EventListenerInterface.h EventManager.h EventPaletteGetByName.h EventProgressUpdate.h +EventTileTabsConfigurationModification.h EventTypeEnum.h FastStatistics.h FileAdapter.h @@ -139,6 +145,7 @@ ProgressObject.h ProgressReportingInterface.h ReductionEnum.h ReductionOperation.h +SpacerTabIndex.h SpecFileDialogViewFilesTypeEnum.h SpeciesEnum.h StereotaxicSpaceEnum.h @@ -146,13 +153,36 @@ StringTableModel.h StructureEnum.h SystemUtilities.h TileTabsConfiguration.h -TileTabsConfigurationModeEnum.h +TileTabsConfigurationLayoutTypeEnum.h +TileTabsBaseConfiguration.h +TileTabsGridLayoutConfiguration.h +TileTabsGridModeEnum.h +TileTabsGridRowColumnContentTypeEnum.h +TileTabsGridRowColumnElement.h +TileTabsGridRowColumnStretchTypeEnum.h TracksModificationInterface.h TriStateSelectionStatusEnum.h Vector3D.h VectorOperation.h +VolumeSliceViewAllPlanesLayoutEnum.h VoxelIJK.h WorkbenchSpecialVersionEnum.h +WuQMacro.h +WuQMacroCommand.h +WuQMacroCommandParameter.h +WuQMacroCommandTypeEnum.h +WuQMacroDataValueTypeEnum.h +WuQMacroFile.h +WuQMacroGroup.h +WuQMacroGroupXmlStreamBase.h +WuQMacroGroupXmlStreamReader.h +WuQMacroGroupXmlStreamWriter.h +WuQMacroModeEnum.h +WuQMacroMouseEventInfo.h +WuQMacroMouseEventTypeEnum.h +WuQMacroShortCutKeyEnum.h +WuQMacroStandardItemTypeEnum.h +WuQMacroWidgetTypeEnum.h YokingGroupEnum.h ${MOC_SOURCE_FILES} @@ -179,11 +209,13 @@ CaretMathExpression.cxx CaretObject.cxx CaretObjectTracksModification.cxx CaretPointLocator.cxx +CaretPreferenceDataValue.cxx CaretPreferences.cxx CaretTemporaryFile.cxx CaretUndoCommand.cxx CaretUndoStack.cxx CaretUnitsTypeEnum.cxx +ConnectivityCorrelation.cxx CubicSpline.cxx DataCompressZLib.cxx DataFile.cxx @@ -200,12 +232,15 @@ Event.cxx EventAlertUser.cxx EventBrowserTabDelete.cxx EventBrowserTabIndicesGetAll.cxx +EventBrowserTabNew.cxx +EventBrowserTabNewClone.cxx EventCaretPreferencesGet.cxx EventGetViewportSize.cxx EventListenerInterface.cxx EventManager.cxx EventPaletteGetByName.cxx EventProgressUpdate.cxx +EventTileTabsConfigurationModification.cxx EventTypeEnum.cxx FastStatistics.cxx FileAdapter.cxx @@ -235,6 +270,7 @@ ProgramParametersException.cxx ProgressObject.cxx ReductionEnum.cxx ReductionOperation.cxx +SpacerTabIndex.cxx SpecFileDialogViewFilesTypeEnum.cxx SpeciesEnum.cxx StereotaxicSpaceEnum.cxx @@ -242,11 +278,34 @@ StringTableModel.cxx StructureEnum.cxx SystemUtilities.cxx TileTabsConfiguration.cxx -TileTabsConfigurationModeEnum.cxx +TileTabsConfigurationLayoutTypeEnum.cxx +TileTabsBaseConfiguration.cxx +TileTabsGridLayoutConfiguration.cxx +TileTabsGridModeEnum.cxx +TileTabsGridRowColumnContentTypeEnum.cxx +TileTabsGridRowColumnElement.cxx +TileTabsGridRowColumnStretchTypeEnum.cxx TriStateSelectionStatusEnum.cxx Vector3D.cxx VectorOperation.cxx +VolumeSliceViewAllPlanesLayoutEnum.cxx WorkbenchSpecialVersionEnum.cxx +WuQMacro.cxx +WuQMacroCommand.cxx +WuQMacroCommandTypeEnum.cxx +WuQMacroCommandParameter.cxx +WuQMacroDataValueTypeEnum.cxx +WuQMacroFile.cxx +WuQMacroGroup.cxx +WuQMacroGroupXmlStreamBase.cxx +WuQMacroGroupXmlStreamReader.cxx +WuQMacroGroupXmlStreamWriter.cxx +WuQMacroModeEnum.cxx +WuQMacroMouseEventInfo.cxx +WuQMacroMouseEventTypeEnum.cxx +WuQMacroShortCutKeyEnum.cxx +WuQMacroStandardItemTypeEnum.cxx +WuQMacroWidgetTypeEnum.cxx YokingGroupEnum.cxx ) @@ -267,9 +326,10 @@ IF (EXISTS ${GIT_REPOSITORY}) COMMAND ${CMAKE_COMMAND} -DINFILE="${CMAKE_SOURCE_DIR}/Common/ApplicationInformation.cxx.in" -DOUTFILE="${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx" + -DVERSION="${WB_VERSION}" -P "${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in" WORKING_DIRECTORY ${GIT_REPOSITORY}/.. - DEPENDS ApplicationInformation.cxx.in ${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in ${GIT_REPOSITORY}/HEAD ${GIT_REPOSITORY}/index + DEPENDS ApplicationInformation.cxx.in ${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in ${CMAKE_SOURCE_DIR}/CMakeLists.txt ${GIT_REPOSITORY}/HEAD ${GIT_REPOSITORY}/index COMMENT "Setting commit info" ) ELSE(EXISTS ${GIT_REPOSITORY}) @@ -278,9 +338,10 @@ ELSE(EXISTS ${GIT_REPOSITORY}) COMMAND ${CMAKE_COMMAND} -DINFILE="${CMAKE_SOURCE_DIR}/Common/ApplicationInformation.cxx.in" -DOUTFILE="${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx" + -DVERSION="${WB_VERSION}" -P "${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. - DEPENDS ApplicationInformation.cxx.in ${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in + DEPENDS ApplicationInformation.cxx.in ${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in ${CMAKE_SOURCE_DIR}/CMakeLists.txt COMMENT "No repository found, setting commit info to 'unknown'. Reconfigure to look for the repository again." ) ENDIF(EXISTS ${GIT_REPOSITORY}) diff --git a/src/Common/CaretBinaryFile.cxx b/src/Common/CaretBinaryFile.cxx index 02f5edb4793562c29fdfee7f3027d299d7d7d0a5..d043f602302816972afa1b7c154a27c63dea81f4 100644 --- a/src/Common/CaretBinaryFile.cxx +++ b/src/Common/CaretBinaryFile.cxx @@ -174,6 +174,7 @@ void ZFileImpl::open(const QString& filename, const CaretBinaryFile::OpenMode& o mode = "rb"; break; case CaretBinaryFile::WRITE_TRUNCATE: + QFile::remove(filename);//attempt to remove file rather than truncating, to improve behavior with file symlinks mode = "wb";//you have to do "w+b" in order to ask it to not truncate, which zlib doesn't support anyway break; default: @@ -290,6 +291,7 @@ void QFileImpl::open(const QString& filename, const CaretBinaryFile::OpenMode& o if (opmode & CaretBinaryFile::WRITE) mode |= QIODevice::WriteOnly; if (opmode & CaretBinaryFile::TRUNCATE) mode |= QIODevice::Truncate;//expect QFile to recognize silliness like TRUNCATE by itself m_file.setFileName(filename); + if (mode & QIODevice::Truncate) m_file.remove();//attempt to delete the existing file rather than truncating, to improve behavior with file symlinks if (!m_file.open(mode)) { if (!m_file.exists()) diff --git a/src/Common/CaretHttpManager.cxx b/src/Common/CaretHttpManager.cxx index d45d7ad987af58cc1c1e8334c58f69e3c74f0b81..6772a7b46ea0d778a9557ea3350eb1fb3f441c99 100644 --- a/src/Common/CaretHttpManager.cxx +++ b/src/Common/CaretHttpManager.cxx @@ -136,14 +136,25 @@ logHeadersFromReply(const QNetworkReply& reply, { AString infoText; infoText.appendWithNewLine("Reply " + caretHttpRequestToName(caretHttpRequest) + " URL (" + QString::number(caretHttpResponse.m_responseCode) + ") Header: "); + bool errorFlag(false); if ( ! caretHttpResponse.m_responseCodeValid) { infoText.appendWithNewLine("RESPONSE CODE IS NOT VALID."); + errorFlag = true; } const QNetworkReply::NetworkError networkErrorCode = reply.error(); if (networkErrorCode != QNetworkReply::NoError) { infoText.appendWithNewLine("Network Error Code (See QNetworkReply::NetworkError for description): " - + QString::number(static_cast(networkErrorCode))); + + QString::number(static_cast(networkErrorCode)) + + "\nDescription: " + + reply.errorString()); + errorFlag = true; } + + if (errorFlag) { + CaretLogWarning(infoText); + return; + } + QList readHeaderList = reply.rawHeaderList(); const int numItems = readHeaderList.size(); if (numItems > 0) { @@ -354,6 +365,7 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret response.m_responseCode = -1; response.m_responseCodeValid = false; response.m_headers.clear(); + response.m_errorMessage.clear(); const QVariant responseCodeVariant = myReply->attribute(QNetworkRequest::HttpStatusCodeAttribute); if ( ! responseCodeVariant.isNull()) { response.m_responseCode = myReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -384,6 +396,15 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret request, response); } + if (response.m_responseCode != 200) { + AString s("QNetworkReply::NetworkError Code=" + + AString::number((int)myReply->error()) + + ", Error=" + + myReply->errorString() + + "\nURL=" + + myUrl.toString(QUrl::None)); + response.m_errorMessage = s; + } QByteArray myBody = myReply->readAll(); int64_t mySize = myBody.size(); diff --git a/src/Common/CaretHttpManager.h b/src/Common/CaretHttpManager.h index 89585f130d98e31aab3645d76037126396028d67..bd768813273a0fb82f40557d8dec1d0d0ee8a100 100644 --- a/src/Common/CaretHttpManager.h +++ b/src/Common/CaretHttpManager.h @@ -76,6 +76,7 @@ namespace caret { bool m_responseCodeValid; QUrl m_redirectionUrl; bool m_redirectionUrlValid; + AString m_errorMessage; std::map m_headers; // map so that newer values replace older values }; diff --git a/src/Common/CaretMathExpression.cxx b/src/Common/CaretMathExpression.cxx index 80f1896177327e13bb836a109e4e11ce5f8ac64c..7e822f9c7fcff40213c3f01836ebe72c374441df 100644 --- a/src/Common/CaretMathExpression.cxx +++ b/src/Common/CaretMathExpression.cxx @@ -295,6 +295,10 @@ double CaretMathExpression::MathNode::eval(const vector& values) const CaretAssert(m_arguments.size() == 1); ret = log10(m_arguments[0]->eval(values)); break; + case MathFunctionEnum::LOG2: + CaretAssert(m_arguments.size() == 1); + ret = log2(m_arguments[0]->eval(values)); + break; case MathFunctionEnum::SQRT: CaretAssert(m_arguments.size() == 1); ret = sqrt(m_arguments[0]->eval(values)); @@ -372,7 +376,7 @@ double CaretMathExpression::MathNode::eval(const vector& values) const } break; } - case INVALID: + case MathFunctionEnum::INVALID: CaretAssertMessage(0, "MathNode is type FUNC but INVALID function"); throw CaretException("parsing problem in CaretMathExpression"); } @@ -835,6 +839,7 @@ CaretPointer CaretMathExpression::funcExpr() case MathFunctionEnum::LN: case MathFunctionEnum::EXP: case MathFunctionEnum::LOG: + case MathFunctionEnum::LOG2: case MathFunctionEnum::SQRT: case MathFunctionEnum::ABS: case MathFunctionEnum::FLOOR: diff --git a/src/Common/CaretPointLocator.cxx b/src/Common/CaretPointLocator.cxx index c34022c0f42b1d90fbf8fdf11f13f0d24ecbed57..2d0074d53043f0a7a50dcee6b1e68d237b059eba 100644 --- a/src/Common/CaretPointLocator.cxx +++ b/src/Common/CaretPointLocator.cxx @@ -196,15 +196,15 @@ int64_t CaretPointLocator::closestPoint(const float target[3], LocatorInfo* info int64_t CaretPointLocator::closestPointLimited(const float target[3], const float& maxDist, LocatorInfo* infoOut) const { + if (infoOut != NULL) + { + infoOut->whichSet = -1; + infoOut->index = -1; + } if (m_tree == NULL) return -1; float curDist2 = m_tree->distSquaredToPoint(target), maxDist2 = maxDist * maxDist; if (curDist2 > maxDist2) { - if (infoOut != NULL) - { - infoOut->whichSet = -1; - infoOut->index = -1; - } return -1; } CaretSimpleMinHeap >*, float> myHeap; @@ -264,9 +264,9 @@ int64_t CaretPointLocator::closestPointLimited(const float target[3], const floa return bestIndex; } -set CaretPointLocator::pointsInRange(const float target[3], const float& maxDist) const -{ - set ret; +vector CaretPointLocator::pointsInRange(const float target[3], const float& maxDist) const +{//each point occurs in only once in the tree, so we can use a vector + vector ret; if (m_tree == NULL) return ret; float curDist2 = m_tree->distSquaredToPoint(target), maxDist2 = maxDist * maxDist; if (curDist2 > maxDist2) return ret; @@ -285,7 +285,7 @@ set CaretPointLocator::pointsInRange(const float target[3], const f float tempf = MathFunctions::distanceSquared3D(myVecRef[i].m_point, target); if (tempf <= maxDist2) { - ret.insert(LocatorInfo(myVecRef[i].m_index, myVecRef[i].m_mySet, myVecRef[i].m_point)); + ret.push_back(LocatorInfo(myVecRef[i].m_index, myVecRef[i].m_mySet, myVecRef[i].m_point)); } } } else { diff --git a/src/Common/CaretPointLocator.h b/src/Common/CaretPointLocator.h index 0558916280b11ab0f8fe605b9710611df4c73947..cc0cb3ad9b80294796c012dfb2db36d64c051c30 100644 --- a/src/Common/CaretPointLocator.h +++ b/src/Common/CaretPointLocator.h @@ -36,11 +36,12 @@ namespace caret { int64_t index; int32_t whichSet; Vector3D coords; + LocatorInfo() { index = -1; whichSet = -1; } LocatorInfo(const int64_t& indexIn, const int32_t& whichSetIn, const Vector3D& coordsIn) : index(indexIn), whichSet(whichSetIn), coords(coordsIn) { } bool operator==(const LocatorInfo& rhs) const { return (index == rhs.index) && (whichSet == rhs.whichSet); }//ignore coords bool operator<(const LocatorInfo& rhs) const { - if (whichSet == rhs.whichSet)//expect multi-set usage with pointsInRange to be rare, but still separate by whichSet + if (whichSet == rhs.whichSet)//expect multi-set usage with pointsInRange to be rare, but still separate by whichSet if sorted { return index < rhs.index; } else { @@ -77,14 +78,17 @@ namespace caret { CaretPointLocator(const float minBounds[3], const float maxBounds[3]); ///make a point locator with the bounding box of this point set, and use this point set as set #0 CaretPointLocator(const float* coordsIn, const int64_t numCoords); + ///convenience constructor for vectors + CaretPointLocator(const std::vector coordsIn) : CaretPointLocator(coordsIn.data(), coordsIn.size() / 3) { } ///add a point set, SAVE THE RETURN VALUE because it is how you identify which point set found points belong to int32_t addPointSet(const float* coordsIn, const int64_t numCoords); + int32_t addPointSet(const std::vector coordsIn) { return addPointSet(coordsIn.data(), coordsIn.size() / 3); } ///remove a point set by its set number void removePointSet(const int32_t whichSet); ///returns the index of the closest point, and optionally which point set and the coords int64_t closestPoint(const float target[3], LocatorInfo* infoOut = NULL) const; int64_t closestPointLimited(const float target[3], const float& maxDist, LocatorInfo* infoOut = NULL) const; - std::set pointsInRange(const float target[3], const float& maxDist) const; + std::vector pointsInRange(const float target[3], const float& maxDist) const; bool anyInRange(const float target[3], const float& maxDist) const; }; } diff --git a/src/Common/CaretPreferenceDataValue.cxx b/src/Common/CaretPreferenceDataValue.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fc0728d4dc6c09e9f9ccf8a8746c6d36321d1466 --- /dev/null +++ b/src/Common/CaretPreferenceDataValue.cxx @@ -0,0 +1,214 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CARET_PREFERENCE_DATA_VALUE_DECLARE__ +#include "CaretPreferenceDataValue.h" +#undef __CARET_PREFERENCE_DATA_VALUE_DECLARE__ + +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::CaretPreferenceDataValue + * \brief Maintains a single caret preference data valud + * \ingroup Common + */ + +/** + * Constructor. + * + * @param preferenceSettings + * QSettings from caret preferences + * @param preferenceName + * Name of the preference + * @param dataType + * Data type of the preference + * @param savedInScene + * Indicates if item is saved to scene and may override the preference when scene restored. + * @param defaultValue + * Default value for the preference + */ +CaretPreferenceDataValue::CaretPreferenceDataValue(QSettings* preferenceSettings, + const QString& preferenceName, + const DataType dataType, + const SavedInScene savedInScene, + const QVariant defaultValue) +: CaretObject(), +m_preferenceSettings(preferenceSettings), +m_preferenceName(preferenceName), +m_dataType(dataType), +m_savedInScene(savedInScene) +{ + CaretAssert(m_preferenceSettings); + CaretAssert( ! m_preferenceName.isEmpty()); + CaretAssert( ! defaultValue.isNull()); + + m_dataValue = m_preferenceSettings->value(m_preferenceName, + defaultValue); + m_sceneDataValue = m_dataValue; +} + +/** + * Destructor. + */ +CaretPreferenceDataValue::~CaretPreferenceDataValue() +{ +} + +/** + * @return Name of preference + */ +QString +CaretPreferenceDataValue::getName() const +{ + return m_preferenceName; +} + +/** + * @return The data type + */ +CaretPreferenceDataValue::DataType +CaretPreferenceDataValue::getDataType() const +{ + return m_dataType; +} + +/** + * @return The data value. Some preferences may be overridden by + * a scene value. If the scene value is valid, it is returned, + * otherwise, the preference value is returned. + * + * @seealso getPreferenceValue() + * + * @param valueType + * Type of value returned (active/preference/scene) + */ +QVariant +CaretPreferenceDataValue::getValue(/*const ValueType valueType*/) const +{ + QVariant valueOut; + if (m_sceneDataValueValid) { + valueOut = m_sceneDataValue; + } + else { + valueOut = m_dataValue; + } + return valueOut; +} + +/** + * @return Always returns the preferences value. + */ +QVariant +CaretPreferenceDataValue::getPreferenceValue() const +{ + return m_dataValue; +} + +/** + * Set the value. This does invalidate the scene value. + * + * @param value + * New value + */ +void +CaretPreferenceDataValue::setValue(const QVariant& value) +{ + /* + * Setting value invalidates scene value + */ + m_sceneDataValueValid = false; + + if (value != m_dataValue) { + m_dataValue = value; + m_preferenceSettings->setValue(m_preferenceName, + m_dataValue); + m_preferenceSettings->sync(); + } +} + +/** + * Set the scene value. Also sets the scene value valid. + * + * @param value + * Value of parameter from the scene. + */ +void +CaretPreferenceDataValue::setSceneValue(const QVariant& value) +{ + m_sceneDataValue = value; + m_sceneDataValueValid = true; + + switch (m_savedInScene) { + case SavedInScene::SAVE_NO: + /* do not allow scene value */ + m_sceneDataValueValid = false; + break; + case SavedInScene::SAVE_YES: + break; + } +} + +/** + * Set the validity of the scene value. + * + * @param validStats + * New validity status of the scene value + */ +void +CaretPreferenceDataValue::setSceneValueValid(const bool validStatus) +{ + m_sceneDataValueValid = validStatus; + + switch (m_savedInScene) { + case SavedInScene::SAVE_NO: + /* do not allow scene value */ + m_sceneDataValueValid = false; + break; + case SavedInScene::SAVE_YES: + break; + } +} + +/** + * @return True if preferences is saved to scenes + */ +bool +CaretPreferenceDataValue::isSavedToScenes() const +{ + bool savedFlag(false); + + switch (m_savedInScene) { + case SavedInScene::SAVE_NO: + break; + case SavedInScene::SAVE_YES: + savedFlag = true; + break; + } + + return savedFlag; +} + + diff --git a/src/Common/CaretPreferenceDataValue.h b/src/Common/CaretPreferenceDataValue.h new file mode 100644 index 0000000000000000000000000000000000000000..390c6ee31800a5b1fe7977a0d0dafe14edaf4d5c --- /dev/null +++ b/src/Common/CaretPreferenceDataValue.h @@ -0,0 +1,106 @@ +#ifndef __CARET_PREFERENCE_DATA_VALUE_H__ +#define __CARET_PREFERENCE_DATA_VALUE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +#include "CaretObject.h" + +class QSettings; + +namespace caret { + + class CaretPreferences; + + class CaretPreferenceDataValue : public CaretObject { + + public: + enum class DataType { + FLOAT, + INTEGER, + STRING + }; + + enum class SavedInScene { + SAVE_NO, + SAVE_YES + }; + + CaretPreferenceDataValue(QSettings* preferenceSettings, + const QString& preferenceName, + const DataType dataType, + const SavedInScene savedInScene, + const QVariant defaultValue); + + virtual ~CaretPreferenceDataValue(); + + CaretPreferenceDataValue(const CaretPreferenceDataValue&) = delete; + + CaretPreferenceDataValue& operator=(const CaretPreferenceDataValue&) = delete; + + QString getName() const; + + DataType getDataType() const; + + QVariant getPreferenceValue() const; + + QVariant getValue(/*const ValueType valueType*/) const; + + void setValue(const QVariant& value); + + void setSceneValue(const QVariant& value); + + void setSceneValueValid(const bool validStatus); + + bool isSavedToScenes() const; + + // ADD_NEW_METHODS_HERE + + private: + QSettings* m_preferenceSettings; + + const QString m_preferenceName; + + const DataType m_dataType; + + const SavedInScene m_savedInScene; + + QVariant m_dataValue; + + QVariant m_sceneDataValue; + + bool m_sceneDataValueValid = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CARET_PREFERENCE_DATA_VALUE_DECLARE__ + // +#endif // __CARET_PREFERENCE_DATA_VALUE_DECLARE__ + +} // namespace +#endif //__CARET_PREFERENCE_DATA_VALUE_H__ diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index 0038e68826acd3241fbd8f33e54900160c13457e..791e93d85d20bbf5ac9ea950fd29750ce1745d7f 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -31,13 +31,13 @@ #include "CaretAssert.h" #include "CaretLogger.h" +#include "CaretPreferenceDataValue.h" #include "ModelTransform.h" #include "TileTabsConfiguration.h" +#include "WuQMacroGroup.h" using namespace caret; - - /** * \class caret::CaretPreferences * \brief Preferences for use in Caret. @@ -53,10 +53,27 @@ using namespace caret; CaretPreferences::CaretPreferences() : CaretObject() { + m_macros.reset(new WuQMacroGroup("Preferences")); + this->qSettings = new QSettings("brainvis.wustl.edu", "Caret7"); this->readPreferences(); + m_volumeCrossHairGapPreference.reset(new CaretPreferenceDataValue(this->qSettings, + "volumeAxesCrosshairGap", + CaretPreferenceDataValue::DataType::FLOAT, + CaretPreferenceDataValue::SavedInScene::SAVE_YES, + 0.0)); + m_preferenceDataValues.push_back(m_volumeCrossHairGapPreference.get()); + + const QString defAllSliceLayout = VolumeSliceViewAllPlanesLayoutEnum::toName(VolumeSliceViewAllPlanesLayoutEnum::ROW_LAYOUT); + m_volumeAllSlicePlanesLayout.reset(new CaretPreferenceDataValue(this->qSettings, + "volumeAllSlicePlanesLayout", + CaretPreferenceDataValue::DataType::STRING, + CaretPreferenceDataValue::SavedInScene::SAVE_NO, + defAllSliceLayout)); + m_preferenceDataValues.push_back(m_volumeAllSlicePlanesLayout.get()); + m_colorsMode = BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES; } @@ -65,6 +82,12 @@ CaretPreferences::CaretPreferences() */ CaretPreferences::~CaretPreferences() { + /** + * Note DO NOT delete items in this vector as they are pointers to items + * in unique_ptr's + */ + m_preferenceDataValues.clear(); + this->removeAllCustomViews(); this->removeAllTileTabsConfigurations(); @@ -72,6 +95,28 @@ CaretPreferences::~CaretPreferences() delete this->qSettings; } +/** + * Some preferences are temporarily overriden with a value from a scene + * and these 'scene overrides' are invalidated by this method + */ +void +CaretPreferences::invalidateSceneDataValues() +{ + for (auto pdv : m_preferenceDataValues) { + pdv->setSceneValueValid(false); + } +} + +/** + * @return The scene data value for items that are saved to + * and restored from scenes. Primarily for use by SessionManager. + */ +std::vector +CaretPreferences::getPreferenceSceneDataValues() +{ + return m_preferenceDataValues; +} + /** * Get the boolean value for the given preference name. * @param name @@ -336,6 +381,64 @@ CaretPreferences::writeCustomViews() this->qSettings->sync(); } +/** + * Read macros from preferences + * + * @param performSync + * If true, synchronize preferences before reading macros + */ +void +CaretPreferences::readMacros(const bool performSync) +{ + if (performSync) { + this->qSettings->sync(); + } + + const QString macrosXmlString = this->getString(NAME_MACROS); + if (macrosXmlString.isEmpty()) { + m_macros->clear(); + } + else { + QString errorMessage; + QString warningMessage; + if ( ! m_macros->readXmlFromStringOld(macrosXmlString, + errorMessage, + warningMessage)) { + CaretLogSevere("Reading macros from preferences: " + + errorMessage); + } + else if ( ! warningMessage.isEmpty()) { + CaretLogWarning(warningMessage); + } + } +} + +/** + * Write macros to preferences + */ +void +CaretPreferences::writeMacros() +{ + if ( ! m_macros->isModified()) { + return; + } + + QString macrosXmlString; + + if (m_macros->getNumberOfMacros() > 0) { + QString errorMessage; + if ( ! m_macros->writeXmlToString(macrosXmlString, + errorMessage)) { + CaretLogSevere("Writing macros to preferences: " + + errorMessage); + } + } + + this->setString(NAME_MACROS, + macrosXmlString); + this->qSettings->sync(); +} + /** * Remove all of the tile tabs configurations. @@ -394,10 +497,13 @@ CaretPreferences::readTileTabsConfigurations(const bool performSync) this->qSettings->setArrayIndex(i); const AString configString = this->qSettings->value(AString::number(i)).toString(); TileTabsConfiguration* ttc = new TileTabsConfiguration(); - if (ttc->decodeFromXML(configString)) { + AString errorMessage; + if (ttc->decodeFromXML(configString, + errorMessage)) { this->tileTabsConfigurations.push_back(ttc); } else { + CaretLogWarning(errorMessage); delete ttc; } } @@ -575,6 +681,10 @@ CaretPreferences::getUserBackgroundAndForegroundColors() void CaretPreferences::setUserBackgroundAndForegroundColors(const BackgroundAndForegroundColors& colors) { + if (this->userColors == colors) { + return; + } + /* * "in memory" colors */ @@ -583,6 +693,10 @@ CaretPreferences::setUserBackgroundAndForegroundColors(const BackgroundAndForegr /* * Update preferences file with colors */ + writeUnsignedByteArray(NAME_COLOR_BACKGROUND_WINDOW, + this->userColors.m_colorBackgroundWindow, + 3); + writeUnsignedByteArray(NAME_COLOR_FOREGROUND_ALL, this->userColors.m_colorForegroundAll, 3); @@ -850,6 +964,10 @@ CaretPreferences::getLoggingLevel() const void CaretPreferences::setLoggingLevel(const LogLevelEnum::Enum loggingLevel) { + if (this->loggingLevel == loggingLevel) { + return; + } + this->loggingLevel = loggingLevel; const AString name = LogLevelEnum::toName(this->loggingLevel); @@ -883,6 +1001,10 @@ CaretPreferences::getOpenDrawingMethod() const void CaretPreferences::setOpenGLDrawingMethod(const OpenGLDrawingMethodEnum::Enum openGLDrawingMethod) { + if (this->openGLDrawingMethod == openGLDrawingMethod) { + return; + } + this->openGLDrawingMethod = openGLDrawingMethod; this->setString(NAME_OPENGL_DRAWING_METHOD, OpenGLDrawingMethodEnum::toName(this->openGLDrawingMethod)); @@ -906,6 +1028,10 @@ CaretPreferences::getManageFilesViewFileType() const void CaretPreferences::setManageFilesViewFileType(const SpecFileDialogViewFilesTypeEnum::Enum manageFilesViewFileType) { + if (this->manageFilesViewFileType == manageFilesViewFileType) { + return; + } + this->manageFilesViewFileType = manageFilesViewFileType; this->setString(NAME_MANAGE_FILES_VIEW_FILE_TYPE, SpecFileDialogViewFilesTypeEnum::toName(this->manageFilesViewFileType)); @@ -929,6 +1055,10 @@ CaretPreferences::isShowSurfaceIdentificationSymbols() const void CaretPreferences::setShowSurfaceIdentificationSymbols(const bool showSymbols) { + if (this->showSurfaceIdentificationSymbols == showSymbols) { + return; + } + this->showSurfaceIdentificationSymbols = showSymbols; this->setBoolean(NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS, this->showSurfaceIdentificationSymbols); @@ -952,6 +1082,10 @@ CaretPreferences::isShowVolumeIdentificationSymbols() const void CaretPreferences::setShowVolumeIdentificationSymbols(const bool showSymbols) { + if (this->showVolumeIdentificationSymbols == showSymbols) { + return; + } + this->showVolumeIdentificationSymbols = showSymbols; this->setBoolean(NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS, this->showVolumeIdentificationSymbols); @@ -975,6 +1109,10 @@ CaretPreferences::isDynamicConnectivityDefaultedOn() const void CaretPreferences::setDynamicConnectivityDefaultedOn(const bool defaultedOn) { + if (this->dynamicConnectivityDefaultedOn == defaultedOn) { + return; + } + this->dynamicConnectivityDefaultedOn = defaultedOn; this->setBoolean(NAME_DYNAMIC_CONNECTIVITY_ON, defaultedOn); @@ -999,6 +1137,10 @@ CaretPreferences::getImageCaptureMethod() const void CaretPreferences::setImageCaptureMethod(const ImageCaptureMethodEnum::Enum imageCaptureMethod) { + if (this->imageCaptureMethod == imageCaptureMethod) { + return; + } + this->imageCaptureMethod = imageCaptureMethod; this->setString(NAME_IMAGE_CAPTURE_METHOD, ImageCaptureMethodEnum::toName(this->imageCaptureMethod)); @@ -1023,6 +1165,10 @@ CaretPreferences::isRemoteFilePasswordSaved() void CaretPreferences::setRemoteFilePasswordSaved(const bool saveRemotePasswordToPreferences) { + if (this->remoteFileLoginSaved == saveRemotePasswordToPreferences) { + return; + } + this->remoteFileLoginSaved = saveRemotePasswordToPreferences; this->setBoolean(NAME_REMOTE_FILE_LOGIN_SAVED, this->remoteFileLoginSaved); @@ -1058,6 +1204,11 @@ void CaretPreferences::setRemoteFileUserNameAndPassword(const AString& userName, const AString& password) { + if ((this->remoteFileUserName == userName) + && (this->remoteFilePassword == password)) { + return; + } + this->remoteFileUserName = userName; this->remoteFilePassword = password; @@ -1086,6 +1237,10 @@ CaretPreferences::getBalsaUserName() const void CaretPreferences::setBalsaUserName(const AString& userName) { + if (this->balsaUserName == userName) { + return; + } + this->balsaUserName = userName; this->setString(NAME_BALSA_USER_NAME, userName); @@ -1108,12 +1263,63 @@ CaretPreferences::isVolumeAxesCrosshairsDisplayed() const void CaretPreferences::setVolumeAxesCrosshairsDisplayed(const bool displayed) { + if (this->displayVolumeAxesCrosshairs == displayed) { + return; + } + this->displayVolumeAxesCrosshairs = displayed; - this->setBoolean(CaretPreferences::NAME_VOLUME_AXES_CROSSHAIRS, + this->setBoolean(CaretPreferences::NAME_VOLUME_AXES_CROSSHAIRS, this->displayVolumeAxesCrosshairs); this->qSettings->sync(); } +/** + * @return The volume all slice planes layout + */ +VolumeSliceViewAllPlanesLayoutEnum::Enum +CaretPreferences::getVolumeAllSlicePlanesLayout() const +{ + QString stringValue(m_volumeAllSlicePlanesLayout->getValue().toString()); + bool validFlag(false); + VolumeSliceViewAllPlanesLayoutEnum::Enum enumValue = + VolumeSliceViewAllPlanesLayoutEnum::fromName(stringValue, &validFlag); + return enumValue; +} + +/** + * Set volume all slice planes layout + * + * @param allViewLayout + * The all slice planes layout + */ +void +CaretPreferences::setVolumeAllSlicePlanesLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum allViewLayout) +{ + const QString stringValue = VolumeSliceViewAllPlanesLayoutEnum::toName(allViewLayout); + m_volumeAllSlicePlanesLayout->setValue(stringValue); +} + +/** + * @return The crosshair gap + */ +float +CaretPreferences::getVolumeCrosshairGap() const +{ + return m_volumeCrossHairGapPreference->getValue().toFloat(); +} + +/** + * Set the volume crosshair gap + * + * @param gap + * New value for crosshair gap. + */ +void +CaretPreferences::setVolumeCrosshairGap(const float gap) +{ + return m_volumeCrossHairGapPreference->setValue(gap); +} + /** * @return Are axes labels displayed? */ @@ -1131,6 +1337,10 @@ CaretPreferences::isVolumeAxesLabelsDisplayed() const void CaretPreferences::setVolumeAxesLabelsDisplayed(const bool displayed) { + if (this->displayVolumeAxesLabels == displayed) { + return; + } + this->displayVolumeAxesLabels = displayed; this->setBoolean(CaretPreferences::NAME_VOLUME_AXES_LABELS, this->displayVolumeAxesLabels); @@ -1155,6 +1365,10 @@ CaretPreferences::isVolumeMontageAxesCoordinatesDisplayed() const void CaretPreferences::setVolumeMontageAxesCoordinatesDisplayed(const bool displayed) { + if (this->displayVolumeAxesCoordinates == displayed) { + return; + } + this->displayVolumeAxesCoordinates = displayed; this->setBoolean(CaretPreferences::NAME_VOLUME_AXES_COORDINATE, this->displayVolumeAxesCoordinates); @@ -1179,6 +1393,10 @@ CaretPreferences::getVolumeMontageGap() const void CaretPreferences::setVolumeMontageGap(const int32_t volumeMontageGap) { + if (this->volumeMontageGap == volumeMontageGap) { + return; + } + this->volumeMontageGap = volumeMontageGap; this->setInteger(CaretPreferences::NAME_VOLUME_MONTAGE_GAP, this->volumeMontageGap); @@ -1203,6 +1421,10 @@ CaretPreferences::getVolumeMontageCoordinatePrecision() const void CaretPreferences::setVolumeMontageCoordinatePrecision(const int32_t volumeMontageCoordinatePrecision) { + if (this->volumeMontageCoordinatePrecision == volumeMontageCoordinatePrecision) { + return; + } + this->volumeMontageCoordinatePrecision = volumeMontageCoordinatePrecision; this->setInteger(CaretPreferences::NAME_VOLUME_MONTAGE_COORDINATE_PRECISION, this->volumeMontageCoordinatePrecision); @@ -1226,8 +1448,12 @@ CaretPreferences::isSplashScreenEnabled() const void CaretPreferences::setSplashScreenEnabled(const bool enabled) { + if (this->splashScreenEnabled == enabled) { + return; + } + this->splashScreenEnabled = enabled; - this->setBoolean(CaretPreferences::NAME_SPLASH_SCREEN, + this->setBoolean(CaretPreferences::NAME_SPLASH_SCREEN, this->splashScreenEnabled); this->qSettings->sync(); } @@ -1249,12 +1475,44 @@ CaretPreferences::isDevelopMenuEnabled() const void CaretPreferences::setDevelopMenuEnabled(const bool enabled) { + if (this->developMenuEnabled == enabled) { + return; + } + this->developMenuEnabled = enabled; this->setBoolean(CaretPreferences::NAME_DEVELOP_MENU, this->developMenuEnabled); this->qSettings->sync(); } +/** + * @return Is Show Data ToolTips enabled? + */ +bool +CaretPreferences::isShowDataToolTipsEnabled() const +{ + return this->dataToolTipsEnabled; +} + +/** + * Set Show Data ToolTips enabled. + * @param enabled + * New status. + */ +void +CaretPreferences::setShowDataToolTipsEnabled(const bool enabled) +{ + if (this->dataToolTipsEnabled == enabled) { + return; + } + + this->dataToolTipsEnabled = enabled; + this->setBoolean(CaretPreferences::NAME_DATA_TOOL_TIPS, + this->dataToolTipsEnabled); + this->qSettings->sync(); +} + + /** * @param Is yoking defaulted on ? */ @@ -1271,6 +1529,10 @@ bool CaretPreferences::isYokingDefaultedOn() const */ void CaretPreferences::setYokingDefaultedOn(const bool status) { + if (this->yokingDefaultedOn == status) { + return; + } + this->yokingDefaultedOn = status; this->setBoolean(CaretPreferences::NAME_YOKING_DEFAULT_ON, this->yokingDefaultedOn); @@ -1293,12 +1555,34 @@ bool CaretPreferences::isVolumeIdentificationDefaultedOn() const */ void CaretPreferences::setVolumeIdentificationDefaultedOn(const bool status) { + if (this->volumeIdentificationDefaultedOn == status) { + return; + } + this->volumeIdentificationDefaultedOn = status; this->setBoolean(CaretPreferences::NAME_VOLUME_IDENTIFICATION_DEFAULTED_ON, this->volumeIdentificationDefaultedOn); this->qSettings->sync(); } +/** + * @return Pointer to the macros. + */ +WuQMacroGroup* +CaretPreferences::getMacros() +{ + return m_macros.get(); +} + +/** + * @return Const pointer to the macros. + */ +const WuQMacroGroup* +CaretPreferences::getMacros() const +{ + return m_macros.get(); +} + /** * Read an unsigned byte array to the preferences. * @@ -1359,6 +1643,18 @@ CaretPreferences::readPreferences() uint8_t colorRGB[3] = { 0, 0, 0 }; + userColors.getColorForegroundWindow(colorRGB); + readUnsignedByteArray(NAME_COLOR_FOREGROUND_WINDOW, + colorRGB, + 3); + userColors.setColorForegroundWindow(colorRGB); + + userColors.getColorBackgroundWindow(colorRGB); + readUnsignedByteArray(NAME_COLOR_BACKGROUND_WINDOW, + colorRGB, + 3); + userColors.setColorBackgroundWindow(colorRGB); + userColors.getColorForegroundAllView(colorRGB); readUnsignedByteArray(NAME_COLOR_FOREGROUND_ALL, colorRGB, @@ -1445,7 +1741,9 @@ CaretPreferences::readPreferences() this->readCustomViews(false); - this->readTileTabsConfigurations(); + this->readTileTabsConfigurations(false); + + this->readMacros(false); AString levelName = this->qSettings->value(NAME_LOGGING_LEVEL, LogLevelEnum::toName(LogLevelEnum::INFO)).toString(); @@ -1454,7 +1752,9 @@ CaretPreferences::readPreferences() if (valid == false) { logLevel = LogLevelEnum::INFO; } - this->setLoggingLevel(logLevel); + /* Do not call setLoggingLevel() as it will cause preferences to sync */ + this->loggingLevel = logLevel; + CaretLogger::getLogger()->setLevel(this->loggingLevel); ImageCaptureMethodEnum::Enum defaultCaptureType = ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_RENDER_PIXMAP; AString imageCaptureMethodName = this->qSettings->value(NAME_IMAGE_CAPTURE_METHOD, @@ -1505,6 +1805,9 @@ CaretPreferences::readPreferences() this->developMenuEnabled = this->getBoolean(CaretPreferences::NAME_DEVELOP_MENU, false); + + this->dataToolTipsEnabled = this->getBoolean(CaretPreferences::NAME_DATA_TOOL_TIPS, + true); this->yokingDefaultedOn = this->getBoolean(CaretPreferences::NAME_YOKING_DEFAULT_ON, true); diff --git a/src/Common/CaretPreferences.h b/src/Common/CaretPreferences.h index 20db3f72b16c8d80e0a1f090b569e4a1e1f0dad1..b839d160be73cd521c5ad0fb3c0d43329102a20e 100644 --- a/src/Common/CaretPreferences.h +++ b/src/Common/CaretPreferences.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include #include "BackgroundAndForegroundColors.h" @@ -30,14 +31,17 @@ #include "ImageCaptureMethodEnum.h" #include "OpenGLDrawingMethodEnum.h" #include "SpecFileDialogViewFilesTypeEnum.h" +#include "VolumeSliceViewAllPlanesLayoutEnum.h" class QSettings; class QStringList; namespace caret { + class CaretPreferenceDataValue; class ModelTransform; class TileTabsConfiguration; + class WuQMacroGroup; class CaretPreferences : public CaretObject { @@ -88,6 +92,14 @@ namespace caret { void setOpenGLDrawingMethod(const OpenGLDrawingMethodEnum::Enum openGLDrawingMethod); + VolumeSliceViewAllPlanesLayoutEnum::Enum getVolumeAllSlicePlanesLayout() const; + + void setVolumeAllSlicePlanesLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum allViewLayout); + + float getVolumeCrosshairGap() const; + + void setVolumeCrosshairGap(const float gap); + bool isVolumeAxesCrosshairsDisplayed() const; void setVolumeAxesCrosshairsDisplayed(const bool displayed); @@ -120,6 +132,10 @@ namespace caret { void setDevelopMenuEnabled(const bool enabled); + bool isShowDataToolTipsEnabled() const; + + void setShowDataToolTipsEnabled(const bool enabled); + void readTileTabsConfigurations(const bool performSync = true); std::vector getTileTabsConfigurationsSortedByName() const; @@ -190,6 +206,18 @@ namespace caret { void setDynamicConnectivityDefaultedOn(const bool defaultedOn); + WuQMacroGroup* getMacros(); + + const WuQMacroGroup* getMacros() const; + + void readMacros(const bool performSync = true); + + void writeMacros(); + + void invalidateSceneDataValues(); + + std::vector getPreferenceSceneDataValues(); + private: CaretPreferences(const CaretPreferences&); @@ -271,6 +299,12 @@ namespace caret { int32_t volumeMontageCoordinatePrecision; + std::unique_ptr m_volumeAllSlicePlanesLayout; + + std::unique_ptr m_volumeCrossHairGapPreference; + + std::vector m_preferenceDataValues; + bool splashScreenEnabled; bool developMenuEnabled; @@ -287,6 +321,8 @@ namespace caret { bool yokingDefaultedOn; + bool dataToolTipsEnabled; + AString remoteFileUserName; AString remoteFilePassword; bool remoteFileLoginSaved; @@ -295,6 +331,8 @@ namespace caret { SpecFileDialogViewFilesTypeEnum::Enum manageFilesViewFileType; + std::unique_ptr m_macros; + static const AString NAME_ANIMATION_START_TIME; static const AString NAME_BALSA_USER_NAME; static const AString NAME_VOLUME_AXES_CROSSHAIRS; @@ -304,6 +342,8 @@ namespace caret { static const AString NAME_VOLUME_MONTAGE_COORDINATE_PRECISION; static const AString NAME_COLOR_BACKGROUND; static const AString NAME_COLOR_FOREGROUND; + static const AString NAME_COLOR_BACKGROUND_WINDOW; + static const AString NAME_COLOR_FOREGROUND_WINDOW; static const AString NAME_COLOR_BACKGROUND_ALL; static const AString NAME_COLOR_FOREGROUND_ALL; static const AString NAME_COLOR_BACKGROUND_CHART; @@ -315,9 +355,11 @@ namespace caret { static const AString NAME_COLOR_CHART_MATRIX_GRID_LINES; static const AString NAME_COLOR_CHART_HISTOGRAM_THRESHOLD; static const AString NAME_DEVELOP_MENU; + static const AString NAME_DATA_TOOL_TIPS; static const AString NAME_DYNAMIC_CONNECTIVITY_ON; static const AString NAME_IMAGE_CAPTURE_METHOD; static const AString NAME_LOGGING_LEVEL; + static const AString NAME_MACROS; static const AString NAME_MANAGE_FILES_VIEW_FILE_TYPE; static const AString NAME_OPENGL_DRAWING_METHOD; static const AString NAME_PREVIOUS_SCENE_FILES; @@ -331,6 +373,7 @@ namespace caret { static const AString NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS; static const AString NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS; static const AString NAME_TILE_TABS_CONFIGURATIONS; + static const AString NAME_TILE_TABS_CONFIGURATIONS_TWO; static const AString NAME_VOLUME_IDENTIFICATION_DEFAULTED_ON; static const AString NAME_YOKING_DEFAULT_ON; @@ -346,6 +389,8 @@ namespace caret { const AString CaretPreferences::NAME_VOLUME_MONTAGE_COORDINATE_PRECISION = "volumeMontageCoordinatePrecision"; const AString CaretPreferences::NAME_COLOR_BACKGROUND = "colorBackground"; const AString CaretPreferences::NAME_COLOR_FOREGROUND = "colorForeground"; + const AString CaretPreferences::NAME_COLOR_BACKGROUND_WINDOW = "colorBackgroundWindow"; + const AString CaretPreferences::NAME_COLOR_FOREGROUND_WINDOW = "colorForegroundWindow"; const AString CaretPreferences::NAME_COLOR_BACKGROUND_ALL = "colorBackgroundAll"; const AString CaretPreferences::NAME_COLOR_FOREGROUND_ALL = "colorForegroundAll"; const AString CaretPreferences::NAME_COLOR_BACKGROUND_CHART = "colorBackgroundChart"; @@ -357,9 +402,11 @@ namespace caret { const AString CaretPreferences::NAME_COLOR_CHART_MATRIX_GRID_LINES = "colorChartMatrixGridLines"; const AString CaretPreferences::NAME_COLOR_CHART_HISTOGRAM_THRESHOLD = "colorChartHistogramThreshold"; const AString CaretPreferences::NAME_DEVELOP_MENU = "developMenu"; + const AString CaretPreferences::NAME_DATA_TOOL_TIPS = "dataToolTips"; const AString CaretPreferences::NAME_DYNAMIC_CONNECTIVITY_ON = "dynamicConnectivityDefaultedOn"; const AString CaretPreferences::NAME_IMAGE_CAPTURE_METHOD = "imageCaptureMethod"; const AString CaretPreferences::NAME_LOGGING_LEVEL = "loggingLevel"; + const AString CaretPreferences::NAME_MACROS = "macros"; const AString CaretPreferences::NAME_MANAGE_FILES_VIEW_FILE_TYPE = "manageFilesViewFileType"; const AString CaretPreferences::NAME_OPENGL_DRAWING_METHOD = "openGLDrawingMethod"; const AString CaretPreferences::NAME_PREVIOUS_SCENE_FILES = "previousSceneFiles"; @@ -373,6 +420,7 @@ namespace caret { const AString CaretPreferences::NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS = "showSurfaceIdentificationSymbols"; const AString CaretPreferences::NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS = "showVolumeIdentificationSymbols"; const AString CaretPreferences::NAME_TILE_TABS_CONFIGURATIONS = "tileTabsConfigurations"; + const AString CaretPreferences::NAME_TILE_TABS_CONFIGURATIONS_TWO = "tileTabsConfigurationsTwo"; const AString CaretPreferences::NAME_VOLUME_IDENTIFICATION_DEFAULTED_ON = "volumeIdentificationDefaultedOn"; const AString CaretPreferences::NAME_YOKING_DEFAULT_ON = "yokingDefaultedOn"; #endif // __CARET_PREFERENCES_DECLARE__ diff --git a/src/Common/ConnectivityCorrelation.cxx b/src/Common/ConnectivityCorrelation.cxx new file mode 100644 index 0000000000000000000000000000000000000000..01a355678f39f746cae051a0b667efa8eb9fa58e --- /dev/null +++ b/src/Common/ConnectivityCorrelation.cxx @@ -0,0 +1,731 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#define __CONNECTIVITY_CORRELATION_DECLARE__ +#include "ConnectivityCorrelation.h" +#undef __CONNECTIVITY_CORRELATION_DECLARE__ + +#include "CaretAssert.h" +#include "CaretOMP.h" +#include "dot_wrapper.h" + +using namespace caret; + + + +/** + * \class caret::ConnectivityCorrelation + * \brief Computes connectivity correlations + * \ingroup Common + * + * Correlation from https://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient + */ + +/** + * Create new instance for data that is in one contiguous "chunk" of memory + * + * @param data + * Points to first timepoint for first brainordinate + * @param numberOfBrainordinates + * Number of brainordinates + * @param nextBrainordinateStride + * Element offset between two consecutive brainordinates (eg: offset from first value for FIRST brainordinate + * to first value for SECOND brainordinate, and so on) + * @param numberOfTimePoints + * Number of timepoints for each brainordinate + * @param nextTimePointStride + * Offset between two consecutive timepoints for a brainordinate + * Use a value of "1" for contiguous data + * @param errorMessageOut + * Contains error information if NULL is returned + * @return + * Pointer to new instance or NULL if there is an error. + * + * Example: Nifti file with time-series data. Each 'brick' contains one timepoint + * for all brainordinates. Brainordinates are "interleaved" + * data = pointer to data + * numberOfBrainordinates = dim[0] * dim[1] * dim[2] (sizeof a 'brick') + * nextBrainordinateStride = 1 + * numberOfTimePoints = number of timepoints + * nextTimePointStride = dim[0] * dim[1] * dim[3] (sizeof a 'brick') + */ +ConnectivityCorrelation* +ConnectivityCorrelation::newInstance(const float* data, + const int64_t numberOfBrainordinates, + const int64_t nextBrainordinateStride, + const int64_t numberOfTimePoints, + const int64_t nextTimePointStride, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + std::vector brainordinateDataPointers; + for (int64_t i = 0; i < numberOfBrainordinates; i++) { + const int64_t offset = i * nextBrainordinateStride; + brainordinateDataPointers.push_back(data + + offset); + } + + CaretAssert(numberOfBrainordinates == static_cast(brainordinateDataPointers.size())); + + /* + * While either of the other two factory methods can be called, the new instance + * for brainordinates is faster when each brainordinates timepoint's are in a + * contigous section of memory (nextTimePointStride == 1). + */ + ConnectivityCorrelation* instanceOut = newInstanceBrainordinates(brainordinateDataPointers, + numberOfTimePoints, + nextTimePointStride, + errorMessageOut); + + return instanceOut; +} + +/** + * Create a new instance where each chunk of memory contains all timepoints for one brainordinate. + * + * @param brainordinateDataPointers + * Each element points to all timepoints for one brainordinate + * @param numberOfTimePoints + * Number of timepoints for each brainordinate + * @param nextTimePointStride + * Offset between two consecutive timepoints for a brainordinate + * Use a value of "1" for contiguous data + * @param errorMessageOut + * Contains error information if NULL is returned + * @return + * Pointer to new instance or NULL if there is an error. + */ +ConnectivityCorrelation* +ConnectivityCorrelation::newInstanceBrainordinates(const std::vector& brainordinateDataPointers, + const int64_t numberOfTimePoints, + const int64_t nextTimePointStride, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + ConnectivityCorrelation* instanceOut = ((nextTimePointStride == 1) + ? new ConnectivityCorrelation(DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA) + : new ConnectivityCorrelation(DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA)); + const bool validFlag = instanceOut->initializeWithBrainordinates(brainordinateDataPointers, + numberOfTimePoints, + nextTimePointStride, + errorMessageOut); + if ( ! validFlag) { + delete instanceOut; + instanceOut = NULL; + } + + return instanceOut; +} + +/** + * Create a new instance where each chunk of memory contains one timepoint for all brainordinates + * + * @param timePointDataPointers + * Each element points to all brainordinates for one timepoint + * @param numberOfBrainordinates + * Number of brainordinates + * @param nextBrainordinateStride + * Element offset between two consecutive brainordinates (eg: offset from first value for FIRST brainordinate + * to first value for SECOND brainordinate, and so on) + * @param errorMessageOut + * Contains error information if NULL is returned + * @return + * Pointer to new instance or NULL if there is an error. + * + * Example: GIFTI functional file (Metric) with time-series data. Each map contains one timepoint + * for all brainordinates. + * timePointDataPointers = pointer to each map's data + * numberOfBrainordinates = Number of vertices in the GIFTI file + * nextBrainordinateStride = 1 + * numberOfTimePoints = number of maps in file (each map is one time point) + */ +ConnectivityCorrelation* +ConnectivityCorrelation::newInstanceTimePoints(const std::vector& timePointDataPointers, + const int64_t numberOfBrainordinates, + const int64_t nextBrainordinateStride, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + ConnectivityCorrelation* instanceOut = new ConnectivityCorrelation(DataTypeEnum::TIMEPOINTS); + const bool validFlag = instanceOut->initializeWithTimePoints(timePointDataPointers, + numberOfBrainordinates, + nextBrainordinateStride, + errorMessageOut); + if ( ! validFlag) { + delete instanceOut; + instanceOut = NULL; + } + + return instanceOut; +} + +/** + * Constructor + * + * @param dataType + * Type of data (brainordinate or timepoint) + * + */ +ConnectivityCorrelation::ConnectivityCorrelation(const DataTypeEnum dataType) +: m_dataType(dataType) +{ + +} + +/** + * Destructor. + */ +ConnectivityCorrelation::~ConnectivityCorrelation() +{ +} + +/** + * Initialize a new instance where a chunk of memory contains all timepoints for one brainordinate. + * + * @param brainordinateDataPointers + * Each element points to all timepoints for one brainordinate + * @param numberOfTimePoints + * Number of timepoints for each brainordinate + * @param nextTimePointStride + * Offset between two consecutive timepoints for a brainordinate + * Use a value of "1" for contiguous data + * @param errorMessageOut + * Contains error information if NULL is returned + * @return + * Pointer to new instance or NULL if there is an error. + */ +bool +ConnectivityCorrelation::initializeWithBrainordinates(const std::vector& brainordinateDataPointers, + const int64_t numberOfTimePoints, + const int64_t nextTimePointStride, + AString& errorMessageOut) +{ + switch (m_dataType) { + case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: + break; + case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: + break; + case DataTypeEnum::INVALID: + CaretAssert(0); + break; + case DataTypeEnum::TIMEPOINTS: + CaretAssert(0); + break; + } + + m_numberOfTimePoints = numberOfTimePoints; + + CaretAssert(brainordinateDataPointers.size() >= 2); + CaretAssert(m_numberOfTimePoints >= 2); + CaretAssert(nextTimePointStride >= 1); + + m_numberOfBrainordinates = static_cast(brainordinateDataPointers.size()); + if (m_numberOfBrainordinates < 2) { + errorMessageOut.appendWithNewLine("There must be at least two brainordinates"); + } + if (numberOfTimePoints < 2) { + errorMessageOut.appendWithNewLine("There must be at least two time points"); + } + if (nextTimePointStride < 1) { + errorMessageOut.appendWithNewLine("TimePoint stride must be at least one"); + } + if ( ! errorMessageOut.isEmpty()) { + return false; + } + + for (int64_t i = 0; i < m_numberOfBrainordinates; i++) { + CaretAssertVectorIndex(brainordinateDataPointers, i); + const float* dataPointer = brainordinateDataPointers[i]; + CaretAssert(dataPointer); + std::unique_ptr gd(new BrainordinateData(dataPointer, + nextTimePointStride)); + m_brainordinateData.push_back(std::move(gd)); + } + CaretAssert(static_cast(m_brainordinateData.size()) == m_numberOfBrainordinates); + + computeBrainordinateMeanAndSumSquared(); + + return true; +} + +/** + * Initialize a new instance where a chunk of memory contains all timepoints for one brainordinate. + * + * @param timePointDataPointers + * Each element points to all brainordinates for one timepoint + * @param numberOfBrainordinates + * Number of brainordinates + * @param nextBrainordinateStride + * Element offset between two consecutive brainordinates (eg: offset from first value for FIRST brainordinate + * to first value for SECOND brainordinate, and so on) + * @param errorMessageOut + * Contains error information if NULL is returned + * @return + * Pointer to new instance or NULL if there is an error. + */ +bool +ConnectivityCorrelation::initializeWithTimePoints(const std::vector& timePointDataPointers, + const int64_t numberOfBrainordinates, + const int64_t nextBrainordinateStride, + AString& errorMessageOut) +{ + CaretAssert(m_dataType == DataTypeEnum::TIMEPOINTS); + m_numberOfBrainordinates = numberOfBrainordinates; + m_numberOfTimePoints = static_cast(timePointDataPointers.size()); + CaretAssert(m_numberOfTimePoints >= 2); + CaretAssert(nextBrainordinateStride >= 1); + + if (m_numberOfBrainordinates < 2) { + errorMessageOut.appendWithNewLine("There must be at least two brainordinates"); + } + if (m_numberOfTimePoints < 2) { + errorMessageOut.appendWithNewLine("There must be at least two time points"); + } + if (nextBrainordinateStride < 1) { + errorMessageOut.appendWithNewLine("Brainordinate stride must be at least one"); + } + if ( ! errorMessageOut.isEmpty()) { + return false; + } + + for (int64_t i = 0; i < m_numberOfTimePoints; i++) { + CaretAssertVectorIndex(timePointDataPointers, i); + const float* dataPointer = timePointDataPointers[i]; + CaretAssert(dataPointer); + + std::unique_ptr td(new TimePointData(dataPointer, + nextBrainordinateStride)); + m_timePointData.push_back(std::move(td)); + } + + computeBrainordinateMeanAndSumSquared(); + + return true; +} + +/** + * Get correlation from the given brainordinate ROI to all other brainordinates + * + * @param brainordinateIndices + * Index of brainordinates in the ROI to correlate to all other brainordinates + * @param dataOut + * Output with correlation values. + */ +void +ConnectivityCorrelation::getCorrelationForBrainordinateROI(const std::vector& brainordinateIndices, + std::vector& dataOut) +{ + dataOut.resize(m_numberOfBrainordinates); + std::fill(dataOut.begin(), dataOut.end(), 0.0); + + const int64_t numBrainordinatesInROI = static_cast(brainordinateIndices.size()); + if (m_numberOfTimePoints > 1) { + if (numBrainordinatesInROI > 0) { + std::vector dataAverage(m_numberOfTimePoints, 0.0); + + for (int32_t iTime = 0; iTime < m_numberOfTimePoints; iTime++) { + double timePointSum(0.0); + for (int64_t jBrain = 0; jBrain < numBrainordinatesInROI; jBrain++) { + CaretAssertVectorIndex(brainordinateIndices, jBrain); + timePointSum += getDataValue(brainordinateIndices[jBrain], iTime); + } + dataAverage[iTime] = timePointSum / static_cast(numBrainordinatesInROI); + } + + double sum(0.0); + double sumSquared(0.0); + for (int64_t j = 0; j < m_numberOfTimePoints; j++) { + CaretAssertVectorIndex(dataAverage, j); + const float d = dataAverage[j]; + sum += d; + sumSquared += (d * d); + } + const float mean = (sum / m_numberOfTimePoints); + const float ssxxSquared = (sumSquared - (m_numberOfTimePoints * mean * mean)); + const float ssxx = std::sqrt(ssxxSquared); + + const float* dataPtr = &dataAverage[0]; +#pragma omp CARET_PARFOR schedule(dynamic) + for (int32_t iBrain = 0; iBrain < m_numberOfBrainordinates; iBrain++) { + CaretAssertVectorIndex(dataOut, iBrain); + switch (m_dataType) { + case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: + dataOut[iBrain] = correlationBrainordinateContiguousDataAux(dataPtr, + mean, + ssxx, + iBrain); + break; + case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: + dataOut[iBrain] = correlationBrainordinateNonContiguousDataAux(dataPtr, + mean, + ssxx, + iBrain); + break; + case DataTypeEnum::INVALID: + CaretAssert(0); + break; + case DataTypeEnum::TIMEPOINTS: + dataOut[iBrain] = correlationTimePointDataAux(dataPtr, + mean, + ssxx, + iBrain); + break; + } + } + } + } +} + + +/** + * Get correlation from the given brainordinate to all other brainordinates + * + * @param brainordinateIndex + * Index of brainordinate to correlate to all other brainordinates + * @param dataOut + * Output with correlation values. + */ +void +ConnectivityCorrelation::getCorrelationForBrainordinate(const int64_t brainordinateIndex, + std::vector& dataOut) +{ + CaretAssert(m_numberOfBrainordinates > 1); + CaretAssert(m_numberOfTimePoints > 1); + if (m_numberOfTimePoints > 0) { + if (m_numberOfBrainordinates > 0) { + dataOut.resize(m_numberOfBrainordinates); +#pragma omp CARET_PARFOR schedule(dynamic) + for (int64_t i = 0; i < m_numberOfBrainordinates; i++) { + CaretAssertVectorIndex(dataOut, i); + switch (m_dataType) { + case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: + dataOut[i] = correlationBrainordinateContiguousData(brainordinateIndex, + i); + break; + case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: + dataOut[i] = correlationBrainordinateNonContiguousData(brainordinateIndex, + i); + break; + case DataTypeEnum::INVALID: + CaretAssert(0); + break; + case DataTypeEnum::TIMEPOINTS: + dataOut[i] = correlationTimePointData(brainordinateIndex, + i); + break; + } + } + } + } +} + +/** + * Get the correlation coefficient for the two given brainordinates + * that contain CONTIGOUS data + * + * @param fromBrainordinateIndex + * Index of a brainordinate + * @param toBrainordinateIndex + * Index of a second brainordinate. + */ +float +ConnectivityCorrelation::correlationBrainordinateContiguousData(const int64_t fromBrainordinateIndex, + const int64_t toBrainordinateIndex) const +{ + CaretAssert(m_dataType == DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA); + + CaretAssertVectorIndex(m_brainordinateData, fromBrainordinateIndex); + const BrainordinateData* fromData = m_brainordinateData[fromBrainordinateIndex].get(); + CaretAssertVectorIndex(m_meanSSData, fromBrainordinateIndex); + const BrainordinateMeanSS* fromMeanSS = m_meanSSData[fromBrainordinateIndex].get(); + + return correlationBrainordinateContiguousDataAux(fromData->m_data, + fromMeanSS->m_mean, + fromMeanSS->m_sqrt_ssxx, + toBrainordinateIndex); +} + +/** + * Get the correlation coefficient for the two given brainordinates + * that contain CONTIGOUS data + * + * @param fromBrainordinateData + * Data for the 'from' brainordinate + * @param fromBrainordinateMean + * Mean of the data for the 'from' brainordinate. + * @param fromBrainordinateSSXX + * Sum-squared of the data for the 'from' brainordinate. + * @param toBrainordinateIndex + * Index of the 'to' brainordinate. + */ +float +ConnectivityCorrelation::correlationBrainordinateContiguousDataAux(const float* fromBrainordinateData, + const float fromBrainordinateMean, + const float fromBrainordinateSSXX, + const int64_t toBrainordinateIndex) const +{ + CaretAssert(m_dataType == DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA); + + CaretAssertVectorIndex(m_brainordinateData, toBrainordinateIndex); + const BrainordinateData* toGroup = m_brainordinateData[toBrainordinateIndex].get(); + + CaretAssertVectorIndex(m_meanSSData, toBrainordinateIndex); + const BrainordinateMeanSS* toMeanSS = m_meanSSData[toBrainordinateIndex].get(); + + double xySum = dsdot(fromBrainordinateData, + toGroup->m_data, + m_numberOfTimePoints); + + const double ssxy = xySum - (m_numberOfTimePoints * fromBrainordinateMean * toMeanSS->m_mean); + + float correlationCoefficient = 0.0; + if ((fromBrainordinateSSXX > 0.0) + && (toMeanSS->m_sqrt_ssxx > 0.0)) { + correlationCoefficient = (ssxy / (fromBrainordinateSSXX * toMeanSS->m_sqrt_ssxx)); + } + return correlationCoefficient; +} + +/** + * Get the correlation coefficient for the two given brainordinates + * that contain NON-CONTIGOUS data + * + * @param fromBrainordinateIndex + * Index of a brainordinate + * @param toBrainordinateIndex + * Index of a second brainordinate. + */ +float +ConnectivityCorrelation::correlationBrainordinateNonContiguousData(const int64_t fromBrainordinateIndex, + const int64_t toBrainordinateIndex) const +{ + CaretAssertVectorIndex(m_brainordinateData, fromBrainordinateIndex); + + std::vector data(m_numberOfTimePoints); + for (int32_t iTime = 0; iTime < m_numberOfTimePoints; iTime++) { + data[iTime] = getDataValue(fromBrainordinateIndex, iTime); + } + + CaretAssertVectorIndex(m_meanSSData, fromBrainordinateIndex); + const BrainordinateMeanSS* fromMeanSS = m_meanSSData[fromBrainordinateIndex].get(); + + + return correlationBrainordinateNonContiguousDataAux(&data[0], + fromMeanSS->m_mean, + fromMeanSS->m_sqrt_ssxx, + toBrainordinateIndex); +} + +/** + * Get the correlation coefficient for the two given brainordinates + * that contain NON-CONTIGOUS data + * + * @param fromBrainordinateData + * Data for the 'from' brainordinate + * @param fromBrainordinateMean + * Mean of the data for the 'from' brainordinate. + * @param fromBrainordinateSSXX + * Sum-squared of the data for the 'from' brainordinate. + * @param toBrainordinateIndex + * Index of the 'to' brainordinate. + */ +float +ConnectivityCorrelation::correlationBrainordinateNonContiguousDataAux(const float* fromBrainordinateData, + const float fromBrainordinateMean, + const float fromBrainordinateSSXX, + const int64_t toBrainordinateIndex) const +{ + CaretAssert(m_dataType == DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA); + + CaretAssertVectorIndex(m_brainordinateData, toBrainordinateIndex); + + const BrainordinateData* toGroup = m_brainordinateData[toBrainordinateIndex].get(); + + CaretAssertVectorIndex(m_meanSSData, toBrainordinateIndex); + const BrainordinateMeanSS* toMeanSS = m_meanSSData[toBrainordinateIndex].get(); + + const float* toData = toGroup->m_data; + const int64_t toStride = toGroup->m_dataStride; + + int64_t toOffset(0); + double xySum(0.0); + for (int32_t i = 0; i < m_numberOfTimePoints; i++) { + xySum += (fromBrainordinateData[i] * toData[toOffset]); + toOffset += toStride; + } + + const double ssxy = xySum - (m_numberOfTimePoints * fromBrainordinateMean * toMeanSS->m_mean); + + float correlationCoefficient = 0.0; + if ((fromBrainordinateSSXX > 0.0) + && (toMeanSS->m_sqrt_ssxx > 0.0)) { + correlationCoefficient = (ssxy / (fromBrainordinateSSXX * toMeanSS->m_sqrt_ssxx)); + } + return correlationCoefficient; +} + +/** + * Get the correlation coefficient for the two given brainordinates + * that contain NON-CONTIGOUS data + * + * @param fromBrainordinateIndex + * Index of a brainordinate + * @param toBrainordinateIndex + * Index of a second brainordinate. + */ +float +ConnectivityCorrelation::correlationTimePointData(const int64_t fromBrainordinateIndex, + const int64_t toBrainordinateIndex) const +{ + CaretAssert(m_dataType == DataTypeEnum::TIMEPOINTS); + + CaretAssert((fromBrainordinateIndex >= 0) && (fromBrainordinateIndex < m_numberOfBrainordinates)); + CaretAssert((toBrainordinateIndex >= 0) && (toBrainordinateIndex < m_numberOfBrainordinates)); + + std::vector data(m_numberOfTimePoints); + for (int32_t iTime = 0; iTime < m_numberOfTimePoints; iTime++) { + data[iTime] = getDataValue(fromBrainordinateIndex, iTime); + } + + CaretAssertVectorIndex(m_meanSSData, fromBrainordinateIndex); + const BrainordinateMeanSS* fromMeanSS = m_meanSSData[fromBrainordinateIndex].get(); + + + return correlationTimePointDataAux(&data[0], + fromMeanSS->m_mean, + fromMeanSS->m_sqrt_ssxx, + toBrainordinateIndex); +} + +/** + * Get the correlation coefficient for the two given brainordinates + * that contain NON-CONTIGOUS data + * + * @param fromBrainordinateData + * Data for the 'from' brainordinate + * @param fromBrainordinateMean + * Mean of the data for the 'from' brainordinate. + * @param fromBrainordinateSSXX + * Sum-squared of the data for the 'from' brainordinate. + * @param toBrainordinateIndex + * Index of the 'to' brainordinate. + */ +float +ConnectivityCorrelation::correlationTimePointDataAux(const float* fromBrainordinateData, + const float fromBrainordinateMean, + const float fromBrainordinateSSXX, + const int64_t toBrainordinateIndex) const +{ + CaretAssert(m_dataType == DataTypeEnum::TIMEPOINTS); + + CaretAssert((toBrainordinateIndex >= 0) && (toBrainordinateIndex < m_numberOfBrainordinates)); + + CaretAssertVectorIndex(m_meanSSData, toBrainordinateIndex); + const BrainordinateMeanSS* toMeanSS = m_meanSSData[toBrainordinateIndex].get(); + + double xySum(0.0); + for (int32_t i = 0; i < m_numberOfTimePoints; i++) { + CaretAssertVectorIndex(m_timePointData, i); + const TimePointData* tpd = m_timePointData[i].get(); + const int64_t toOffset = (toBrainordinateIndex * tpd->m_dataStride); + + xySum += (fromBrainordinateData[i] * tpd->m_data[toOffset]); + } + + const double ssxy = xySum - (m_numberOfTimePoints * fromBrainordinateMean * toMeanSS->m_mean); + + float correlationCoefficient = 0.0; + if ((fromBrainordinateSSXX > 0.0) + && (toMeanSS->m_sqrt_ssxx > 0.0)) { + correlationCoefficient = (ssxy / (fromBrainordinateSSXX * toMeanSS->m_sqrt_ssxx)); + } + return correlationCoefficient; +} + +/** + * Compute the mean and sum-squared for all brainordinates + */ +void +ConnectivityCorrelation::computeBrainordinateMeanAndSumSquared() +{ + const float numTimePointsFloat(m_numberOfTimePoints); + + /* + * Set the size of the vector so that loop can run in parallel + */ + m_meanSSData.resize(m_numberOfBrainordinates); + +#pragma omp CARET_PARFOR schedule(dynamic) + for (int64_t i = 0; i < m_numberOfBrainordinates; i++) { + double sum(0.0); + double sumSquared(0.0); + + switch (m_dataType) { + case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: + case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: + { + CaretAssertVectorIndex(m_brainordinateData, i); + const float* data = m_brainordinateData[i]->m_data; + CaretAssert(data); + const int64_t stride = m_brainordinateData[i]->m_dataStride; + for (int64_t j = 0; j < m_numberOfTimePoints; j++) { + const int64_t offset = (j * stride); + const float d = data[offset]; + sum += d; + sumSquared += (d * d); + } + } + break; + case DataTypeEnum::INVALID: + CaretAssert(0); + break; + case DataTypeEnum::TIMEPOINTS: + { + for (int64_t j = 0; j < m_numberOfTimePoints; j++) { + CaretAssertVectorIndex(m_timePointData, j); + const int64_t offset = (i * m_timePointData[j]->m_dataStride); + const float d = m_timePointData[j]->m_data[offset]; + sum += d; + sumSquared += (d * d); + } + } + break; + } + + + const float mean = (sum / numTimePointsFloat); + const float ssxxSquared = (sumSquared - (numTimePointsFloat * mean * mean)); + const float ssxx = std::sqrt(ssxxSquared); + + BrainordinateMeanSS* bmss = new BrainordinateMeanSS(mean, + ssxx); + CaretAssertVectorIndex(m_meanSSData, i); + m_meanSSData[i].reset(bmss); + } + + CaretAssert(static_cast(m_meanSSData.size()) == m_numberOfBrainordinates); +} + diff --git a/src/Common/ConnectivityCorrelation.h b/src/Common/ConnectivityCorrelation.h new file mode 100644 index 0000000000000000000000000000000000000000..4f2254959a66392c04718cd1abef0b02476cd069 --- /dev/null +++ b/src/Common/ConnectivityCorrelation.h @@ -0,0 +1,257 @@ +#ifndef __CONNECTIVITY_CORRELATION_H__ +#define __CONNECTIVITY_CORRELATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretAssert.h" +#include "CaretObject.h" + + +namespace caret { + + class ConnectivityCorrelation : public CaretObject { + + public: + static ConnectivityCorrelation* newInstance(const float* data, + const int64_t numberOfBrainordinates, + const int64_t nextBrainordinateStride, + const int64_t numberOfTimePoints, + const int64_t nextTimePointStride, + AString& errorMessageOut); + + static ConnectivityCorrelation* newInstanceBrainordinates(const std::vector& brainordinateDataPointers, + const int64_t numberOfTimePoints, + const int64_t nextTimePointStride, + AString& errorMessageOut); + + static ConnectivityCorrelation* newInstanceTimePoints(const std::vector& timePointDataPointers, + const int64_t numberOfBrainordinates, + const int64_t nextBrainordinateStride, + AString& errorMessageOut); + + /** + * Destructor + */ + ~ConnectivityCorrelation(); + + ConnectivityCorrelation(const ConnectivityCorrelation&) = delete; + + ConnectivityCorrelation& operator=(const ConnectivityCorrelation&) = delete; + + void getCorrelationForBrainordinate(const int64_t brainordinateIndex, + std::vector& dataOut); + + void getCorrelationForBrainordinateROI(const std::vector& brainordinateIndices, + std::vector& dataOut); + + + + // ADD_NEW_METHODS_HERE + + private: + enum class DataTypeEnum { + INVALID, + BRAINORDINATES_NON_CONTIGUOUS_DATA, + BRAINORDINATES_CONTIGUOUS_DATA, + TIMEPOINTS + }; + + ConnectivityCorrelation(const DataTypeEnum dataType); + + /** + * Contains timepoints for one brainordinate + */ + class BrainordinateData { + public: + /** + * Constructor. + * + * @param data + * Pointer to data containing a brainordinate's timepoints + * @param dataStride + * Offset between consecutive elements (1 for contiguous data) + */ + BrainordinateData(const float* data, + const int64_t dataStride) + : m_data(data), + m_dataStride(dataStride) { } + + /* + * @return Data value for this brainordinate at the given time point index + * + * @param timePointIndex + * Index of the timepoint + */ + inline float getTimePointValue(const int64_t timePointIndex) const { + return m_data[timePointIndex * m_dataStride]; + } + const float* m_data; + + const int64_t m_dataStride; + }; + + class BrainordinateMeanSS { + public: + /* + * Constructor + * + * @param mean + * Mean value of 'data' + * @param sqrtSumSquared + * Square root of sum-squared of data + */ + BrainordinateMeanSS(const float mean, + const float sqrtSumSquared) + : m_mean(mean), + m_sqrt_ssxx(sqrtSumSquared) { } + + const float m_mean; + + const float m_sqrt_ssxx; + }; + + /** + * Contains all brainordinate values for one timepoint + */ + class TimePointData { + public: + /** + * Constructor. + * + * @param data + * Pointer to data + * @param dataStride + * Offset between consecutive elements (1 for contiguous data) + */ + TimePointData(const float* data, + const int64_t dataStride) + : m_data(data), + m_dataStride(dataStride) { } + + /* + * @return Data value for this brainordinate at the given time point index + * + * @param timePointIndex + * Index of the timepoint + */ + inline float getBrainordinateValue(const int64_t brainordinateIndex) const { + return m_data[brainordinateIndex * m_dataStride]; + } + + const float* m_data; + + const int64_t m_dataStride; + }; + + /** + * Get the data value for the given brainordinate and timepoint indices + * + * @param brainordinateIndex + * Index of the brainordinate + * @param timePointIndex + * Index of the time point + * @return + * The data value + */ + inline float getDataValue(const int64_t brainordinateIndex, + const int64_t timePointIndex) const { + float dataValue(0.0); + + switch (m_dataType) { + case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: + case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: + CaretAssertVectorIndex(m_brainordinateData, brainordinateIndex); + dataValue = m_brainordinateData[brainordinateIndex]->getTimePointValue(timePointIndex); + break; + case DataTypeEnum::INVALID: + CaretAssert(0); + break; + case DataTypeEnum::TIMEPOINTS: + CaretAssertVectorIndex(m_timePointData, timePointIndex); + dataValue = m_timePointData[timePointIndex]->getBrainordinateValue(brainordinateIndex); + break; + } + + return dataValue; + } + + bool initializeWithBrainordinates(const std::vector& brainordinateDataPointers, + const int64_t numberOfTimePoints, + const int64_t nextTimePointStride, + AString& errorMessageOut); + + bool initializeWithTimePoints(const std::vector& timePointDataPointers, + const int64_t numberOfBrainordinates, + const int64_t nextBrainordinateStride, + AString& errorMessageOut); + + void computeBrainordinateMeanAndSumSquared(); + + float correlationBrainordinateContiguousData(const int64_t fromBrainordinateIndex, + const int64_t toBrainordinateIndex) const; + + float correlationBrainordinateContiguousDataAux(const float* fromBrainordinateData, + const float fromBrainordinateMean, + const float fromBrainordinateSSXX, + const int64_t toBrainordinateIndex) const; + + float correlationBrainordinateNonContiguousData(const int64_t fromBrainordinateIndex, + const int64_t toBrainordinateIndex) const; + + float correlationBrainordinateNonContiguousDataAux(const float* fromBrainordinateData, + const float fromBrainordinateMean, + const float fromBrainordinateSSXX, + const int64_t toBrainordinateIndex) const; + + float correlationTimePointData(const int64_t fromBrainordinateIndex, + const int64_t toBrainordinateIndex) const; + + float correlationTimePointDataAux(const float* fromBrainordinateData, + const float fromBrainordinateMean, + const float fromBrainordinateSSXX, + const int64_t toBrainordinateIndex) const; + + DataTypeEnum m_dataType = DataTypeEnum::INVALID; + + int64_t m_numberOfBrainordinates = -1; + + int64_t m_numberOfTimePoints = -1; + + std::vector> m_brainordinateData; + + std::vector> m_timePointData; + + std::vector> m_meanSSData; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CONNECTIVITY_CORRELATION_DECLARE__ + // +#endif // __CONNECTIVITY_CORRELATION_DECLARE__ + +} // namespace +#endif //__CONNECTIVITY_CORRELATION_H__ diff --git a/src/Common/DataFileTypeEnum.cxx b/src/Common/DataFileTypeEnum.cxx index cc40d27b0764f181779002cd2eac846567f8de40..94d297af423b8d2e8e450a4c7f8391b726b386a3 100644 --- a/src/Common/DataFileTypeEnum.cxx +++ b/src/Common/DataFileTypeEnum.cxx @@ -123,7 +123,6 @@ DataFileTypeEnum::initialize() "Annotation", "ANNOTATION", false, - "annot", "wb_annot")); enumData.push_back(DataFileTypeEnum(ANNOTATION_TEXT_SUBSTITUTION, @@ -272,7 +271,14 @@ DataFileTypeEnum::initialize() "func.gii", "shape.gii")); - enumData.push_back(DataFileTypeEnum(PALETTE, + enumData.push_back(DataFileTypeEnum(METRIC_DYNAMIC, + "METRIC_DYNAMIC", + "Metric - Dynamic", + "METRIC_DYNAMIC", + true, + "func_dynconn")); // this file is never written + + enumData.push_back(DataFileTypeEnum(PALETTE, "PALETTE", "Palette", "PALETTE", @@ -324,6 +330,13 @@ DataFileTypeEnum::initialize() false, "nii", "nii.gz")); + + enumData.push_back(DataFileTypeEnum(VOLUME_DYNAMIC, + "VOLUME_DYNAMIC", + "Volume - Dynamic", + "VOLUME DYNAMIC", + false, + "vol_dynconn")); // this file is never written } /** @@ -612,23 +625,89 @@ DataFileTypeEnum::getAllFileExtensions(const Enum enumValue) /** * @return All valid file extensions for all file types except UNKNOWN - * and CONNECTIVITY_DENSE_DYNAMIC + * and dynanmic connectivity files + * + * @param includeNonWritableFileTypesFlag + * If true, include non-writable files such as dynamic connectvity files */ std::vector -DataFileTypeEnum::getFilesExtensionsForEveryFile() +DataFileTypeEnum::getFilesExtensionsForEveryFile(const bool includeNonWritableFileTypesFlag) { std::vector allExtensions; for (std::vector::iterator enumIter = enumData.begin(); enumIter != enumData.end(); enumIter++) { - if (enumIter->enumValue == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { - /* nothing */ - } - else if (enumIter->enumValue == DataFileTypeEnum::UNKNOWN) { - /* nothing */ + bool validFlag(true); + + switch (enumIter->enumValue) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + validFlag = includeNonWritableFileTypesFlag; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + validFlag = includeNonWritableFileTypesFlag; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + validFlag = false; + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + validFlag = includeNonWritableFileTypesFlag; + break; } - else { + + if (validFlag) { allExtensions.insert(allExtensions.end(), enumIter->fileExtensions.begin(), enumIter->fileExtensions.end()); @@ -841,24 +920,92 @@ DataFileTypeEnum::getAllEnums(std::vector& allEnums, allEnums.clear(); - const bool includeDenseDynamicFlag = (options & OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC); - const bool includeUnknownFlag = (options & OPTIONS_INCLUDE_UNKNOWN); + const bool includeDenseDynamicFlag = (options & OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC); + const bool includeMetricDynamicFlag = (options & OPTIONS_INCLUDE_METRIC_DENSE_DYNAMIC); + const bool includeVolumeDynamicFlag = (options & OPTIONS_INCLUDE_VOLUME_DENSE_DYNAMIC); + const bool includeUnknownFlag = (options & OPTIONS_INCLUDE_UNKNOWN); - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - if (iter->enumValue == CONNECTIVITY_DENSE_DYNAMIC) { - if ( ! includeDenseDynamicFlag) { - continue; - } - } - if (iter->enumValue == UNKNOWN) { - if ( ! includeUnknownFlag) { - continue; - } + for (const auto dataType : enumData) { + bool addEnumFlag(true); + + switch (dataType.enumValue) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + if ( ! includeDenseDynamicFlag) { + addEnumFlag = false; + } + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + if ( ! includeMetricDynamicFlag) { + addEnumFlag = false; + } + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + if ( ! includeUnknownFlag) { + addEnumFlag = false; + } + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + if ( ! includeVolumeDynamicFlag) { + addEnumFlag = false; + } + break; } - allEnums.push_back(iter->enumValue); + if (addEnumFlag) { + allEnums.push_back(dataType.enumValue); + } } } diff --git a/src/Common/DataFileTypeEnum.h b/src/Common/DataFileTypeEnum.h index a2a6a80169946569dc37656f9e8b342fc4285d99..0143dd8dbe75862135ac90f8023aaf7044a4116a 100644 --- a/src/Common/DataFileTypeEnum.h +++ b/src/Common/DataFileTypeEnum.h @@ -77,6 +77,8 @@ public: LABEL, /** Metric */ METRIC, + /** Metric Dynamic Connectivity */ + METRIC_DYNAMIC, /** Palette */ PALETTE, /** RGBA */ @@ -90,7 +92,9 @@ public: /** Unknown */ UNKNOWN, /** Volume */ - VOLUME + VOLUME, + /** Volume Dynamic Connectivity*/ + VOLUME_DYNAMIC }; /** @@ -102,8 +106,12 @@ public: OPTIONS_NONE = 0, /** Include the dense dynamic data file type */ OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC = 1, + /** Include the metric dynamic data file type */ + OPTIONS_INCLUDE_METRIC_DENSE_DYNAMIC = 2, + /** Include the volume dynamic data file type */ + OPTIONS_INCLUDE_VOLUME_DENSE_DYNAMIC = 4, /** Include the unknown data file type */ - OPTIONS_INCLUDE_UNKNOWN = 2 + OPTIONS_INCLUDE_UNKNOWN = 8 }; ~DataFileTypeEnum(); @@ -140,7 +148,7 @@ public: static std::vector getAllFileExtensions(const Enum enumValue); - static std::vector getFilesExtensionsForEveryFile(); + static std::vector getFilesExtensionsForEveryFile(const bool includeNonWritableFileTypesFlag = false); static bool isFileUsedWithOneStructure(const Enum enumValue); diff --git a/src/Common/DeveloperFlagsEnum.cxx b/src/Common/DeveloperFlagsEnum.cxx index 4cae6e410ad4a5ceaadb6f389960d8777c22ddd8..e884cbc09b0944f26414089d0f6ee71e9349e53c 100644 --- a/src/Common/DeveloperFlagsEnum.cxx +++ b/src/Common/DeveloperFlagsEnum.cxx @@ -76,18 +76,22 @@ using namespace caret; * Name of enumerated value. * @param guiName * User-friendly name for use in user-interface. + * @param checkable + * Checkable status (NO, YES) * @param defaultValue * Default value for flag */ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, const AString& name, const AString& guiName, + const CheckableEnum checkable, const bool defaultValue) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; + this->checkable = checkable; this->flagStatus = defaultValue; } @@ -109,14 +113,40 @@ DeveloperFlagsEnum::initialize() } initializedFlag = true; - enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_UNUSED, - "DEVELOPER_FLAG_UNUSED", - "Developer Flag Unused", - false)); - enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA, - "DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA", - "Flip Palette Not Data", - false)); + std::vector checkableItems; + checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_UNUSED, + "DEVELOPER_FLAG_UNUSED", + "Developer Flag Unused", + CheckableEnum::YES, + false)); + checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA, + "DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA", + "Flip Palette Not Data", + CheckableEnum::YES, + false)); + checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_TEXTURE_VOLUME, + "DEVELOPER_FLAG_TEXTURE_VOLUME", + "Texture Volume Drawing", + CheckableEnum::YES, + false)); + checkableItems.push_back(DeveloperFlagsEnum(DELELOPER_FLAG_VOXEL_SMOOTH, + "DELELOPER_FLAG_VOXEL_SMOOTH", + "Smooth Texture Volume Voxels", + CheckableEnum::YES, + false)); + + checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_BALSA, + "DEVELOPER_FLAG_BALSA", + "Visit BALSA...", + CheckableEnum::NO, + false)); + + std::vector notCheckableItems; + + enumData.insert(enumData.end(), + checkableItems.begin(), checkableItems.end()); + enumData.insert(enumData.end(), + notCheckableItems.begin(), notCheckableItems.end()); } /** @@ -407,4 +437,26 @@ DeveloperFlagsEnum::setFlag(const Enum enumValue, enumInstance->flagStatus = flagStatus; } +/** + * @return True if the developer flag is checkable + */ +bool +DeveloperFlagsEnum::isCheckable(const Enum enumValue) +{ + bool checkableStatus(false); + + if (initializedFlag == false) initialize(); + DeveloperFlagsEnum* enumInstance = findData(enumValue); + switch (enumInstance->checkable) { + case CheckableEnum::NO: + checkableStatus = false; + break; + case CheckableEnum::YES: + checkableStatus = true; + break; + } + + return checkableStatus; +} + diff --git a/src/Common/DeveloperFlagsEnum.h b/src/Common/DeveloperFlagsEnum.h index 2a352066ecd1ab6267a72318c8d97fe500b738b5..b8ac7412bdcafa8ec40c2663ec4c81346c5a6f4e 100644 --- a/src/Common/DeveloperFlagsEnum.h +++ b/src/Common/DeveloperFlagsEnum.h @@ -36,7 +36,10 @@ public: */ enum Enum { DEVELOPER_FLAG_UNUSED, - DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA + DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA, + DEVELOPER_FLAG_TEXTURE_VOLUME, + DELELOPER_FLAG_VOXEL_SMOOTH, + DEVELOPER_FLAG_BALSA }; ~DeveloperFlagsEnum(); @@ -64,10 +67,18 @@ public: static void setFlag(const Enum enumValue, const bool flagStatus); + static bool isCheckable(const Enum enumValue); + private: + enum class CheckableEnum { + NO, + YES + }; + DeveloperFlagsEnum(const Enum enumValue, const AString& name, const AString& guiName, + const CheckableEnum checkable, const bool defaultValue); static DeveloperFlagsEnum* findData(const Enum enumValue); @@ -98,6 +109,9 @@ private: /** Flag status */ bool flagStatus; + + /** Checkable status */ + CheckableEnum checkable; }; #ifdef __DEVELOPER_FLAGS_ENUM_DECLARE__ diff --git a/src/Brain/EventBrowserTabNew.cxx b/src/Common/EventBrowserTabNew.cxx similarity index 100% rename from src/Brain/EventBrowserTabNew.cxx rename to src/Common/EventBrowserTabNew.cxx diff --git a/src/Brain/EventBrowserTabNew.h b/src/Common/EventBrowserTabNew.h similarity index 100% rename from src/Brain/EventBrowserTabNew.h rename to src/Common/EventBrowserTabNew.h diff --git a/src/Common/EventBrowserTabNewClone.cxx b/src/Common/EventBrowserTabNewClone.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1456c02641d00699377aaf67accffc7550298ff4 --- /dev/null +++ b/src/Common/EventBrowserTabNewClone.cxx @@ -0,0 +1,102 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ +#include "EventBrowserTabNewClone.h" +#undef __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventBrowserTabNewClone + * \brief Get a browser tab that is cloned from another browser tab + * \ingroup Common + * + * Get a browser tab that is cloned from another browser tab + */ + +/** + * Constructor. + * + * @param indexOfBrowserTabThatWillBeCloned + * Index of browser tab that is cloned. + */ +EventBrowserTabNewClone::EventBrowserTabNewClone(const int32_t indexOfBrowserTabThatWillBeCloned) +: Event(EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE), +m_indexOfBrowserTabThatWasClonded(indexOfBrowserTabThatWillBeCloned) +{ + +} + +/** + * Destructor. + */ +EventBrowserTabNewClone::~EventBrowserTabNewClone() +{ +} + +/** + * @return The new browser tab. + */ +BrowserTabContent* +EventBrowserTabNewClone::getNewBrowserTab() const +{ + return m_newBrowserTabContent; +} + +/** + * Set the new browser tab and its index. + * + * @param newBrowserTab + * The new browser tab. + * @param newBrowserTabIndex + * Index of the new browser tab. + */ +void +EventBrowserTabNewClone::setNewBrowserTab(BrowserTabContent* newBrowserTab, + const int32_t newBrowserTabIndex) +{ + m_newBrowserTabContent = newBrowserTab; + m_newBrowserTabIndex = newBrowserTabIndex; +} + +/** + * @return Index of the new browser index. + */ +int32_t +EventBrowserTabNewClone::getNewBrowserTabIndex() const +{ + return m_newBrowserTabIndex; +} + +/** + * @return Index of the browser tab that was cloned + */ +int32_t +EventBrowserTabNewClone::getIndexOfBrowserTabThatWasCloned() const +{ + return m_indexOfBrowserTabThatWasClonded; +} diff --git a/src/Common/EventBrowserTabNewClone.h b/src/Common/EventBrowserTabNewClone.h new file mode 100644 index 0000000000000000000000000000000000000000..e04dcb228e5b40861662b9f4d7b50e316a2450ca --- /dev/null +++ b/src/Common/EventBrowserTabNewClone.h @@ -0,0 +1,74 @@ +#ifndef __EVENT_BROWSER_TAB_NEW_CLONE_H__ +#define __EVENT_BROWSER_TAB_NEW_CLONE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class BrowserTabContent; + + class EventBrowserTabNewClone : public Event { + + public: + EventBrowserTabNewClone(const int32_t indexOfBrowserTabThatWillBeCloned); + + virtual ~EventBrowserTabNewClone(); + + EventBrowserTabNewClone(const EventBrowserTabNewClone&) = delete; + + EventBrowserTabNewClone& operator=(const EventBrowserTabNewClone&) = delete; + + BrowserTabContent* getNewBrowserTab() const; + + void setNewBrowserTab(BrowserTabContent* newBrowserTab, + const int32_t newBrowserTabIndex); + + int32_t getNewBrowserTabIndex() const; + + int32_t getIndexOfBrowserTabThatWasCloned() const; + + // ADD_NEW_METHODS_HERE + + private: + // ADD_NEW_MEMBERS_HERE + + const int32_t m_indexOfBrowserTabThatWasClonded = -1; + + BrowserTabContent* m_newBrowserTabContent = NULL; + + int32_t m_newBrowserTabIndex = -1; + + }; + +#ifdef __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ + // +#endif // __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ + +} // namespace +#endif //__EVENT_BROWSER_TAB_NEW_CLONE_H__ diff --git a/src/Common/EventGetViewportSize.cxx b/src/Common/EventGetViewportSize.cxx index 41908bfd4dc5a41502a6d7f49d464d7c979f38e9..b2df0fee8c19da444f967b2462347937f0c26b37 100644 --- a/src/Common/EventGetViewportSize.cxx +++ b/src/Common/EventGetViewportSize.cxx @@ -37,31 +37,15 @@ using namespace caret; */ /** - * Constructor for finding a specific tab index. - * - * @param tabIndex - * Index of tab for which viewport size is requested. - */ -//EventGetViewportSize::EventGetViewportSize(const int32_t tabIndex) -//: Event(EventTypeEnum::EVENT_BROWSER_TAB_GET_VIEWPORT_SIZE), -//m_mode(MODE_TAB_INDEX), -//m_tabIndex(tabIndex), -//m_viewportValid(false) -//{ -// m_viewport[0] = 0; -// m_viewport[1] = 0; -// m_viewport[2] = 0; -// m_viewport[3] = 0; -//} - -/** - * Constructor for finding a surface or volume montage. + * Constructor for finding size of a viewport * * @param mode * The mode. + * @param index + * Index of a tab or window. */ EventGetViewportSize::EventGetViewportSize(const Mode mode, - const int32_t index) + const int32_t index) : Event(EventTypeEnum::EVENT_GET_VIEWPORT_SIZE), m_mode(mode), m_index(index), @@ -73,6 +57,22 @@ m_viewportValid(false) m_viewport[3] = 0; } +/** + * Constructor for finding size of a viewport + * + * @param spacerTabIndex + * Index of the spacer tab + */ +EventGetViewportSize::EventGetViewportSize(const SpacerTabIndex& spacerTabIndex) +: Event(EventTypeEnum::EVENT_GET_VIEWPORT_SIZE), +m_mode(MODE_SPACER_TAB_INDEX), +m_index(-1), +m_spacerTabIndex(spacerTabIndex), +m_viewportValid(false) +{ + +} + /** * Destructor. */ @@ -107,6 +107,15 @@ EventGetViewportSize::getIndex() const return m_index; } +/** + * @return The spacer tab index. + */ +SpacerTabIndex +EventGetViewportSize::getSpacerTabIndex() const +{ + return m_spacerTabIndex; +} + /** * Get the viewport size. * diff --git a/src/Common/EventGetViewportSize.h b/src/Common/EventGetViewportSize.h index 5587a2b8cb67b4a7405c6c77133c999eef6c8fa5..de6b19f5125f32839f56b6c1fcfce038cf0e8d56 100644 --- a/src/Common/EventGetViewportSize.h +++ b/src/Common/EventGetViewportSize.h @@ -23,8 +23,7 @@ #include "Event.h" - - +#include "SpacerTabIndex.h" namespace caret { @@ -32,16 +31,18 @@ namespace caret { public: enum Mode { + MODE_SPACER_TAB_INDEX, MODE_SURFACE_MONTAGE, MODE_TAB_BEFORE_MARGINS_INDEX, MODE_TAB_AFTER_MARGINS_INDEX, MODE_VOLUME_MONTAGE, MODE_WINDOW_INDEX, }; -// EventGetViewportSize(const int32_t tabIndex); EventGetViewportSize(const Mode mode, - const int32_t index); + const int32_t index); + + EventGetViewportSize(const SpacerTabIndex& spacerTabIndex); virtual ~EventGetViewportSize(); @@ -49,6 +50,8 @@ namespace caret { int32_t getIndex() const; + SpacerTabIndex getSpacerTabIndex() const; + bool isViewportSizeValid() const; void getViewportSize(int32_t viewportOut[4]) const; @@ -64,11 +67,13 @@ namespace caret { const Mode m_mode; - const int32_t m_index; + const int32_t m_index = -1; - int32_t m_viewport[4]; + SpacerTabIndex m_spacerTabIndex; + + bool m_viewportValid = false; - bool m_viewportValid; + int32_t m_viewport[4]; // ADD_NEW_MEMBERS_HERE diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 0ea65a89f95e32b9eaa4f065bca492fa22b80065..17ce49d8c5340884af380b0e3ded43ddc2f538d6 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -369,6 +369,8 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) switch (eventType) { case EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE: case EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE: + case EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE: + case EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR: { sendEvent(Event(eventType).getPointer()); } @@ -400,6 +402,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED: case EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_NEW: + case EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE: case EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT: case EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS: case EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET: @@ -410,6 +413,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS: case EventTypeEnum::EVENT_CARET_PREFERENCES_GET: + case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS: case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED: @@ -428,6 +432,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME: + case EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW: case EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY: @@ -443,6 +448,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_MODEL_GET_ALL: case EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED: case EventTypeEnum::EVENT_MODEL_SURFACE_GET: + case EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE: case EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS: case EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM: case EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE: @@ -450,11 +456,14 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW: case EventTypeEnum::EVENT_PALETTE_GET_BY_NAME: + case EventTypeEnum::EVENT_SCENE_ACTIVE: case EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG: + case EventTypeEnum::EVENT_SPACER_TAB_GET: case EventTypeEnum::EVENT_SPEC_FILE_READ_DATA_FILES: case EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE: case EventTypeEnum::EVENT_SURFACES_GET: case EventTypeEnum::EVENT_SURFACE_STRUCTURES_VALID_GET: + case EventTypeEnum::EVENT_TILE_TABS_MODIFICATION: case EventTypeEnum::EVENT_TOOLBOX_SELECTION_DISPLAY: case EventTypeEnum::EVENT_USER_INTERFACE_UPDATE: case EventTypeEnum::EVENT_PROGRESS_UPDATE: diff --git a/src/Common/EventTileTabsConfigurationModification.cxx b/src/Common/EventTileTabsConfigurationModification.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4f4a12d682c0d7573a834b572f1802a689b30c38 --- /dev/null +++ b/src/Common/EventTileTabsConfigurationModification.cxx @@ -0,0 +1,129 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ +#include "EventTileTabsConfigurationModification.h" +#undef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventTileTabsConfigurationModification + * \brief Event for modifying a tile tabs configuration. + * \ingroup Common + */ + +/** + * Constructor. + * + * @param tileTabsConfiguration + * Tile tabs configuration that will be modified + * @param rowColumnIndex + * Index of the row or column used for modification + * @param rowColumnType + * 'Row' or "Column' type + * @param operation + * Enumerated type with type of modification. + */ +EventTileTabsConfigurationModification::EventTileTabsConfigurationModification(TileTabsConfiguration* tileTabsConfiguration, + const int32_t rowColumnIndex, + const RowColumnType rowColumnType, + const Operation operation) +: Event(EventTypeEnum::EVENT_TILE_TABS_MODIFICATION), +m_tileTabsConfiguration(tileTabsConfiguration), +m_rowColumnIndex(rowColumnIndex), +m_rowColumnType(rowColumnType), +m_operation(operation), +m_windowIndex(-1) +{ + +} + +/** + * Destructor. + */ +EventTileTabsConfigurationModification::~EventTileTabsConfigurationModification() +{ +} + +/** + * @return Tile tabs configuration that is modified. + */ +TileTabsConfiguration* +EventTileTabsConfigurationModification::getTileTabsConfiguration() +{ + return m_tileTabsConfiguration; +} + + +/** + * @return Index of the window. + */ +int32_t +EventTileTabsConfigurationModification::getWindowIndex() const +{ + return m_windowIndex; +} + +/** + * Set the window index. + * + * @param windowIndex + * Index of the window. + */ +void +EventTileTabsConfigurationModification::setWindowIndex(const int32_t windowIndex) +{ + m_windowIndex = windowIndex; +} + +/** + * @return The index of the row or column. + */ +int32_t +EventTileTabsConfigurationModification::getRowColumnIndex() const +{ + return m_rowColumnIndex; +} + +/** + * @return The type ROW or COLUMN + */ +EventTileTabsConfigurationModification::RowColumnType +EventTileTabsConfigurationModification::getRowColumnType() const +{ + return m_rowColumnType; +} + +/** + * @return The operation. + */ +EventTileTabsConfigurationModification::Operation +EventTileTabsConfigurationModification::getOperation() const +{ + return m_operation; +} + diff --git a/src/Common/EventTileTabsConfigurationModification.h b/src/Common/EventTileTabsConfigurationModification.h new file mode 100644 index 0000000000000000000000000000000000000000..202fa67c998e3d954b36136e084450eab35146b6 --- /dev/null +++ b/src/Common/EventTileTabsConfigurationModification.h @@ -0,0 +1,105 @@ +#ifndef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ +#define __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class TileTabsConfiguration; + + class EventTileTabsConfigurationModification : public Event { + + public: + /** + * Row or Column + */ + enum class RowColumnType { + COLUMN, + ROW + }; + + /** + * Operation + */ + enum class Operation { + DELETE_IT, /* DELETE is reserved word on Windows */ + DUPLICATE_AFTER, + DUPLICATE_BEFORE, + INSERT_SPACER_BEFORE, + INSERT_SPACER_AFTER, + MOVE_AFTER, + MOVE_BEFORE + }; + + EventTileTabsConfigurationModification(TileTabsConfiguration* tileTabsConfiguration, + const int32_t rowColumnIndex, + const RowColumnType rowColumnType, + const Operation operation); + + virtual ~EventTileTabsConfigurationModification(); + + EventTileTabsConfigurationModification(const EventTileTabsConfigurationModification&) = delete; + + EventTileTabsConfigurationModification& operator=(const EventTileTabsConfigurationModification&) = delete; + + TileTabsConfiguration* getTileTabsConfiguration(); + + int32_t getRowColumnIndex() const; + + RowColumnType getRowColumnType() const; + + Operation getOperation() const; + + int32_t getWindowIndex() const; + + void setWindowIndex(const int32_t windowIndex); + + // ADD_NEW_METHODS_HERE + + private: + TileTabsConfiguration* m_tileTabsConfiguration; + + const int32_t m_rowColumnIndex; + + const RowColumnType m_rowColumnType; + + const Operation m_operation; + + int32_t m_windowIndex = -1; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ + // +#endif // __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ + +} // namespace +#endif //__EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index cc4ff6720de07a7cf19106ff753233e74c51a465..8e3619a83fca36b59cd0258a418dbf8c079979e7 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -142,6 +142,10 @@ EventTypeEnum::initialize() "EVENT_BROWSER_TAB_NEW", "Create a browser tab")); + enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_NEW_CLONE, + "EVENT_BROWSER_TAB_NEW_CLONE", + "Create a browser tab by cloning an existing browser tab")); + enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_CONTENT, "EVENT_BROWSER_WINDOW_CONTENT", "Event for browser window content")); @@ -182,6 +186,10 @@ EventTypeEnum::initialize() "EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS", "Get Caret Mappable data file maps viewed in overlays")); + enumData.push_back(EventTypeEnum(EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS, + "EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS", + "Get all selected mappable data and map indices in displayed overlays")); + enumData.push_back(EventTypeEnum(EVENT_CARET_PREFERENCES_GET, "EVENT_CARET_PREFERENCES_GET", "Get the Caret Preferences")); @@ -254,6 +262,10 @@ EventTypeEnum::initialize() "EVENT_GET_VIEWPORT_SIZE", "Get the viewport size")); + enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_TIMING_ONE_WINDOW, + "EVENT_GRAPHICS_TIMING_ONE_WINDOW", + "Graphics timing in one window")); + enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, "EVENT_GRAPHICS_UPDATE_ALL_WINDOWS", "Update all graphics windows")); @@ -314,6 +326,14 @@ EventTypeEnum::initialize() "EVENT_MODEL_SURFACE_GET", "Get a specific model surface")); + enumData.push_back(EventTypeEnum(EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE, + "EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE", + "Movie recording manual mode capture")); + + enumData.push_back(EventTypeEnum(EVENT_MOVIE_RECORDING_DIALOG_UPDATE, + "EVENT_MOVIE_RECORDING_DIALOG_UPDATE", + "Update the movie recording dialog")); + enumData.push_back(EventTypeEnum(EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS, "EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS", "Get the color for node identification symbols from all charts that contain nodes")); @@ -342,10 +362,18 @@ EventTypeEnum::initialize() "EVENT_PALETTE_GET_BY_NAME", "Read the selected files in a spec file")); + enumData.push_back(EventTypeEnum(EVENT_SCENE_ACTIVE, + "EVENT_SCENE_ACTIVE", + "Get/Set the active scene")); + enumData.push_back(EventTypeEnum(EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG, "EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG", "Show a dialog with warnings encountered reading data files")); + enumData.push_back(EventTypeEnum(EVENT_SPACER_TAB_GET, + "EVENT_SPACER_TAB_GET", + "Get a spacer tagb")); + enumData.push_back(EventTypeEnum(EVENT_SPEC_FILE_READ_DATA_FILES, "EVENT_SPEC_FILE_READ_DATA_FILES", "Read the selected data files in a spec file")); @@ -362,6 +390,10 @@ EventTypeEnum::initialize() "EVENT_SURFACE_STRUCTURES_VALID_GET", "GGet valid surface strucutures and their number of node")); + enumData.push_back(EventTypeEnum(EVENT_TILE_TABS_MODIFICATION, + "EVENT_TILE_TABS_MODIFICATION", + "Tile tabs modification")); + enumData.push_back(EventTypeEnum(EVENT_TOOLBOX_SELECTION_DISPLAY, "EVENT_TOOLBOX_SELECTION_DISPLAY", "Display or hide the selection toolbox")); @@ -386,6 +418,10 @@ EventTypeEnum::initialize() "EVENT_UPDATE_VOLUME_EDITING_TOOLBAR", "Update the volume editing toolbar")); + enumData.push_back(EventTypeEnum(EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR, + "EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR", + "Update the volume slices indices and coords in the toolbar")); + enumData.push_back(EventTypeEnum(EVENT_COUNT, "EVENT_COUNT", "Count of events")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 702fd796d6f6e89900c303d8178594d3f6657fb9..ade6bdd81f7dbcb237595dd7a7da236e2147a9be 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -76,6 +76,8 @@ public: EVENT_BROWSER_TAB_GET_ALL_VIEWED, /** Create a new browser tab */ EVENT_BROWSER_TAB_NEW, + /** Create a new browser tab by cloning an existing browser tab */ + EVENT_BROWSER_TAB_NEW_CLONE, /** Event for browser window content */ EVENT_BROWSER_WINDOW_CONTENT, /** Get the content of a browser window */ @@ -96,6 +98,8 @@ public: EVENT_CARET_MAPPABLE_DATA_FILES_GET, /** Get CaretMappableDataFiles and their maps viewed as overlays */ EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS, + /** Get all mappable files and selected maps in all displayed overlays */ + EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS, /** Event to get the Caret Preferences */ EVENT_CARET_PREFERENCES_GET, /** Event for yoking the loading of matrix chart rows/columns */ @@ -134,6 +138,8 @@ public: EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT, /** Delete a texture name for an OpenGL context */ EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME, + /** Time the OpenGL graphics in a window */ + EVENT_GRAPHICS_TIMING_ONE_WINDOW, /** Update all graphics windows */ EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, /** Update graphics in a window */ @@ -164,6 +170,10 @@ public: EVENT_MODEL_GET_ALL_DISPLAYED, /** model surface - get */ EVENT_MODEL_SURFACE_GET, + /** Update the movie dialog */ + EVENT_MOVIE_RECORDING_DIALOG_UPDATE, + /** Movie manual mode image recording */ + EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE, /** Get the color for a node's identification symbol from a chart that contains the node */ EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS, /** Get the transformation for converting object coordinates to window coordinates */ @@ -178,8 +188,12 @@ public: EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW, /** Get a palette by name from a palette file */ EVENT_PALETTE_GET_BY_NAME, + /** Get the active scene */ + EVENT_SCENE_ACTIVE, /** Show a dialog containing warnings encountered when reading data files */ EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG, + /** Get a spacer tab by tab number */ + EVENT_SPACER_TAB_GET, /** Read the selected files in a spec file */ EVENT_SPEC_FILE_READ_DATA_FILES, /** Invalidate surface coloring */ @@ -188,6 +202,8 @@ public: EVENT_SURFACES_GET, /** Get valid surface strucutures and their number of nodes */ EVENT_SURFACE_STRUCTURES_VALID_GET, + /** Tile tabs modification */ + EVENT_TILE_TABS_MODIFICATION, /** Display/Hide the selection toolbox */ EVENT_TOOLBOX_SELECTION_DISPLAY, /** Update the User-Interface */ @@ -198,6 +214,8 @@ public: EVENT_UPDATE_INFORMATION_WINDOWS, /** Update the volume editing toolbar */ EVENT_UPDATE_VOLUME_EDITING_TOOLBAR, + /** Update the slice indices and coordinates in the toolbar */ + EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR, /** Update yoked windows */ EVENT_UPDATE_YOKED_WINDOWS, /* THIS MUST ALWAYS BE LAST - NOT an event type but is number of event types */ diff --git a/src/Common/FileInformation.cxx b/src/Common/FileInformation.cxx index fdfd25c5a2d45cff3a503009cb1e183d0d2d2c27..b67393f2299d15074c14e283a1c405aa07386f8d 100644 --- a/src/Common/FileInformation.cxx +++ b/src/Common/FileInformation.cxx @@ -488,7 +488,8 @@ FileInformation::getCanonicalPath() const AString FileInformation::getFileExtension() const { - const std::vector workbenchExtensions = DataFileTypeEnum::getFilesExtensionsForEveryFile(); + const bool includeNonWritableFileTypesFlag(true); + const std::vector workbenchExtensions = DataFileTypeEnum::getFilesExtensionsForEveryFile(includeNonWritableFileTypesFlag); for (std::vector::const_iterator extIter = workbenchExtensions.begin(); extIter != workbenchExtensions.end(); diff --git a/src/Common/HtmlStringBuilder.cxx b/src/Common/HtmlStringBuilder.cxx index 78be7e4936fe3ce95db010ee6fb12385801076e1..ab14f8f908977cd6896450355c4f2c864f893f7e 100644 --- a/src/Common/HtmlStringBuilder.cxx +++ b/src/Common/HtmlStringBuilder.cxx @@ -259,6 +259,19 @@ HtmlStringBuilder::toString() const return this->stringBuilder; } +/** + * Convert to a string in HTML format WITH leading and trailing + * HTML and BODY tags. + * + * @return String containing text. + * + */ +AString +HtmlStringBuilder::toStringWithHtmlBodyForToolTip() +{ + return toStringWithHtmlBodyPrivate(true); +} + /** * Convert to a string in HTML format WITH leading and trailing * HTML and BODY tags. @@ -268,14 +281,46 @@ HtmlStringBuilder::toString() const */ AString HtmlStringBuilder::toStringWithHtmlBody() +{ + return toStringWithHtmlBodyPrivate(false); +} + +/** + * Convert to a string in HTML format WITH leading and trailing + * HTML and BODY tags. + * + * @param toolTipFlag + * If true, set the style so text does not wrap when + * placed into a QToolTip (see QToolTip documentation). + * @return String containing text. + * + */ +AString +HtmlStringBuilder::toStringWithHtmlBodyPrivate(const bool toolTipFlag) { AString sb; sb.reserve(this->stringBuilder.length() + 100); sb.append(""); + if (toolTipFlag) { + sb.append("

"); + } + + /* + * If the string ends with a line break, remove the line break + */ + const AString lastBreak("

"); + if (this->stringBuilder.endsWith(lastBreak)) { + this->stringBuilder.resize(this->stringBuilder.length() - lastBreak.length()); + } sb.append(this->stringBuilder); + + if (toolTipFlag) { + sb.append("

"); + } sb.append(""); return sb; } + diff --git a/src/Common/HtmlStringBuilder.h b/src/Common/HtmlStringBuilder.h index 9c4b9800ebdceb66c827a3341344d1f0b8567d7f..c3026c30d94ad2cb82cb9e0d6b43f4d187c24ccd 100644 --- a/src/Common/HtmlStringBuilder.h +++ b/src/Common/HtmlStringBuilder.h @@ -83,7 +83,11 @@ namespace caret { AString toStringWithHtmlBody(); + AString toStringWithHtmlBodyForToolTip(); + private: + AString toStringWithHtmlBodyPrivate(const bool toolTipFlag); + AString stringBuilder; }; diff --git a/src/Common/MathFunctionEnum.cxx b/src/Common/MathFunctionEnum.cxx index ca02a1bf180d719f20f34ee7e79b5442d30b3963..5bd8d899b6da932cac2125265efaefd3747c518f 100644 --- a/src/Common/MathFunctionEnum.cxx +++ b/src/Common/MathFunctionEnum.cxx @@ -67,7 +67,6 @@ MathFunctionEnum::initialize() } initializedFlag = true; - //enumData.push_back(MathFunctionEnum(INVALID, "INVALID"));//should this be in the data? I don't think it should, it is a placeholder for "no matching enum value" enumData.push_back(MathFunctionEnum(SIN, "sin", "1 argument, the sine of the argument (units are radians)")); enumData.push_back(MathFunctionEnum(COS, "cos", "1 argument, the cosine of the argument (units are radians)")); enumData.push_back(MathFunctionEnum(TAN, "tan", "1 argument, the tangent of the argument (units are radians)")); @@ -84,6 +83,7 @@ MathFunctionEnum::initialize() enumData.push_back(MathFunctionEnum(LN, "ln", "1 argument, the natural logarithm of the argument")); enumData.push_back(MathFunctionEnum(EXP, "exp", "1 argument, the constant e raised to the power of the argument")); enumData.push_back(MathFunctionEnum(LOG, "log", "1 argument, the base 10 logarithm of the argument")); + enumData.push_back(MathFunctionEnum(LOG2, "log2", "1 argument, the base 2 logarithm of the argument")); enumData.push_back(MathFunctionEnum(SQRT, "sqrt", "1 argument, the square root of the argument")); enumData.push_back(MathFunctionEnum(ABS, "abs", "1 argument, the absolute value of the argument")); enumData.push_back(MathFunctionEnum(FLOOR, "floor", "1 argument, the largest integer not greater than the argument")); diff --git a/src/Common/MathFunctionEnum.h b/src/Common/MathFunctionEnum.h index f2070aa4accaa61b793e08b69384c160f61cfad3..fe744fd8597c337617bf13f42faf2d2812d996cb 100644 --- a/src/Common/MathFunctionEnum.h +++ b/src/Common/MathFunctionEnum.h @@ -57,6 +57,7 @@ public: LN, EXP, LOG, + LOG2, SQRT, ABS, FLOOR, diff --git a/src/Common/MathFunctions.cxx b/src/Common/MathFunctions.cxx index f741aebcd7a04919d2fc9bec32fda3c11885c9b6..a2bdc652ad4dd2185632a1524784eb71d96b5711 100644 --- a/src/Common/MathFunctions.cxx +++ b/src/Common/MathFunctions.cxx @@ -672,6 +672,40 @@ MathFunctions::dotProduct( return p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2]; } +/** + * Add an offset to a vector + * + * @param v + * The vector + * @param offset + * Offset added to the vector. + */ +void +MathFunctions::addOffsetToVector(double v[3], + const double offset[3]) +{ + v[0] += offset[0]; + v[1] += offset[1]; + v[2] += offset[2]; +} + +/** + * Subtract an offset from a vector + * + * @param v + * The vector + * @param offset + * Offset subtracted from the vector. + */ +void +MathFunctions::subtractOffsetFromVector(double v[3], + const double offset[3]) +{ + v[0] -= offset[0]; + v[1] -= offset[1]; + v[2] -= offset[2]; +} + /** * Calculate the area for a triangle. * @param v1 - XYZ coordinates for vertex 1 @@ -1939,6 +1973,38 @@ MathFunctions::signedAngle( return phi; } +/** + * @return The angle formed by two vectors. + * cos = (u . v) / (||u|| * ||v||) + * + * @param u + * First vector. + * @param v + * Second vector. + */ +float +MathFunctions::angleInDegreesBetweenVectors(const float u[3], const float v[3]) +{ + float angle = 0.0; + + const float numerator = MathFunctions::dotProduct(u, v); + const float uLength = MathFunctions::vectorLength(u); + const float vLength = MathFunctions::vectorLength(v); + const float denominator = uLength * vLength; + if (denominator > 0.0) { + float a = numerator / denominator; + if (a > 1.0) { + a = 1.0; + } + else if (a < -1.0) { + a = -1.0; + } + const float angleRadians = std::acos(a); + angle = MathFunctions::toDegrees(angleRadians); + } + return angle; +} + /** * Determine if an integer is an odd number. * @param number Integer to test. @@ -2471,3 +2537,171 @@ float MathFunctions::q_func(const float& x) } return ret; } + +/** + * Expand a box by given amounts in X and Y. + * + * @param bottomLeft + * Bottom left corner of annotation. + * @param bottomRight + * Bottom right corner of annotation. + * @param topRight + * Top right corner of annotation. + * @param topLeft + * Top left corner of annotation. + * @param extraSpaceX + * Extra space to add in X. + * @param extraSpaceY + * Extra space to add in Y. + */ +void +MathFunctions::expandBox(float bottomLeft[3], + float bottomRight[3], + float topRight[3], + float topLeft[3], + const float extraSpaceX, + const float extraSpaceY) +{ + float widthVector[3]; + MathFunctions::subtractVectors(topRight, topLeft, widthVector); + MathFunctions::normalizeVector(widthVector); + + float heightVector[3]; + MathFunctions::subtractVectors(topLeft, bottomLeft, heightVector); + MathFunctions::normalizeVector(heightVector); + + const float widthSpacingX = extraSpaceX * widthVector[0]; + const float widthSpacingY = extraSpaceY * widthVector[1]; + + const float heightSpacingX = extraSpaceX * heightVector[0]; + const float heightSpacingY = extraSpaceY * heightVector[1]; + + + topLeft[0] += (-widthSpacingX + heightSpacingX); + topLeft[1] += (-widthSpacingY + heightSpacingY); + + topRight[0] += (widthSpacingX + heightSpacingX); + topRight[1] += (widthSpacingY + heightSpacingY); + + bottomLeft[0] += (-widthSpacingX - heightSpacingX); + bottomLeft[1] += (-widthSpacingY - heightSpacingY); + + bottomRight[0] += (widthSpacingX - heightSpacingX); + bottomRight[1] += (widthSpacingY - heightSpacingY); +} + +/** + * Expand the end points of a line. + * + * @param u + * First point in line. + * @param v + * Second point in line. + * #param extraSpacePercent + * Percentage amount to expand the points. + */ +void +MathFunctions::expandLinePercentage3D(float u[3], + float v[3], + const float extraSpacePercent) +{ + float vector[3]; + MathFunctions::subtractVectors(v, u, vector); + const float length = MathFunctions::normalizeVector(vector) / 2.0; + const float extraVector[3] { + vector[0] * (length * extraSpacePercent), + vector[1] * (length * extraSpacePercent), + vector[2] * (length * extraSpacePercent) + }; + + for (int32_t i = 0; i < 3; i++) { + u[i] -= extraVector[i]; + v[i] += extraVector[i]; + } +} + +/** + * Expand the end points of a line. + * + * @param u + * First point in line. + * @param v + * Second point in line. + * #param extraSpacePixels + * Pixels amount to expand the points. + */ +void +MathFunctions::expandLinePixels3D(double u[3], + double v[3], + const double extraSpacePixels) +{ + double vector[3]; + MathFunctions::subtractVectors(v, u, vector); + MathFunctions::normalizeVector(vector); + const double halfExtra = extraSpacePixels / 2.0; + const double extraVector[3] { + vector[0] * halfExtra, + vector[1] * halfExtra, + vector[2] * halfExtra + }; + + for (int32_t i = 0; i < 3; i++) { + u[i] -= extraVector[i]; + v[i] += extraVector[i]; + } +} + +/** + * Expand a box by given amounts in X and Y. + * + * @param bottomLeft + * Bottom left corner of annotation. + * @param bottomRight + * Bottom right corner of annotation. + * @param topRight + * Top right corner of annotation. + * @param topLeft + * Top left corner of annotation. + * @param extraSpacePixels + * Extra space to add, ion pixels. + */ +void +MathFunctions::expandBoxPixels3D(double bottomLeft[3], + double bottomRight[3], + double topRight[3], + double topLeft[3], + const double extraSpacePixels) +{ + expandLinePixels3D(bottomLeft, bottomRight, extraSpacePixels); + expandLinePixels3D(topLeft, topRight, extraSpacePixels); + expandLinePixels3D(bottomLeft, topLeft, extraSpacePixels); + expandLinePixels3D(bottomRight, topRight, extraSpacePixels); +} + +/** + * Expand a box by given amounts in X and Y. + * + * @param bottomLeft + * Bottom left corner of annotation. + * @param bottomRight + * Bottom right corner of annotation. + * @param topRight + * Top right corner of annotation. + * @param topLeft + * Top left corner of annotation. + * @param extraSpacePercentage + * Extra space to add, percentage is zero to one with one interpreted as 100%. + */ +void +MathFunctions::expandBoxPercentage3D(float bottomLeft[3], + float bottomRight[3], + float topRight[3], + float topLeft[3], + const float extraSpacePercentage) +{ + expandLinePercentage3D(bottomLeft, bottomRight, extraSpacePercentage); + expandLinePercentage3D(topLeft, topRight, extraSpacePercentage); + expandLinePercentage3D(bottomLeft, topLeft, extraSpacePercentage); + expandLinePercentage3D(bottomRight, topRight, extraSpacePercentage); +} + diff --git a/src/Common/MathFunctions.h b/src/Common/MathFunctions.h index 0555612c53b96d75fb272840c91df9dc7fb209ae..d2300b39f211460bb7dca76a1bda50ca8ce5ce91 100644 --- a/src/Common/MathFunctions.h +++ b/src/Common/MathFunctions.h @@ -172,6 +172,12 @@ public: const double p1[3], const double p2[3]); + static void addOffsetToVector(double v[3], + const double offset[3]); + + static void subtractOffsetFromVector(double v[3], + const double offset[3]); + static float triangleArea( const float v1[3], const float v2[3], @@ -327,6 +333,8 @@ public: const float pk[3], const float n[3]); + static float angleInDegreesBetweenVectors(const float u[3], const float v[3]); + static bool isOddNumber(const int32_t number); static bool isEvenNumber(const int32_t number); @@ -398,6 +406,33 @@ public: ///one minus cdf of standard normal distribution static float q_func(const float& x); + static void expandBox(float bottomLeft[3], + float bottomRight[3], + float topRight[3], + float topLeft[3], + const float extraSpaceX, + const float extraSpaceY); + + static void expandBoxPixels3D(double bottomLeft[3], + double bottomRight[3], + double topRight[3], + double topLeft[3], + const double extraSpacePixels); + + static void expandBoxPercentage3D(float bottomLeft[3], + float bottomRight[3], + float topRight[3], + float topLeft[3], + const float extraSpacePercentage); + + static void expandLinePercentage3D(float u[3], + float v[3], + const float extraSpacePercent); + + static void expandLinePixels3D(double u[3], + double v[3], + const double extraSpacePixels); + }; } // namespace diff --git a/src/Common/ReductionEnum.cxx b/src/Common/ReductionEnum.cxx index ad3442b62a99b9713e2a04bd87892dd20b7fd755..f753ccfb478ff6bc21b5197f30801a570679d12e 100644 --- a/src/Common/ReductionEnum.cxx +++ b/src/Common/ReductionEnum.cxx @@ -81,6 +81,7 @@ ReductionEnum::initialize() enumData.push_back(ReductionEnum(VARIANCE, "VARIANCE", "the variance of the data")); enumData.push_back(ReductionEnum(TSNR, "TSNR", "mean divided by sample standard deviation (N-1 denominator)")); enumData.push_back(ReductionEnum(COV, "COV", "sample standard deviation (N-1 denominator) divided by mean")); + enumData.push_back(ReductionEnum(L2NORM, "L2NORM", "square root of sum of squares")); enumData.push_back(ReductionEnum(MEDIAN, "MEDIAN", "the median of the data")); enumData.push_back(ReductionEnum(MODE, "MODE", "the mode of the data")); enumData.push_back(ReductionEnum(COUNT_NONZERO, "COUNT_NONZERO", "the number of nonzero elements in the data")); diff --git a/src/Common/ReductionEnum.h b/src/Common/ReductionEnum.h index a4b8f895b095aebffcfcdcc9d7b1ba1a0ec01e16..e7fe0f9d73c10ef4c06a01f81dec297ec164fcb2 100644 --- a/src/Common/ReductionEnum.h +++ b/src/Common/ReductionEnum.h @@ -52,6 +52,7 @@ public: VARIANCE, TSNR, COV, + L2NORM, PRODUCT, MEDIAN, MODE, diff --git a/src/Common/ReductionOperation.cxx b/src/Common/ReductionOperation.cxx index 6fe6784b2143172bf9520e5990e1639e8598ec1c..ce98a22560b844b7e4388ca77fc8935d57f317a5 100644 --- a/src/Common/ReductionOperation.cxx +++ b/src/Common/ReductionOperation.cxx @@ -83,6 +83,12 @@ float ReductionOperation::reduce(const float* data, const int64_t& numElems, con } } } + case ReductionEnum::L2NORM: + { + double sum = 0.0; + for (int64_t i = 0; i < numElems; ++i) sum += data[i] * data[i]; + return sqrt(sum); + } case ReductionEnum::PRODUCT: { double prod = 1.0; @@ -183,6 +189,7 @@ float ReductionOperation::reduce(const float* data, const int64_t& numElems, con return count; } } + CaretAssertMessage(false, "unhandled reduction type"); return 0.0f; } @@ -387,6 +394,12 @@ float ReductionOperation::reduceWeighted(const float* data, const float* weights return 0.0f; } } + case ReductionEnum::L2NORM: + { + double sum = 0.0; + for (int64_t i = 0; i < numElems; ++i) sum += weights[i] * data[i] * data[i]; + return sqrt(sum);//if all weights are 1, this should match unweighted, so don't divide by sum of weights + } case ReductionEnum::MEDIAN: { vector toSort; @@ -446,6 +459,7 @@ float ReductionOperation::reduceWeighted(const float* data, const float* weights return bestval; } } + CaretAssertMessage(false, "unhandled reduction type"); return 0.0f; } diff --git a/src/Common/SpacerTabIndex.cxx b/src/Common/SpacerTabIndex.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4b74acb3d75ddb2435ab59166597cc200a281e16 --- /dev/null +++ b/src/Common/SpacerTabIndex.cxx @@ -0,0 +1,326 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SPACER_TAB_INDEX_DECLARE__ +#include "SpacerTabIndex.h" +#undef __SPACER_TAB_INDEX_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + + +/** + * \class caret::SpacerTabIndex + * \brief Index of a spacer tab in a tile tabs configuration + * \ingroup Scenes + */ + +/** + * Constructor of invalid element. + */ +SpacerTabIndex::SpacerTabIndex() +: CaretObject(), +m_windowIndex(-1), +m_rowIndex(-1), +m_columnIndex(-1) +{ +} + +/** + * Constructor with indices + */ +SpacerTabIndex::SpacerTabIndex(const int32_t windowIndex, + const int32_t rowIndex, + const int32_t columnIndex) +: CaretObject(), +m_windowIndex(windowIndex), +m_rowIndex(rowIndex), +m_columnIndex(columnIndex) +{ +} + +/** + * Destructor. + */ +SpacerTabIndex::~SpacerTabIndex() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +SpacerTabIndex::SpacerTabIndex(const SpacerTabIndex& obj) +: CaretObject(obj) +{ + this->copyHelperSpacerTabIndex(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +SpacerTabIndex& +SpacerTabIndex::operator=(const SpacerTabIndex& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperSpacerTabIndex(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +SpacerTabIndex::copyHelperSpacerTabIndex(const SpacerTabIndex& obj) +{ + m_windowIndex = obj.m_windowIndex; + m_rowIndex = obj.m_rowIndex; + m_columnIndex = obj.m_columnIndex; +} + +/** + * Inequality operator. + * @param obj + * Instance compared to this for equality. + * @return + * True if this instance and 'obj' instance are considered NOT equal. + */ +bool +SpacerTabIndex::operator!=(const SpacerTabIndex& obj) const +{ + return ( ! (*this == obj)); +} + +/** + * Equality operator. + * @param obj + * Instance compared to this for equality. + * @return + * True if this instance and 'obj' instance are considered equal. + */ +bool +SpacerTabIndex::operator==(const SpacerTabIndex& obj) const +{ + if (this == &obj) { + return true; + } + + if ((m_windowIndex == obj.m_windowIndex) + && (m_rowIndex == obj.m_rowIndex) + && (m_columnIndex == obj.m_columnIndex)) { + return true; + } + + return false; +} + +/** + * Comparison operator. + * + * @param rhs + * Other instance for comparison + * @return True if 'this' is less than 'rhs', else false. + */ +bool +SpacerTabIndex::operator<(const SpacerTabIndex& rhs) const +{ + if (m_windowIndex != rhs.m_windowIndex) { + return (m_windowIndex < rhs.m_windowIndex); + } + if (m_rowIndex != rhs.m_rowIndex) { + return (m_rowIndex < rhs.m_rowIndex); + } + if (m_columnIndex != rhs.m_columnIndex) { + return (m_columnIndex < rhs.m_columnIndex); + } + + return false; +} + +/** + * @return True if the index is valid, else false. + */ +bool +SpacerTabIndex::isValid() const +{ + if ((m_windowIndex >= 0) + && (m_rowIndex >= 0) + && (m_columnIndex >= 0)) { + return true; + } + + return false; +} + + +/** + * @return The window index + */ +int32_t +SpacerTabIndex::getWindowIndex() const +{ + return m_windowIndex; +} + +/** + * @return The row index + */ +int32_t +SpacerTabIndex::getRowIndex() const +{ + return m_rowIndex; +} + +/** + * @return The column index + */ +int32_t +SpacerTabIndex::getColumnIndex() const +{ + return m_columnIndex; +} + +/** + * Set the row index. + * + * @param rowIndex + * New row index. + */ +void +SpacerTabIndex::setRowIndex(const int32_t rowIndex) +{ + m_rowIndex = rowIndex; +} + +/** + * Set the column index. + * + * @param columnIndex + * New column index. + */ +void +SpacerTabIndex::setColumnIndex(const int32_t columnIndex) + +{ + m_columnIndex = columnIndex; +} +/** + * Reset to invalid indices. + */ +void +SpacerTabIndex::reset() +{ + m_windowIndex = -1; + m_rowIndex = -1; + m_columnIndex = -1; +} + + +/** + * @return Format for XML attribute (window index, row index, + * and column index separated by commas). + * NOTE: THESE INDICES START AT ZERO + */ +AString +SpacerTabIndex::getXmlAttributeText() const +{ + AString s("%1,%2,%3"); + s = s.arg(m_windowIndex).arg(m_rowIndex).arg(m_columnIndex); + return s; +} + +/** + * Set from XML text in the form (w,r,c) where 'w' is the + * window index, 'r' is the row index, and 'c' is the + * column index. + * NOTE: THESE INDICES START AT ZERO + */ +void +SpacerTabIndex::setFromXmlAttributeText(const AString& text) +{ + reset(); + + if ( ! text.isEmpty()) { + std::vector indices; + AString::toNumbers(text, indices); + if (indices.size() >= 3) { + m_windowIndex = indices[0]; + m_rowIndex = indices[1]; + m_columnIndex = indices[2]; + } + } +} + +/** + * @return Row and column in text form (eg: "Row=2, Column=3") + * for use in the GUI and viewed by user. + * NOTE: THESE INDICES START AT ONE + */ +AString +SpacerTabIndex::getRowColumnGuiText() const +{ + AString s("Row=%1, Column=%2"); + s = s.arg(m_rowIndex+1).arg(m_columnIndex+1); + return s; +} + +/** + * @return Window, row, and column in text form (eg: "Window=1, Row=2, Column=3") + * for use in the GUI and viewed by user. + * NOTE: THESE INDICES START AT ONE + */ +AString +SpacerTabIndex::getWindowRowColumnGuiText() const +{ + AString s("Window=%1, "); + s = s.arg(m_windowIndex+1); + s.append(getRowColumnGuiText()); + + return s; +} + + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + * NOTE: THESE INDICES START AT ZERO + */ +AString +SpacerTabIndex::toString() const +{ + AString s("SpacerTabIndex: windowIndex=%1, rowIndex=%2, columnIndex=%3"); + s = s.arg(m_windowIndex).arg(m_rowIndex).arg(m_columnIndex); + + return s; +} + diff --git a/src/Common/SpacerTabIndex.h b/src/Common/SpacerTabIndex.h new file mode 100644 index 0000000000000000000000000000000000000000..9c90318e8154dbe2d2c0c55e3dcdf5410fc3b509 --- /dev/null +++ b/src/Common/SpacerTabIndex.h @@ -0,0 +1,97 @@ +#ifndef __SPACER_TAB_INDEX_H__ +#define __SPACER_TAB_INDEX_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +namespace caret { + class SceneClassAssistant; + + class SpacerTabIndex : public CaretObject { + + public: + SpacerTabIndex(); + + SpacerTabIndex(const int32_t windowIndex, + const int32_t rowIndex, + const int32_t columnIndex); + + virtual ~SpacerTabIndex(); + + SpacerTabIndex(const SpacerTabIndex& obj); + + SpacerTabIndex& operator=(const SpacerTabIndex& obj); + + bool operator==(const SpacerTabIndex& obj) const; + + bool operator!=(const SpacerTabIndex& obj) const; + + bool operator<(const SpacerTabIndex& rhs) const; + + bool isValid() const; + + void reset(); + + int32_t getWindowIndex() const; + + int32_t getRowIndex() const; + + int32_t getColumnIndex() const; + + AString getRowColumnGuiText() const; + + AString getWindowRowColumnGuiText() const; + + AString getXmlAttributeText() const; + + void setFromXmlAttributeText(const AString& text); + + void setRowIndex(const int32_t rowIndex); + + void setColumnIndex(const int32_t columnIndex); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperSpacerTabIndex(const SpacerTabIndex& obj); + + int32_t m_windowIndex; + int32_t m_rowIndex; + int32_t m_columnIndex; + + // ADD_NEW_MEMBERS_HERE + + friend class SpacerTabContent; + }; + +#ifdef __SPACER_TAB_INDEX_DECLARE__ + // +#endif // __SPACER_TAB_INDEX_DECLARE__ + +} // namespace +#endif //__SPACER_TAB_INDEX_H__ diff --git a/src/Common/SystemUtilities.cxx b/src/Common/SystemUtilities.cxx index 8f1fda4f116d8e744a1744b684b27603e5c8bc5d..69369ef5628fb528ac8e58113d2fd5ae45770d7d 100644 --- a/src/Common/SystemUtilities.cxx +++ b/src/Common/SystemUtilities.cxx @@ -672,6 +672,11 @@ SystemUtilities::getWorkbenchHome() AString SystemUtilities::getLocalHostName() { + /* + * NOTE: THIS FUNCTION DOES NOT SEEM TO WORK ON MACOS 10.14 MOJAVE. + * THE LOCALHOST NAME IS .LOCAL WHERE IS THE COMPUTER'NAME + * AND QHostInfo::fromName() DOES NOT MAKE IT FULLY QUALIFIED + */ QString hostName; QHostInfo hostInfo = QHostInfo::fromName(QHostInfo::localHostName()); diff --git a/src/Common/TileTabsBaseConfiguration.cxx b/src/Common/TileTabsBaseConfiguration.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e22e23a4bd8c34a5b8bd9e79d2f2c166f72091f3 --- /dev/null +++ b/src/Common/TileTabsBaseConfiguration.cxx @@ -0,0 +1,328 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include + +#define __TILE_TABS_BASE_CONFIGURATION_DECLARE__ +#include "TileTabsBaseConfiguration.h" +#undef __TILE_TABS_BASE_CONFIGURATION_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "SystemUtilities.h" +#include "TileTabsGridLayoutConfiguration.h" + +using namespace caret; + + + +/** + * \class caret::TileTabsBaseConfiguration + * \brief Defines a tile tabs configuration + * \ingroup Common + */ + +/** + * Constructor that creates a 2 by 2 configuration. + */ +TileTabsBaseConfiguration::TileTabsBaseConfiguration(const TileTabsConfigurationLayoutTypeEnum::Enum layoutType) +: CaretObject(), +m_layoutType(layoutType) +{ + initializeTileTabsBaseConfiguration(); +} + +/** + * Destructor. + */ +TileTabsBaseConfiguration::~TileTabsBaseConfiguration() +{ +} + +/** + * Copy constructor. + * + * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() + * + * @param obj + * Object that is copied. + */ +TileTabsBaseConfiguration::TileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj) +: CaretObject(obj), +m_layoutType(obj.m_layoutType) +{ + const AString savedUniqueID = m_uniqueIdentifier; + initializeTileTabsBaseConfiguration(); + m_uniqueIdentifier = savedUniqueID; + this->copyHelperTileTabsBaseConfiguration(obj); +} + +/** + * Assignment operator. + * + * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() + * + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +TileTabsBaseConfiguration& +TileTabsBaseConfiguration::operator=(const TileTabsBaseConfiguration& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperTileTabsBaseConfiguration(obj); + } + return *this; +} + +/** + * Initialize an instance of a tile tabs configuration. + */ +void +TileTabsBaseConfiguration::initializeTileTabsBaseConfiguration() +{ + m_name.clear(); + m_uniqueIdentifier = SystemUtilities::createUniqueID(); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +TileTabsBaseConfiguration::copyHelperTileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj) +{ + if (this == &obj) { + return; + } + + m_name = obj.m_name; + //DO NOT CHANGE THE UNIQUE IDENTIFIER: m_uniqueIdentifier +} + +/** + * Copies the tile tabs configuration rows, columns, and + * stretch factors. Name is NOT copied. + */ +void +TileTabsBaseConfiguration::copy(const TileTabsBaseConfiguration& rhs) +{ + CaretAssertToDoFatal(); // need to do this a different way + AString savedName = m_name; + copyHelperTileTabsBaseConfiguration(rhs); + m_name = savedName; +} + +/** + * @return Type of layout for the configuration + */ +TileTabsConfigurationLayoutTypeEnum::Enum +TileTabsBaseConfiguration::getLayoutType() const +{ + return m_layoutType; +} + +/** + * @return the name of the tile tabs configuration. + */ +AString +TileTabsBaseConfiguration::getName() const +{ + return m_name; +} + +/** + * @return Get the unique identifier that uniquely identifies each configuration. + */ +AString +TileTabsBaseConfiguration::getUniqueIdentifier() const +{ + return m_uniqueIdentifier; +} + +/** + * Set the name of the tile tabs configuration. + * + * @param name + * New name for configuration. + */ +void +TileTabsBaseConfiguration::setName(const AString& name) +{ + m_name = name; +} + +/** + * Set the unique identifier of the tile tabs configuration. + * + * @param uniqueID + * New unique identifier for configuration. + */ +void +TileTabsBaseConfiguration::setUniqueIdentifierProtected(const AString& uniqueID) +{ + m_uniqueIdentifier = uniqueID; +} + + +/** + * @return Encoded tile tabs configuration in XML + */ +AString +TileTabsBaseConfiguration::encodeInXML() const +{ + AString s; + encodeInXML(s); + return s; +} + +/** + * Decode the tile tabs configuration from XML + * + * @param xmlString + * String containing XML. + * @param errorMessageOut + * Contains error information if decoding fails. + * @return + * Pointer to the configuration or NULL if there was an error. + */ +TileTabsBaseConfiguration* +TileTabsBaseConfiguration::decodeFromXML(const AString& xmlString, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + TileTabsBaseConfiguration* configurationOut(NULL); + + QXmlStreamReader xml(xmlString); + + if (xml.readNextStartElement()) { + const QStringRef tagName(xml.name()); + if (tagName == TileTabsGridLayoutConfiguration::s_v1_rootTagName) { + TileTabsGridLayoutConfiguration* v1 = new TileTabsGridLayoutConfiguration(); + v1->decodeFromXML(xml, + tagName.toString()); + configurationOut = v1; + } + else if (tagName == TileTabsGridLayoutConfiguration::s_v2_rootTagName) { + TileTabsGridLayoutConfiguration* v2 = new TileTabsGridLayoutConfiguration(); + v2->decodeFromXML(xml, + tagName.toString()); + configurationOut = v2; + } + else { + xml.raiseError("TileTabsBaseConfiguration first element is " + + xml.name().toString() + + " but should be " + + TileTabsGridLayoutConfiguration::s_v1_rootTagName + + " or " + + TileTabsGridLayoutConfiguration::s_v2_rootTagName); + } + } + else { + xml.raiseError("TileTabsBaseConfiguration failed to find start elemnent."); + } + + if (xml.hasError()) { + errorMessageOut = ("Tile Tabs Configuration Read Error at line number=" + + AString::number(xml.lineNumber()) + + " column number=" + + AString::number(xml.columnNumber()) + + " description=" + + xml.errorString()); + if (configurationOut != NULL) { + delete configurationOut; + configurationOut = NULL; + } + return configurationOut; + } + + const bool debugFlag(false); + if (debugFlag) { +// AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); +// std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; +// AString em; +// TileTabsBaseConfiguration temp; +// QXmlStreamReader tempReader(xmlText); +// tempReader.readNextStartElement(); +// temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); +// if (tempReader.hasError()) { +// std::cout << "Decode error: " << tempReader.errorString() << std::endl; +// } +// else { +// std::cout << "Decoded: " << temp.toString() << std::endl; +// } +// +// std::cout << std::endl; + } + return configurationOut; +} + + +/** + * @return String version of an instance. + */ +AString +TileTabsBaseConfiguration::toString() const +{ + AString s("Name: %1, Unique ID: %2\n"); + s = s.arg(m_name).arg(m_uniqueIdentifier); +// +// int32_t indx(0); +// for (const auto item : m_columns) { +// s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); +// indx++; +// } +// indx = 0; +// for (const auto item : m_rows) { +// s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); +// indx++; +// } + + return s; +} + +/** + * Compare two tile tabs configurations by name. + * + * @param ttc1 + * First tile tab configuration. + * @param ttc2 + * Second tile tab configuration. + * @return + * True if ttc1 is "less than" when compared by name, else false. + */ +bool +TileTabsBaseConfiguration::lessThanComparisonByName(const TileTabsBaseConfiguration* ttc1, + const TileTabsBaseConfiguration* ttc2) +{ + if (ttc1->getName() < ttc2->getName()) { + return true; + } + return false; +} + diff --git a/src/Common/TileTabsBaseConfiguration.h b/src/Common/TileTabsBaseConfiguration.h new file mode 100644 index 0000000000000000000000000000000000000000..8e5ed2571775634f405e29d1230526ab301e7c91 --- /dev/null +++ b/src/Common/TileTabsBaseConfiguration.h @@ -0,0 +1,120 @@ +#ifndef __TILE_TABS_BASE_CONFIGURATION_H__ +#define __TILE_TABS_BASE_CONFIGURATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretException.h" +#include "CaretObject.h" +#include "TileTabsConfigurationLayoutTypeEnum.h" +#include "TileTabsGridModeEnum.h" +#include "TileTabsGridRowColumnElement.h" + +class QXmlStreamReader; +class QXmlStreamWriter; + +namespace caret { + + class TileTabsBaseConfiguration : public CaretObject { + + protected: + TileTabsBaseConfiguration(const TileTabsConfigurationLayoutTypeEnum::Enum layoutType); + + public: + virtual ~TileTabsBaseConfiguration(); + + TileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj); + + TileTabsBaseConfiguration& operator=(const TileTabsBaseConfiguration& obj); + + void copy(const TileTabsBaseConfiguration& rhs); + + virtual TileTabsBaseConfiguration* newCopyWithNewUniqueIdentifier() const = 0; + + TileTabsConfigurationLayoutTypeEnum::Enum getLayoutType() const; + + AString getName() const; + + void setName(const AString& name); + + AString getUniqueIdentifier() const; + + + AString encodeInXML() const; + + static TileTabsBaseConfiguration* decodeFromXML(const AString& xmlString, + AString& errorMessageOut); + + AString toString() const override; + + static bool lessThanComparisonByName(const TileTabsBaseConfiguration* ttc1, + const TileTabsBaseConfiguration* ttc2); + + // ADD_NEW_METHODS_HERE + + + protected: + /** + * Decode the configuration using the given XML stream reader and root element + * If there is an error, xml.raiseError() should be used to specify the error + * and caller of this method can test for the error using xml.isError(). + * + * @param xml + * The XML stream reader. + * @param rootElement + * The root element. + */ + virtual void decodeFromXML(QXmlStreamReader& xml, + const QString& rootElementText) = 0; + + /** + * Encode the configuration in XML. + * + * @param xmlTextOut + * Contains XML representation of configuration. + */ + virtual void encodeInXML(AString& xmlTextOut) const = 0; + + void setUniqueIdentifierProtected(const AString& uniqueID); + + void copyHelperTileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj); + + private: + + void initializeTileTabsBaseConfiguration(); + + // ADD_NEW_MEMBERS_HERE + + const TileTabsConfigurationLayoutTypeEnum::Enum m_layoutType; + + AString m_name; + + /** Unique identifier does not get copied */ + AString m_uniqueIdentifier; + + + }; + +#ifdef __TILE_TABS_BASE_CONFIGURATION_DECLARE__ + +#endif // __TILE_TABS_BASE_CONFIGURATION_DECLARE__ + +} // namespace +#endif //__TILE_TABS_BASE_CONFIGURATION_H__ diff --git a/src/Common/TileTabsConfiguration.cxx b/src/Common/TileTabsConfiguration.cxx index a88239e22d1d78abe3b19a760feda39b2644ee70..01db9f5cb3313d9e5aaea64e575b00aa93930832 100644 --- a/src/Common/TileTabsConfiguration.cxx +++ b/src/Common/TileTabsConfiguration.cxx @@ -20,12 +20,14 @@ /*LICENSE_END*/ #include +#include #define __TILE_TABS_CONFIGURATION_DECLARE__ #include "TileTabsConfiguration.h" #undef __TILE_TABS_CONFIGURATION_DECLARE__ -#include +#include +#include #include "CaretAssert.h" #include "CaretLogger.h" @@ -68,7 +70,9 @@ TileTabsConfiguration::~TileTabsConfiguration() TileTabsConfiguration::TileTabsConfiguration(const TileTabsConfiguration& obj) : CaretObject(obj) { + const AString savedUniqueID = m_uniqueIdentifier; initialize(); + m_uniqueIdentifier = savedUniqueID; this->copyHelperTileTabsConfiguration(obj); } @@ -114,17 +118,12 @@ TileTabsConfiguration::newCopyWithNewUniqueIdentifier() const void TileTabsConfiguration::initialize() { - m_rowStretchFactors.resize(getMaximumNumberOfRows(), - 1.0); - m_columnStretchFactors.resize(getMaximumNumberOfColumns(), - 1.0); - m_numberOfColumns = 0; - m_numberOfRows = 0; - setNumberOfRows(2); setNumberOfColumns(2); - + + m_name.clear(); m_uniqueIdentifier = SystemUtilities::createUniqueID(); + m_centeringCorrectionEnabled = false; } /** @@ -139,11 +138,10 @@ TileTabsConfiguration::copyHelperTileTabsConfiguration(const TileTabsConfigurati return; } - m_numberOfColumns = obj.m_numberOfColumns; - m_numberOfRows = obj.m_numberOfRows; - m_rowStretchFactors = obj.m_rowStretchFactors; - m_columnStretchFactors = obj.m_columnStretchFactors; - m_name = obj.m_name; + m_name = obj.m_name; + m_columns = obj.m_columns; + m_rows = obj.m_rows; + m_centeringCorrectionEnabled = obj.m_centeringCorrectionEnabled; //DO NOT CHANGE THE UNIQUE IDENTIFIER: m_uniqueIdentifier } @@ -159,6 +157,54 @@ TileTabsConfiguration::copy(const TileTabsConfiguration& rhs) m_name = savedName; } +/** + * Get infoformation for the given elemnent in the columns. + * + * @param Information for element. + */ +TileTabsGridRowColumnElement* +TileTabsConfiguration::getColumn(const int32_t columnIndex) +{ + CaretAssertVectorIndex(m_columns, columnIndex); + return &m_columns[columnIndex]; +} + +/** + * Get infoformation for the given elemnent in the columns. + * + * @param Information for element. + */ +const TileTabsGridRowColumnElement* +TileTabsConfiguration::getColumn(const int32_t columnIndex) const +{ + CaretAssertVectorIndex(m_columns, columnIndex); + return &m_columns[columnIndex]; +} + +/** + * Get infoformation for the given elemnent in the rows. + * + * @param Information for element. + */ +TileTabsGridRowColumnElement* +TileTabsConfiguration::getRow(const int32_t rowIndex) +{ + CaretAssertVectorIndex(m_rows, rowIndex); + return &m_rows[rowIndex]; +} + +/** + * Get infoformation for the given elemnent in the rows. + * + * @param Information for element. + */ +const TileTabsGridRowColumnElement* +TileTabsConfiguration::getRow(const int32_t rowIndex) const +{ + CaretAssertVectorIndex(m_rows, rowIndex); + return &m_rows[rowIndex]; +} + /** * Get the row heights and column widths for this tile tabs configuration using the * given window width and height. @@ -182,7 +228,7 @@ bool TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, - const TileTabsConfigurationModeEnum::Enum configurationMode, + const TileTabsGridModeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut) { @@ -201,7 +247,7 @@ TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t w columnWidthsOut.clear(); switch (configurationMode) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: { /* * Update number of rows/columns in the default configuration @@ -219,7 +265,7 @@ TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t w columnWidthsOut.push_back(windowWidth / numCols); } } break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: { /* * Rows/columns from user configuration @@ -230,14 +276,43 @@ TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t w /* * Determine height of each row */ + float rowPercentTotal = 0.0; float rowStretchTotal = 0.0; for (int32_t i = 0; i < numRows; i++) { - rowStretchTotal += getRowStretchFactor(i); + const TileTabsGridRowColumnElement* e = getRow(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + rowPercentTotal += (e->getPercentStretch() / 100.0); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + rowStretchTotal += e->getWeightStretch(); + break; + } + } + + float windowWeightHeight = windowHeight; + if (rowPercentTotal > 0.0) { + if (rowPercentTotal >= 1.0) { + windowWeightHeight = 0.0; + } + else { + windowWeightHeight = (1.0 - rowPercentTotal) * windowHeight; + } } - CaretAssert(rowStretchTotal > 0.0); for (int32_t i = 0; i < numRows; i++) { - const int32_t h = static_cast((getRowStretchFactor(i) / rowStretchTotal) - * windowHeight); + int32_t h = 0; + const TileTabsGridRowColumnElement* e = getRow(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + h = (e->getPercentStretch() / 100.0) * windowHeight; + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + if (rowStretchTotal > 0.0) { + h = static_cast((e->getWeightStretch() / rowStretchTotal) + * windowWeightHeight); + } + break; + } rowHeightsOut.push_back(h); } @@ -245,14 +320,44 @@ TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t w /* * Determine width of each column */ + float columnPercentTotal = 0.0; float columnStretchTotal = 0.0; for (int32_t i = 0; i < numCols; i++) { - columnStretchTotal += getColumnStretchFactor(i); + const TileTabsGridRowColumnElement* e = getColumn(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + columnPercentTotal += (e->getPercentStretch() / 100.0); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + columnStretchTotal += e->getWeightStretch(); + break; + } + } + + float windowWeightWidth = windowWidth; + if (columnPercentTotal > 0.0) { + if (columnPercentTotal >= 1.0) { + windowWeightWidth = 0.0; + } + else { + windowWeightWidth = (1.0 - columnPercentTotal) * windowWidth; + } } - CaretAssert(columnStretchTotal > 0.0); + for (int32_t i = 0; i < numCols; i++) { - const int32_t w = static_cast((getColumnStretchFactor(i) / columnStretchTotal) - * windowWidth); + int32_t w = 0; + const TileTabsGridRowColumnElement* e = getColumn(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + w = (e->getPercentStretch() / 100.0) * windowWidth; + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + if (columnStretchTotal > 0.0) { + w = static_cast((e->getWeightStretch() / columnStretchTotal) + * windowWeightWidth); + } + break; + } columnWidthsOut.push_back(w); } } break; @@ -260,34 +365,34 @@ TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t w if ((numRows == static_cast(rowHeightsOut.size())) && (numCols == static_cast(columnWidthsOut.size()))) { - /* - * Verify all rows fit within the window - */ - int32_t rowHeightsSum = 0; - for (int32_t i = 0; i < numRows; i++) { - rowHeightsSum += rowHeightsOut[i]; - } - if (rowHeightsSum > windowHeight) { - CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); - rowHeightsOut[numRows - 1] -= (rowHeightsSum - windowHeight); - } - - /* - * Adjust width of last column so that it does not extend beyond viewport - */ - int32_t columnWidthsSum = 0; - for (int32_t i = 0; i < numCols; i++) { - columnWidthsSum += columnWidthsOut[i]; - } - if (columnWidthsSum > windowWidth) { - CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); - columnWidthsOut[numCols - 1] = columnWidthsSum - windowWidth; - } - - CaretLogFiner("Tile Tabs Row Heights: " - + AString::fromNumbers(rowHeightsOut, ", ")); - CaretLogFiner("Tile Tabs Column Widths: " - + AString::fromNumbers(columnWidthsOut, ", ")); +// /* +// * Verify all rows fit within the window +// */ +// int32_t rowHeightsSum = 0; +// for (int32_t i = 0; i < numRows; i++) { +// rowHeightsSum += rowHeightsOut[i]; +// } +// if (rowHeightsSum > windowHeight) { +// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); +//// rowHeightsOut[numRows - 1] -= (rowHeightsSum - windowHeight); +// } +// +// /* +// * Adjust width of last column so that it does not extend beyond viewport +// */ +// int32_t columnWidthsSum = 0; +// for (int32_t i = 0; i < numCols; i++) { +// columnWidthsSum += columnWidthsOut[i]; +// } +// if (columnWidthsSum > windowWidth) { +// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); +//// columnWidthsOut[numCols - 1] = columnWidthsSum - windowWidth; +// } +// +// CaretLogFiner("Tile Tabs Row Heights: " +// + AString::fromNumbers(rowHeightsOut, ", ")); +// CaretLogFiner("Tile Tabs Column Widths: " +// + AString::fromNumbers(columnWidthsOut, ", ")); return true; } @@ -341,7 +446,7 @@ TileTabsConfiguration::setName(const AString& name) int32_t TileTabsConfiguration::getNumberOfRows() const { - return m_numberOfRows; + return m_rows.size(); } /** @@ -353,25 +458,7 @@ TileTabsConfiguration::getNumberOfRows() const void TileTabsConfiguration::setNumberOfRows(const int32_t numberOfRows) { - const int32_t oldNumerOfRows = m_numberOfRows; - - CaretAssert(numberOfRows >= 1); - m_numberOfRows = numberOfRows; - if (m_numberOfRows > getMaximumNumberOfRows()) { - CaretLogSevere("Requested number of rows is " - + AString::number(m_numberOfRows) - + " but maximum is " - + getMaximumNumberOfRows()); - m_numberOfRows = getMaximumNumberOfRows(); - } - - /* - * Stretch factors default to 1.0 - */ - for (int32_t iRow = oldNumerOfRows; iRow < m_numberOfRows; iRow++) { - CaretAssertVectorIndex(m_rowStretchFactors, iRow); - m_rowStretchFactors[iRow] = 1.0; - } + m_rows.resize(numberOfRows); } /** @@ -380,7 +467,7 @@ TileTabsConfiguration::setNumberOfRows(const int32_t numberOfRows) int32_t TileTabsConfiguration::getNumberOfColumns() const { - return m_numberOfColumns; + return m_columns.size(); } /** @@ -392,93 +479,7 @@ TileTabsConfiguration::getNumberOfColumns() const void TileTabsConfiguration::setNumberOfColumns(const int32_t numberOfColumns) { - const int32_t oldNumberOfColumns = m_numberOfColumns; - - CaretAssert(numberOfColumns >= 1); - - m_numberOfColumns = numberOfColumns; - if (m_numberOfColumns > getMaximumNumberOfColumns()) { - CaretLogSevere("Requested number of columns is " - + AString::number(m_numberOfColumns) - + " but maximum is " - + getMaximumNumberOfColumns()); - m_numberOfColumns = getMaximumNumberOfColumns(); - } - - /* - * Stretch factors default to 1.0 - */ - for (int32_t iCol = oldNumberOfColumns; iCol < m_numberOfColumns; iCol++) { - CaretAssertVectorIndex(m_columnStretchFactors, iCol); - m_columnStretchFactors[iCol] = 1.0; - } -} - -/** - * Get stretch factor for a column. - * - * @param columnIndex - * Index of the column. - * @return - * Stretch factor for the column. - */ -float -TileTabsConfiguration::getColumnStretchFactor(const int32_t columnIndex) const -{ - CaretAssertVectorIndex(m_columnStretchFactors, columnIndex); - - return m_columnStretchFactors[columnIndex]; -} - -/** - * Set stretch factor for a column. - * - * @param columnIndex - * Index of the column. - * @param stretchFactor - * Stretch factor for the column. - */ -void -TileTabsConfiguration::setColumnStretchFactor(const int32_t columnIndex, - const float stretchFactor) -{ - CaretAssertVectorIndex(m_columnStretchFactors, columnIndex); - - m_columnStretchFactors[columnIndex] = stretchFactor; -} - -/** - * Get stretch factor for a column. - * - * @param columnIndex - * Index of the column. - * @return - * Stretch factor for the column. - */ -float -TileTabsConfiguration::getRowStretchFactor(const int32_t rowIndex) const -{ - CaretAssertVectorIndex(m_rowStretchFactors, rowIndex); - - return m_rowStretchFactors[rowIndex]; -} - -/** - * Set stretch factor for a column. - * - * @param rowIndex - * Index of the row. - * @param stretchFactor - * Stretch factor for the column. - */ -void -TileTabsConfiguration::setRowStretchFactor(const int32_t rowIndex, - const float stretchFactor) -{ - CaretAssertVectorIndex(m_rowStretchFactors, rowIndex); - - m_rowStretchFactors[rowIndex] = stretchFactor; - + m_columns.resize(numberOfColumns); } /** @@ -509,6 +510,28 @@ TileTabsConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTa } } +/** + * @return True if the centering correction is enabled. + */ +bool +TileTabsConfiguration::isCenteringCorrectionEnabled() const +{ + return m_centeringCorrectionEnabled; +} + +/** + * Set the enabled status of the centering correction + * + * @param status + * New status for enabling the centering correction + */ +void +TileTabsConfiguration::setCenteringCorrectionEnabled(const bool status) +{ + m_centeringCorrectionEnabled = status; +} + + /** * Updates the number of rows and columns for the automatic configuration * based upon the number of tabs. @@ -526,248 +549,615 @@ TileTabsConfiguration::updateAutomaticConfigurationRowsAndColumns(const int32_t setNumberOfRows(numRows); setNumberOfColumns(numCols); - - std::fill(m_columnStretchFactors.begin(), - m_columnStretchFactors.end(), - 1.0); - std::fill(m_rowStretchFactors.begin(), - m_rowStretchFactors.end(), - 1.0); } - /** * @return Encoded tile tabs configuration in XML */ AString TileTabsConfiguration::encodeInXML() const { - QDomDocument doc(s_rootTagName); - QDomElement root = doc.createElement(s_rootTagName); - doc.appendChild(root); - - QDomElement versionTag = doc.createElement(s_versionTagName); - versionTag.setAttribute(s_versionNumberAttributeName, - (int)1); - root.appendChild(versionTag); - - QDomElement nameTag = doc.createElement(s_nameTagName); - nameTag.appendChild(doc.createTextNode(m_name)); - root.appendChild(nameTag); - - QDomElement uniqueIdentifierTag = doc.createElement(s_uniqueIdentifierTagName); - uniqueIdentifierTag.appendChild(doc.createTextNode(m_uniqueIdentifier)); - root.appendChild(uniqueIdentifierTag); - - QDomElement rowStretchFactorsTag = doc.createElement(s_rowStretchFactorsTagName); - rowStretchFactorsTag.setAttribute(s_rowStretchFactorsTotalCountAttributeName, - static_cast(m_rowStretchFactors.size())); - rowStretchFactorsTag.setAttribute(s_rowStretchFactorsSelectedCountAttributeName, - static_cast(m_numberOfRows)); - rowStretchFactorsTag.appendChild(doc.createTextNode(AString::fromNumbers(m_rowStretchFactors, - " "))); - root.appendChild(rowStretchFactorsTag); - - QDomElement columnStretchFactorsTag = doc.createElement(s_columnStretchFactorsTagName); - columnStretchFactorsTag.setAttribute(s_columnStretchFactorsTotalCountAttributeName, - static_cast(m_columnStretchFactors.size())); - columnStretchFactorsTag.setAttribute(s_columnStretchFactorsSelectedCountAttributeName, - static_cast(m_numberOfColumns)); - columnStretchFactorsTag.appendChild(doc.createTextNode(AString::fromNumbers(m_columnStretchFactors, - " "))); - root.appendChild(columnStretchFactorsTag); - - const AString xmlString = doc.toString(); + return encodeVersionInXML(2); +} + +/** + * @return Encoded tile tabs configuration in XML + * using the give XML version of TileTabsConfiguration. + */ +AString +TileTabsConfiguration::encodeVersionInXML(const int32_t versionNumber) const +{ + AString s; + + switch (versionNumber) { + case 1: + s = encodeInXMLWithStreamWriterVersionOne(); + break; + case 2: + s = encodeInXMLWithStreamWriterVersionTwo(); + break; + default: + CaretAssertMessage(0, "Requested invalid version=" + AString::number(versionNumber)); + break; + } + + return s; +} + + +/** + * @return Encoded tile tabs configuration in XML with Stream Writer + */ +AString +TileTabsConfiguration::encodeInXMLWithStreamWriterVersionOne() const +{ + AString xmlString; + QXmlStreamWriter writer(&xmlString); + writer.setAutoFormatting(true); + + writer.writeStartElement(s_v1_rootTagName); + + writer.writeStartElement(s_v1_versionTagName); + writer.writeAttribute(s_v1_versionNumberAttributeName, "1"); + writer.writeEndElement(); + + writer.writeTextElement(s_nameTagName, m_name); + writer.writeTextElement(s_uniqueIdentifierTagName, m_uniqueIdentifier); + + const int32_t numberOfRows = getNumberOfRows(); + writer.writeStartElement(s_v1_rowStretchFactorsTagName); + writer.writeAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName, AString::number(numberOfRows)); + writer.writeAttribute(s_v1_rowStretchFactorsTotalCountAttributeName, AString::number(numberOfRows)); + std::vector rowStretchFactors; + for (const auto e : m_rows) { + rowStretchFactors.push_back(e.getWeightStretch()); + } + writer.writeCharacters(AString::fromNumbers(rowStretchFactors, " ")); + writer.writeEndElement(); + + const int32_t numberOfColumns = getNumberOfColumns(); + writer.writeStartElement(s_v1_columnStretchFactorsTagName); + writer.writeAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName, AString::number(numberOfColumns)); + writer.writeAttribute(s_v1_columnStretchFactorsTotalCountAttributeName, AString::number(numberOfColumns)); + std::vector columnStretchFactors; + for (const auto e : m_columns) { + columnStretchFactors.push_back(e.getWeightStretch()); + } + writer.writeCharacters(AString::fromNumbers(columnStretchFactors, " ")); + writer.writeEndElement(); + + writer.writeEndElement(); + + return xmlString; +} + +/** + * @return Encoded tile tabs configuration in XML with Stream Writer + */ +AString +TileTabsConfiguration::encodeInXMLWithStreamWriterVersionTwo() const +{ + AString xmlString; + QXmlStreamWriter writer(&xmlString); + writer.setAutoFormatting(true); + + writer.writeStartElement(s_v2_rootTagName); + writer.writeAttribute(s_v2_versionAttributeName, "2"); + + writer.writeTextElement(s_nameTagName, m_name); + writer.writeTextElement(s_uniqueIdentifierTagName, m_uniqueIdentifier); + writer.writeTextElement(s_v2_centeringCorrectionName, AString::fromBool(m_centeringCorrectionEnabled)); + + encodeRowColumnElement(writer, s_v2_columnsTagName, m_columns); + encodeRowColumnElement(writer, s_v2_rowsTagName, m_rows); + + writer.writeEndElement(); + return xmlString; } /** - * Decode the tile tabs configuration from XML. + * Encode a vector of elements into xml. + * + * @param writer + * The XML stream writer. + * @param tagName + * Tag name for enclosing the elements. + * @param elements + * Vector of elements added to XML. + */ +void +TileTabsConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer, + const AString tagName, + const std::vector& elements) const +{ + writer.writeStartElement(tagName); + + for (const auto e : elements) { + writer.writeStartElement(s_v2_elementTagName); + writer.writeAttribute(s_v2_contentTypeAttributeName, TileTabsGridRowColumnContentTypeEnum::toName(e.getContentType())); + writer.writeAttribute(s_v2_stretchTypeAttributeName, TileTabsGridRowColumnStretchTypeEnum::toName(e.getStretchType())); + writer.writeAttribute(s_v2_percentStretchAttributeName, AString::number(e.getPercentStretch(), 'f', 2)); + writer.writeAttribute(s_v2_weightStretchAttributeName, AString::number(e.getWeightStretch(), 'f', 2)); + writer.writeEndElement(); + } + + writer.writeEndElement(); +} + +/** + * Decode the tile tabs configuration from XML with stream reader. * * @param xmlString * String containing XML. + * @param errorMessageOut + * Will contain error information. * @return - * True if configuration was successfully read from the XML, else false. + * True if decoding is successful, else false. */ bool -TileTabsConfiguration::decodeFromXML(const AString& xmlString) +TileTabsConfiguration::decodeFromXMLWithStreamReader(const AString& xmlString, + AString& errorMessageOut) { - setNumberOfRows(2); - setNumberOfColumns(2); + m_centeringCorrectionEnabled = false; - try { - QDomDocument doc(s_rootTagName); - if (doc.setContent(xmlString) == false) { - throw CaretException("Error parsing DomDocument"); - } - - QDomNodeList nodeList = doc.elementsByTagName(s_versionTagName); - if (nodeList.isEmpty()) { - throw CaretException("Error finding version tag"); - } - QDomElement versionElement = nodeList.at(0).toElement(); - if (versionElement.isNull()) { - throw CaretException("Error finding version element"); - } - const AString versionNumberString = versionElement.attribute(s_versionNumberAttributeName, - ""); - if (versionNumberString.isEmpty()) { - throw CaretException("Error finding version number attribute"); + QXmlStreamReader xml(xmlString); + + if (xml.readNextStartElement()) { + const QStringRef tagName(xml.name()); + if (tagName == s_v1_rootTagName) { + decodeFromXMLWithStreamReaderVersionOne(xml); } - - const int versionNumber = versionNumberString.toInt(); - if (versionNumber == 1) { - parseVersionOneXML(doc); + else if (tagName == s_v2_rootTagName) { + /* + * Version 2 uses a different root tag than version 1. The reason is that + * the older code for decoding from XML will throw an exception if it + * encounters invalid elements or the version number is invalid. The problem + * is that the exception is not caught and wb_view will terminate. + */ + QString versionNumberText("Unknown"); + const QXmlStreamAttributes atts = xml.attributes(); + if (atts.hasAttribute(s_v2_versionAttributeName)) { + versionNumberText = atts.value(s_v2_versionAttributeName).toString(); + } + + if (versionNumberText == "2") { + decodeFromXMLWithStreamReaderVersionTwo(xml); + } + else { + xml.raiseError("TileTabsConfiguration invalid version=" + + versionNumberText); + } } else { - throw CaretException("Invalid version number attribute " - + versionNumberString); + xml.raiseError("TileTabsConfiguration first element is " + + xml.name().toString() + + " but should be " + + s_v1_rootTagName + + " or " + + s_v2_rootTagName); } } - catch (const CaretException& e) { - CaretLogSevere("Error parsing tile tabs configuration XML:\n" - + e.whatString() - + "\n\n" - + xmlString); + else { + xml.raiseError("TileTabsConfiguration failed to find start elemnent."); + } + + if (xml.hasError()) { + errorMessageOut = ("Tile Tabs Configuration Read Error at line number=" + + AString::number(xml.lineNumber()) + + " column number=" + + AString::number(xml.columnNumber()) + + " description=" + + xml.errorString()); return false; } + const bool debugFlag(false); + if (debugFlag) { + AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); + std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; + AString em; + TileTabsConfiguration temp; + QXmlStreamReader tempReader(xmlText); + tempReader.readNextStartElement(); + temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); + if (tempReader.hasError()) { + std::cout << "Decode error: " << tempReader.errorString() << std::endl; + } + else { + std::cout << "Decoded: " << temp.toString() << std::endl; + } + + std::cout << std::endl; + } return true; } /** - * Parse XML for Version One. + * Decode Version One of the tile tabs configuration from XML with stream reader. * - * @param doc - * XML DOM document. + * @param xml + * Stream XML parser. */ void -TileTabsConfiguration::parseVersionOneXML(QDomDocument& doc) +TileTabsConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml) { - QDomNodeList nameNodeList = doc.elementsByTagName(s_nameTagName); - if (nameNodeList.isEmpty()) { - throw CaretException("Error finding name tag"); + std::set invalidElements; + + AString name; + AString uniqueID; + std::vector rowStretchFactors; + std::vector columnStretchFactors; + int32_t numberOfRows(0); + int32_t numberOfColumns(0); + + QString message; + + while ( ! xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + const QStringRef tagName(xml.name()); + + if (tagName == s_v1_versionTagName) { + /* ignore */ + } + else if (tagName == s_nameTagName) { + name = xml.readElementText(); + } + else if (tagName == s_uniqueIdentifierTagName) { + uniqueID = xml.readElementText(); + } + else if (tagName == s_v1_rowStretchFactorsTagName) { + QXmlStreamAttributes atts = xml.attributes(); + if (atts.hasAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName)) { + numberOfRows = atts.value(s_v1_rowStretchFactorsSelectedCountAttributeName).toInt(); + } + + AString::toNumbers(xml.readElementText(), rowStretchFactors); + } + else if (tagName == s_v1_columnStretchFactorsTagName) { + QXmlStreamAttributes atts = xml.attributes(); + if (atts.hasAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName)) { + numberOfColumns = atts.value(s_v1_columnStretchFactorsSelectedCountAttributeName).toInt(); + } + AString::toNumbers(xml.readElementText(), columnStretchFactors); + } + else { + invalidElements.insert(tagName.toString()); + xml.skipCurrentElement(); + } + } } - QDomElement nameElement = nameNodeList.at(0).toElement(); - if (nameElement.isNull()) { - throw CaretException("Error finding name element"); + + static int32_t missingNameCounter = 1; + if (name.isEmpty()) { + name = ("Config_V1_" + + AString::number(missingNameCounter)); + missingNameCounter++; + } + if (uniqueID.isEmpty()) { + uniqueID = SystemUtilities::createUniqueID(); + } + if (rowStretchFactors.empty()) { + message.append(s_v1_rowStretchFactorsTagName + + " not found or invalid. "); + } + if (columnStretchFactors.empty()) { + message.append(s_v1_columnStretchFactorsTagName + + " not found or invalid. "); + } + if (numberOfRows <= 0) { + message.append(s_v1_rowStretchFactorsTagName + + " attribute " + + s_v1_rowStretchFactorsSelectedCountAttributeName + + " is missing or invalid." ); + } + if (numberOfRows <= 0) { + message.append(s_v1_columnStretchFactorsTagName + + " attribute " + + s_v1_columnStretchFactorsSelectedCountAttributeName + + " is missing or invalid." ); + } + + if ( ! invalidElements.empty()) { + /* + * If invalid elements were encountered, don't throw + */ + AString msg("Invalid element(s) ignored: "); + for (const auto s : invalidElements) { + msg.append(s + " "); + } + CaretLogWarning(msg); } - m_name = nameElement.text(); - QDomNodeList uniqueIdNodeList = doc.elementsByTagName(s_uniqueIdentifierTagName); - if (uniqueIdNodeList.isEmpty()) { - CaretLogWarning("Tile Tabs Configuration " - + m_name - + " is missing its unique identifier"); - m_uniqueIdentifier = SystemUtilities::createUniqueID(); + if (message.isEmpty()) { + m_name = name; + m_uniqueIdentifier = uniqueID; + + m_rows.clear(); + m_columns.clear(); + + for (int32_t i = 0; i < numberOfRows; i++) { + TileTabsGridRowColumnElement element; + CaretAssertVectorIndex(rowStretchFactors, i); + element.setWeightStretch(rowStretchFactors[i]); + element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); + element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); + m_rows.push_back(element); + } + CaretAssert(numberOfRows == static_cast(m_rows.size())); + + for (int32_t i = 0; i < numberOfColumns; i++) { + TileTabsGridRowColumnElement element; + CaretAssertVectorIndex(columnStretchFactors, i); + element.setWeightStretch(columnStretchFactors[i]); + element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); + element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); + m_columns.push_back(element); + } + CaretAssert(numberOfColumns == static_cast(m_columns.size())); } else { - QDomElement uniqueIdElement = uniqueIdNodeList.at(0).toElement(); - if (uniqueIdElement.isNull()) { - throw CaretException("Error finding unique identifier element"); + xml.raiseError(message); + } +} + +/** + * Decode Version Two of the tile tabs configuration from XML with stream reader. + * + * @param xml + * Stream XML parser. + */ +void +TileTabsConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml) +{ + m_rows.clear(); + m_columns.clear(); + m_uniqueIdentifier.clear(); + + std::set invalidElements; + + AString name; + AString uniqueID; + + QString message; + + enum class ReadMode { + OTHER, + COLUMNS, + ROWS + }; + ReadMode readMode = ReadMode::OTHER; + + AString centeringCorrectionTextString; + + while ( ! xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + const QStringRef tagName(xml.name()); + + if (tagName == s_nameTagName) { + name = xml.readElementText(); + } + else if (tagName == s_uniqueIdentifierTagName) { + uniqueID = xml.readElementText(); + } + else if (tagName == s_v2_columnsTagName) { + readMode = ReadMode::COLUMNS; + } + else if (tagName == s_v2_rowsTagName) { + readMode = ReadMode::ROWS; + } + else if (tagName == s_v2_centeringCorrectionName) { + centeringCorrectionTextString = xml.readElementText(); + } + else if (tagName == s_v2_elementTagName) { + switch (readMode) { + case ReadMode::OTHER: + CaretAssert(0); + break; + case ReadMode::COLUMNS: + { + AString errorMessage; + TileTabsGridRowColumnElement e; + if (decodeRowColumnElement(xml, e, errorMessage)) { + m_columns.push_back(e); + } + else { + message.append(errorMessage); + } + } + break; + case ReadMode::ROWS: + { + AString errorMessage; + TileTabsGridRowColumnElement e; + if (decodeRowColumnElement(xml, e, errorMessage)) { + m_rows.push_back(e); + } + else { + message.append(errorMessage); + } + } + break; + } + } + else { + invalidElements.insert(tagName.toString()); + xml.skipCurrentElement(); + } + } + else if (xml.isEndElement()) { + const QStringRef tagName(xml.name()); + + if (tagName == s_v2_columnsTagName) { + readMode = ReadMode::OTHER; + } + else if (tagName == s_v2_rowsTagName) { + readMode = ReadMode::OTHER; + } } - m_uniqueIdentifier = uniqueIdElement.text(); } - QDomNodeList rowNodeList = doc.elementsByTagName(s_rowStretchFactorsTagName); - if (rowNodeList.isEmpty()) { - throw CaretException("Error finding row stretch factors tag"); + static int32_t missingNameCounter = 1; + if (name.isEmpty()) { + name = ("Config_" + + AString::number(missingNameCounter)); + missingNameCounter++; } - QDomElement rowElement = rowNodeList.at(0).toElement(); - if (rowElement.isNull()) { - throw CaretException("Error finding row element"); + if (uniqueID.isEmpty()) { + uniqueID = SystemUtilities::createUniqueID(); } - const AString numberOfRowsString = rowElement.attribute(s_rowStretchFactorsSelectedCountAttributeName, - ""); - if (numberOfRowsString.isEmpty()) { - throw CaretException("Error finding number of rows attribute"); - } - const int32_t selectedNumberOfRows = numberOfRowsString.toInt(); - if (selectedNumberOfRows <= 0) { - throw CaretException("Invalid number of rows attribute " - + numberOfRowsString); + if ( ! invalidElements.empty()) { + /* + * If invalid elements were encountered, don't throw + */ + AString msg("Invalid element(s) ignored: "); + for (const auto s : invalidElements) { + msg.append(s + " "); + } + CaretLogWarning(msg); } - const AString totalNumberOfRowsString = rowElement.attribute(s_rowStretchFactorsTotalCountAttributeName, - ""); - int32_t totalNumberOfRows = 0; - if (totalNumberOfRowsString.isEmpty()) { - CaretLogWarning("Total number of rows attribute is missing."); + if (message.isEmpty()) { + m_name = name; + m_uniqueIdentifier = uniqueID; + + /* + * Only set centering correction if it is found. This allows usage + * of the default value in the event this is not found in the XML. + */ + if ( ! centeringCorrectionTextString.isEmpty()) { + m_centeringCorrectionEnabled = centeringCorrectionTextString.toBool(); + } + } else { - totalNumberOfRows = totalNumberOfRowsString.toInt(); + xml.raiseError(message); } +} + +/** + * Decode elements in a row or column. + * + * @param reader + * The XML stream reader. + * @param element + * row/column element that is read + * @param errorMessageOut + * Contains error information. + * @return + * True if read successfully, else false. + */ +bool +TileTabsConfiguration::decodeRowColumnElement(QXmlStreamReader& reader, + TileTabsGridRowColumnElement& element, + AString& errorMessageOut) +{ + const QXmlStreamAttributes atts = reader.attributes(); + + errorMessageOut.clear(); - const AString rowStretchFactorsText = rowElement.text(); - std::vector rowStretchFactors; - AString::toNumbers(rowStretchFactorsText, - rowStretchFactors); - if (static_cast(rowStretchFactors.size()) != totalNumberOfRows) { - throw CaretException("Stretch factor number of rows is " - + AString::number(totalNumberOfRows) - + " but have " - + AString::number(static_cast(rowStretchFactors.size())) - + " stretch factors."); + if (atts.hasAttribute(s_v2_contentTypeAttributeName)) { + bool validFlag(false); + const AString s = atts.value(s_v2_contentTypeAttributeName).toString(); + element.setContentType(TileTabsGridRowColumnContentTypeEnum::fromName(s, &validFlag)); + if ( ! validFlag) { + errorMessageOut.append("Content type \"" + s + "\" is not valid. "); + } + } + else { + errorMessageOut.append("Content type is missing. "); } - - QDomNodeList columnNodeList = doc.elementsByTagName(s_columnStretchFactorsTagName); - if (columnNodeList.isEmpty()) { - throw CaretException("Error finding column stretch factors tag"); + if (atts.hasAttribute(s_v2_stretchTypeAttributeName)) { + bool validFlag(false); + const AString s = atts.value(s_v2_stretchTypeAttributeName).toString(); + element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::fromName(s, &validFlag)); + if ( ! validFlag) { + errorMessageOut.append("Stretch type \"" + s + "\" is not valid. "); + } } - QDomElement columnElement = columnNodeList.at(0).toElement(); - if (columnElement.isNull()) { - throw CaretException("Error finding column element"); + else { + errorMessageOut.append("Stretch type is missing. "); } - const AString numberOfColumnsString = columnElement.attribute(s_columnStretchFactorsSelectedCountAttributeName, - ""); - if (numberOfColumnsString.isEmpty()) { - throw CaretException("Error finding number of columns attribute"); + if (atts.hasAttribute(s_v2_percentStretchAttributeName)) { + const float f = atts.value(s_v2_percentStretchAttributeName).toFloat(); + if ((f >= 0.0) && (f < 100.0)) { + element.setPercentStretch(f); + } + else { + errorMessageOut.append("Stretch percentage=" + AString::number(f) + " is invalid."); + } } - const int32_t selectedNumberOfColumns = numberOfColumnsString.toInt(); - if (selectedNumberOfColumns <= 0) { - throw CaretException("Invalid number of columns attribute " - + numberOfColumnsString); + else { + errorMessageOut.append("Stretch percentage is missing. "); } - - const AString totalNumberOfColumnsString = columnElement.attribute(s_columnStretchFactorsTotalCountAttributeName, - ""); - int32_t totalNumberOfColumns = 0; - if (totalNumberOfColumnsString.isEmpty()) { - CaretLogWarning("Total number of columns attribute is missing."); + if (atts.hasAttribute(s_v2_weightStretchAttributeName)) { + const float f = atts.value(s_v2_weightStretchAttributeName).toFloat(); + if ((f >= 0.0) && (f < 100.0)) { + element.setWeightStretch(f); + } + else { + errorMessageOut.append("Stretch weight=" + AString::number(f) + " is invalid."); + } } else { - totalNumberOfColumns = totalNumberOfColumnsString.toInt(); + errorMessageOut.append("Stretch weight is missing. "); } - - const AString columnStretchFactorsText = columnElement.text(); - std::vector columnStretchFactors; - AString::toNumbers(columnStretchFactorsText, - columnStretchFactors); - if (static_cast(columnStretchFactors.size()) != totalNumberOfColumns) { - throw CaretException("Stretch factor number of columns is " - + AString::number(totalNumberOfColumns) - + " but have " - + AString::number(static_cast(columnStretchFactors.size())) - + " stretch factors."); + + if (errorMessageOut.isEmpty()) { + return true; } + return false; +} + +/** + * Decode the tile tabs configuration from XML using DOM + * + * @param xmlString + * String containing XML. + * @param errorMessageOut + * Contains error information if decoding fails. + * @return + * True if configuration was successfully read from the XML, else false. + */ +bool +TileTabsConfiguration::decodeFromXML(const AString& xmlString, + AString& errorMessageOut) +{ + errorMessageOut.clear(); - setNumberOfRows(selectedNumberOfRows); - setNumberOfColumns(selectedNumberOfColumns); + return decodeFromXMLWithStreamReader(xmlString, + errorMessageOut); +} - const int32_t maxRowStretchFactors = std::min(totalNumberOfRows, - static_cast(m_rowStretchFactors.size())); - for (int32_t i = 0; i < maxRowStretchFactors; i++) { - m_rowStretchFactors[i] = rowStretchFactors[i]; +/** + * @return String version of an instance. + */ +AString +TileTabsConfiguration::toString() const +{ + AString s("Name: %1, Unique ID: %2\n"); + s = s.arg(m_name).arg(m_uniqueIdentifier); + + int32_t indx(0); + for (const auto item : m_columns) { + s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); + indx++; } - const int32_t maxColumnStretchFactors = std::min(totalNumberOfColumns, - static_cast(m_columnStretchFactors.size())); - for (int32_t i = 0; i < maxColumnStretchFactors; i++) { - m_columnStretchFactors[i] = columnStretchFactors[i]; + indx = 0; + for (const auto item : m_rows) { + s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); + indx++; } + + return s; } /** diff --git a/src/Common/TileTabsConfiguration.h b/src/Common/TileTabsConfiguration.h index 1b26b99b95eafc2c2cb1c279f9f68c7e05290cf5..87661333ff9234d0b12ed542b0277cc1a00148fb 100644 --- a/src/Common/TileTabsConfiguration.h +++ b/src/Common/TileTabsConfiguration.h @@ -23,10 +23,11 @@ #include "CaretException.h" #include "CaretObject.h" -#include "TileTabsConfigurationModeEnum.h" - -class QDomDocument; +#include "TileTabsGridModeEnum.h" +#include "TileTabsGridRowColumnElement.h" +class QXmlStreamReader; +class QXmlStreamWriter; namespace caret { @@ -48,7 +49,7 @@ namespace caret { bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, - const TileTabsConfigurationModeEnum::Enum configurationMode, + const TileTabsGridModeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut); @@ -66,34 +67,31 @@ namespace caret { void setNumberOfColumns(const int32_t numberOfColumns); - float getColumnStretchFactor(const int32_t columnIndex) const; - - void setColumnStretchFactor(const int32_t columnIndex, - const float stretchFactor); + TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex); + + const TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex) const; - float getRowStretchFactor(const int32_t rowIndex) const; + TileTabsGridRowColumnElement* getRow(const int32_t rowIndex); - void setRowStretchFactor(const int32_t rowIndex, - const float stretchFactor); + const TileTabsGridRowColumnElement* getRow(const int32_t rowIndex) const; AString encodeInXML() const; - bool decodeFromXML(const AString& xmlString); + AString encodeVersionInXML(const int32_t versionNumber) const; + + bool decodeFromXML(const AString& xmlString, + AString& errorMessageOut); void updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs); - static bool lessThanComparisonByName(const TileTabsConfiguration* ttc1, - const TileTabsConfiguration* ttc2); + bool isCenteringCorrectionEnabled() const; - /** - * @return Maximum number of rows in a tile tabs configuration - */ - static inline int32_t getMaximumNumberOfRows() { return 20; } + void setCenteringCorrectionEnabled(const bool status); - /** - * @return Maximum number of columns in a tile tabs configuration - */ - static inline int32_t getMaximumNumberOfColumns() { return 20; } + AString toString() const override; + + static bool lessThanComparisonByName(const TileTabsConfiguration* ttc1, + const TileTabsConfiguration* ttc2); static void getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, int32_t& numberOfRowsOut, @@ -104,7 +102,24 @@ namespace caret { private: void copyHelperTileTabsConfiguration(const TileTabsConfiguration& obj); - void parseVersionOneXML(QDomDocument& doc); + bool decodeFromXMLWithStreamReader(const AString& xmlString, + AString& errorMessageOut); + + void decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml); + + void decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml); + + AString encodeInXMLWithStreamWriterVersionOne() const; + + AString encodeInXMLWithStreamWriterVersionTwo() const; + + void encodeRowColumnElement(QXmlStreamWriter& writer, + const AString tagName, + const std::vector& elements) const; + + bool decodeRowColumnElement(QXmlStreamReader& reader, + TileTabsGridRowColumnElement& element, + AString& errorMessageOut); void initialize(); @@ -115,40 +130,62 @@ namespace caret { /** Unique identifier does not get copied */ AString m_uniqueIdentifier; - int32_t m_numberOfRows; + std::vector m_columns; - int32_t m_numberOfColumns; + std::vector m_rows; - std::vector m_rowStretchFactors; + bool m_centeringCorrectionEnabled = false; - std::vector m_columnStretchFactors; - - static const AString s_rootTagName; - static const AString s_versionTagName; static const AString s_nameTagName; static const AString s_uniqueIdentifierTagName; - static const AString s_versionNumberAttributeName; - static const AString s_columnStretchFactorsTagName; - static const AString s_columnStretchFactorsSelectedCountAttributeName; - static const AString s_columnStretchFactorsTotalCountAttributeName; - static const AString s_rowStretchFactorsTagName; - static const AString s_rowStretchFactorsSelectedCountAttributeName; - static const AString s_rowStretchFactorsTotalCountAttributeName; + + static const AString s_v1_rootTagName; + static const AString s_v1_versionTagName; + static const AString s_v1_versionNumberAttributeName; + static const AString s_v1_columnStretchFactorsTagName; + static const AString s_v1_columnStretchFactorsSelectedCountAttributeName; + static const AString s_v1_columnStretchFactorsTotalCountAttributeName; + static const AString s_v1_rowStretchFactorsTagName; + static const AString s_v1_rowStretchFactorsSelectedCountAttributeName; + static const AString s_v1_rowStretchFactorsTotalCountAttributeName; + + static const AString s_v2_rootTagName; + static const AString s_v2_versionAttributeName; + static const AString s_v2_columnsTagName; + static const AString s_v2_contentTypeAttributeName; + static const AString s_v2_elementTagName; + static const AString s_v2_percentStretchAttributeName; + static const AString s_v2_rowsTagName; + static const AString s_v2_stretchTypeAttributeName; + static const AString s_v2_weightStretchAttributeName; + static const AString s_v2_centeringCorrectionName; }; #ifdef __TILE_TABS_CONFIGURATION_DECLARE__ - const AString TileTabsConfiguration::s_rootTagName = "TileTabsConfiguration"; - const AString TileTabsConfiguration::s_versionTagName = "Version"; - const AString TileTabsConfiguration::s_versionNumberAttributeName = "Number"; const AString TileTabsConfiguration::s_nameTagName = "Name"; const AString TileTabsConfiguration::s_uniqueIdentifierTagName = "UniqueIdentifier"; - const AString TileTabsConfiguration::s_columnStretchFactorsTagName = "ColumnStretchFactors"; - const AString TileTabsConfiguration::s_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; - const AString TileTabsConfiguration::s_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; - const AString TileTabsConfiguration::s_rowStretchFactorsTagName = "RowStretchFactors"; - const AString TileTabsConfiguration::s_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; - const AString TileTabsConfiguration::s_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; + + const AString TileTabsConfiguration::s_v1_rootTagName = "TileTabsConfiguration"; + const AString TileTabsConfiguration::s_v1_versionTagName = "Version"; + const AString TileTabsConfiguration::s_v1_versionNumberAttributeName = "Number"; + const AString TileTabsConfiguration::s_v1_columnStretchFactorsTagName = "ColumnStretchFactors"; + const AString TileTabsConfiguration::s_v1_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; + const AString TileTabsConfiguration::s_v1_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; + const AString TileTabsConfiguration::s_v1_rowStretchFactorsTagName = "RowStretchFactors"; + const AString TileTabsConfiguration::s_v1_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; + const AString TileTabsConfiguration::s_v1_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; + + const AString TileTabsConfiguration::s_v2_rootTagName = "TileTabsConfigurationTwo"; + const AString TileTabsConfiguration::s_v2_versionAttributeName = "Version"; + const AString TileTabsConfiguration::s_v2_columnsTagName = "Columns"; + const AString TileTabsConfiguration::s_v2_contentTypeAttributeName = "ContentType"; + const AString TileTabsConfiguration::s_v2_elementTagName = "Element"; + const AString TileTabsConfiguration::s_v2_percentStretchAttributeName = "PercentStretch"; + const AString TileTabsConfiguration::s_v2_rowsTagName = "Rows"; + const AString TileTabsConfiguration::s_v2_stretchTypeAttributeName = "StretchType"; + const AString TileTabsConfiguration::s_v2_weightStretchAttributeName = "WeightStretch"; + const AString TileTabsConfiguration::s_v2_centeringCorrectionName = "CenteringCorrection"; #endif // __TILE_TABS_CONFIGURATION_DECLARE__ } // namespace diff --git a/src/Common/TileTabsConfigurationLayoutTypeEnum.cxx b/src/Common/TileTabsConfigurationLayoutTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fe45e41cb3c6517a8fb38f0e1389a191332ad7a5 --- /dev/null +++ b/src/Common/TileTabsConfigurationLayoutTypeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ +#include "TileTabsConfigurationLayoutTypeEnum.h" +#undef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::TileTabsConfigurationLayoutTypeEnum + * \brief Types of tile tabs layouts + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_tileTabsConfigurationLayoutTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void tileTabsConfigurationLayoutTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "TileTabsConfigurationLayoutTypeEnum.h" + * + * Instatiate: + * m_tileTabsConfigurationLayoutTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_tileTabsConfigurationLayoutTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_tileTabsConfigurationLayoutTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(tileTabsConfigurationLayoutTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_tileTabsConfigurationLayoutTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const TileTabsConfigurationLayoutTypeEnum::Enum VARIABLE = m_tileTabsConfigurationLayoutTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +TileTabsConfigurationLayoutTypeEnum::TileTabsConfigurationLayoutTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +TileTabsConfigurationLayoutTypeEnum::~TileTabsConfigurationLayoutTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +TileTabsConfigurationLayoutTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(TileTabsConfigurationLayoutTypeEnum(GRID, + "GRID", + "Grid")); + + enumData.push_back(TileTabsConfigurationLayoutTypeEnum(MANUAL, + "MANUAL", + "Manual")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const TileTabsConfigurationLayoutTypeEnum* +TileTabsConfigurationLayoutTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const TileTabsConfigurationLayoutTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsConfigurationLayoutTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsConfigurationLayoutTypeEnum::Enum +TileTabsConfigurationLayoutTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsConfigurationLayoutTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsConfigurationLayoutTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsConfigurationLayoutTypeEnum::Enum +TileTabsConfigurationLayoutTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsConfigurationLayoutTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +TileTabsConfigurationLayoutTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +TileTabsConfigurationLayoutTypeEnum::Enum +TileTabsConfigurationLayoutTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsConfigurationLayoutTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +TileTabsConfigurationLayoutTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsConfigurationLayoutTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(TileTabsConfigurationLayoutTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsConfigurationLayoutTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(TileTabsConfigurationLayoutTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/TileTabsConfigurationLayoutTypeEnum.h b/src/Common/TileTabsConfigurationLayoutTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..8a57604bdf62ac5b762b961d3399091f08aa9730 --- /dev/null +++ b/src/Common/TileTabsConfigurationLayoutTypeEnum.h @@ -0,0 +1,104 @@ +#ifndef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ +#define __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class TileTabsConfigurationLayoutTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** */ + GRID, + /** */ + MANUAL + }; + + + ~TileTabsConfigurationLayoutTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + TileTabsConfigurationLayoutTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const TileTabsConfigurationLayoutTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ +std::vector TileTabsConfigurationLayoutTypeEnum::enumData; +bool TileTabsConfigurationLayoutTypeEnum::initializedFlag = false; +int32_t TileTabsConfigurationLayoutTypeEnum::integerCodeCounter = 0; +#endif // __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ diff --git a/src/Common/TileTabsGridLayoutConfiguration.cxx b/src/Common/TileTabsGridLayoutConfiguration.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dbe571bf669530c64eb2da88a10aa080ecb4bc8f --- /dev/null +++ b/src/Common/TileTabsGridLayoutConfiguration.cxx @@ -0,0 +1,1092 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include + +#define __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ +#include "TileTabsGridLayoutConfiguration.h" +#undef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "SystemUtilities.h" + +using namespace caret; + + + +/** + * \class caret::TileTabsGridLayoutConfiguration + * \brief Defines a tile tabs configuration + * \ingroup Common + */ + +/** + * Constructor that creates a 2 by 2 configuration. + */ +TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration() +: TileTabsBaseConfiguration(TileTabsConfigurationLayoutTypeEnum::GRID) +{ + initialize(); +} + +/** + * Destructor. + */ +TileTabsGridLayoutConfiguration::~TileTabsGridLayoutConfiguration() +{ +} + +/** + * Copy constructor. + * + * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() + * + * @param obj + * Object that is copied. + */ +TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj) +: TileTabsBaseConfiguration(obj) +{ + initialize(); + this->copyHelperTileTabsGridLayoutConfiguration(obj); +} + +/** + * Assignment operator. + * + * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() + * + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +TileTabsGridLayoutConfiguration& +TileTabsGridLayoutConfiguration::operator=(const TileTabsGridLayoutConfiguration& obj) +{ + if (this != &obj) { + TileTabsBaseConfiguration::operator=(obj); + this->copyHelperTileTabsGridLayoutConfiguration(obj); + } + return *this; +} + +/** + * Copy this instance and give it a new unique identifier. + * Note that copy constructor does not create a new unique identifier. + * + * @return The new Copy. + */ +TileTabsGridLayoutConfiguration* +TileTabsGridLayoutConfiguration::newCopyWithNewUniqueIdentifier() const +{ + TileTabsGridLayoutConfiguration* newCopy = new TileTabsGridLayoutConfiguration(*this); + CaretAssert(newCopy); + return newCopy; +} + + +/** + * Initialize an instance of a tile tabs configuration. + */ +void +TileTabsGridLayoutConfiguration::initialize() +{ + setNumberOfRows(2); + setNumberOfColumns(2); + + m_centeringCorrectionEnabled = false; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +TileTabsGridLayoutConfiguration::copyHelperTileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj) +{ + if (this == &obj) { + return; + } + + copyHelperTileTabsBaseConfiguration(obj); + m_columns = obj.m_columns; + m_rows = obj.m_rows; + m_centeringCorrectionEnabled = obj.m_centeringCorrectionEnabled; +} + +/** + * Copies the tile tabs configuration rows, columns, and + * stretch factors. Name is NOT copied. + */ +void +TileTabsGridLayoutConfiguration::copy(const TileTabsGridLayoutConfiguration& rhs) +{ + AString savedName = getName(); + copyHelperTileTabsGridLayoutConfiguration(rhs); + setName(savedName); +} + +/** + * Get infoformation for the given elemnent in the columns. + * + * @param Information for element. + */ +TileTabsGridRowColumnElement* +TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) +{ + CaretAssertVectorIndex(m_columns, columnIndex); + return &m_columns[columnIndex]; +} + +/** + * Get infoformation for the given elemnent in the columns. + * + * @param Information for element. + */ +const TileTabsGridRowColumnElement* +TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) const +{ + CaretAssertVectorIndex(m_columns, columnIndex); + return &m_columns[columnIndex]; +} + +/** + * Get infoformation for the given elemnent in the rows. + * + * @param Information for element. + */ +TileTabsGridRowColumnElement* +TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) +{ + CaretAssertVectorIndex(m_rows, rowIndex); + return &m_rows[rowIndex]; +} + +/** + * Get infoformation for the given elemnent in the rows. + * + * @param Information for element. + */ +const TileTabsGridRowColumnElement* +TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) const +{ + CaretAssertVectorIndex(m_rows, rowIndex); + return &m_rows[rowIndex]; +} + +/** + * Get the row heights and column widths for this tile tabs configuration using the + * given window width and height. + * + * @param windowWidth + * Width of window. + * @param windowHeight + * Height of window. + * @param numberOfModelsToDraw + * Number of models to draw. + * @param configurationMode + * The tile tabs configuration mode + * @param rowHeightsOut + * Output containing height of each row. + * @param columnWidthsOut + * Output containing width of each column. + * @return + * True if the ouput is valid, else false. + */ +bool +TileTabsGridLayoutConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, + const int32_t windowHeight, + const int32_t numberOfModelsToDraw, + const TileTabsGridModeEnum::Enum configurationMode, + std::vector& rowHeightsOut, + std::vector& columnWidthsOut) +{ + /* + * NOTE: When computing widths and heights, do not round. + * Rounding may cause the bottom most row or column to extend + * outside the graphics region. Shrinking the last row or + * column is not desired since it might cause the last model + * to be drawn slightly smaller than the others. + */ + + int32_t numRows = 0; + int32_t numCols = 0; + + rowHeightsOut.clear(); + columnWidthsOut.clear(); + + switch (configurationMode) { + case TileTabsGridModeEnum::AUTOMATIC: + { + /* + * Update number of rows/columns in the default configuration + * so that if a scene is saved, the correct number of rows + * and columns are saved to the scene. + */ + updateAutomaticConfigurationRowsAndColumns(numberOfModelsToDraw); + numRows = getNumberOfRows(); + numCols = getNumberOfColumns(); + + for (int32_t i = 0; i < numRows; i++) { + rowHeightsOut.push_back(windowHeight / numRows); + } + for (int32_t i = 0; i < numCols; i++) { + columnWidthsOut.push_back(windowWidth / numCols); + } + } break; + case TileTabsGridModeEnum::CUSTOM: + { + /* + * Rows/columns from user configuration + */ + numRows = getNumberOfRows(); + numCols = getNumberOfColumns(); + + /* + * Determine height of each row + */ + float rowPercentTotal = 0.0; + float rowStretchTotal = 0.0; + for (int32_t i = 0; i < numRows; i++) { + const TileTabsGridRowColumnElement* e = getRow(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + rowPercentTotal += (e->getPercentStretch() / 100.0); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + rowStretchTotal += e->getWeightStretch(); + break; + } + } + + float windowWeightHeight = windowHeight; + if (rowPercentTotal > 0.0) { + if (rowPercentTotal >= 1.0) { + windowWeightHeight = 0.0; + } + else { + windowWeightHeight = (1.0 - rowPercentTotal) * windowHeight; + } + } + for (int32_t i = 0; i < numRows; i++) { + int32_t h = 0; + const TileTabsGridRowColumnElement* e = getRow(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + h = (e->getPercentStretch() / 100.0) * windowHeight; + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + if (rowStretchTotal > 0.0) { + h = static_cast((e->getWeightStretch() / rowStretchTotal) + * windowWeightHeight); + } + break; + } + + rowHeightsOut.push_back(h); + } + + /* + * Determine width of each column + */ + float columnPercentTotal = 0.0; + float columnStretchTotal = 0.0; + for (int32_t i = 0; i < numCols; i++) { + const TileTabsGridRowColumnElement* e = getColumn(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + columnPercentTotal += (e->getPercentStretch() / 100.0); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + columnStretchTotal += e->getWeightStretch(); + break; + } + } + + float windowWeightWidth = windowWidth; + if (columnPercentTotal > 0.0) { + if (columnPercentTotal >= 1.0) { + windowWeightWidth = 0.0; + } + else { + windowWeightWidth = (1.0 - columnPercentTotal) * windowWidth; + } + } + + for (int32_t i = 0; i < numCols; i++) { + int32_t w = 0; + const TileTabsGridRowColumnElement* e = getColumn(i); + switch (e->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + w = (e->getPercentStretch() / 100.0) * windowWidth; + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + if (columnStretchTotal > 0.0) { + w = static_cast((e->getWeightStretch() / columnStretchTotal) + * windowWeightWidth); + } + break; + } + columnWidthsOut.push_back(w); + } + } break; + } + + if ((numRows == static_cast(rowHeightsOut.size())) + && (numCols == static_cast(columnWidthsOut.size()))) { +// /* +// * Verify all rows fit within the window +// */ +// int32_t rowHeightsSum = 0; +// for (int32_t i = 0; i < numRows; i++) { +// rowHeightsSum += rowHeightsOut[i]; +// } +// if (rowHeightsSum > windowHeight) { +// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); +//// rowHeightsOut[numRows - 1] -= (rowHeightsSum - windowHeight); +// } +// +// /* +// * Adjust width of last column so that it does not extend beyond viewport +// */ +// int32_t columnWidthsSum = 0; +// for (int32_t i = 0; i < numCols; i++) { +// columnWidthsSum += columnWidthsOut[i]; +// } +// if (columnWidthsSum > windowWidth) { +// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); +//// columnWidthsOut[numCols - 1] = columnWidthsSum - windowWidth; +// } +// +// CaretLogFiner("Tile Tabs Row Heights: " +// + AString::fromNumbers(rowHeightsOut, ", ")); +// CaretLogFiner("Tile Tabs Column Widths: " +// + AString::fromNumbers(columnWidthsOut, ", ")); + return true; + } + + const QString msg("Row and heights failed rows=" + + AString::number(numRows) + + " rowHeights=" + + AString::number(rowHeightsOut.size()) + + " cols=" + + AString::number(numCols) + + " rowHeights=" + + AString::number(columnWidthsOut.size())); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return false; +} + +/** + * @return Number of rows. + */ +int32_t +TileTabsGridLayoutConfiguration::getNumberOfRows() const +{ + return m_rows.size(); +} + +/** + * Set number of rows. + * + * @param numberOfRows + * New number of rows. + */ +void +TileTabsGridLayoutConfiguration::setNumberOfRows(const int32_t numberOfRows) +{ + m_rows.resize(numberOfRows); +} + +/** + * @return Number of columns. + */ +int32_t +TileTabsGridLayoutConfiguration::getNumberOfColumns() const +{ + return m_columns.size(); +} + +/** + * Set number of rows. + * + * @param numberOfColumns + * New number of rows. + */ +void +TileTabsGridLayoutConfiguration::setNumberOfColumns(const int32_t numberOfColumns) +{ + m_columns.resize(numberOfColumns); +} + +/** + * Get the number of rows and columns for an automatic layout with the + * given number of tabs. + * @param numberOfTabs + * Number of tabs. + * @param numberOfRowsOut + * Output with number of rows. + * @param numberOfColumnsOut + * Output with number of columns. + */ +void +TileTabsGridLayoutConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, + int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut) +{ + CaretAssert(numberOfTabs >= 0); + + numberOfRowsOut = (int)std::sqrt((double)numberOfTabs); + numberOfColumnsOut = numberOfRowsOut; + int32_t row2 = numberOfRowsOut * numberOfRowsOut; + if (row2 < numberOfTabs) { + numberOfColumnsOut++; + } + if ((numberOfRowsOut * numberOfColumnsOut) < numberOfTabs) { + numberOfRowsOut++; + } +} + +/** + * @return True if the centering correction is enabled. + */ +bool +TileTabsGridLayoutConfiguration::isCenteringCorrectionEnabled() const +{ + return m_centeringCorrectionEnabled; +} + +/** + * Set the enabled status of the centering correction + * + * @param status + * New status for enabling the centering correction + */ +void +TileTabsGridLayoutConfiguration::setCenteringCorrectionEnabled(const bool status) +{ + m_centeringCorrectionEnabled = status; +} + + +/** + * Updates the number of rows and columns for the automatic configuration + * based upon the number of tabs. + * + * Since screen width typically exceeds height, ensure the number of + * columns is always greater than the number of rows. + */ +void +TileTabsGridLayoutConfiguration::updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs) +{ + int32_t numRows(0), numCols(0); + getRowsAndColumnsForNumberOfTabs(numberOfTabs, + numRows, + numCols); + + setNumberOfRows(numRows); + setNumberOfColumns(numCols); +} + +/** + * Encode the configuration in XML. + * + * @param xmlTextOut + * Contains XML representation of configuration. + */ +void +TileTabsGridLayoutConfiguration::encodeInXML(AString& xmlTextOut) const +{ + xmlTextOut = encodeVersionInXML(2); +} + +/** + * @return Encoded tile tabs configuration in XML + * using the give XML version of TileTabsGridLayoutConfiguration. + */ +AString +TileTabsGridLayoutConfiguration::encodeVersionInXML(const int32_t versionNumber) const +{ + AString s; + + switch (versionNumber) { + case 1: + s = encodeInXMLWithStreamWriterVersionOne(); + break; + case 2: + s = encodeInXMLWithStreamWriterVersionTwo(); + break; + default: + CaretAssertMessage(0, "Requested invalid version=" + AString::number(versionNumber)); + break; + } + + return s; +} + + +/** + * @return Encoded tile tabs configuration in XML with Stream Writer + */ +AString +TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionOne() const +{ + AString xmlString; + QXmlStreamWriter writer(&xmlString); + writer.setAutoFormatting(true); + + writer.writeStartElement(s_v1_rootTagName); + + writer.writeStartElement(s_v1_versionTagName); + writer.writeAttribute(s_v1_versionNumberAttributeName, "1"); + writer.writeEndElement(); + + writer.writeTextElement(s_nameTagName, getName()); + writer.writeTextElement(s_uniqueIdentifierTagName, getUniqueIdentifier()); + + const int32_t numberOfRows = getNumberOfRows(); + writer.writeStartElement(s_v1_rowStretchFactorsTagName); + writer.writeAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName, AString::number(numberOfRows)); + writer.writeAttribute(s_v1_rowStretchFactorsTotalCountAttributeName, AString::number(numberOfRows)); + std::vector rowStretchFactors; + for (const auto e : m_rows) { + rowStretchFactors.push_back(e.getWeightStretch()); + } + writer.writeCharacters(AString::fromNumbers(rowStretchFactors, " ")); + writer.writeEndElement(); + + const int32_t numberOfColumns = getNumberOfColumns(); + writer.writeStartElement(s_v1_columnStretchFactorsTagName); + writer.writeAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName, AString::number(numberOfColumns)); + writer.writeAttribute(s_v1_columnStretchFactorsTotalCountAttributeName, AString::number(numberOfColumns)); + std::vector columnStretchFactors; + for (const auto e : m_columns) { + columnStretchFactors.push_back(e.getWeightStretch()); + } + writer.writeCharacters(AString::fromNumbers(columnStretchFactors, " ")); + writer.writeEndElement(); + + writer.writeEndElement(); + + return xmlString; +} + +/** + * @return Encoded tile tabs configuration in XML with Stream Writer + */ +AString +TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionTwo() const +{ + AString xmlString; + QXmlStreamWriter writer(&xmlString); + writer.setAutoFormatting(true); + + writer.writeStartElement(s_v2_rootTagName); + writer.writeAttribute(s_v2_versionAttributeName, "2"); + + writer.writeTextElement(s_nameTagName, getName()); + writer.writeTextElement(s_uniqueIdentifierTagName, getUniqueIdentifier()); + writer.writeTextElement(s_v2_centeringCorrectionName, AString::fromBool(m_centeringCorrectionEnabled)); + + encodeRowColumnElement(writer, s_v2_columnsTagName, m_columns); + encodeRowColumnElement(writer, s_v2_rowsTagName, m_rows); + + writer.writeEndElement(); + + return xmlString; +} + +/** + * Encode a vector of elements into xml. + * + * @param writer + * The XML stream writer. + * @param tagName + * Tag name for enclosing the elements. + * @param elements + * Vector of elements added to XML. + */ +void +TileTabsGridLayoutConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer, + const AString tagName, + const std::vector& elements) const +{ + writer.writeStartElement(tagName); + + for (const auto e : elements) { + writer.writeStartElement(s_v2_elementTagName); + writer.writeAttribute(s_v2_contentTypeAttributeName, TileTabsGridRowColumnContentTypeEnum::toName(e.getContentType())); + writer.writeAttribute(s_v2_stretchTypeAttributeName, TileTabsGridRowColumnStretchTypeEnum::toName(e.getStretchType())); + writer.writeAttribute(s_v2_percentStretchAttributeName, AString::number(e.getPercentStretch(), 'f', 2)); + writer.writeAttribute(s_v2_weightStretchAttributeName, AString::number(e.getWeightStretch(), 'f', 2)); + writer.writeEndElement(); + } + + writer.writeEndElement(); +} + +/** + * Decode the configuration using the given XML stream reader and root element + * If there is an error, xml.raiseError() should be used to specify the error + * and caller of this method can test for the error using xml.isError(). + * + * @param xml + * The XML stream reader. + * @param rootElement + * The root element. + */ +void +TileTabsGridLayoutConfiguration::decodeFromXML(QXmlStreamReader& xml, + const QString& rootElementText) +{ + CaretAssert( ! rootElementText.isEmpty()); + + m_centeringCorrectionEnabled = false; + + if (rootElementText == s_v1_rootTagName) { + decodeFromXMLWithStreamReaderVersionOne(xml); + } + else if (rootElementText == s_v2_rootTagName) { + /* + * Version 2 uses a different root tag than version 1. The reason is that + * the older code for decoding from XML will throw an exception if it + * encounters invalid elements or the version number is invalid. The problem + * is that the exception is not caught and wb_view will terminate. + */ + QString versionNumberText("Unknown"); + const QXmlStreamAttributes atts = xml.attributes(); + if (atts.hasAttribute(s_v2_versionAttributeName)) { + versionNumberText = atts.value(s_v2_versionAttributeName).toString(); + } + + if (versionNumberText == "2") { + decodeFromXMLWithStreamReaderVersionTwo(xml); + } + else { + xml.raiseError("TileTabsGridLayoutConfiguration invalid version=" + + versionNumberText); + } + } + else { + xml.raiseError("TileTabsGridLayoutConfiguration first element is " + + xml.name().toString() + + " but should be " + + s_v1_rootTagName + + " or " + + s_v2_rootTagName); + } + +// const bool debugFlag(false); +// if (debugFlag) { +// AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); +// std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; +// AString em; +// TileTabsGridLayoutConfiguration temp; +// QXmlStreamReader tempReader(xmlText); +// tempReader.readNextStartElement(); +// temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); +// if (tempReader.hasError()) { +// std::cout << "Decode error: " << tempReader.errorString() << std::endl; +// } +// else { +// std::cout << "Decoded: " << temp.toString() << std::endl; +// } +// +// std::cout << std::endl; +// } +// return true; +} + +/** + * Decode Version One of the tile tabs configuration from XML with stream reader. + * + * @param xml + * Stream XML parser. + */ +void +TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml) +{ + std::set invalidElements; + + AString name; + AString uniqueID; + std::vector rowStretchFactors; + std::vector columnStretchFactors; + int32_t numberOfRows(0); + int32_t numberOfColumns(0); + + QString message; + + while ( ! xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + const QStringRef tagName(xml.name()); + + if (tagName == s_v1_versionTagName) { + /* ignore */ + } + else if (tagName == s_nameTagName) { + name = xml.readElementText(); + } + else if (tagName == s_uniqueIdentifierTagName) { + uniqueID = xml.readElementText(); + } + else if (tagName == s_v1_rowStretchFactorsTagName) { + QXmlStreamAttributes atts = xml.attributes(); + if (atts.hasAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName)) { + numberOfRows = atts.value(s_v1_rowStretchFactorsSelectedCountAttributeName).toInt(); + } + + AString::toNumbers(xml.readElementText(), rowStretchFactors); + } + else if (tagName == s_v1_columnStretchFactorsTagName) { + QXmlStreamAttributes atts = xml.attributes(); + if (atts.hasAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName)) { + numberOfColumns = atts.value(s_v1_columnStretchFactorsSelectedCountAttributeName).toInt(); + } + AString::toNumbers(xml.readElementText(), columnStretchFactors); + } + else { + invalidElements.insert(tagName.toString()); + xml.skipCurrentElement(); + } + } + } + + static int32_t missingNameCounter = 1; + if (name.isEmpty()) { + name = ("Config_V1_" + + AString::number(missingNameCounter)); + missingNameCounter++; + } + if (uniqueID.isEmpty()) { + uniqueID = SystemUtilities::createUniqueID(); + } + if (rowStretchFactors.empty()) { + message.append(s_v1_rowStretchFactorsTagName + + " not found or invalid. "); + } + if (columnStretchFactors.empty()) { + message.append(s_v1_columnStretchFactorsTagName + + " not found or invalid. "); + } + if (numberOfRows <= 0) { + message.append(s_v1_rowStretchFactorsTagName + + " attribute " + + s_v1_rowStretchFactorsSelectedCountAttributeName + + " is missing or invalid." ); + } + if (numberOfRows <= 0) { + message.append(s_v1_columnStretchFactorsTagName + + " attribute " + + s_v1_columnStretchFactorsSelectedCountAttributeName + + " is missing or invalid." ); + } + + if ( ! invalidElements.empty()) { + /* + * If invalid elements were encountered, don't throw + */ + AString msg("Invalid element(s) ignored: "); + for (const auto s : invalidElements) { + msg.append(s + " "); + } + CaretLogWarning(msg); + } + + if (message.isEmpty()) { + setName(name); + setUniqueIdentifierProtected(uniqueID); + + m_rows.clear(); + m_columns.clear(); + + for (int32_t i = 0; i < numberOfRows; i++) { + TileTabsGridRowColumnElement element; + CaretAssertVectorIndex(rowStretchFactors, i); + element.setWeightStretch(rowStretchFactors[i]); + element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); + element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); + m_rows.push_back(element); + } + CaretAssert(numberOfRows == static_cast(m_rows.size())); + + for (int32_t i = 0; i < numberOfColumns; i++) { + TileTabsGridRowColumnElement element; + CaretAssertVectorIndex(columnStretchFactors, i); + element.setWeightStretch(columnStretchFactors[i]); + element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); + element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); + m_columns.push_back(element); + } + CaretAssert(numberOfColumns == static_cast(m_columns.size())); + } + else { + xml.raiseError(message); + } +} + +/** + * Decode Version Two of the tile tabs configuration from XML with stream reader. + * + * @param xml + * Stream XML parser. + */ +void +TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml) +{ + m_rows.clear(); + m_columns.clear(); + setName(""); + setUniqueIdentifierProtected(""); + + std::set invalidElements; + + AString name; + AString uniqueID; + + QString message; + + enum class ReadMode { + OTHER, + COLUMNS, + ROWS + }; + ReadMode readMode = ReadMode::OTHER; + + AString centeringCorrectionTextString; + + while ( ! xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + const QStringRef tagName(xml.name()); + + if (tagName == s_nameTagName) { + name = xml.readElementText(); + } + else if (tagName == s_uniqueIdentifierTagName) { + uniqueID = xml.readElementText(); + } + else if (tagName == s_v2_columnsTagName) { + readMode = ReadMode::COLUMNS; + } + else if (tagName == s_v2_rowsTagName) { + readMode = ReadMode::ROWS; + } + else if (tagName == s_v2_centeringCorrectionName) { + centeringCorrectionTextString = xml.readElementText(); + } + else if (tagName == s_v2_elementTagName) { + switch (readMode) { + case ReadMode::OTHER: + CaretAssert(0); + break; + case ReadMode::COLUMNS: + { + AString errorMessage; + TileTabsGridRowColumnElement e; + if (decodeRowColumnElement(xml, e, errorMessage)) { + m_columns.push_back(e); + } + else { + message.append(errorMessage); + } + } + break; + case ReadMode::ROWS: + { + AString errorMessage; + TileTabsGridRowColumnElement e; + if (decodeRowColumnElement(xml, e, errorMessage)) { + m_rows.push_back(e); + } + else { + message.append(errorMessage); + } + } + break; + } + } + else { + invalidElements.insert(tagName.toString()); + xml.skipCurrentElement(); + } + } + else if (xml.isEndElement()) { + const QStringRef tagName(xml.name()); + + if (tagName == s_v2_columnsTagName) { + readMode = ReadMode::OTHER; + } + else if (tagName == s_v2_rowsTagName) { + readMode = ReadMode::OTHER; + } + } + } + + static int32_t missingNameCounter = 1; + if (name.isEmpty()) { + name = ("Config_" + + AString::number(missingNameCounter)); + missingNameCounter++; + } + if (uniqueID.isEmpty()) { + uniqueID = SystemUtilities::createUniqueID(); + } + + if ( ! invalidElements.empty()) { + /* + * If invalid elements were encountered, don't throw + */ + AString msg("Invalid element(s) ignored: "); + for (const auto s : invalidElements) { + msg.append(s + " "); + } + CaretLogWarning(msg); + } + + if (message.isEmpty()) { + setName(name); + setUniqueIdentifierProtected(uniqueID); + + /* + * Only set centering correction if it is found. This allows usage + * of the default value in the event this is not found in the XML. + */ + if ( ! centeringCorrectionTextString.isEmpty()) { + m_centeringCorrectionEnabled = centeringCorrectionTextString.toBool(); + } + + } + else { + xml.raiseError(message); + } +} + +/** + * Decode elements in a row or column. + * + * @param reader + * The XML stream reader. + * @param element + * row/column element that is read + * @param errorMessageOut + * Contains error information. + * @return + * True if read successfully, else false. + */ +bool +TileTabsGridLayoutConfiguration::decodeRowColumnElement(QXmlStreamReader& reader, + TileTabsGridRowColumnElement& element, + AString& errorMessageOut) +{ + const QXmlStreamAttributes atts = reader.attributes(); + + errorMessageOut.clear(); + + if (atts.hasAttribute(s_v2_contentTypeAttributeName)) { + bool validFlag(false); + const AString s = atts.value(s_v2_contentTypeAttributeName).toString(); + element.setContentType(TileTabsGridRowColumnContentTypeEnum::fromName(s, &validFlag)); + if ( ! validFlag) { + errorMessageOut.append("Content type \"" + s + "\" is not valid. "); + } + } + else { + errorMessageOut.append("Content type is missing. "); + } + + if (atts.hasAttribute(s_v2_stretchTypeAttributeName)) { + bool validFlag(false); + const AString s = atts.value(s_v2_stretchTypeAttributeName).toString(); + element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::fromName(s, &validFlag)); + if ( ! validFlag) { + errorMessageOut.append("Stretch type \"" + s + "\" is not valid. "); + } + } + else { + errorMessageOut.append("Stretch type is missing. "); + } + + if (atts.hasAttribute(s_v2_percentStretchAttributeName)) { + const float f = atts.value(s_v2_percentStretchAttributeName).toFloat(); + if ((f >= 0.0) && (f < 100.0)) { + element.setPercentStretch(f); + } + else { + errorMessageOut.append("Stretch percentage=" + AString::number(f) + " is invalid."); + } + } + else { + errorMessageOut.append("Stretch percentage is missing. "); + } + + if (atts.hasAttribute(s_v2_weightStretchAttributeName)) { + const float f = atts.value(s_v2_weightStretchAttributeName).toFloat(); + if ((f >= 0.0) && (f < 100.0)) { + element.setWeightStretch(f); + } + else { + errorMessageOut.append("Stretch weight=" + AString::number(f) + " is invalid."); + } + } + else { + errorMessageOut.append("Stretch weight is missing. "); + } + + if (errorMessageOut.isEmpty()) { + return true; + } + return false; +} + +/** + * @return String version of an instance. + */ +AString +TileTabsGridLayoutConfiguration::toString() const +{ + AString s = TileTabsBaseConfiguration::toString(); + + int32_t indx(0); + for (const auto item : m_columns) { + s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); + indx++; + } + indx = 0; + for (const auto item : m_rows) { + s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); + indx++; + } + + return s; +} + diff --git a/src/Common/TileTabsGridLayoutConfiguration.h b/src/Common/TileTabsGridLayoutConfiguration.h new file mode 100644 index 0000000000000000000000000000000000000000..35eeb543b8478aefbf303fa6061a7156529dfe80 --- /dev/null +++ b/src/Common/TileTabsGridLayoutConfiguration.h @@ -0,0 +1,178 @@ +#ifndef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ +#define __TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretException.h" +#include "TileTabsBaseConfiguration.h" +#include "TileTabsGridModeEnum.h" +#include "TileTabsGridRowColumnElement.h" + +class QXmlStreamReader; +class QXmlStreamWriter; + +namespace caret { + + class TileTabsGridLayoutConfiguration : public TileTabsBaseConfiguration { + + public: + TileTabsGridLayoutConfiguration(); + + virtual ~TileTabsGridLayoutConfiguration(); + + TileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj); + + TileTabsGridLayoutConfiguration& operator=(const TileTabsGridLayoutConfiguration& obj); + + void copy(const TileTabsGridLayoutConfiguration& rhs); + + virtual TileTabsGridLayoutConfiguration* newCopyWithNewUniqueIdentifier() const override; + + bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, + const int32_t windowHeight, + const int32_t numberOfModelsToDraw, + const TileTabsGridModeEnum::Enum configurationMode, + std::vector& rowHeightsOut, + std::vector& columnWidthsOut); + + int32_t getNumberOfRows() const; + + void setNumberOfRows(const int32_t numberOfRows); + + int32_t getNumberOfColumns() const; + + void setNumberOfColumns(const int32_t numberOfColumns); + + TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex); + + const TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex) const; + + TileTabsGridRowColumnElement* getRow(const int32_t rowIndex); + + const TileTabsGridRowColumnElement* getRow(const int32_t rowIndex) const; + + void updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs); + + bool isCenteringCorrectionEnabled() const; + + void setCenteringCorrectionEnabled(const bool status); + + virtual AString toString() const override; + + static void getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, + int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut); + // ADD_NEW_METHODS_HERE + + protected: + public: + virtual void decodeFromXML(QXmlStreamReader& xml, + const QString& rootElement) override; + + virtual void encodeInXML(AString& xmlTextOut) const override; + + private: + void copyHelperTileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj); + + void decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml); + + void decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml); + + AString encodeVersionInXML(const int32_t versionNumber) const; + + AString encodeInXMLWithStreamWriterVersionOne() const; + + AString encodeInXMLWithStreamWriterVersionTwo() const; + + void encodeRowColumnElement(QXmlStreamWriter& writer, + const AString tagName, + const std::vector& elements) const; + + bool decodeRowColumnElement(QXmlStreamReader& reader, + TileTabsGridRowColumnElement& element, + AString& errorMessageOut); + + void initialize(); + + // ADD_NEW_MEMBERS_HERE + + std::vector m_columns; + + std::vector m_rows; + + bool m_centeringCorrectionEnabled = false; + + static const AString s_nameTagName; + static const AString s_uniqueIdentifierTagName; + + static const AString s_v1_rootTagName; + static const AString s_v1_versionTagName; + static const AString s_v1_versionNumberAttributeName; + static const AString s_v1_columnStretchFactorsTagName; + static const AString s_v1_columnStretchFactorsSelectedCountAttributeName; + static const AString s_v1_columnStretchFactorsTotalCountAttributeName; + static const AString s_v1_rowStretchFactorsTagName; + static const AString s_v1_rowStretchFactorsSelectedCountAttributeName; + static const AString s_v1_rowStretchFactorsTotalCountAttributeName; + + static const AString s_v2_rootTagName; + static const AString s_v2_versionAttributeName; + static const AString s_v2_columnsTagName; + static const AString s_v2_contentTypeAttributeName; + static const AString s_v2_elementTagName; + static const AString s_v2_percentStretchAttributeName; + static const AString s_v2_rowsTagName; + static const AString s_v2_stretchTypeAttributeName; + static const AString s_v2_weightStretchAttributeName; + static const AString s_v2_centeringCorrectionName; + + + friend class TileTabsBaseConfiguration; + }; + +#ifdef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ + const AString TileTabsGridLayoutConfiguration::s_nameTagName = "Name"; + const AString TileTabsGridLayoutConfiguration::s_uniqueIdentifierTagName = "UniqueIdentifier"; + + const AString TileTabsGridLayoutConfiguration::s_v1_rootTagName = "TileTabsGridLayoutConfiguration"; + const AString TileTabsGridLayoutConfiguration::s_v1_versionTagName = "Version"; + const AString TileTabsGridLayoutConfiguration::s_v1_versionNumberAttributeName = "Number"; + const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsTagName = "ColumnStretchFactors"; + const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; + const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; + const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsTagName = "RowStretchFactors"; + const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; + const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; + + const AString TileTabsGridLayoutConfiguration::s_v2_rootTagName = "TileTabsGridLayoutConfigurationTwo"; + const AString TileTabsGridLayoutConfiguration::s_v2_versionAttributeName = "Version"; + const AString TileTabsGridLayoutConfiguration::s_v2_columnsTagName = "Columns"; + const AString TileTabsGridLayoutConfiguration::s_v2_contentTypeAttributeName = "ContentType"; + const AString TileTabsGridLayoutConfiguration::s_v2_elementTagName = "Element"; + const AString TileTabsGridLayoutConfiguration::s_v2_percentStretchAttributeName = "PercentStretch"; + const AString TileTabsGridLayoutConfiguration::s_v2_rowsTagName = "Rows"; + const AString TileTabsGridLayoutConfiguration::s_v2_stretchTypeAttributeName = "StretchType"; + const AString TileTabsGridLayoutConfiguration::s_v2_weightStretchAttributeName = "WeightStretch"; + const AString TileTabsGridLayoutConfiguration::s_v2_centeringCorrectionName = "CenteringCorrection"; +#endif // __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ + +} // namespace +#endif //__TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ diff --git a/src/Common/TileTabsConfigurationModeEnum.cxx b/src/Common/TileTabsGridModeEnum.cxx similarity index 64% rename from src/Common/TileTabsConfigurationModeEnum.cxx rename to src/Common/TileTabsGridModeEnum.cxx index ace7e4b90d326cdffaa857c773c4ff3a599e374b..15547e3dff88bf2f002e790afb1ecb0937642393 100644 --- a/src/Common/TileTabsConfigurationModeEnum.cxx +++ b/src/Common/TileTabsGridModeEnum.cxx @@ -20,9 +20,9 @@ /*LICENSE_END*/ #include -#define __TILE_TABS_CONFIGURATION_MODE_ENUM_DECLARE__ -#include "TileTabsConfigurationModeEnum.h" -#undef __TILE_TABS_CONFIGURATION_MODE_ENUM_DECLARE__ +#define __TILE_TABS_GRID_MODE_ENUM_DECLARE__ +#include "TileTabsGridModeEnum.h" +#undef __TILE_TABS_GRID_MODE_ENUM_DECLARE__ #include "CaretAssert.h" @@ -30,8 +30,8 @@ using namespace caret; /** - * \class caret::TileTabsConfigurationModeEnum - * \brief Enumerated type for Tile Tab Configuration Types + * \class caret::TileTabsGridModeEnum + * \brief Enumerated type for Grid Tile Tab Configuration Mode (auto, custom) * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * @@ -40,30 +40,30 @@ using namespace caret; * class EnumComboBoxTemplate; * * Declare the member: - * EnumComboBoxTemplate* m_tileTabsConfigurationModeEnumComboBox; + * EnumComboBoxTemplate* m_TileTabsGridModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: - * void tileTabsConfigurationModeEnumComboBoxItemActivated(); + * void TileTabsGridModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "TileTabsConfigurationModeEnum.h" + * #include "TileTabsGridModeEnum.h" * * Instatiate: - * m_tileTabsConfigurationModeEnumComboBox = new EnumComboBoxTemplate(this); - * m_tileTabsConfigurationModeEnumComboBox->setup(); + * m_TileTabsGridModeEnumComboBox = new EnumComboBoxTemplate(this); + * m_TileTabsGridModeEnumComboBox->setup(); * * Get notified when the user changes the selection: - * QObject::connect(m_tileTabsConfigurationModeEnumComboBox, SIGNAL(itemActivated()), - * this, SLOT(tileTabsConfigurationModeEnumComboBoxItemActivated())); + * QObject::connect(m_TileTabsGridModeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(TileTabsGridModeEnumComboBoxItemActivated())); * * Update the selection: - * m_tileTabsConfigurationModeEnumComboBox->setSelectedItem(NEW_VALUE); + * m_TileTabsGridModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const TileTabsConfigurationModeEnum::Enum VARIABLE = m_tileTabsConfigurationModeEnumComboBox->getSelectedItem(); + * const TileTabsGridModeEnum::Enum VARIABLE = m_TileTabsGridModeEnumComboBox->getSelectedItem(); * */ @@ -78,7 +78,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -TileTabsConfigurationModeEnum::TileTabsConfigurationModeEnum(const Enum enumValue, +TileTabsGridModeEnum::TileTabsGridModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -91,7 +91,7 @@ TileTabsConfigurationModeEnum::TileTabsConfigurationModeEnum(const Enum enumValu /** * Destructor. */ -TileTabsConfigurationModeEnum::~TileTabsConfigurationModeEnum() +TileTabsGridModeEnum::~TileTabsGridModeEnum() { } @@ -99,18 +99,18 @@ TileTabsConfigurationModeEnum::~TileTabsConfigurationModeEnum() * Initialize the enumerated metadata. */ void -TileTabsConfigurationModeEnum::initialize() +TileTabsGridModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(TileTabsConfigurationModeEnum(AUTOMATIC, + enumData.push_back(TileTabsGridModeEnum(AUTOMATIC, "AUTOMATIC", "Automatic")); - enumData.push_back(TileTabsConfigurationModeEnum(CUSTOM, + enumData.push_back(TileTabsGridModeEnum(CUSTOM, "CUSTOM", "Custom")); @@ -123,14 +123,14 @@ TileTabsConfigurationModeEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const TileTabsConfigurationModeEnum* -TileTabsConfigurationModeEnum::findData(const Enum enumValue) +const TileTabsGridModeEnum* +TileTabsGridModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const TileTabsConfigurationModeEnum* d = &enumData[i]; + const TileTabsGridModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -147,10 +147,10 @@ TileTabsConfigurationModeEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -TileTabsConfigurationModeEnum::toName(Enum enumValue) { +TileTabsGridModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const TileTabsConfigurationModeEnum* enumInstance = findData(enumValue); + const TileTabsGridModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -164,18 +164,18 @@ TileTabsConfigurationModeEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -TileTabsConfigurationModeEnum::Enum -TileTabsConfigurationModeEnum::fromName(const AString& name, bool* isValidOut) +TileTabsGridModeEnum::Enum +TileTabsGridModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = TileTabsConfigurationModeEnum::enumData[0].enumValue; + Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const TileTabsConfigurationModeEnum& d = *iter; + const TileTabsGridModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -187,7 +187,7 @@ TileTabsConfigurationModeEnum::fromName(const AString& name, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsConfigurationModeEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsGridModeEnum")); } return enumValue; } @@ -200,10 +200,10 @@ TileTabsConfigurationModeEnum::fromName(const AString& name, bool* isValidOut) * String representing enumerated value. */ AString -TileTabsConfigurationModeEnum::toGuiName(Enum enumValue) { +TileTabsGridModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const TileTabsConfigurationModeEnum* enumInstance = findData(enumValue); + const TileTabsGridModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -217,18 +217,18 @@ TileTabsConfigurationModeEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -TileTabsConfigurationModeEnum::Enum -TileTabsConfigurationModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +TileTabsGridModeEnum::Enum +TileTabsGridModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = TileTabsConfigurationModeEnum::enumData[0].enumValue; + Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const TileTabsConfigurationModeEnum& d = *iter; + const TileTabsGridModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -240,7 +240,7 @@ TileTabsConfigurationModeEnum::fromGuiName(const AString& guiName, bool* isValid *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsConfigurationModeEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsGridModeEnum")); } return enumValue; } @@ -252,10 +252,10 @@ TileTabsConfigurationModeEnum::fromGuiName(const AString& guiName, bool* isValid * Integer code for data type. */ int32_t -TileTabsConfigurationModeEnum::toIntegerCode(Enum enumValue) +TileTabsGridModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const TileTabsConfigurationModeEnum* enumInstance = findData(enumValue); + const TileTabsGridModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -270,18 +270,18 @@ TileTabsConfigurationModeEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -TileTabsConfigurationModeEnum::Enum -TileTabsConfigurationModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +TileTabsGridModeEnum::Enum +TileTabsGridModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = TileTabsConfigurationModeEnum::enumData[0].enumValue; + Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const TileTabsConfigurationModeEnum& enumInstance = *iter; + const TileTabsGridModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -293,7 +293,7 @@ TileTabsConfigurationModeEnum::fromIntegerCode(const int32_t integerCode, bool* *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsConfigurationModeEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsGridModeEnum")); } return enumValue; } @@ -306,13 +306,13 @@ TileTabsConfigurationModeEnum::fromIntegerCode(const int32_t integerCode, bool* * A vector that is OUTPUT containing all of the enumerated values. */ void -TileTabsConfigurationModeEnum::getAllEnums(std::vector& allEnums) +TileTabsGridModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -328,16 +328,16 @@ TileTabsConfigurationModeEnum::getAllEnums(std::vector& allNames, const bool isSorted) +TileTabsGridModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(TileTabsConfigurationModeEnum::toName(iter->enumValue)); + allNames.push_back(TileTabsGridModeEnum::toName(iter->enumValue)); } if (isSorted) { @@ -354,16 +354,16 @@ TileTabsConfigurationModeEnum::getAllNames(std::vector& allNames, const * If true, the names are sorted in alphabetical order. */ void -TileTabsConfigurationModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +TileTabsGridModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(TileTabsConfigurationModeEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(TileTabsGridModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Common/TileTabsConfigurationModeEnum.h b/src/Common/TileTabsGridModeEnum.h similarity index 77% rename from src/Common/TileTabsConfigurationModeEnum.h rename to src/Common/TileTabsGridModeEnum.h index 11704af4f92341fdcbb3a6562300fed16640ab5f..4478b4fb3034e7d157381f1f9c0f5e1dd03f3756 100644 --- a/src/Common/TileTabsConfigurationModeEnum.h +++ b/src/Common/TileTabsGridModeEnum.h @@ -1,5 +1,5 @@ -#ifndef __TILE_TABS_CONFIGURATION_MODE_ENUM_H__ -#define __TILE_TABS_CONFIGURATION_MODE_ENUM_H__ +#ifndef __TILE_TABS_GRID_MODE_ENUM_H__ +#define __TILE_TABS_GRID_MODE_ENUM_H__ /*LICENSE_START*/ /* @@ -28,7 +28,7 @@ namespace caret { -class TileTabsConfigurationModeEnum { +class TileTabsGridModeEnum { public: /** @@ -42,7 +42,7 @@ public: }; - ~TileTabsConfigurationModeEnum(); + ~TileTabsGridModeEnum(); static AString toName(Enum enumValue); @@ -63,14 +63,14 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: - TileTabsConfigurationModeEnum(const Enum enumValue, + TileTabsGridModeEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const TileTabsConfigurationModeEnum* findData(const Enum enumValue); + static const TileTabsGridModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -94,11 +94,11 @@ private: AString guiName; }; -#ifdef __TILE_TABS_CONFIGURATION_MODE_ENUM_DECLARE__ -std::vector TileTabsConfigurationModeEnum::enumData; -bool TileTabsConfigurationModeEnum::initializedFlag = false; -int32_t TileTabsConfigurationModeEnum::integerCodeCounter = 0; -#endif // __TILE_TABS_CONFIGURATION_MODE_ENUM_DECLARE__ +#ifdef __TILE_TABS_GRID_MODE_ENUM_DECLARE__ +std::vector TileTabsGridModeEnum::enumData; +bool TileTabsGridModeEnum::initializedFlag = false; +int32_t TileTabsGridModeEnum::integerCodeCounter = 0; +#endif // __TILE_TABS_GRID_MODE_ENUM_DECLARE__ } // namespace -#endif //__TILE_TABS_CONFIGURATION_MODE_ENUM_H__ +#endif //__TILE_TABS_GRID_MODE_ENUM_H__ diff --git a/src/Common/TileTabsGridRowColumnContentTypeEnum.cxx b/src/Common/TileTabsGridRowColumnContentTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4008e22ec3143e55063460bee29d9781db6c84c1 --- /dev/null +++ b/src/Common/TileTabsGridRowColumnContentTypeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ +#include "TileTabsGridRowColumnContentTypeEnum.h" +#undef __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::TileTabsGridRowColumnContentTypeEnum + * \brief Content type for a row or column in a tile tabs grid + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_TileTabsGridRowColumnContentTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void TileTabsGridRowColumnContentTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "TileTabsGridRowColumnContentTypeEnum.h" + * + * Instatiate: + * m_TileTabsGridRowColumnContentTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_TileTabsGridRowColumnContentTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_TileTabsGridRowColumnContentTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(TileTabsGridRowColumnContentTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_TileTabsGridRowColumnContentTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const TileTabsGridRowColumnContentTypeEnum::Enum VARIABLE = m_TileTabsGridRowColumnContentTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +TileTabsGridRowColumnContentTypeEnum::TileTabsGridRowColumnContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +TileTabsGridRowColumnContentTypeEnum::~TileTabsGridRowColumnContentTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +TileTabsGridRowColumnContentTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(TileTabsGridRowColumnContentTypeEnum(SPACE, + "SPACE", + "Space")); + + enumData.push_back(TileTabsGridRowColumnContentTypeEnum(TAB, + "TAB", + "Tab")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const TileTabsGridRowColumnContentTypeEnum* +TileTabsGridRowColumnContentTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const TileTabsGridRowColumnContentTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsGridRowColumnContentTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsGridRowColumnContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsGridRowColumnContentTypeEnum::Enum +TileTabsGridRowColumnContentTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsGridRowColumnContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsGridRowColumnContentTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsGridRowColumnContentTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsGridRowColumnContentTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsGridRowColumnContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsGridRowColumnContentTypeEnum::Enum +TileTabsGridRowColumnContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsGridRowColumnContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsGridRowColumnContentTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsGridRowColumnContentTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +TileTabsGridRowColumnContentTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const TileTabsGridRowColumnContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +TileTabsGridRowColumnContentTypeEnum::Enum +TileTabsGridRowColumnContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsGridRowColumnContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsGridRowColumnContentTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsGridRowColumnContentTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +TileTabsGridRowColumnContentTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsGridRowColumnContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(TileTabsGridRowColumnContentTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsGridRowColumnContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(TileTabsGridRowColumnContentTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/TileTabsGridRowColumnContentTypeEnum.h b/src/Common/TileTabsGridRowColumnContentTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..fabf3fc9ac46c0e8121eaafa8af9589af679960f --- /dev/null +++ b/src/Common/TileTabsGridRowColumnContentTypeEnum.h @@ -0,0 +1,104 @@ +#ifndef __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_H__ +#define __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class TileTabsGridRowColumnContentTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Space */ + SPACE, + /** Tab */ + TAB + }; + + + ~TileTabsGridRowColumnContentTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + TileTabsGridRowColumnContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const TileTabsGridRowColumnContentTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ +std::vector TileTabsGridRowColumnContentTypeEnum::enumData; +bool TileTabsGridRowColumnContentTypeEnum::initializedFlag = false; +int32_t TileTabsGridRowColumnContentTypeEnum::integerCodeCounter = 0; +#endif // __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_H__ diff --git a/src/Common/TileTabsGridRowColumnElement.cxx b/src/Common/TileTabsGridRowColumnElement.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4c757352407a119da44309283fd61a51604f6506 --- /dev/null +++ b/src/Common/TileTabsGridRowColumnElement.cxx @@ -0,0 +1,206 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ +#include "TileTabsGridRowColumnElement.h" +#undef __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::TileTabsGridRowColumnElement + * \brief Contents on an element in a Tile Tabs Configuration grid row or column. + * \ingroup Common + */ + +/** + * Constructor. + */ +TileTabsGridRowColumnElement::TileTabsGridRowColumnElement() +: CaretObject() +{ + clear(); +} + +/** + * Destructor. + */ +TileTabsGridRowColumnElement::~TileTabsGridRowColumnElement() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +TileTabsGridRowColumnElement::TileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj) +: CaretObject(obj) +{ + this->copyHelperTileTabsGridRowColumnElement(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +TileTabsGridRowColumnElement& +TileTabsGridRowColumnElement::operator=(const TileTabsGridRowColumnElement& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperTileTabsGridRowColumnElement(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +TileTabsGridRowColumnElement::copyHelperTileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj) +{ + m_contentType = obj.m_contentType; + m_stretchType = obj.m_stretchType; + m_percentStretch = obj.m_percentStretch; + m_weightStretch = obj.m_weightStretch; +} + +/** + * Clear this instance. + */ +void +TileTabsGridRowColumnElement::clear() +{ + m_contentType = TileTabsGridRowColumnContentTypeEnum::TAB; + m_stretchType = TileTabsGridRowColumnStretchTypeEnum::WEIGHT; + m_percentStretch = 20.0; + m_weightStretch = 1.0; +} + +/** + * @return Content type (spacer or tab) + */ +TileTabsGridRowColumnContentTypeEnum::Enum +TileTabsGridRowColumnElement::getContentType() const +{ + return m_contentType; +} + +/** + * Set the content type (spacer or tab) + * + * @param contentType + * New value for content type. + */ +void +TileTabsGridRowColumnElement::setContentType(const TileTabsGridRowColumnContentTypeEnum::Enum contentType) +{ + m_contentType = contentType; +} + +/** + * @return The stretch type (percent or weight) + */ +TileTabsGridRowColumnStretchTypeEnum::Enum +TileTabsGridRowColumnElement::getStretchType() const +{ + return m_stretchType; +} + +/** + * Set the stretch type (percent or weight) + * + * @param stretchType + * New value for stretch type. + */ +void +TileTabsGridRowColumnElement::setStretchType(const TileTabsGridRowColumnStretchTypeEnum::Enum stretchType) +{ + m_stretchType = stretchType; +} + +/** + * @return The percent stretch value. + */ +float +TileTabsGridRowColumnElement::getPercentStretch() const +{ + return m_percentStretch; +} + +/** + * Set the percent stretch value. + * + * @param percentStretch + * New value for percent stretch. + */ +void +TileTabsGridRowColumnElement::setPercentStretch(const float percentStretch) +{ + m_percentStretch = percentStretch; +} + +/** + * @return The weight stretch value. + */ +float +TileTabsGridRowColumnElement::getWeightStretch() const +{ + return m_weightStretch; +} + +/** + * Set the weight stretch value. + * + * @param weightStretch + * New value for weight stretch. + */ +void +TileTabsGridRowColumnElement::setWeightStretch(const float weightStretch) +{ + m_weightStretch = weightStretch; +} + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +TileTabsGridRowColumnElement::toString() const +{ + AString s("TileTabsGridRowColumnElement: "); + s.append("ContentType=" + TileTabsGridRowColumnContentTypeEnum::toGuiName(m_contentType)); + s.append(" StretchType=" + TileTabsGridRowColumnStretchTypeEnum::toGuiName(m_stretchType)); + s.append(" PercentStretch=" + AString::number(m_percentStretch)); + s.append(" WeightStretch=" + AString::number(m_weightStretch)); + return s; +} + diff --git a/src/Common/TileTabsGridRowColumnElement.h b/src/Common/TileTabsGridRowColumnElement.h new file mode 100644 index 0000000000000000000000000000000000000000..5cb80c1835072b7ee94c9e3e5ea58bb8014caf0e --- /dev/null +++ b/src/Common/TileTabsGridRowColumnElement.h @@ -0,0 +1,88 @@ +#ifndef __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_H__ +#define __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "TileTabsGridRowColumnContentTypeEnum.h" +#include "TileTabsGridRowColumnStretchTypeEnum.h" + +namespace caret { + + class TileTabsGridRowColumnElement : public CaretObject { + + public: + TileTabsGridRowColumnElement(); + + virtual ~TileTabsGridRowColumnElement(); + + TileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj); + + TileTabsGridRowColumnElement& operator=(const TileTabsGridRowColumnElement& obj); + + void clear(); + + TileTabsGridRowColumnContentTypeEnum::Enum getContentType() const; + + void setContentType(const TileTabsGridRowColumnContentTypeEnum::Enum contentType); + + TileTabsGridRowColumnStretchTypeEnum::Enum getStretchType() const; + + void setStretchType(const TileTabsGridRowColumnStretchTypeEnum::Enum stretchType); + + float getPercentStretch() const; + + void setPercentStretch(const float percentStretch); + + float getWeightStretch() const; + + void setWeightStretch(const float weightStretch); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperTileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj); + + TileTabsGridRowColumnContentTypeEnum::Enum m_contentType = TileTabsGridRowColumnContentTypeEnum::TAB; + + TileTabsGridRowColumnStretchTypeEnum::Enum m_stretchType = TileTabsGridRowColumnStretchTypeEnum::WEIGHT; + + float m_percentStretch = 20.0; + + float m_weightStretch = 1.0; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ + // +#endif // __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ + +} // namespace +#endif //__TILE_TABS_GRID_ROW_COLUMN_ELEMENT_H__ diff --git a/src/Common/TileTabsGridRowColumnStretchTypeEnum.cxx b/src/Common/TileTabsGridRowColumnStretchTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..156938d1dc0e5c570c3703d78b5bea547deffee2 --- /dev/null +++ b/src/Common/TileTabsGridRowColumnStretchTypeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ +#include "TileTabsGridRowColumnStretchTypeEnum.h" +#undef __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::TileTabsGridRowColumnStretchTypeEnum + * \brief Stretch type for tile tabs grid configuration. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_TileTabsGridRowColumnStretchTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void TileTabsGridRowColumnStretchTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "TileTabsGridRowColumnStretchTypeEnum.h" + * + * Instatiate: + * m_TileTabsGridRowColumnStretchTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_TileTabsGridRowColumnStretchTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_TileTabsGridRowColumnStretchTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(TileTabsGridRowColumnStretchTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_TileTabsGridRowColumnStretchTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const TileTabsGridRowColumnStretchTypeEnum::Enum VARIABLE = m_TileTabsGridRowColumnStretchTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +TileTabsGridRowColumnStretchTypeEnum::TileTabsGridRowColumnStretchTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +TileTabsGridRowColumnStretchTypeEnum::~TileTabsGridRowColumnStretchTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +TileTabsGridRowColumnStretchTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(TileTabsGridRowColumnStretchTypeEnum(PERCENT, + "PERCENT", + "Percent")); + + enumData.push_back(TileTabsGridRowColumnStretchTypeEnum(WEIGHT, + "WEIGHT", + "Weight")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const TileTabsGridRowColumnStretchTypeEnum* +TileTabsGridRowColumnStretchTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const TileTabsGridRowColumnStretchTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsGridRowColumnStretchTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsGridRowColumnStretchTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsGridRowColumnStretchTypeEnum::Enum +TileTabsGridRowColumnStretchTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsGridRowColumnStretchTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsGridRowColumnStretchTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsGridRowColumnStretchTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsGridRowColumnStretchTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsGridRowColumnStretchTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsGridRowColumnStretchTypeEnum::Enum +TileTabsGridRowColumnStretchTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsGridRowColumnStretchTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsGridRowColumnStretchTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsGridRowColumnStretchTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +TileTabsGridRowColumnStretchTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const TileTabsGridRowColumnStretchTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +TileTabsGridRowColumnStretchTypeEnum::Enum +TileTabsGridRowColumnStretchTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsGridRowColumnStretchTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsGridRowColumnStretchTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsGridRowColumnStretchTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +TileTabsGridRowColumnStretchTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsGridRowColumnStretchTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(TileTabsGridRowColumnStretchTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsGridRowColumnStretchTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(TileTabsGridRowColumnStretchTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/TileTabsGridRowColumnStretchTypeEnum.h b/src/Common/TileTabsGridRowColumnStretchTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..bdea3d7305ca63bb14dfea00f21ad0b0ac1bd712 --- /dev/null +++ b/src/Common/TileTabsGridRowColumnStretchTypeEnum.h @@ -0,0 +1,104 @@ +#ifndef __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_H__ +#define __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class TileTabsGridRowColumnStretchTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Percent */ + PERCENT, + /** Weight */ + WEIGHT + }; + + + ~TileTabsGridRowColumnStretchTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + TileTabsGridRowColumnStretchTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const TileTabsGridRowColumnStretchTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ +std::vector TileTabsGridRowColumnStretchTypeEnum::enumData; +bool TileTabsGridRowColumnStretchTypeEnum::initializedFlag = false; +int32_t TileTabsGridRowColumnStretchTypeEnum::integerCodeCounter = 0; +#endif // __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_H__ diff --git a/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.cxx b/src/Common/VolumeSliceViewAllPlanesLayoutEnum.cxx similarity index 100% rename from src/Brain/VolumeSliceViewAllPlanesLayoutEnum.cxx rename to src/Common/VolumeSliceViewAllPlanesLayoutEnum.cxx diff --git a/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.h b/src/Common/VolumeSliceViewAllPlanesLayoutEnum.h similarity index 100% rename from src/Brain/VolumeSliceViewAllPlanesLayoutEnum.h rename to src/Common/VolumeSliceViewAllPlanesLayoutEnum.h diff --git a/src/Common/VoxelIJK.h b/src/Common/VoxelIJK.h index 1ee3c34b7afc69a23b5ea0f530adf2b0f3607e4d..9d7c8d3499d172988749bfbd8b9b3f9222c636e4 100644 --- a/src/Common/VoxelIJK.h +++ b/src/Common/VoxelIJK.h @@ -36,7 +36,7 @@ namespace caret { m_ijk[1] = ijk[1]; m_ijk[2] = ijk[2]; } - bool operator<(const VoxelIJK& rhs) const//so it kan be the key of a map + bool operator<(const VoxelIJK& rhs) const//so it can be the key of a map { if (m_ijk[2] < rhs.m_ijk[2]) return true;//compare such that when sorted, m_ijk[0] moves fastest if (m_ijk[2] > rhs.m_ijk[2]) return false; @@ -51,6 +51,7 @@ namespace caret { m_ijk[2] == rhs.m_ijk[2]); } bool operator!=(const VoxelIJK& rhs) const { return !((*this) == rhs); } + inline operator int64_t*() { return m_ijk; } }; } diff --git a/src/Common/WuQMacro.cxx b/src/Common/WuQMacro.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3832b97f8c131dfd8ab52e672f4c3c7feb9b3ef9 --- /dev/null +++ b/src/Common/WuQMacro.cxx @@ -0,0 +1,511 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_DECLARE__ +#include "WuQMacro.h" +#undef __WU_Q_MACRO_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "WuQMacroCommand.h" +#include "WuQMacroMouseEventInfo.h" +#include "WuQMacroStandardItemTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacro + * \brief Contains a sequence of WuQMacroCommand's + * \ingroup WuQMacro + * + * Subclasses QStandardItem so that instance can be in a tree widget + */ + +/** + * Constructor. + */ +WuQMacro::WuQMacro() +: QStandardItem(), +TracksModificationInterface() +{ + setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable); + m_uniqueIdentifier = QUuid::createUuid().toString(); +} + +/** + * Destructor. + */ +WuQMacro::~WuQMacro() +{ + clearCommands(); +} + +/** + * Clear (remove) all commands in this macro + */ +void +WuQMacro::clearCommands() +{ + const int32_t numItems = rowCount(); + removeRows(0, numItems); + CaretAssert(rowCount() == 0); +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +WuQMacro::WuQMacro(const WuQMacro& obj) +: QStandardItem(obj), +TracksModificationInterface() +{ + setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable); + m_uniqueIdentifier = QUuid::createUuid().toString(); + + this->copyHelperWuQMacro(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +WuQMacro& +WuQMacro::operator=(const WuQMacro& obj) +{ + if (this != &obj) { + QStandardItem::operator=(obj); + this->copyHelperWuQMacro(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +WuQMacro::copyHelperWuQMacro(const WuQMacro& obj) +{ + /* Note: unique identifier is NOT copied */ + + clearCommands(); + + const int32_t numRows = obj.rowCount(); + for (int32_t i = 0; i < numRows; i++) { + const QStandardItem* item = obj.child(i); + CaretAssert(item); + const WuQMacroCommand* command = dynamic_cast(item); + CaretAssert(command); + WuQMacroCommand* commandCopy = new WuQMacroCommand(*command); + CaretAssert(commandCopy); + appendMacroCommand(commandCopy); + } + + setText(obj.text()); + m_description = obj.m_description; + m_shortCutKey = obj.m_shortCutKey; +} + +/** + * @return The type of this item for Qt + */ +int +WuQMacro::type() const +{ + /* + * This must be different than the type returned by of macro + * subclasses of QStandardItem + */ + return WuQMacroStandardItemTypeEnum::toIntegerCode(WuQMacroStandardItemTypeEnum::MACRO); +} + +/** + * Append a macro command to this macro + * + * @param macroCommand + * The macro command. + */ +void +WuQMacro::appendMacroCommand(WuQMacroCommand* macroCommand) +{ + CaretAssert(macroCommand); + const int32_t numCommands = getNumberOfMacroCommands(); + if (numCommands > 0) { + WuQMacroCommand* lastCommand = getMacroCommandAtIndex(numCommands - 1); + /* + * 'Compact' macro commands for mouse events + */ + if (lastCommand->isMouseEventMatch(macroCommand)) { + WuQMacroMouseEventInfo* lastMouseInfo = lastCommand->getMouseEventInfo(); + CaretAssert(lastMouseInfo); + + const WuQMacroMouseEventInfo* mouseInfo = macroCommand->getMouseEventInfo(); + CaretAssert(mouseInfo); + const int32_t numXY = mouseInfo->getNumberOfLocalXY(); + for (int32_t i = 0; i < numXY; i++) { + lastMouseInfo->addLocalXY(mouseInfo->getLocalX(i), + mouseInfo->getLocalY(i)); + } + + /* + * No longer needed since mouse x/y appended to last command + */ + delete macroCommand; + macroCommand = NULL; + } + } + + if (macroCommand != NULL) { + appendRow(macroCommand); + } + + setModified(); +} + +/** + * Insert the given macro command at the given index + * + * @param index + * Index of where to insert the macro command + * @param macroCommand + * Macro command to insert. + */ +void +WuQMacro::insertMacroCommandAtIndex(const int32_t index, + WuQMacroCommand* macroCommand) +{ + CaretAssert((index >= 0) + && (index <= getNumberOfMacroCommands())); + CaretAssert(macroCommand); + + insertRow(index, + macroCommand); + setModified(); +} + +/** + * @return The unique identifier + */ +QString +WuQMacro::getUniqueIdentifier() const +{ + return m_uniqueIdentifier; +} + +/** + * Set unique identifier of macro + * + * @param uniqueIdentifier + * New unique identifier + */void +WuQMacro::setUniqueIdentifier(const QString& uniqueIdentifier) +{ + if (uniqueIdentifier.isEmpty()) { + return; + } + if (m_uniqueIdentifier != uniqueIdentifier) { + m_uniqueIdentifier = uniqueIdentifier; + setModified(); + } +} + +/** + * @return Name of macro + */ +QString +WuQMacro::getName() const +{ + return text(); +} + +/** + * Set name of macro + * + * @param name + * New name + */ +void +WuQMacro::setName(const QString& name) +{ + if (name != text()) { + setText(name); + setModified(); + } +} + +/** + * @return Description of macro + */ +QString +WuQMacro::getDescription() const +{ + return m_description; +} + +/** + * Set description of macro + * + * @param description + * New description + */ +void +WuQMacro::setDescription(const QString& description) +{ + if (m_description != description) { + m_description = description; + setModified(); + } +} + +/** + * @return The short cut key + */ +WuQMacroShortCutKeyEnum::Enum +WuQMacro::getShortCutKey() const +{ + return m_shortCutKey; +} + +/** + * Set the short cut key + * + * @param shortCutKey + * New short cut key + */ +void +WuQMacro::setShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) +{ + if (m_shortCutKey != shortCutKey) { + m_shortCutKey = shortCutKey; + setModified(); + } +} + +/** + * @return The number of macro commands in this macro + */ +int32_t +WuQMacro::getNumberOfMacroCommands() const +{ + return rowCount(); +} + +/** + * @return + * The macro command at the given index + * @param index + * Index of the macro command + */ +const WuQMacroCommand* +WuQMacro::getMacroCommandAtIndex(const int32_t index) const +{ + CaretAssert((index >= 0) + && (index < rowCount())); + QStandardItem* item = child(index); + CaretAssert(item); + WuQMacroCommand* command = dynamic_cast(item); + CaretAssert(command); + return command; +} + +/** + * @return + * The macro command at the given index + * @param index + * Index of the macro command + */ +WuQMacroCommand* +WuQMacro::getMacroCommandAtIndex(const int32_t index) +{ + CaretAssert((index >= 0) + && (index < rowCount())); + QStandardItem* item = child(index); + CaretAssert(item); + WuQMacroCommand* command = dynamic_cast(item); + CaretAssert(command); + return command; +} + +/** + * @return + * Index of the given macro command + * @param macroCommand + * The macro command + */ +int32_t +WuQMacro::getIndexOfMacroCommand(const WuQMacroCommand* macroCommand) const +{ + CaretAssert(macroCommand); + + const int32_t num = getNumberOfMacroCommands(); + for (int32_t i = 0; i < num; i++) { + if (getMacroCommandAtIndex(i) == macroCommand) { + return i; + break; + } + } + return -1; +} + +/** + * Delete macro command at the given index + * + * @param index + * Index of macro command + */ +void +WuQMacro::deleteMacroCommandAtIndex(const int32_t index) +{ + CaretAssert((index >= 0) + && (index < getNumberOfMacroCommands())); + removeRow(index); + setModified(); +} + +/** + * Delete the given macro command + + * @param macroCommand + */ +void +WuQMacro::deleteMacroCommand(WuQMacroCommand* macroCommand) +{ + const int32_t index = getIndexOfMacroCommand(macroCommand); + if (index >= 0) { + deleteMacroCommandAtIndex(index); + } +} + +/** + * Move the given macro command down one position + * + * @param macroCommand + */ +void +WuQMacro::moveMacroCommandDown(WuQMacroCommand* macroCommand) +{ + const int32_t index = getIndexOfMacroCommand(macroCommand); + if ((index >= 0) + && (index < getNumberOfMacroCommands() - 1)) { + /* Note that take child removes item but does not remove row */ + QStandardItem* item = takeChild(index); + removeRow(index); + CaretAssert(item); + insertMacroCommandAtIndex(index + 1, + dynamic_cast(item)); + } +} + +/** + * Move the given macro command up one position + * + * @param macroCommand + */ +void +WuQMacro::moveMacroCommandUp(WuQMacroCommand* macroCommand) +{ + const int32_t index = getIndexOfMacroCommand(macroCommand); + if ((index > 0) + && (index < getNumberOfMacroCommands())) { + /* Note that take child removes item but does not remove row */ + QStandardItem* item = takeChild(index); + removeRow(index); + CaretAssert(item); + insertMacroCommandAtIndex(index - 1, + dynamic_cast(item)); + } +} + +/** + * @return True if this instance is modified + */ +bool +WuQMacro::isModified() const +{ + if (m_modifiedStatusFlag) { + return true; + } + + const int32_t numItems = getNumberOfMacroCommands(); + for (int32_t i = 0; i < numItems; i++) { + if (getMacroCommandAtIndex(i)->isModified()) { + return true; + } + } + + return false; +} + +/** + * Clear the modified status + */ +void +WuQMacro::clearModified() +{ + m_modifiedStatusFlag = false; + + const int32_t numItems = getNumberOfMacroCommands(); + for (int32_t i = 0; i < numItems; i++) { + getMacroCommandAtIndex(i)->clearModified(); + } +} + +/** + * Set the modification status to modified + */ +void +WuQMacro::setModified() +{ + m_modifiedStatusFlag = true; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +WuQMacro::toString() const +{ + QString s("WuQMacro\n"); + + s.append("Name=" + text() + "\n"); + s.append("Description=" + m_description + "\n"); + s.append("ShortCutKey=" + WuQMacroShortCutKeyEnum::toGuiName(m_shortCutKey) + "\n"); + s.append("UUID=" + m_uniqueIdentifier + "\n"); + + const int32_t numItems = getNumberOfMacroCommands(); + for (int32_t i = 0; i < numItems; i++) { + s.append(getMacroCommandAtIndex(i)->toString()); + } + + return s; +} + diff --git a/src/Common/WuQMacro.h b/src/Common/WuQMacro.h new file mode 100644 index 0000000000000000000000000000000000000000..75dc08e1f3de42d13a1b1d29d6b2773ac6486c17 --- /dev/null +++ b/src/Common/WuQMacro.h @@ -0,0 +1,118 @@ +#ifndef __WU_Q_MACRO_H__ +#define __WU_Q_MACRO_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + +#include + +#include "TracksModificationInterface.h" +#include "WuQMacroShortCutKeyEnum.h" + +namespace caret { + + class WuQMacroCommand; + + class WuQMacro : public QStandardItem, public TracksModificationInterface { + + public: + WuQMacro(); + + virtual ~WuQMacro(); + + WuQMacro(const WuQMacro& obj); + + WuQMacro& operator=(const WuQMacro& obj); + + void appendMacroCommand(WuQMacroCommand* macroCommand); + + void insertMacroCommandAtIndex(const int32_t index, + WuQMacroCommand* macroCommand); + + int32_t getNumberOfMacroCommands() const; + + const WuQMacroCommand* getMacroCommandAtIndex(const int32_t index) const; + + WuQMacroCommand* getMacroCommandAtIndex(const int32_t index); + + int32_t getIndexOfMacroCommand(const WuQMacroCommand* macroCommand) const; + + void deleteMacroCommandAtIndex(const int32_t index); + + void deleteMacroCommand(WuQMacroCommand* macroCommand); + + void moveMacroCommandDown(WuQMacroCommand* macroCommand); + + void moveMacroCommandUp(WuQMacroCommand* macroCommand); + + QString getUniqueIdentifier() const; + + void setUniqueIdentifier(const QString& uniqueIdentifier); + + QString getName() const; + + void setName(const QString& name); + + QString getDescription() const; + + void setDescription(const QString& description); + + WuQMacroShortCutKeyEnum::Enum getShortCutKey() const; + + void setShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey); + + virtual AString toString() const; + + virtual bool isModified() const override; + + virtual void clearModified() override; + + virtual void setModified() override; + + virtual int type() const override; + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperWuQMacro(const WuQMacro& obj); + + void clearCommands(); + + QString m_uniqueIdentifier; + + QString m_description; + + WuQMacroShortCutKeyEnum::Enum m_shortCutKey = WuQMacroShortCutKeyEnum::Key_None; + + bool m_modifiedStatusFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_DECLARE__ + // +#endif // __WU_Q_MACRO_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_H__ diff --git a/src/Common/WuQMacroCommand.cxx b/src/Common/WuQMacroCommand.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a5b590334dd6d08293c3f0a3166759ad0a94519a --- /dev/null +++ b/src/Common/WuQMacroCommand.cxx @@ -0,0 +1,868 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_COMMAND_DECLARE__ +#include "WuQMacroCommand.h" +#undef __WU_Q_MACRO_COMMAND_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroMouseEventInfo.h" +#include "WuQMacroStandardItemTypeEnum.h" + +using namespace caret; + +/** + * \class caret::WuQMacroCommand + * \brief Issues a QObject's signal so that its slots execute + * \ingroup WuQMacro + */ + +/** + * Create a new instance of a macro comand for a custom command + * + * @param commandType + * Type of command + * @param customOperationTypeName + * Name of a custom operation + * @param mouseEventInfo + * Information about mouse event. + * @param widgetType + * Type of widget + * @param version + * Version of command + * @param objectName + * Name of object + * @param objectDescriptiveName + * Descriptive name of macro command + * @param objectToolTip + * ToolTip for object + * @param delayInSeconds + * Delay in seconds + * @param errorMessageOut + * Output with error messag if new instance fails + * @return + * The widget command or NULL if failure + */ +WuQMacroCommand* +WuQMacroCommand::newInstanceCustomCommand(const QString& customOperationName, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delayInSeconds, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + + if (customOperationName.isEmpty()) { + errorMessageOut = "Custom operation may not be empty for a custom operation macro command"; + return NULL; + } + + WuQMacroMouseEventInfo* mouseEventInfo(NULL); + WuQMacroCommand* mc = new WuQMacroCommand(WuQMacroCommandTypeEnum::CUSTOM_OPERATION, + customOperationName, + mouseEventInfo, + WuQMacroWidgetTypeEnum::INVALID, + version, + objectName, + objectDescriptiveName, + objectToolTip, + delayInSeconds); + return mc; +} + +/** + * Create a new instance of a macro command for mouse operation + * + * @param commandType + * Type of command + * @param customOperationTypeName + * Name of a custom operation + * @param mouseEventInfo + * Information about mouse event (will take ownership) + * @param widgetType + * Type of widget + * @param version + * Version of command + * @param objectName + * Name of object + * @param objectDescriptiveName + * Descriptive name of macro command + * @param objectToolTip + * ToolTip for object + * @param delayInSeconds + * Delay in seconds + * @param errorMessageOut + * Output with error messag if new instance fails + * @return + * The widget command or NULL if failure + */ +WuQMacroCommand* +WuQMacroCommand::newInstanceMouseCommand(WuQMacroMouseEventInfo* mouseEventInfo, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delayInSeconds, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + + if (mouseEventInfo == NULL) { + errorMessageOut = "Mouse info is invalid (NULL) for a macro mouse command"; + return NULL; + } + + const QString customOperationName(""); + WuQMacroCommand* mc = new WuQMacroCommand(WuQMacroCommandTypeEnum::MOUSE, + customOperationName, + mouseEventInfo, + WuQMacroWidgetTypeEnum::INVALID, + version, + objectName, + objectDescriptiveName, + objectToolTip, + delayInSeconds); + return mc; +} + +/** + * Create a new instance of a macro command for a Qt Widget + * + * @param commandType + * Type of command + * @param customOperationTypeName + * Name of a custom operation + * @param mouseEventInfo + * Information about mouse event. + * @param widgetType + * Type of widget + * @param version + * Version of command + * @param objectName + * Name of object + * @param objectDescriptiveName + * Descriptive name of macro command + * @param objectToolTip + * ToolTip for object + * @param delayInSeconds + * Delay in seconds + * @param errorMessageOut + * Output with error messag if new instance fails + * @return + * The widget command or NULL if failure + */ +WuQMacroCommand* +WuQMacroCommand::newInstanceWidgetCommand(const WuQMacroWidgetTypeEnum::Enum widgetType, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delayInSeconds, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + + if (widgetType == WuQMacroWidgetTypeEnum::INVALID) { + errorMessageOut = "Widget type is invalid for Widget Macro Command"; + return NULL; + } + + const QString customOperationName(""); + WuQMacroMouseEventInfo* mouseEventInfo(NULL); + WuQMacroCommand* mc = new WuQMacroCommand(WuQMacroCommandTypeEnum::WIDGET, + customOperationName, + mouseEventInfo, + widgetType, + version, + objectName, + objectDescriptiveName, + objectToolTip, + delayInSeconds); + return mc; +} + +/** + * Constructor for a macro command + * + * @param commandType + * Type of command + * @param customOperationTypeName + * Name of a custom operation + * @param mouseEventInfo + * Information about mouse event. + * @param widgetType + * Type of widget + * @param version + * Version of command + * @param objectName + * Name of object + * @param objectDescriptiveName + * Descriptive name of macro command + * @param objectToolTip + * ToolTip for object + * @param delayInSeconds + * Delay in seconds + */ +WuQMacroCommand::WuQMacroCommand(const WuQMacroCommandTypeEnum::Enum commandType, + const QString& customOperationTypeName, + WuQMacroMouseEventInfo* mouseEventInfo, + const WuQMacroWidgetTypeEnum::Enum widgetType, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delayInSeconds) +: QStandardItem(), +TracksModificationInterface(), +m_commandType(commandType), +m_customOperationTypeName(customOperationTypeName), +m_macroMouseEvent(mouseEventInfo), +m_widgetType(widgetType), +m_version(version), +m_objectName(objectName), +m_descriptiveName(objectDescriptiveName), +m_delayInSeconds(delayInSeconds) +{ + if (objectDescriptiveName.isEmpty()) { + CaretLogWarning("Empty descriptive name for " + + objectName); + } + + switch (m_commandType) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + break; + case WuQMacroCommandTypeEnum::MOUSE: + CaretAssert(m_macroMouseEvent); + setText("Mouse"); + break; + case WuQMacroCommandTypeEnum::WIDGET: + break; + } + + setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable); + setToolTip(objectToolTip); + + updateTitle(); + setModified(); +} + + +/** + * Destructor. + */ +WuQMacroCommand::~WuQMacroCommand() +{ + if (m_macroMouseEvent != NULL) { + delete m_macroMouseEvent; + } + removeAllParameters(); +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +WuQMacroCommand::WuQMacroCommand(const WuQMacroCommand& obj) +: QStandardItem(obj), +TracksModificationInterface() +{ + setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable); + this->copyHelperWuQMacroCommand(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +WuQMacroCommand& +WuQMacroCommand::operator=(const WuQMacroCommand& obj) +{ + if (this != &obj) { + QStandardItem::operator=(obj); + this->copyHelperWuQMacroCommand(obj); + } + return *this; +} + +/** + * @return The type of this item for Qt + */ +int +WuQMacroCommand::type() const +{ + /* + * This must be different than the type returned by of macro + * subclasses of QStandardItem + */ + return WuQMacroStandardItemTypeEnum::toIntegerCode(WuQMacroStandardItemTypeEnum::MACRO_COMMAND); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +WuQMacroCommand::copyHelperWuQMacroCommand(const WuQMacroCommand& obj) +{ + m_commandType = obj.m_commandType; + m_customOperationTypeName = obj.m_customOperationTypeName; + if (m_macroMouseEvent != NULL) { + m_macroMouseEvent = NULL; + } + if (obj.m_macroMouseEvent != NULL) { + m_macroMouseEvent = new WuQMacroMouseEventInfo(*obj.m_macroMouseEvent); + } + m_widgetType = obj.m_widgetType; + m_version = obj.m_version; + m_objectName = obj.m_objectName; + m_descriptiveName = obj.m_descriptiveName; + m_delayInSeconds = obj.m_delayInSeconds; + removeAllParameters(); + for (const auto p : obj.m_parameters) { + m_parameters.push_back(new WuQMacroCommandParameter(*p)); + } + setText(obj.text()); + updateTitle(); + setModified(); +} + +/** + * Update the title for this command + */ +void +WuQMacroCommand::updateTitle() +{ + QString title = "Unknown"; + + QVariant dataValue; + if (getNumberOfParameters() > 0) { + CaretAssertVectorIndex(m_parameters, 0); + dataValue = m_parameters[0]->getValue(); + } + + QVariant dataValueTwo; + if (getNumberOfParameters() > 1) { + CaretAssertVectorIndex(m_parameters, 1); + dataValueTwo = m_parameters[1]->getValue(); + } + + switch (m_widgetType) { + case WuQMacroWidgetTypeEnum::ACTION: + title = ("Turn " + + QString((dataValue.toBool() ? "On" : "Off"))); + break; + case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: + title = ("Turn " + + QString((dataValue.toBool() ? "On" : "Off"))); + break; + case WuQMacroWidgetTypeEnum::ACTION_GROUP: + title = ("Select Name " + + dataValue.toString() + + " else " + + " index " + + QString::number(dataValueTwo.toInt())); + break; + case WuQMacroWidgetTypeEnum::BUTTON_GROUP: + title = ("Select Name " + + dataValue.toString() + + " else " + + " index " + + QString::number(dataValueTwo.toInt())); + break; + case WuQMacroWidgetTypeEnum::CHECK_BOX: + title = ("Turn " + + QString((dataValue.toBool() ? "On" : "Off"))); + break; + case WuQMacroWidgetTypeEnum::COMBO_BOX: + title = ("Select Name " + + dataValue.toString() + + " else " + + " index " + + QString::number(dataValueTwo.toInt())); + break; + case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: + title = ("Set to value " + + QString::number(dataValue.toFloat())); + break; + case WuQMacroWidgetTypeEnum::INVALID: + break; + case WuQMacroWidgetTypeEnum::LINE_EDIT: + title = ("Set to text " + + dataValue.toString()); + break; + case WuQMacroWidgetTypeEnum::LIST_WIDGET: + title = ("Select Name " + + dataValue.toString() + + " else " + + " index " + + QString::number(dataValueTwo.toInt())); + break; + case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: + title = "Set value"; + break; + case WuQMacroWidgetTypeEnum::MENU: + title = ("Select Name " + + dataValue.toString() + + " else " + + " index " + + QString::number(dataValueTwo.toInt())); + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON: + title = ("Click Button"); + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: + title = ("Turn " + + QString((dataValue.toBool() ? "On" : "Off"))); + break; + case WuQMacroWidgetTypeEnum::RADIO_BUTTON: + title = "Click Button"; + break; + case WuQMacroWidgetTypeEnum::SLIDER: + title = ("Move to " + + AString::number(dataValue.toInt())); + break; + case WuQMacroWidgetTypeEnum::SPIN_BOX: + title = ("Set to " + + AString::number(dataValue.toInt())); + break; + case WuQMacroWidgetTypeEnum::TAB_BAR: + title = ("Select Name " + + dataValue.toString() + + " else " + + " index " + + QString::number(dataValueTwo.toInt())); + break; + case WuQMacroWidgetTypeEnum::TAB_WIDGET: + title = ("Select Name " + + dataValue.toString() + + " else " + + " index " + + QString::number(dataValueTwo.toInt())); + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON: + title = ("Click Button"); + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: + title = ("Turn " + + QString((dataValue.toBool() ? "On" : "Off"))); + break; + } + + if ( ! m_descriptiveName.isEmpty()) { + setText(m_descriptiveName); + } + else { + setText(title + + " " + + m_objectName); + } +} + +/** + * @return The command type + */ +WuQMacroCommandTypeEnum::Enum +WuQMacroCommand::getCommandType() const +{ + return m_commandType; +} + +/** + * @return The command's widget type + */ +WuQMacroWidgetTypeEnum::Enum +WuQMacroCommand::getWidgetType() const +{ + return m_widgetType; +} + +/** + * @return Version of the command + */ +int32_t +WuQMacroCommand::getVersion() const +{ + return m_version; +} + +/** + * Add a parameter to the macro command + * + * @param dataType + * Data type of the parameter + * @param name + * Name of the parameter + * @param value + * Value of the parameter + */ +void +WuQMacroCommand::addParameter(const WuQMacroDataValueTypeEnum::Enum dataType, + const QString& name, + const QVariant& value) +{ + WuQMacroCommandParameter* parameter = new WuQMacroCommandParameter(dataType, + name, + value); + addParameter(parameter); +} + +/** + * Add a parameter to the macro command + * + * @param parameter + * Parameter to add + */ +void +WuQMacroCommand::addParameter(WuQMacroCommandParameter* parameter) +{ + CaretAssert(parameter); + if (parameter == NULL) { + return; + } + + m_parameters.push_back(parameter); + setModified(); +} + + +/** + * @return The number of parameters + */ +int32_t +WuQMacroCommand::getNumberOfParameters() const +{ + return m_parameters.size(); +} + +/** + * @return Parameter at the given index + * + * @param index + * Index of the parameter. + */ +WuQMacroCommandParameter* +WuQMacroCommand::getParameterAtIndex(const int32_t index) +{ + CaretAssertVectorIndex(m_parameters, index); + return m_parameters[index]; +} + +/** + * @return Parameter at the given index (const method) + * + * @param index + * Index of the parameter. + */ +const WuQMacroCommandParameter* +WuQMacroCommand::getParameterAtIndex(const int32_t index) const +{ + CaretAssertVectorIndex(m_parameters, index); + return m_parameters[index]; +} + +/** + * Get the index of the given parameter in this macro + * + * @param parameter + * Paramater for which index is requested + * @return + * Index of parameter or -1 If not found + */ +int32_t +WuQMacroCommand::getIndexOfParameter(const WuQMacroCommandParameter* parameter) const +{ + CaretAssert(parameter); + + const int32_t numParams = getNumberOfParameters(); + for (int32_t i = 0; i < numParams; i++) { + CaretAssertVectorIndex(m_parameters, i); + if (m_parameters[i] == parameter) { + return i; + } + } + + return -1; +} + +/** + * Remove all parameters in this command + */ +void +WuQMacroCommand::removeAllParameters() +{ + for (auto p : m_parameters) { + delete p; + } + m_parameters.clear(); +} + +/** + * @return The object's name + */ +QString +WuQMacroCommand::getObjectName() const +{ + return m_objectName; +} + +/** + * @return The object's descriptive name + */ +QString +WuQMacroCommand::getDescriptiveName() const +{ + return m_descriptiveName; +} + +/** + * @return ToolTip for the object + */ +QString +WuQMacroCommand::getObjectToolTip() const +{ + return toolTip(); +} + +/** + * Set the object's tooltip + * + * @param objectToolTip + * New value for object tooltip + */ +void +WuQMacroCommand::setObjectToolTip(const QString& objectToolTip) +{ + if (toolTip() != objectToolTip) { + setToolTip(objectToolTip); + setModified(); + } +} + +/** + * @return Point to mouse event information + */ +const WuQMacroMouseEventInfo* +WuQMacroCommand::getMouseEventInfo() const +{ + return m_macroMouseEvent; +} + +/** + * @return Point to mouse event information + */ +WuQMacroMouseEventInfo* +WuQMacroCommand::getMouseEventInfo() +{ + return m_macroMouseEvent; +} + +/** + * Set the mouse event info + * + * @param mouseEventInfo + * The new mouse event info + */ +void +WuQMacroCommand::setMouseEventInfo(WuQMacroMouseEventInfo* mouseEventInfo) +{ + if (m_macroMouseEvent != NULL) { + delete m_macroMouseEvent; + m_macroMouseEvent = NULL; + } + + m_macroMouseEvent = mouseEventInfo; + + if (m_macroMouseEvent != NULL) { + QString title; + + switch (m_macroMouseEvent->getMouseEventType()) { + case WuQMacroMouseEventTypeEnum::BUTTON_PRESS: + title = "Mouse Press "; + break; + case WuQMacroMouseEventTypeEnum::BUTTON_RELEASE: + title = "Mouse Release "; + break; + case WuQMacroMouseEventTypeEnum::DOUBLE_CLICKED: + title = "Mouse Double Click "; + break; + case WuQMacroMouseEventTypeEnum::MOVE: + title = "Mouse Move "; + break; + } + + title.append(m_objectName); + setText(title); + } +} + +/** + * @return True if this command the same mouse event type as the given command. + * Must be mouse move events only. + * + * @param command + * The other command + */ +bool +WuQMacroCommand::isMouseEventMatch(const WuQMacroCommand* command) const +{ + if (command->getCommandType() == WuQMacroCommandTypeEnum::MOUSE) { + if (getCommandType() == WuQMacroCommandTypeEnum::MOUSE) { + const WuQMacroMouseEventInfo* myMouse = getMouseEventInfo(); + CaretAssert(myMouse); + const WuQMacroMouseEventInfo* otherMouse = command->getMouseEventInfo(); + CaretAssert(otherMouse); + if ((myMouse->getMouseEventType() == WuQMacroMouseEventTypeEnum::MOVE) + && (myMouse->getMouseEventType() == WuQMacroMouseEventTypeEnum::MOVE)) { + if ((myMouse->getMouseButton() == otherMouse->getMouseButton()) + && (myMouse->getMouseButtonsMask() == otherMouse->getMouseButtonsMask()) + && (myMouse->getKeyboardModifiersMask() == otherMouse->getKeyboardModifiersMask()) + && (myMouse->getWidgetWidth() == otherMouse->getWidgetWidth()) + && (myMouse->getWidgetHeight() == otherMouse->getWidgetHeight())) { + return true; + } + } + } + } + + return false; +} + +/** + * @return Delay in seconds + */ +float +WuQMacroCommand::getDelayInSeconds() const +{ + return m_delayInSeconds; +} + +/** + * Set delay in seconds + * + * @param seconds + * New delay value + */ +void +WuQMacroCommand::setDelayInSeconds(const float seconds) +{ + if (seconds != m_delayInSeconds) { + m_delayInSeconds = seconds; + setModified(); + } +} + +/** + * @return The custom operation command type name + * Used when class type is WuQMacroWidgetTypeEnum::CUSTOM_OPERATION + */ +QString +WuQMacroCommand::getCustomOperationTypeName() const +{ + return m_customOperationTypeName; +} + +/** + * Set the custom operation command type name + * Used when class type is WuQMacroWidgetTypeEnum::CUSTOM_OPERATION + * + * @param customOperationCommandTypeName + * New value + */ +void +WuQMacroCommand::setCustomOperationTypeName(const QString& customOperationTypeName) +{ + if (m_customOperationTypeName != customOperationTypeName) { + m_customOperationTypeName = customOperationTypeName; + setModified(); + } +} + +/** + * @return True if this instance is modified + */ +bool +WuQMacroCommand::isModified() const +{ + if (m_modifiedStatusFlag) { + return true; + } + + for (const auto p : m_parameters) { + if (p->isModified()) { + return true; + } + } + + return false; +} + +/** + * Clear the modified status + */ +void +WuQMacroCommand::clearModified() +{ + m_modifiedStatusFlag = false; + + for (auto p : m_parameters) { + p->clearModified(); + } +} + +/** + * Set the modification status to modified + */ +void +WuQMacroCommand::setModified() +{ + m_modifiedStatusFlag = true; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +WuQMacroCommand::toString() const +{ + QString s("WuQMacroCommand text=%1 name=%2, commandType=%3, widgetType=%4"); + s = s.arg(text() + ).arg(m_objectName + ).arg(WuQMacroCommandTypeEnum::toName(m_commandType) + ).arg(WuQMacroWidgetTypeEnum::toName(m_widgetType)); + + for (const auto p : m_parameters) { + s.append(", value=" + p->getValue().toString()); + } + return s; +} + diff --git a/src/Common/WuQMacroCommand.h b/src/Common/WuQMacroCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..af0fd5612192d900b57178fb51e7e34b2613da3c --- /dev/null +++ b/src/Common/WuQMacroCommand.h @@ -0,0 +1,179 @@ +#ifndef __WU_Q_MACRO_COMMAND_H__ +#define __WU_Q_MACRO_COMMAND_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include +#include + +#include "TracksModificationInterface.h" +#include "WuQMacroCommandTypeEnum.h" +#include "WuQMacroDataValueTypeEnum.h" +#include "WuQMacroWidgetTypeEnum.h" + +class QObject; + +namespace caret { + + class WuQMacroCommandParameter; + class WuQMacroMouseEventInfo; + + class WuQMacroCommand : public QStandardItem, public TracksModificationInterface { + + public: + + static WuQMacroCommand* newInstanceCustomCommand(const QString& customOperationName, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delay, + QString& errorMessageOut); + + static WuQMacroCommand* newInstanceMouseCommand(WuQMacroMouseEventInfo* mouseEventInfo, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delay, + QString& errorMessageOut); + + static WuQMacroCommand* newInstanceWidgetCommand(const WuQMacroWidgetTypeEnum::Enum widgetType, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delay, + QString& errorMessageOut); + + WuQMacroCommand(const WuQMacroCommandTypeEnum::Enum commandType, + const QString& customOperationTypeName, + WuQMacroMouseEventInfo* mouseEventInfo, + const WuQMacroWidgetTypeEnum::Enum widgetType, + const int32_t version, + const QString& objectName, + const QString& objectDescriptiveName, + const QString& objectToolTip, + const float delayValue); + + virtual ~WuQMacroCommand(); + + WuQMacroCommand(const WuQMacroCommand& obj); + + WuQMacroCommand& operator=(const WuQMacroCommand& obj); + + WuQMacroCommandTypeEnum::Enum getCommandType() const; + + WuQMacroWidgetTypeEnum::Enum getWidgetType() const; + + int32_t getVersion() const; + + QString getObjectName() const; + + QString getDescriptiveName() const; + + QString getObjectToolTip() const; + + void setObjectToolTip(const QString& objectToolTip); + + void addParameter(WuQMacroCommandParameter* parameter); + + void addParameter(const WuQMacroDataValueTypeEnum::Enum dataType, + const QString& name, + const QVariant& value); + + int32_t getNumberOfParameters() const; + + WuQMacroCommandParameter* getParameterAtIndex(const int32_t); + + const WuQMacroCommandParameter* getParameterAtIndex(const int32_t) const; + + int32_t getIndexOfParameter(const WuQMacroCommandParameter* parameter) const; + + WuQMacroMouseEventInfo* getMouseEventInfo(); + + const WuQMacroMouseEventInfo* getMouseEventInfo() const; + + void setMouseEventInfo(WuQMacroMouseEventInfo* mouseEventInfo); + + bool isMouseEventMatch(const WuQMacroCommand* command) const; + + float getDelayInSeconds() const; + + void setDelayInSeconds(const float seconds); + + QString getCustomOperationTypeName() const; + + void setCustomOperationTypeName(const QString& customOperationTypeName); + + // ADD_NEW_METHODS_HERE + + virtual bool isModified() const override; + + virtual void clearModified() override; + + virtual void setModified() override; + + virtual AString toString() const; + + virtual int type() const override; + + private: + void copyHelperWuQMacroCommand(const WuQMacroCommand& obj); + + void updateTitle(); + + void removeAllParameters(); + + WuQMacroCommandTypeEnum::Enum m_commandType; + + QString m_customOperationTypeName; + + WuQMacroMouseEventInfo* m_macroMouseEvent; + + WuQMacroWidgetTypeEnum::Enum m_widgetType; + + int32_t m_version; + + QString m_objectName; + + QString m_descriptiveName; + + float m_delayInSeconds = 1.0f; + + std::vector m_parameters; + + bool m_modifiedStatusFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_COMMAND_DECLARE__ + // +#endif // __WU_Q_MACRO_COMMAND_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_COMMAND_H__ diff --git a/src/Common/WuQMacroCommandParameter.cxx b/src/Common/WuQMacroCommandParameter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c4bb92c5f2fad63340970e304cd37e48b895c4b5 --- /dev/null +++ b/src/Common/WuQMacroCommandParameter.cxx @@ -0,0 +1,183 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ +#include "WuQMacroCommandParameter.h" +#undef __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::WuQMacroCommandParameter + * \brief A paramater contained in a WuQMacroCommand + * \ingroup Common + */ + +/** + * Constructor. + */ +WuQMacroCommandParameter::WuQMacroCommandParameter() +: CaretObjectTracksModification() +{ + +} + +/** + * Constructor. + * + * @param dataType + * Data type of the parameter + * @param name + * Name of the parameter + * @param value + * Value of the parameter + */ +WuQMacroCommandParameter::WuQMacroCommandParameter(const WuQMacroDataValueTypeEnum::Enum dataType, + const QString& name, + const QVariant& value) +: CaretObjectTracksModification(), +m_dataType(dataType), +m_name(name), +m_value(value) +{ + +} + + +/** + * Destructor. + */ +WuQMacroCommandParameter::~WuQMacroCommandParameter() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +WuQMacroCommandParameter::WuQMacroCommandParameter(const WuQMacroCommandParameter& obj) +: CaretObjectTracksModification(obj) +{ + this->copyHelperWuQMacroCommandParameter(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +WuQMacroCommandParameter& +WuQMacroCommandParameter::operator=(const WuQMacroCommandParameter& obj) +{ + if (this != &obj) { + CaretObjectTracksModification::operator=(obj); + this->copyHelperWuQMacroCommandParameter(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +WuQMacroCommandParameter::copyHelperWuQMacroCommandParameter(const WuQMacroCommandParameter& obj) +{ + m_dataType = obj.m_dataType; + m_name = obj.m_name; + m_customDataType = obj.m_customDataType; + m_value = obj.m_value; + setModified(); +} + +/** + * @return Data type of this parameter + */ +WuQMacroDataValueTypeEnum::Enum +WuQMacroCommandParameter::getDataType() const +{ + return m_dataType; +} + +/** + * @return Name of this parameter + */ +QString +WuQMacroCommandParameter::getName() const +{ + return m_name; +} + +/** + * @return Value of this parameter + */ +QVariant +WuQMacroCommandParameter::getValue() const +{ + return m_value; +} + +/** + * Set the value of this parameter + * + * @param value + * New value of parameter + */ +void +WuQMacroCommandParameter::setValue(const QVariant& value) +{ + if (value != m_value) { + m_value = value; + setModified(); + } +} + +/** + * @return The custom type data type name + */ +QString +WuQMacroCommandParameter::getCustomDataType() const +{ + return m_customDataType; +} + +/** + * Set the custom type data type name + * + * @param customDataType + * The custom data type + */ +void +WuQMacroCommandParameter::setCustomDataType(const QString& customDataType) +{ + if (m_customDataType != customDataType) { + m_customDataType = customDataType; + setModified(); + } +} + diff --git a/src/Common/WuQMacroCommandParameter.h b/src/Common/WuQMacroCommandParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..8f95be048a9a7beb02dbe930eff2c41f0fc16e5d --- /dev/null +++ b/src/Common/WuQMacroCommandParameter.h @@ -0,0 +1,84 @@ +#ifndef __WU_Q_MACRO_COMMAND_PARAMETER_H__ +#define __WU_Q_MACRO_COMMAND_PARAMETER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include "CaretObjectTracksModification.h" +#include "WuQMacroDataValueTypeEnum.h" + + +namespace caret { + + class WuQMacroCommandParameter : public CaretObjectTracksModification { + + public: + WuQMacroCommandParameter(const WuQMacroDataValueTypeEnum::Enum dataType, + const QString& name, + const QVariant& value); + + WuQMacroCommandParameter(); + + virtual ~WuQMacroCommandParameter(); + + WuQMacroCommandParameter(const WuQMacroCommandParameter& obj); + + WuQMacroCommandParameter& operator=(const WuQMacroCommandParameter& obj); + + WuQMacroDataValueTypeEnum::Enum getDataType() const; + + QString getName() const; + + QVariant getValue() const; + + void setValue(const QVariant& value); + + QString getCustomDataType() const; + + void setCustomDataType(const QString& userDataType); + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperWuQMacroCommandParameter(const WuQMacroCommandParameter& obj); + + WuQMacroDataValueTypeEnum::Enum m_dataType = WuQMacroDataValueTypeEnum::INVALID; + + QString m_name; + + QString m_customDataType; + + QVariant m_value; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ + // +#endif // __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_COMMAND_PARAMETER_H__ diff --git a/src/Common/WuQMacroCommandTypeEnum.cxx b/src/Common/WuQMacroCommandTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6254b3b548897af4cf01db8e4c4f3ee89ea6bd36 --- /dev/null +++ b/src/Common/WuQMacroCommandTypeEnum.cxx @@ -0,0 +1,377 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ +#include "WuQMacroCommandTypeEnum.h" +#undef __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroCommandTypeEnum + * \brief Enumerated type for command type in a WuQMacroCommand + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_wuQMacroCommandTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void wuQMacroCommandTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WuQMacroCommandTypeEnum.h" + * + * Instatiate: + * m_wuQMacroCommandTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_wuQMacroCommandTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_wuQMacroCommandTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(wuQMacroCommandTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_wuQMacroCommandTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WuQMacroCommandTypeEnum::Enum VARIABLE = m_wuQMacroCommandTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WuQMacroCommandTypeEnum::WuQMacroCommandTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WuQMacroCommandTypeEnum::~WuQMacroCommandTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WuQMacroCommandTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WuQMacroCommandTypeEnum(CUSTOM_OPERATION, + "CUSTOM_OPERATION", + "CustomOperation")); + + enumData.push_back(WuQMacroCommandTypeEnum(MOUSE, + "MOUSE", + "Mouse")); + + enumData.push_back(WuQMacroCommandTypeEnum(WIDGET, + "WIDGET", + "Widget")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WuQMacroCommandTypeEnum* +WuQMacroCommandTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WuQMacroCommandTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroCommandTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroCommandTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroCommandTypeEnum::Enum +WuQMacroCommandTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroCommandTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroCommandTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroCommandTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroCommandTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroCommandTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroCommandTypeEnum::Enum +WuQMacroCommandTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroCommandTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroCommandTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroCommandTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WuQMacroCommandTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WuQMacroCommandTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WuQMacroCommandTypeEnum::Enum +WuQMacroCommandTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroCommandTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroCommandTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroCommandTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WuQMacroCommandTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroCommandTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WuQMacroCommandTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroCommandTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WuQMacroCommandTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/WuQMacroCommandTypeEnum.h b/src/Common/WuQMacroCommandTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..6d51b5ddd6d9b372af04d585ee2bea181f1fa680 --- /dev/null +++ b/src/Common/WuQMacroCommandTypeEnum.h @@ -0,0 +1,106 @@ +#ifndef __WU_Q_MACRO_COMMAND_TYPE_ENUM_H__ +#define __WU_Q_MACRO_COMMAND_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WuQMacroCommandTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Custom operation */ + CUSTOM_OPERATION, + /** Mouse Operation */ + MOUSE, + /** Widget or Action Signal/Slot */ + WIDGET + }; + + + ~WuQMacroCommandTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WuQMacroCommandTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WuQMacroCommandTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ +std::vector WuQMacroCommandTypeEnum::enumData; +bool WuQMacroCommandTypeEnum::initializedFlag = false; +int32_t WuQMacroCommandTypeEnum::integerCodeCounter = 0; +#endif // __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_COMMAND_TYPE_ENUM_H__ diff --git a/src/Common/WuQMacroDataValueTypeEnum.cxx b/src/Common/WuQMacroDataValueTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4b40c1403a39b66482f704d0b0504c5967a2510a --- /dev/null +++ b/src/Common/WuQMacroDataValueTypeEnum.cxx @@ -0,0 +1,400 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ +#include "WuQMacroDataValueTypeEnum.h" +#undef __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroDataValueTypeEnum + * \brief Enumerated type for macro data values + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_wuQMacroDataValueTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void wuQMacroDataValueTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WuQMacroDataValueTypeEnum.h" + * + * Instatiate: + * m_wuQMacroDataValueTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_wuQMacroDataValueTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_wuQMacroDataValueTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(wuQMacroDataValueTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_wuQMacroDataValueTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WuQMacroDataValueTypeEnum::Enum VARIABLE = m_wuQMacroDataValueTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WuQMacroDataValueTypeEnum::WuQMacroDataValueTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WuQMacroDataValueTypeEnum::~WuQMacroDataValueTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WuQMacroDataValueTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WuQMacroDataValueTypeEnum(INVALID, + "INVALID", + "Invalid")); + + enumData.push_back(WuQMacroDataValueTypeEnum(AXIS, + "AXIS", + "Axis")); + + enumData.push_back(WuQMacroDataValueTypeEnum(BOOLEAN, + "BOOLEAN", + "Boolean")); + + enumData.push_back(WuQMacroDataValueTypeEnum(FLOAT, + "FLOAT", + "Float")); + + enumData.push_back(WuQMacroDataValueTypeEnum(INTEGER, + "INTEGER", + "Integer")); + + enumData.push_back(WuQMacroDataValueTypeEnum(MOUSE, + "MOUSE", + "Mouse")); + + enumData.push_back(WuQMacroDataValueTypeEnum(NONE, + "NONE", + "None")); + + enumData.push_back(WuQMacroDataValueTypeEnum(STRING, + "STRING", + "String")); + + enumData.push_back(WuQMacroDataValueTypeEnum(STRING_LIST, + "STRING_LIST", + "StringList")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WuQMacroDataValueTypeEnum* +WuQMacroDataValueTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WuQMacroDataValueTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroDataValueTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroDataValueTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroDataValueTypeEnum::Enum +WuQMacroDataValueTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroDataValueTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroDataValueTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroDataValueTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroDataValueTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroDataValueTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroDataValueTypeEnum::Enum +WuQMacroDataValueTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroDataValueTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroDataValueTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroDataValueTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WuQMacroDataValueTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WuQMacroDataValueTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WuQMacroDataValueTypeEnum::Enum +WuQMacroDataValueTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroDataValueTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroDataValueTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroDataValueTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WuQMacroDataValueTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroDataValueTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WuQMacroDataValueTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroDataValueTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WuQMacroDataValueTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/WuQMacroDataValueTypeEnum.h b/src/Common/WuQMacroDataValueTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..bbb7d5512076fce7099b371bafa90f0d6518291a --- /dev/null +++ b/src/Common/WuQMacroDataValueTypeEnum.h @@ -0,0 +1,118 @@ +#ifndef __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_H__ +#define __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WuQMacroDataValueTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Invalid */ + INVALID, + /** Axis */ + AXIS, + /** Boolean */ + BOOLEAN, + /** Float */ + FLOAT, + /** Integer */ + INTEGER, + /** Mouse */ + MOUSE, + /** None (no data value associated with object */ + NONE, + /** String */ + STRING, + /** String List*/ + STRING_LIST + }; + + + ~WuQMacroDataValueTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WuQMacroDataValueTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WuQMacroDataValueTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ +std::vector WuQMacroDataValueTypeEnum::enumData; +bool WuQMacroDataValueTypeEnum::initializedFlag = false; +int32_t WuQMacroDataValueTypeEnum::integerCodeCounter = 0; +#endif // __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_H__ diff --git a/src/Common/WuQMacroFile.cxx b/src/Common/WuQMacroFile.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4c359f463b61c8e6ef82db65be18fa2510f78eb2 --- /dev/null +++ b/src/Common/WuQMacroFile.cxx @@ -0,0 +1,284 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_FILE_DECLARE__ +#include "WuQMacroFile.h" +#undef __WU_Q_MACRO_FILE_DECLARE__ + +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "DataFileException.h" +#include "WuQMacro.h" +#include "WuQMacroGroup.h" +#include "WuQMacroGroupXmlStreamReader.h" +#include "WuQMacroGroupXmlStreamWriter.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacroFile + * \brief File for storing macros + * \ingroup Common + */ + +/** + * Constructor. + */ +WuQMacroFile::WuQMacroFile() +: DataFile() +{ + m_macroGroup.reset(new WuQMacroGroup("File")); +} + +/** + * Destructor. + */ +WuQMacroFile::~WuQMacroFile() +{ +} + +/** + * @return True if this file is empty (has no macros) + */ +bool +WuQMacroFile::isEmpty() const +{ + return (m_macroGroup->getNumberOfMacros() == 0); +} + +/** + * @return Macro group in this file + */ +WuQMacroGroup* +WuQMacroFile::getMacroGroup() +{ + return m_macroGroup.get(); +} + +/** + * @return Macro group in this file (const method) + */ +const WuQMacroGroup* +WuQMacroFile::getMacroGroup() const +{ + return m_macroGroup.get(); +} + + +/** + * @return File filter for macro file in a QFileDialog + */ +QString +WuQMacroFile::getFileDialogFilter() +{ + QString f("Macros (*" + + getFileExtension() + + ")"); + return f; +} + +/** + * @return Extension for a macro file + */ +QString +WuQMacroFile::getFileExtension() +{ + return ".wb_macro"; +} + +/** + * Set the status to unmodified. + */ +void +WuQMacroFile::clearModified() +{ + DataFile::clearModified(); + m_macroGroup->clearModified(); +} + +/** + * Is the object modified? + * @return true if modified, else false. + */ +bool +WuQMacroFile::isModified() const +{ + if (DataFile::isModified()) { + return true; + } + if (m_macroGroup->isModified()) { + return true; + } + return false; +} + +/** + * Clear the contents of the file. + */ +void +WuQMacroFile::clear() +{ + m_macroGroup->clear(); +} + +/** + * Append macros in the given group to this file + * + * @param macroGroup + * The macro group whose macros are appended to this macro group + */ +void +WuQMacroFile::appendMacroGroup(const WuQMacroGroup* macroGroup) +{ + const int32_t numMacros = macroGroup->getNumberOfMacros(); + for (int32_t i = 0; i < numMacros; i++) { + const WuQMacro* macro = macroGroup->getMacroAtIndex(i); + CaretAssert(macro); + addMacro(new WuQMacro(*macro)); + } + setModified(); +} + +/** + * Add a macro to this file. + * This file will take ownership of the macro. + * + * @param macro + * Macro to add to file + */ +void +WuQMacroFile::addMacro(WuQMacro* macro) +{ + CaretAssert(macro); + m_macroGroup->addMacro(macro); +} + +/** + * Set the macro group's name to the name of the file + * without the extension + */ +void +WuQMacroFile::setMacroGroupName(const QString& filename) +{ + if (filename.isEmpty()) { + return; + } + + QFileInfo fileInfo(filename); + QString macroGroupName(fileInfo.fileName()); + const int extIndex = macroGroupName.indexOf(getFileExtension()); + if (extIndex > 0) { + macroGroupName.resize(extIndex); + } + m_macroGroup->setName(macroGroupName); +} + + +/** + * Read the data file. + * + * @param filename + * Name of the data file. + * @throws DataFileException + * If the file was not successfully read. + */ +void +WuQMacroFile::readFile(const AString& filename) +{ + if (filename.isEmpty()) { + throw DataFileException("Filename is empty"); + } + + QFile file(filename); + if (file.open(QFile::ReadOnly)) { + setMacroGroupName(filename); + + QTextStream textStream(&file); + const QString fileContentString = textStream.readAll(); + + QString errorMessage; + WuQMacroGroupXmlStreamReader reader; + if ( ! reader.readFromString(fileContentString, + m_macroGroup.get(), + errorMessage)) { + file.close(); + throw DataFileException(errorMessage); + } + + setFileName(filename); + clearModified(); + } + else { + throw DataFileException("Unable to open file for writing: " + + filename); + } +} + +/** + * Write the data file. + * + * @param filename + * Name of the data file. + * @throws DataFileException + * If the file was not successfully written. + */ +void +WuQMacroFile::writeFile(const AString& filename) +{ + if (filename.isEmpty()) { + throw DataFileException("Filename is empty"); + } + + QFile file(filename); + if (file.open(QFile::WriteOnly)) { + setMacroGroupName(filename); + + /* + * Place the macro group into a string + */ + QString fileContentString; + WuQMacroGroupXmlStreamWriter writer; + writer.writeToString(m_macroGroup.get(), + fileContentString); + + /* + * Write string containing macros and close file + */ + QTextStream textStream(&file); + textStream << fileContentString; + file.close(); + + setFileName(filename); + clearModified(); + } + else { + throw DataFileException("Unable to open file for writing: " + + filename); + } +} + + diff --git a/src/Common/WuQMacroFile.h b/src/Common/WuQMacroFile.h new file mode 100644 index 0000000000000000000000000000000000000000..ca04944d5c41266ef192d13344bb08fba4f9990f --- /dev/null +++ b/src/Common/WuQMacroFile.h @@ -0,0 +1,84 @@ +#ifndef __WU_Q_MACRO_FILE_H__ +#define __WU_Q_MACRO_FILE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "DataFile.h" + + + +namespace caret { + + class WuQMacro; + class WuQMacroGroup; + + class WuQMacroFile : public DataFile { + + public: + WuQMacroFile(); + + virtual ~WuQMacroFile(); + + virtual bool isEmpty() const override; + + WuQMacroGroup* getMacroGroup(); + + const WuQMacroGroup* getMacroGroup() const; + + virtual void readFile(const AString& filename) override; + + virtual void writeFile(const AString& filename) override; + + static QString getFileDialogFilter(); + + static QString getFileExtension(); + + virtual void clearModified(); + + virtual bool isModified() const; + + virtual void clear(); + + void addMacro(WuQMacro* macro); + + void appendMacroGroup(const WuQMacroGroup* macroGroup); + + // ADD_NEW_METHODS_HERE + + private: + void setMacroGroupName(const QString& filename); + + std::unique_ptr m_macroGroup; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_FILE_DECLARE__ + // +#endif // __WU_Q_MACRO_FILE_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_FILE_H__ diff --git a/src/Common/WuQMacroGroup.cxx b/src/Common/WuQMacroGroup.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8ff4550ef66c4af2643dac70f1be8873f0b8a9d8 --- /dev/null +++ b/src/Common/WuQMacroGroup.cxx @@ -0,0 +1,622 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_GROUP_DECLARE__ +#include "WuQMacroGroup.h" +#undef __WU_Q_MACRO_GROUP_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "WuQMacro.h" +#include "WuQMacroGroupXmlStreamReader.h" +#include "WuQMacroGroupXmlStreamWriter.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacroGroup + * \brief Contains a group of macros + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param name + * Name of group + */ +WuQMacroGroup::WuQMacroGroup(const QString& name) +: QStandardItemModel(), TracksModificationInterface(), +m_name(name) +{ + m_uniqueIdentifier = QUuid::createUuid().toString(); +} + +/** + * Destructor. + */ +WuQMacroGroup::~WuQMacroGroup() +{ + clearPrivate(); +} + +/** + * Clear (remove all macros) + */ +void +WuQMacroGroup::clearPrivate() +{ + /* Note: Do not clear unique identifier */ +} + +/** + * @return Name of group + */ +QString +WuQMacroGroup::getName() const +{ + return m_name; +} + +/** + * Set name of group + * + * @param name + * Name of group + */ +void +WuQMacroGroup::setName(const QString& name) +{ + if (m_name != name) { + m_name = name; + setModified(); + } +} + +/** + * @return The unique identifier + */ +QString +WuQMacroGroup::getUniqueIdentifier() const +{ + return m_uniqueIdentifier; +} + +/** + * Set unique identifier of macro + * + * @param uniqueIdentifier + * New unique identifier + */void +WuQMacroGroup::setUniqueIdentifier(const QString& uniqueIdentifier) +{ + if (uniqueIdentifier.isEmpty()) { + return; + } + if (m_uniqueIdentifier != uniqueIdentifier) { + m_uniqueIdentifier = uniqueIdentifier; + setModified(); + } +} + +/** + * Add a macro + * + * @param macro + * Macro added to this group. This group will take ownership of the macro. + */ +void +WuQMacroGroup::addMacro(WuQMacro* macro) +{ + appendRow(macro); + setModified(); +} + +/** + * Insert the given macro at the given index + * + * @param index + * Index of where to insert the macro + * @param macro + * Macro to insert. + */ +void +WuQMacroGroup::insertMacroAtIndex(const int32_t index, + WuQMacro* macro) +{ + CaretAssert((index >= 0) + && (index <= getNumberOfMacros())); + CaretAssert(macro); + + insertRow(index, + macro); + setModified(); +} + +/** + * Append macros in the given group to this group + * + * @param macroGroup + * The macro group whose macros are appended to this macro group + */ +void +WuQMacroGroup::appendMacroGroup(const WuQMacroGroup* macroGroup) +{ + const int32_t numMacros = macroGroup->getNumberOfMacros(); + for (int32_t i = 0; i < numMacros; i++) { + const WuQMacro* macro = macroGroup->getMacroAtIndex(i); + CaretAssert(macro); + appendRow(new WuQMacro(*macro)); + } + setModified(); +} + +/** + * @return Number of macros in group + */ +int32_t +WuQMacroGroup::getNumberOfMacros() const +{ + return rowCount(); +} + +/** + * @return Is this empty (contains no macros) ? + */ +bool +WuQMacroGroup::isEmpty() const +{ + return (getNumberOfMacros() <= 0); +} + +/** + * Get the macro with the given name + * + * @param name + * Name of the macro + * @return + * Pointer to macro with the name or NULL if not found + */ +WuQMacro* +WuQMacroGroup::getMacroByName(const QString& name) +{ + const int32_t numItems = rowCount(); + for (int32_t i = 0; i < numItems; i++) { + WuQMacro* macro = getMacroAtIndex(i); + if (macro->getName() == name) { + return macro; + } + } + + return NULL; +} + +/** + * Get the macro with the given name + * + * @param name + * Name of the macro + * @return + * Pointer to macro with the name or NULL if not found + */ +const WuQMacro* +WuQMacroGroup::getMacroByName(const QString& name) const +{ + const int32_t numItems = rowCount(); + for (int32_t i = 0; i < numItems; i++) { + const WuQMacro* macro = getMacroAtIndex(i); + if (macro->getName() == name) { + return macro; + } + } + + return NULL; +} + +/** + * Get the macro with the given unique identifier + * + * @param uniqueIdentifier + * Unique identifier of the macro + * @return + * Pointer to macro with the unique identifier or NULL if not found + */ +WuQMacro* +WuQMacroGroup::getMacroWithUniqueIdentifier(const QString& uniqueIdentifier) +{ + const int32_t numItems = rowCount(); + for (int32_t i = 0; i < numItems; i++) { + WuQMacro* macro = getMacroAtIndex(i); + if (macro->getUniqueIdentifier() == uniqueIdentifier) { + return macro; + } + } + + return NULL; +} + +/** + * Get the macro with the given unique identifier (const method) + * + * @param uniqueIdentifier + * Unique identifier of the macro + * @return + * Pointer to macro with the unique identifier or NULL if not found + */ +const WuQMacro* +WuQMacroGroup::getMacroWithUniqueIdentifier(const QString& uniqueIdentifier) const +{ + const int32_t numItems = rowCount(); + for (int32_t i = 0; i < numItems; i++) { + const WuQMacro* macro = getMacroAtIndex(i); + if (macro->getUniqueIdentifier() == uniqueIdentifier) { + return macro; + } + } + + return NULL; +} + +/** + * Get the macro with the given short cut key + * + * @param name + * Name of the macro + * @return + * Pointer to macro with the short cut key or NULL if not found + */ +WuQMacro* +WuQMacroGroup::getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) +{ + const int32_t numItems = rowCount(); + for (int32_t i = 0; i < numItems; i++) { + WuQMacro* macro = getMacroAtIndex(i); + if (macro->getShortCutKey() == shortCutKey) { + return macro; + } + } + + return NULL; +} + +/** + * Get the macro with the given short cut key + * + * @param name + * Name of the macro + * @return + * Pointer to macro with the short cut key or NULL if not found + */ +const WuQMacro* +WuQMacroGroup::getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const +{ + const int32_t numItems = rowCount(); + for (int32_t i = 0; i < numItems; i++) { + const WuQMacro* macro = getMacroAtIndex(i); + if (macro->getShortCutKey() == shortCutKey) { + return macro; + } + } + + return NULL; +} + +/** + * @return + * Macro at the given index + * @param index + * Index of the macro + */ +WuQMacro* +WuQMacroGroup::getMacroAtIndex(const int32_t index) +{ + CaretAssert((index >= 0) + && (index < rowCount())); + QStandardItem* standardItem = item(index); + CaretAssert(standardItem); + WuQMacro* macro = dynamic_cast(standardItem); + CaretAssert(macro); + return macro; +} + +/** + * @return + * Macro at the given index + * @param index + * Index of the macro + */ +const WuQMacro* +WuQMacroGroup::getMacroAtIndex(const int32_t index) const +{ + CaretAssert((index >= 0) + && (index < rowCount())); + QStandardItem* standardItem = item(index); + CaretAssert(standardItem); + WuQMacro* macro = dynamic_cast(standardItem); + CaretAssert(macro); + return macro; + +} + +/** + * Get the index of the given macro + * + * @param macro + * The macro for index + * @return + * Index of macro or -1 if not found + */ +int32_t +WuQMacroGroup::getIndexOfMacro(const WuQMacro* macro) +{ + const int32_t count = getNumberOfMacros(); + for (int32_t i = 0; i < count; i++) { + if (getMacroAtIndex(i) == macro) { + return i; + } + } + + return -1; +} + +/** + * @return True if this macro group contains the given macro + * + * @param macro + * Macro for inclusion testing + */ +bool +WuQMacroGroup::containsMacro(const WuQMacro* macro) +{ + const int32_t index = getIndexOfMacro(macro); + if (index >= 0) { + return true; + } + else { + return false; + } +} + +/** + * Delete the given macro from this group + * + * @param macro + * Macro for deletion + */ +void +WuQMacroGroup::deleteMacro(const WuQMacro* macro) +{ + const int32_t index = getIndexOfMacro(macro); + if (index >= 0) { + deleteMacroAtIndex(index); + } +} + +/** + * Delete the macro at the given index + * + * @param index + * Index of macro for deletion + */ +void +WuQMacroGroup::deleteMacroAtIndex(const int32_t index) +{ + /* + * Note that 'takeItem' removes the item and the + * row becomes NULL so also need to remove the row. + */ + CaretAssert((index >= 0) + && (index < rowCount())); + QStandardItem* item = takeItem(index); + CaretAssert(item); + removeRow(index); + delete item; + + setModified(); +} + +/** + * Move the given macro down one position + * + * @param macro + */ +void +WuQMacroGroup::moveMacroDown(WuQMacro* macro) +{ + const int32_t index = getIndexOfMacro(macro); + if ((index >= 0) + && (index < getNumberOfMacros() - 1)) { + /* Note that take item removes item but does not remove row */ + QStandardItem* item = takeItem(index); + removeRow(index); + CaretAssert(item); + insertMacroAtIndex(index + 1, + dynamic_cast(item)); + } +} + +/** + * Move the given macro up one position + * + * @param macro + */ +void +WuQMacroGroup::moveMacroUp(WuQMacro* macro) +{ + const int32_t index = getIndexOfMacro(macro); + if ((index > 0) + && (index < getNumberOfMacros())) { + /* Note that take child removes item but does not remove row */ + QStandardItem* item = takeItem(index); + removeRow(index); + CaretAssert(item); + insertMacroAtIndex(index - 1, + dynamic_cast(item)); + } +} + +/** + * Take all macros from this macro group. After calling + * this method, 'this' macro group contains no macros + * + * @return All macros from this group. + */ +std::vector +WuQMacroGroup::takeAllMacros() +{ + std::vector macrosOut; + + const int32_t numMacros = rowCount(); + for (int32_t i = 0; i < numMacros; i++) { + WuQMacro* macro = dynamic_cast(takeItem(i)); + CaretAssert(macro); + macrosOut.push_back(macro); + } + + removeRows(0, numMacros); + CaretAssert(rowCount() == 0); + + return macrosOut; +} + +/** + * @return True if this instance is modified + */ +bool +WuQMacroGroup::isModified() const +{ + if (m_modifiedStatusFlag) { + return true; + } + + + const int32_t count = getNumberOfMacros(); + for (int32_t i = 0; i < count; i++) { + if (getMacroAtIndex(i)->isModified()) { + return true; + break; + } + } + + return false; +} + +/** + * Clear the modified status + */ +void +WuQMacroGroup::clearModified() +{ + m_modifiedStatusFlag = false; + + const int32_t count = getNumberOfMacros(); + for (int32_t i = 0; i < count; i++) { + getMacroAtIndex(i)->clearModified(); + } +} + +/** + * Set the modification status to modified + */ +void +WuQMacroGroup::setModified() +{ + m_modifiedStatusFlag = true; +} + + +/** + * Read from a string containing XML. If successful, + * the modified status is cleared. + * + * @param xmlString + * String containing XML + * @param errorMessageOut + * Contains error information if reading fails + * @param nonFatalWarningMessageOut + * May contain non-fatal warnings when reading is successful + * @return + * True if successful, else false + */ +bool +WuQMacroGroup::readXmlFromStringOld(const QString& xmlString, + QString& errorMessageOut, + QString& nonFatalWarningMessageOut) +{ + errorMessageOut.clear(); + nonFatalWarningMessageOut.clear(); + + WuQMacroGroupXmlStreamReader reader; + if ( ! reader.readFromString(xmlString, + this, + errorMessageOut)) { + return false; + } + + clearModified(); + + return true; +} + +/** + * Write to a string containing XML. If successful, + * the modified status is cleared. + * + * @param xmlString + * String to which XML is written + * @param errorMessageOut + * Contains error information if reading fails + * @return + * True if successful, else false + */ +bool +WuQMacroGroup::writeXmlToString(QString& xmlString, + QString& errorMessageOut) +{ + xmlString.clear(); + errorMessageOut.clear(); + + WuQMacroGroupXmlStreamWriter writer; + writer.writeToString(this, + xmlString); + clearModified(); + + return true; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +WuQMacroGroup::toString() const +{ + QString s("WuQMacroGroup name=" + m_name + "\n"); + const int32_t count = getNumberOfMacros(); + for (int32_t i = 0; i < count; i++) { + s.append(getMacroAtIndex(i)->toString() + "\n"); + } + return s; +} + diff --git a/src/Common/WuQMacroGroup.h b/src/Common/WuQMacroGroup.h new file mode 100644 index 0000000000000000000000000000000000000000..6c5928908f062007d825e9226985c5567a021c2c --- /dev/null +++ b/src/Common/WuQMacroGroup.h @@ -0,0 +1,128 @@ +#ifndef __WU_Q_MACRO_GROUP_H__ +#define __WU_Q_MACRO_GROUP_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*LICENSE_END*/ + +#include + +#include + +#include "CaretObjectTracksModification.h" +#include "TracksModificationInterface.h" +#include "WuQMacroShortCutKeyEnum.h" + +namespace caret { + + class WuQMacro; + + class WuQMacroGroup : public QStandardItemModel, public TracksModificationInterface { + + public: + WuQMacroGroup(const QString& groupName); + + virtual ~WuQMacroGroup(); + + QString getName() const; + + void setName(const QString& name); + + QString getUniqueIdentifier() const; + + void setUniqueIdentifier(const QString& uniqueIdentifier); + + void addMacro(WuQMacro* macro); + + void insertMacroAtIndex(const int32_t index, + WuQMacro* macro); + + void appendMacroGroup(const WuQMacroGroup* macroGroup); + + int32_t getNumberOfMacros() const; + + bool isEmpty() const; + + WuQMacro* getMacroByName(const QString& name); + + const WuQMacro* getMacroByName(const QString& name) const; + + WuQMacro* getMacroAtIndex(const int32_t index); + + const WuQMacro* getMacroAtIndex(const int32_t index) const; + + int32_t getIndexOfMacro(const WuQMacro* macro); + + WuQMacro* getMacroWithUniqueIdentifier(const QString& uniqueIdentifier); + + const WuQMacro* getMacroWithUniqueIdentifier(const QString& uniqueIdentifier) const; + + WuQMacro* getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey); + + const WuQMacro* getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const; + + bool containsMacro(const WuQMacro* macro); + + void deleteMacro(const WuQMacro* macro); + + void deleteMacroAtIndex(const int32_t index); + + void moveMacroDown(WuQMacro* macro); + + void moveMacroUp(WuQMacro* macro); + + std::vector takeAllMacros(); + + virtual bool isModified() const override; + + virtual void clearModified() override; + + virtual void setModified() override; + + bool readXmlFromStringOld(const QString& xmlString, + QString& errorMessageOut, + QString& nonFatalWarningMessageOut); + + bool writeXmlToString(QString& xmlString, + QString& errorMessageOut); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void clearPrivate(); + + QString m_uniqueIdentifier; + + QString m_name; + + bool m_modifiedStatusFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_GROUP_DECLARE__ + // +#endif // __WU_Q_MACRO_GROUP_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_GROUP_H__ diff --git a/src/Common/WuQMacroGroupXmlStreamBase.cxx b/src/Common/WuQMacroGroupXmlStreamBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8da464f07987b51228d2075e8f0a33eba740e82f --- /dev/null +++ b/src/Common/WuQMacroGroupXmlStreamBase.cxx @@ -0,0 +1,62 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ +#include "WuQMacroGroupXmlStreamBase.h" +#undef __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::WuQMacroGroupXmlStreamBase + * \brief Base class for reading/writing macro group in XML + * \ingroup Common + */ + +/** + * Constructor. + */ +WuQMacroGroupXmlStreamBase::WuQMacroGroupXmlStreamBase() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +WuQMacroGroupXmlStreamBase::~WuQMacroGroupXmlStreamBase() +{ +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +WuQMacroGroupXmlStreamBase::toString() const +{ + return "WuQMacroGroupXmlStreamBase"; +} + diff --git a/src/Common/WuQMacroGroupXmlStreamBase.h b/src/Common/WuQMacroGroupXmlStreamBase.h new file mode 100644 index 0000000000000000000000000000000000000000..e39c21fda677521973d78122938720b880e3c0a6 --- /dev/null +++ b/src/Common/WuQMacroGroupXmlStreamBase.h @@ -0,0 +1,139 @@ +#ifndef __WU_Q_MACRO_GROUP_XML_STREAM_BASE_H__ +#define __WU_Q_MACRO_GROUP_XML_STREAM_BASE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class WuQMacroGroupXmlStreamBase : public CaretObject { + + protected: + WuQMacroGroupXmlStreamBase(); + + public: + virtual ~WuQMacroGroupXmlStreamBase(); + + WuQMacroGroupXmlStreamBase(const WuQMacroGroupXmlStreamBase&) = delete; + + WuQMacroGroupXmlStreamBase& operator=(const WuQMacroGroupXmlStreamBase&) = delete; + + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + static const QString ATTRIBUTE_COMMAND_TYPE; + static const QString ATTRIBUTE_NAME; + static const QString ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME; + static const QString ATTRIBUTE_DELAY; + static const QString ATTRIBUTE_SHORT_CUT_KEY; + static const QString ATTRIBUTE_UNIQUE_IDENTIFIER; + static const QString ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME; + static const QString ATTRIBUTE_VERSION; + static const QString ATTRIBUTE_WIDGET_TYPE; + + static const QString ATTRIBUTE_MOUSE_BUTTON; + static const QString ATTRIBUTE_MOUSE_BUTTONS_MASK; + static const QString ATTRIBUTE_MOUSE_EVENT_TYPE; + static const QString ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK; + static const QString ATTRIBUTE_MOUSE_LOCAL_X; + static const QString ATTRIBUTE_MOUSE_LOCAL_Y; + static const QString ATTRIBUTE_MOUSE_SCREEN_X; + static const QString ATTRIBUTE_MOUSE_SCREEN_Y; + static const QString ATTRIBUTE_MOUSE_WIDGET_WIDTH; + static const QString ATTRIBUTE_MOUSE_WIDGET_HEIGHT; + static const QString ATTRIBUTE_MOUSE_WINDOW_X; + static const QString ATTRIBUTE_MOUSE_WINDOW_Y; + + static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE; + static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME; + static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE; + static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE; + + static const QString ELEMENT_DESCRIPTION; + static const QString ELEMENT_MACRO; + static const QString ELEMENT_MACRO_COMMAND; + static const QString ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO; + static const QString ELEMENT_MACRO_COMMAND_PARAMETER; + static const QString ELEMENT_MACRO_COMMAND_TOOL_TIP; + static const QString ELEMENT_MACRO_GROUP; + + static const QString VALUE_BOOL_FALSE; + static const QString VALUE_BOOL_TRUE; + static const QString VALUE_VERSION_ONE; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_COMMAND_TYPE = "CommandType"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_NAME = "Name"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME = "CustomOperationTypeName"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_DELAY = "Delay"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME = "DescriptiveName"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_SHORT_CUT_KEY = "ShortCutKey"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_UNIQUE_IDENTIFIER = "UniqueIdentifier"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_VERSION = "Version"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_WIDGET_TYPE = "WidgetType"; + + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_BUTTON = "MouseButton"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_BUTTONS_MASK = "MouseButtonsMask"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_EVENT_TYPE = "MouseEventType"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK = "KeyboardModifiersMask"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_LOCAL_X = "LocalX"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_LOCAL_Y = "LocalY"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_SCREEN_X = "ScreenX"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_SCREEN_Y = "ScreenY"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WIDGET_WIDTH = "WidgetWidth"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WIDGET_HEIGHT = "WidgetHeight"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WINDOW_X = "WindowX"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WINDOW_Y = "WindowY"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE = "DataType"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME = "Name"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE = "CustomDataType"; + const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE = "Value"; + + const QString WuQMacroGroupXmlStreamBase::ELEMENT_DESCRIPTION = "Description"; + const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO = "Macro"; + const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND = "MacroCommand"; + const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO = "MouseEventInfo"; + const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND_PARAMETER = "Parameter"; + const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND_TOOL_TIP = "ToolTip"; + const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_GROUP = "MacroGroup"; + + + const QString WuQMacroGroupXmlStreamBase::VALUE_BOOL_FALSE = "false"; + const QString WuQMacroGroupXmlStreamBase::VALUE_BOOL_TRUE = "true"; + const QString WuQMacroGroupXmlStreamBase::VALUE_VERSION_ONE = "1"; +#endif // __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_GROUP_XML_STREAM_BASE_H__ diff --git a/src/Common/WuQMacroGroupXmlStreamReader.cxx b/src/Common/WuQMacroGroupXmlStreamReader.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d4f02ca2a17bcdf252534edf2c340b2690c880cb --- /dev/null +++ b/src/Common/WuQMacroGroupXmlStreamReader.cxx @@ -0,0 +1,686 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ +#include "WuQMacroGroupXmlStreamReader.h" +#undef __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ + +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "WuQMacro.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroGroup.h" +#include "WuQMacroMouseEventInfo.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacroGroupXmlStreamReader + * \brief Reads macro group from XML format + * \ingroup Common + */ + +/** + * Constructor. + */ +WuQMacroGroupXmlStreamReader::WuQMacroGroupXmlStreamReader() +: WuQMacroGroupXmlStreamBase() +{ +} + +/** + * Destructor. + */ +WuQMacroGroupXmlStreamReader::~WuQMacroGroupXmlStreamReader() +{ +} + +/** + * Read XML from the given string into the given macro group + * + * @param xmlString + * The string containing XML + * @param macroGroup + * The macro group + * @param errorMessageOut + * Output error message + * @return + * True if successful, else false is returned and description in errorMessageOut + */ +bool +WuQMacroGroupXmlStreamReader::readFromString(const QString& xmlString, + WuQMacroGroup* macroGroup, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + CaretAssert(macroGroup); + macroGroup->clear(); + + + if (xmlString.isEmpty()) { + errorMessageOut = "String that should contain XML is empty."; + return false; + } + + QXmlStreamReader xmlReader(xmlString); + + if (xmlReader.atEnd()) { + xmlReader.raiseError("At end when trying to start reading. Appears to have no XML content."); + } + else { + xmlReader.readNextStartElement(); + readMacroGroup(xmlReader, + macroGroup); + } + + if (xmlReader.hasError()) { + errorMessageOut = xmlReader.errorString(); + macroGroup->clear(); + return false; + } + + macroGroup->clearModified(); + + return true; +} + +/** + * Read macro group from the given XML stream reader. It assumes that + * the start element for the macro group has already been read and is + * the current element. If xmlReader.hasError() is set after this + * method is called, there was an error reading the macro group. + * + * @param xmlReader + * The XML stream reader + * @param macroGroup + * The macro group + */ +void +WuQMacroGroupXmlStreamReader::readMacroGroup(QXmlStreamReader& xmlReader, + WuQMacroGroup* macroGroup) +{ + if (xmlReader.name() == ELEMENT_MACRO_GROUP) { + const QXmlStreamAttributes attributes = xmlReader.attributes(); + const QStringRef name = attributes.value(ATTRIBUTE_NAME); + const QStringRef versionText = attributes.value(ATTRIBUTE_VERSION); + QString uniqueIdentifier = attributes.value(ATTRIBUTE_UNIQUE_IDENTIFIER).toString(); + if (uniqueIdentifier.isEmpty()) { + addToWarnings(xmlReader, + ELEMENT_MACRO_GROUP + + " is missing attribute or value is empty: " + + ATTRIBUTE_UNIQUE_IDENTIFIER); + } + if (versionText.isEmpty()) { + xmlReader.raiseError(ATTRIBUTE_VERSION + + " is missing from element " + + ELEMENT_MACRO_GROUP); + } + else if (versionText == VALUE_VERSION_ONE) { + macroGroup->setName(name.toString()); + macroGroup->setUniqueIdentifier(uniqueIdentifier); + + readVersionOne(xmlReader, + macroGroup); + } + else { + xmlReader.raiseError(ATTRIBUTE_VERSION + + "=" + + versionText.toString() + + " is not supported by " + + ELEMENT_MACRO_GROUP + + ". Check for software update."); + } + } + else { + xmlReader.raiseError("Element should be \"" + + ELEMENT_MACRO_GROUP + + "\" but is \"" + + xmlReader.text().toString() + + "\" while reading MacroGroup"); + } + + if ( ! m_warningMessage.isEmpty()) { + CaretLogWarning("Reading Macro's Warnings: " + + m_warningMessage); + m_warningMessage.clear(); + } +} + +/** + * Read version one of macro group + * + * @param xmlReader + * The XML stream reader + * @param macroGroup + * The macro group + */ +void +WuQMacroGroupXmlStreamReader::readVersionOne(QXmlStreamReader& xmlReader, + WuQMacroGroup* macroGroup) +{ + CaretAssert(macroGroup); + + WuQMacro* macro(NULL); + + /* + * Gets set when ending scene info directory element is read + */ + bool endElementFound(false); + + while ( (! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + if (xmlReader.isStartElement()) { + const QString elementName = xmlReader.name().toString(); + + if (elementName == ELEMENT_MACRO) { + macro = readMacroVersionOne(xmlReader); + if (macro != NULL) { + macroGroup->addMacro(macro); + } + } + else { + addToWarnings(xmlReader, + "Unexpected element=" + + elementName + + "\""); + xmlReader.skipCurrentElement(); + } + } + else if (xmlReader.isEndElement()) { + if (xmlReader.name() == ELEMENT_MACRO_GROUP) { + endElementFound = true; + } + } + } +} + +/** + * Read version one of macro + * + * @param xmlReader + * The XML stream reader + * @return The macro + */ +WuQMacro* +WuQMacroGroupXmlStreamReader::readMacroVersionOne(QXmlStreamReader& xmlReader) +{ + WuQMacro* macro(NULL); + + const QXmlStreamAttributes attributes = xmlReader.attributes(); + QString macroName = attributes.value(ATTRIBUTE_NAME).toString(); + QString shortCutKeyString = attributes.value(ATTRIBUTE_SHORT_CUT_KEY).toString(); + if (shortCutKeyString.isEmpty()) { + shortCutKeyString = WuQMacroShortCutKeyEnum::toName(WuQMacroShortCutKeyEnum::Key_None); + addToWarnings(xmlReader, + ELEMENT_MACRO + + " is missing attribute or value is empty: " + + ATTRIBUTE_SHORT_CUT_KEY); + } + QString uniqueIdentifier = attributes.value(ATTRIBUTE_UNIQUE_IDENTIFIER).toString(); + if (uniqueIdentifier.isEmpty()) { + addToWarnings(xmlReader, + ELEMENT_MACRO + + " is missing attribute or value is empty: " + + ATTRIBUTE_UNIQUE_IDENTIFIER); + } + + bool validShortCutKey(false); + WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::fromName(shortCutKeyString, + &validShortCutKey); + if ( ! validShortCutKey) { + shortCutKey = WuQMacroShortCutKeyEnum::Key_None; + addToWarnings(xmlReader, + ELEMENT_MACRO + + " attribute " + + ATTRIBUTE_SHORT_CUT_KEY + + " has invalid value " + + shortCutKeyString); + } + + + if (macroName.isEmpty()) { + addToWarnings(xmlReader, + ELEMENT_MACRO + + " is missing attribute or value is empty: " + + ATTRIBUTE_NAME); + static uint32_t missingCounter = 1; + macroName = ("Missing Name_" + + QString::number(missingCounter)); + } + + macro = new WuQMacro(); + macro->setName(macroName); + macro->setShortCutKey(shortCutKey); + macro->setUniqueIdentifier(uniqueIdentifier); + + /* + * Gets set when ending scene info directory element is read + */ + bool endElementFound(false); + + while ( (! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + if (xmlReader.isStartElement()) { + const QString elementName = xmlReader.name().toString(); + + if (elementName == ELEMENT_MACRO_COMMAND) { + WuQMacroCommand* command = readMacroCommandVersionOne(xmlReader); + if (command != NULL) { + macro->appendMacroCommand(command); + } + } + else if (elementName == ELEMENT_DESCRIPTION) { + const QString text = xmlReader.readElementText(); + macro->setDescription(text); + } + else { + addToWarnings(xmlReader, + "Unexpected element=" + + elementName + + "\""); + xmlReader.skipCurrentElement(); + } + } + else if (xmlReader.isEndElement()) { + if (xmlReader.name() == ELEMENT_MACRO) { + endElementFound = true; + } + } + } + + return macro; +} + +WuQMacroCommand* +WuQMacroGroupXmlStreamReader::readMacroCommandVersionOne(QXmlStreamReader& xmlReader) +{ + WuQMacroCommand* macroCommand(NULL); + std::unique_ptr commandContent(readMacroCommandAttributesVersionOne(xmlReader)); + + if (commandContent != NULL) { + /* + * Gets set when ending scene info directory element is read + */ + bool endElementFound(false); + + while ( (! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + if (xmlReader.isStartElement()) { + const QString elementName = xmlReader.name().toString(); + + if (elementName == ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO) { + WuQMacroMouseEventInfo* mouseEventInfo = readMacroMouseEventInfo(xmlReader); + if (mouseEventInfo != NULL) { + commandContent->m_mouseInfo = mouseEventInfo; + } + } + else if (elementName == ELEMENT_MACRO_COMMAND_TOOL_TIP) { + const QString text = xmlReader.readElementText(); + commandContent->m_toolTip = text; + } + else if (elementName == ELEMENT_MACRO_COMMAND_PARAMETER) { + WuQMacroCommandParameter* parameter = readMacroCommandParameter(xmlReader); + if (parameter != NULL) { + commandContent->m_parameters.push_back(parameter); + } + } + else { + addToWarnings(xmlReader, + "Unexpected element=" + + elementName + + "\""); + xmlReader.skipCurrentElement(); + } + } + else if (xmlReader.isEndElement()) { + if (xmlReader.name() == ELEMENT_MACRO_COMMAND) { + endElementFound = true; + + QString errorMessage; + switch (commandContent->m_commandType) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + macroCommand = WuQMacroCommand::newInstanceCustomCommand(commandContent->m_customOperationTypeName, + commandContent->m_version, + commandContent->m_objectName, + commandContent->m_descriptiveName, + commandContent->m_toolTip, + commandContent->m_delay, + errorMessage); + break; + case WuQMacroCommandTypeEnum::MOUSE: + macroCommand = WuQMacroCommand::newInstanceMouseCommand(commandContent->m_mouseInfo, + commandContent->m_version, + commandContent->m_objectName, + commandContent->m_descriptiveName, + commandContent->m_toolTip, + commandContent->m_delay, + errorMessage); + break; + case WuQMacroCommandTypeEnum::WIDGET: + macroCommand = WuQMacroCommand::newInstanceWidgetCommand(commandContent->m_widgetType, + commandContent->m_version, + commandContent->m_objectName, + commandContent->m_descriptiveName, + commandContent->m_toolTip, + commandContent->m_delay, + errorMessage); + break; + } + + if (macroCommand != NULL) { + for (auto p : commandContent->m_parameters) { + macroCommand->addParameter(p); + } + } + else { + CaretLogSevere("Error reading macro due to error: " + + errorMessage); + } + } + } + } + } + else { + xmlReader.skipCurrentElement(); + } + + return macroCommand; +} + +/** + * Read version one of macro command parameter + * + * @param xmlReader + * The XML stream reader + * @Return The macro parameter + */ +WuQMacroCommandParameter* +WuQMacroGroupXmlStreamReader::readMacroCommandParameter(QXmlStreamReader& xmlReader) +{ + const QXmlStreamAttributes attributes = xmlReader.attributes(); + const QStringRef dataTypeString = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE); + const QString parameterName = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME).toString(); + const QString customDataType = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE).toString(); + const QStringRef valueString = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE); + + QString es; + if (dataTypeString.isEmpty()) es.append(ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE + " "); + if ( ! es.isEmpty()) { + addToWarnings(xmlReader, + ELEMENT_MACRO_COMMAND_PARAMETER + + " is missing attribute(s): " + + es); + return NULL; + } + + bool dataTypeValid(false); + WuQMacroDataValueTypeEnum::Enum dataType = WuQMacroDataValueTypeEnum::fromName(dataTypeString.toString(), + &dataTypeValid); + if (! dataTypeValid) { + addToWarnings(xmlReader, + (dataTypeString.toString() + + " is not valid for attribute " + + ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE + + " ")); + return NULL; + } + + QVariant value; + switch (dataType) { + case WuQMacroDataValueTypeEnum::AXIS: + value.setValue(valueString.toString()); + break; + case WuQMacroDataValueTypeEnum::INVALID: + value.setValue(QString("")); + break; + case WuQMacroDataValueTypeEnum::BOOLEAN: + { + const bool boolValue = ((valueString == VALUE_BOOL_TRUE) ? true : false); + value.setValue(boolValue); + } + break; + case WuQMacroDataValueTypeEnum::FLOAT: + { + const double floatValue = valueString.toFloat(); + value.setValue(floatValue); + } + break; + case WuQMacroDataValueTypeEnum::INTEGER: + { + const int32_t intValue = valueString.toInt(); + value.setValue(intValue); + } + break; + case WuQMacroDataValueTypeEnum::MOUSE: + CaretAssertMessage(0, "Mouse is special case handled above"); + break; + case WuQMacroDataValueTypeEnum::NONE: + value.setValue(QString()); + break; + case WuQMacroDataValueTypeEnum::STRING: + value.setValue(valueString.toString()); + break; + case WuQMacroDataValueTypeEnum::STRING_LIST: + value.setValue(valueString.toString()); + break; + } + + WuQMacroCommandParameter* parameter = new WuQMacroCommandParameter(dataType, + parameterName, + value); + parameter->setCustomDataType(customDataType); + + return parameter; +} + +/** + * Read version one of macro command attributes into a command + * + * @param xmlReader + * The XML stream reader + * @Return The macro command's content + */ +WuQMacroGroupXmlStreamReader::MacroCommandContent* +WuQMacroGroupXmlStreamReader::readMacroCommandAttributesVersionOne(QXmlStreamReader& xmlReader) +{ + const QXmlStreamAttributes attributes = xmlReader.attributes(); + const QStringRef objectName = attributes.value(ATTRIBUTE_NAME); + const QStringRef delayString = attributes.value(ATTRIBUTE_DELAY); + const QStringRef versionString = attributes.value(ATTRIBUTE_VERSION); + const QStringRef descriptiveNameString = attributes.value(ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME); + const QStringRef commandTypeString = attributes.value(ATTRIBUTE_COMMAND_TYPE); + const QStringRef widgetTypeString = attributes.value(ATTRIBUTE_WIDGET_TYPE); + const QStringRef customOperationCommandNameString = attributes.value(ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME); + + QString es; + if (objectName.isEmpty()) es.append(ATTRIBUTE_NAME + " "); + if (commandTypeString.isEmpty()) es.append(ATTRIBUTE_WIDGET_TYPE + " "); + + bool commandTypeValid(false); + const WuQMacroCommandTypeEnum::Enum commandType = WuQMacroCommandTypeEnum::fromName(commandTypeString.toString(), + &commandTypeValid); + + if (commandTypeValid) { + if (widgetTypeString.isEmpty()) { + es.append(ATTRIBUTE_WIDGET_TYPE + " "); + } + } + else { + es.append(ATTRIBUTE_COMMAND_TYPE + " "); + } + if ( ! es.isEmpty()) { + addToWarnings(xmlReader, + ELEMENT_MACRO_COMMAND + + " is missing attribute(s): " + + es); + return NULL; + } + + + bool objectTypeValid(false); + WuQMacroWidgetTypeEnum::Enum widgetType = WuQMacroWidgetTypeEnum::fromName(widgetTypeString.toString(), + &objectTypeValid); + if (! objectTypeValid) { + es.append(widgetTypeString.toString() + + " is not valid for attribute " + + ATTRIBUTE_WIDGET_TYPE + + " "); + return NULL; + } + + if ( ! es.isEmpty()) { + addToWarnings(xmlReader, + es); + return NULL; + } + + + const int32_t versionNumber = (versionString.isEmpty() + ? 1 + : versionString.toInt()); + + + bool valid(false); + float delayValue = delayString.toFloat(&valid); + if ( ! valid) { + delayValue = 1.0; + } + + MacroCommandContent* macroCommandContent = new MacroCommandContent(); + macroCommandContent->m_commandType = commandType; + macroCommandContent->m_customOperationTypeName = customOperationCommandNameString.toString(); + macroCommandContent->m_widgetType = widgetType; + macroCommandContent->m_version = versionNumber; + macroCommandContent->m_objectName = objectName.toString(); + macroCommandContent->m_descriptiveName = descriptiveNameString.toString(); + macroCommandContent->m_delay = delayValue; + + return macroCommandContent; +} + +/** + * @param xmlReader + * The XML stream reader + * @return Read and return the mouse event information + */ +WuQMacroMouseEventInfo* +WuQMacroGroupXmlStreamReader::readMacroMouseEventInfo(QXmlStreamReader& xmlReader) +{ + const QXmlStreamAttributes attributes = xmlReader.attributes(); + const QString mouseEventTypeString = attributes.value(ATTRIBUTE_MOUSE_EVENT_TYPE).toString(); + const QString xLocalString = attributes.value(ATTRIBUTE_MOUSE_LOCAL_X).toString(); + const QString yLocalString = attributes.value(ATTRIBUTE_MOUSE_LOCAL_Y).toString(); + const QString mouseButtonString = attributes.value(ATTRIBUTE_MOUSE_BUTTON).toString(); + const QString mouseButtonsMaskString = attributes.value(ATTRIBUTE_MOUSE_BUTTONS_MASK).toString(); + const QString keyboardModifiersMaskString = attributes.value(ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK).toString(); + const QString widgetWidthString = attributes.value(ATTRIBUTE_MOUSE_WIDGET_WIDTH).toString(); + const QString widgetHeightString = attributes.value(ATTRIBUTE_MOUSE_WIDGET_HEIGHT).toString(); + + QString es; + if (mouseEventTypeString.isEmpty()) es.append(ATTRIBUTE_MOUSE_EVENT_TYPE + " "); + if (mouseButtonString.isEmpty()) es.append(ATTRIBUTE_MOUSE_BUTTON + " "); + if (mouseButtonsMaskString.isEmpty()) es.append(ATTRIBUTE_MOUSE_BUTTONS_MASK + " "); + if (keyboardModifiersMaskString.isEmpty()) es.append(ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK + " "); + if (widgetWidthString.isEmpty()) es.append(ATTRIBUTE_MOUSE_WIDGET_WIDTH + " "); + if (widgetHeightString.isEmpty()) es.append(ATTRIBUTE_MOUSE_WIDGET_HEIGHT + " "); + if ( ! es.isEmpty()) { + addToWarnings(xmlReader, + ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO + + " is missing required attribute(s): " + + es); + return NULL; + } + + bool validMouseEventTypeFlag(false); + const WuQMacroMouseEventTypeEnum::Enum mouseEventType = WuQMacroMouseEventTypeEnum::fromName(mouseEventTypeString, + &validMouseEventTypeFlag); + if ( ! validMouseEventTypeFlag) { + addToWarnings(xmlReader, + mouseEventTypeString + + " is not valid for attribute " + + ATTRIBUTE_MOUSE_EVENT_TYPE); + return NULL; + } + + WuQMacroMouseEventInfo* mouseInfo = new WuQMacroMouseEventInfo(mouseEventType, + mouseButtonString.toUInt(), + mouseButtonsMaskString.toUInt(), + keyboardModifiersMaskString.toUInt(), + widgetWidthString.toInt(), + widgetHeightString.toInt()); + if (( ! xLocalString.isEmpty()) + && ( ! yLocalString.isEmpty())) { + mouseInfo->addLocalXY(xLocalString.toInt(), + yLocalString.toInt()); + } + + QString xyString = xmlReader.readElementText(); + if ( ! xyString.isEmpty()) { + QTextStream stream(&xyString); + while ( ! stream.atEnd()) { + int32_t x, y; + stream >> x; + if ( ! stream.atEnd()) { + stream >> y; + mouseInfo->addLocalXY(x, y); + } + } + } + + return mouseInfo; +} + +/** + * Add to the warning message. Warnings are used to skip over invalid + * elements instead of declaring the entire XML invalid. + * + * @param xmlReader + * The XML stream reader + * @param warning + * The warning message + */ +void +WuQMacroGroupXmlStreamReader::addToWarnings(QXmlStreamReader& xmlReader, + const QString& warning) +{ + if ( ! m_warningMessage.isEmpty()) { + m_warningMessage.append("\n"); + } + m_warningMessage.append("Line=" + + QString::number(xmlReader.lineNumber()) + + ", Column=" + + QString::number(xmlReader.columnNumber()) + + ": " + + warning); +} + + + diff --git a/src/Common/WuQMacroGroupXmlStreamReader.h b/src/Common/WuQMacroGroupXmlStreamReader.h new file mode 100644 index 0000000000000000000000000000000000000000..f58f9316c5b5723e403b064cfb0cabc5b0009a20 --- /dev/null +++ b/src/Common/WuQMacroGroupXmlStreamReader.h @@ -0,0 +1,104 @@ +#ifndef __WU_Q_MACRO_GROUP_XML_STREAM_READER_H__ +#define __WU_Q_MACRO_GROUP_XML_STREAM_READER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQMacroCommandTypeEnum.h" +#include "WuQMacroGroupXmlStreamBase.h" +#include "WuQMacroWidgetTypeEnum.h" + +class QXmlStreamReader; + +namespace caret { + + class WuQMacro; + class WuQMacroCommand; + class WuQMacroCommandParameter; + class WuQMacroGroup; + class WuQMacroMouseEventInfo; + + class WuQMacroGroupXmlStreamReader : public WuQMacroGroupXmlStreamBase { + + public: + WuQMacroGroupXmlStreamReader(); + + virtual ~WuQMacroGroupXmlStreamReader(); + + WuQMacroGroupXmlStreamReader(const WuQMacroGroupXmlStreamReader&) = delete; + + WuQMacroGroupXmlStreamReader& operator=(const WuQMacroGroupXmlStreamReader&) = delete; + + bool readFromString(const QString& xmlString, + WuQMacroGroup* macroGroup, + QString& errorMessageOut); + + void readMacroGroup(QXmlStreamReader& xmlReader, + WuQMacroGroup* macroGroup); + + // ADD_NEW_METHODS_HERE + + private: + class MacroCommandContent { + public: + WuQMacroCommandTypeEnum::Enum m_commandType = WuQMacroCommandTypeEnum::WIDGET; + QString m_customOperationTypeName; + WuQMacroMouseEventInfo* m_mouseInfo = NULL; // DO NOT DELETE + WuQMacroWidgetTypeEnum::Enum m_widgetType = WuQMacroWidgetTypeEnum::INVALID; + int32_t m_version = - 1; + QString m_objectName; + QString m_descriptiveName; + QString m_toolTip; + float m_delay = 1.0f; + std::vector m_parameters; // DO NOT DELETE + }; + + WuQMacroMouseEventInfo* readMacroMouseEventInfo(QXmlStreamReader& xmlReader); + + void readVersionOne(QXmlStreamReader& xmlReader, + WuQMacroGroup* macroGroup); + + WuQMacro* readMacroVersionOne(QXmlStreamReader& xmlReader); + + MacroCommandContent* readMacroCommandAttributesVersionOne(QXmlStreamReader& xmlReader); + + WuQMacroCommand* readMacroCommandVersionOne(QXmlStreamReader& xmlReader); + + WuQMacroCommandParameter* readMacroCommandParameter(QXmlStreamReader& xmlReader); + + void addToWarnings(QXmlStreamReader& xmlReader, + const QString& warning); + + QString m_warningMessage; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ + // +#endif // __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_GROUP_XML_STREAM_READER_H__ diff --git a/src/Common/WuQMacroGroupXmlStreamWriter.cxx b/src/Common/WuQMacroGroupXmlStreamWriter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..04280a19241443498301b42ba642d36527ecb94b --- /dev/null +++ b/src/Common/WuQMacroGroupXmlStreamWriter.cxx @@ -0,0 +1,281 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ +#include "WuQMacroGroupXmlStreamWriter.h" +#undef __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +#include "WuQMacro.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroGroup.h" +#include "WuQMacroMouseEventInfo.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacroGroupXmlStreamWriter + * \brief Writes contents of macro group to XML format + * \ingroup Common + */ + +/** + * Constructor + */ +WuQMacroGroupXmlStreamWriter::WuQMacroGroupXmlStreamWriter() +: WuQMacroGroupXmlStreamBase() +{ +} + +/** + * Destructor. + */ +WuQMacroGroupXmlStreamWriter::~WuQMacroGroupXmlStreamWriter() +{ +} + +/** + * Wite the given macro group to the given xml writer + * + * @param xmlWriter + * The XML stream writer + * @param macroGroup + * Macro group that is written to XML + */ +void +WuQMacroGroupXmlStreamWriter::writeXml(QXmlStreamWriter* xmlWriter, + const WuQMacroGroup* macroGroup) +{ + CaretAssert(xmlWriter); + CaretAssert(macroGroup); + + if (macroGroup->getNumberOfMacros() <= 0) { + return; + } + + m_xmlStreamWriter = xmlWriter; + + m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_GROUP); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_NAME, macroGroup->getName()); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_VERSION, "1"); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_UNIQUE_IDENTIFIER, + macroGroup->getUniqueIdentifier()); + + const int32_t numMacros = macroGroup->getNumberOfMacros(); + for (int32_t i = 0; i < numMacros; i++) { + const WuQMacro* macro = macroGroup->getMacroAtIndex(i); + CaretAssert(macro); + writeMacroToXML(macro); + } + m_xmlStreamWriter->writeEndElement(); + + m_xmlStreamWriter = NULL; +} + +/** + * Write the macro group to a text string + * + * @param macroGroup + * Macro group that is written to XML + * @param contentTextString + * Pointer to string to which XML is written + */ +void +WuQMacroGroupXmlStreamWriter::writeToString(const WuQMacroGroup* macroGroup, + QString& contentTextString) +{ + CaretAssert(macroGroup); + contentTextString.clear(); + + std::unique_ptr xmlWriter(new QXmlStreamWriter(&contentTextString)); + xmlWriter->setAutoFormatting(true); + writeXml(xmlWriter.get(), + macroGroup); +} + + +/** + * Write a macro to XML format + * + * @param macro + * The macro + */ +void +WuQMacroGroupXmlStreamWriter::writeMacroToXML(const WuQMacro* macro) +{ + CaretAssert(macro); + + m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_NAME, + macro->getName()); + const QString shortCutText = WuQMacroShortCutKeyEnum::toName(macro->getShortCutKey()); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_SHORT_CUT_KEY, + shortCutText); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_UNIQUE_IDENTIFIER, + macro->getUniqueIdentifier()); + m_xmlStreamWriter->writeTextElement(ELEMENT_DESCRIPTION, + macro->getDescription()); + + const int32_t numCommands = macro->getNumberOfMacroCommands(); + for (int32_t i = 0; i < numCommands; i++) { + const WuQMacroCommand* macroCommand = macro->getMacroCommandAtIndex(i); + CaretAssert(macroCommand); + writeMacroCommandToXML(macroCommand); + } + + m_xmlStreamWriter->writeEndElement(); +} + +/** + * Write a macro command to XML format + * + * @param macroCommand + * The macro command + */ +void +WuQMacroGroupXmlStreamWriter::writeMacroCommandToXML(const WuQMacroCommand* macroCommand) +{ + CaretAssert(macroCommand); + + m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_COMMAND); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_NAME, + macroCommand->getObjectName()); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_COMMAND_TYPE, + WuQMacroCommandTypeEnum::toName(macroCommand->getCommandType())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_WIDGET_TYPE, + WuQMacroWidgetTypeEnum::toName(macroCommand->getWidgetType())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_VERSION, + QString::number(macroCommand->getVersion())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME, + macroCommand->getDescriptiveName()); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_DELAY, + QString::number(macroCommand->getDelayInSeconds(), 'f', 2)); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME, + macroCommand->getCustomOperationTypeName()); + + + switch (macroCommand->getCommandType()) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + break; + case WuQMacroCommandTypeEnum::MOUSE: + writeMacroMouseEventInfo(macroCommand->getMouseEventInfo()); + break; + case WuQMacroCommandTypeEnum::WIDGET: + break; + } + + const QString toolTip = macroCommand->getObjectToolTip(); + if (toolTip != NULL) { + m_xmlStreamWriter->writeTextElement(ELEMENT_MACRO_COMMAND_TOOL_TIP, + toolTip); + } + + const int32_t numberOfParameters = macroCommand->getNumberOfParameters(); + for (int32_t i = 0; i < numberOfParameters; i++) { + const WuQMacroCommandParameter* parameter = macroCommand->getParameterAtIndex(i); + CaretAssert(parameter); + + m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_COMMAND_PARAMETER); + + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE, + WuQMacroDataValueTypeEnum::toName(parameter->getDataType())); + + const QVariant value(parameter->getValue()); + QString stringValue; + switch (parameter->getDataType()) { + case WuQMacroDataValueTypeEnum::INVALID: + break; + case WuQMacroDataValueTypeEnum::AXIS: + stringValue = value.toString(); + break; + case WuQMacroDataValueTypeEnum::BOOLEAN: + stringValue = (value.toBool() ? VALUE_BOOL_TRUE : VALUE_BOOL_FALSE); + break; + case WuQMacroDataValueTypeEnum::FLOAT: + stringValue = QString::number(value.toFloat()); + break; + case WuQMacroDataValueTypeEnum::INTEGER: + stringValue = QString::number(value.toInt()); + break; + case WuQMacroDataValueTypeEnum::MOUSE: + stringValue = "MouseEvent"; + break; + case WuQMacroDataValueTypeEnum::NONE: + stringValue = ""; + break; + case WuQMacroDataValueTypeEnum::STRING: + stringValue = value.toString(); + break; + case WuQMacroDataValueTypeEnum::STRING_LIST: + stringValue = value.toString(); + break; + } + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME, + parameter->getName()); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE, + parameter->getCustomDataType()); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE, + stringValue); + m_xmlStreamWriter->writeEndElement(); + } + + m_xmlStreamWriter->writeEndElement(); +} + +/** + * Write a macro mouse event info to XML format + * + * @param mouseEventInfo + * The macro mouse event info + */ +void +WuQMacroGroupXmlStreamWriter::writeMacroMouseEventInfo(const WuQMacroMouseEventInfo* mouseEventInfo) +{ + CaretAssert(mouseEventInfo); + + m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO); + + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_BUTTON, QString::number(mouseEventInfo->getMouseButton())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_BUTTONS_MASK, QString::number(mouseEventInfo->getMouseButtonsMask())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_EVENT_TYPE, WuQMacroMouseEventTypeEnum::toName(mouseEventInfo->getMouseEventType())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK, QString::number(mouseEventInfo->getKeyboardModifiersMask())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_WIDGET_WIDTH, QString::number(mouseEventInfo->getWidgetWidth())); + m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_WIDGET_HEIGHT, QString::number(mouseEventInfo->getWidgetHeight())); + + QString xyString; + QTextStream textStream(&xyString); + const int32_t numXY = mouseEventInfo->getNumberOfLocalXY(); + for (int32_t i = 0; i < numXY; i++) { + textStream << mouseEventInfo->getLocalX(i) << " " + << mouseEventInfo->getLocalY(i) << " "; + } + + m_xmlStreamWriter->writeCharacters(xyString); + + m_xmlStreamWriter->writeEndElement(); +} + diff --git a/src/Common/WuQMacroGroupXmlStreamWriter.h b/src/Common/WuQMacroGroupXmlStreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..48ea6ebd5a2fa7ccfff0f26dc5062b49c7b59036 --- /dev/null +++ b/src/Common/WuQMacroGroupXmlStreamWriter.h @@ -0,0 +1,77 @@ +#ifndef __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_H__ +#define __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQMacroGroupXmlStreamBase.h" + +class QXmlStreamWriter; + +namespace caret { + + class WuQMacro; + class WuQMacroCommand; + class WuQMacroGroup; + class WuQMacroMouseEventInfo; + + class WuQMacroGroupXmlStreamWriter : public WuQMacroGroupXmlStreamBase { + + public: + WuQMacroGroupXmlStreamWriter(); + + virtual ~WuQMacroGroupXmlStreamWriter(); + + void writeXml(QXmlStreamWriter* xmlStreamWriter, + const WuQMacroGroup* macroGroup); + + void writeToString(const WuQMacroGroup* macroGroup, + QString& contentTextString); + + WuQMacroGroupXmlStreamWriter(const WuQMacroGroupXmlStreamWriter&) = delete; + + WuQMacroGroupXmlStreamWriter& operator=(const WuQMacroGroupXmlStreamWriter&) = delete; + + + // ADD_NEW_METHODS_HERE + + private: + void writeMacroToXML(const WuQMacro* macro); + + void writeMacroCommandToXML(const WuQMacroCommand* macroCommand); + + void writeMacroMouseEventInfo(const WuQMacroMouseEventInfo* mouseEventInfo); + + QXmlStreamWriter* m_xmlStreamWriter; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ + // +#endif // __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_GROUP_XML_STREAM_WRITER_H__ diff --git a/src/Common/WuQMacroModeEnum.cxx b/src/Common/WuQMacroModeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..74e3f6e1b2065bea86e42c729914881d864ca1d2 --- /dev/null +++ b/src/Common/WuQMacroModeEnum.cxx @@ -0,0 +1,383 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WU_Q_MACRO_MODE_ENUM_DECLARE__ +#include "WuQMacroModeEnum.h" +#undef __WU_Q_MACRO_MODE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroModeEnum + * \brief + * + * + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_wuQMacroModeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void wuQMacroModeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WuQMacroModeEnum.h" + * + * Instatiate: + * m_wuQMacroModeEnumComboBox = new EnumComboBoxTemplate(this); + * m_wuQMacroModeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_wuQMacroModeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(wuQMacroModeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_wuQMacroModeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WuQMacroModeEnum::Enum VARIABLE = m_wuQMacroModeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WuQMacroModeEnum::WuQMacroModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WuQMacroModeEnum::~WuQMacroModeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WuQMacroModeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WuQMacroModeEnum(OFF, + "OFF", + "Off")); + + enumData.push_back(WuQMacroModeEnum(RECORDING_INSERT_COMMANDS, + "RECORDING_INSERT_COMMANDS", + "Recording Insert Commands")); + + enumData.push_back(WuQMacroModeEnum(RECORDING_NEW_MACRO, + "RECORDING_NEW_MACRO", + "Recording New Macro")); + + enumData.push_back(WuQMacroModeEnum(RUNNING, + "RUNNING", + "Running")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WuQMacroModeEnum* +WuQMacroModeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WuQMacroModeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroModeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroModeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroModeEnum::Enum +WuQMacroModeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroModeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroModeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroModeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroModeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroModeEnum::Enum +WuQMacroModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroModeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroModeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WuQMacroModeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WuQMacroModeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WuQMacroModeEnum::Enum +WuQMacroModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroModeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroModeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WuQMacroModeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroModeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WuQMacroModeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WuQMacroModeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/WuQMacroModeEnum.h b/src/Common/WuQMacroModeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..f5fff4fc5dfa00777ceaab52d8ba5150a1db3b8c --- /dev/null +++ b/src/Common/WuQMacroModeEnum.h @@ -0,0 +1,108 @@ +#ifndef __WU_Q_MACRO_MODE_ENUM_H__ +#define __WU_Q_MACRO_MODE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WuQMacroModeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Off */ + OFF, + /** Recording and inserting commands into a macro */ + RECORDING_INSERT_COMMANDS, + /** Recording a new macro */ + RECORDING_NEW_MACRO, + /** Macro is running */ + RUNNING + }; + + + ~WuQMacroModeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WuQMacroModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WuQMacroModeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WU_Q_MACRO_MODE_ENUM_DECLARE__ +std::vector WuQMacroModeEnum::enumData; +bool WuQMacroModeEnum::initializedFlag = false; +int32_t WuQMacroModeEnum::integerCodeCounter = 0; +#endif // __WU_Q_MACRO_MODE_ENUM_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_MODE_ENUM_H__ diff --git a/src/Common/WuQMacroMouseEventInfo.cxx b/src/Common/WuQMacroMouseEventInfo.cxx new file mode 100644 index 0000000000000000000000000000000000000000..99e021a53957940ff4e8e78e9b4358997df6a68b --- /dev/null +++ b/src/Common/WuQMacroMouseEventInfo.cxx @@ -0,0 +1,272 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ +#include "WuQMacroMouseEventInfo.h" +#undef __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::WuQMacroMouseEventInfo + * \brief Information about and related to a QMouseEvent + * \ingroup Common + */ + +/** + * Constructor. + * @param mouseEventType + * Type of mouse event + * @param mouseButton + * Button that caused the event + * @param mouseButtonsMask + * Mask with buttons down during mouse event + * @param keyboardModifiersMask + * Mask with any keys down during mouse event + * @param widgetWidth + * Width of widget where mouse event occurred + * @param widgetHeight + * Width of widget where mouse event occurred + */ +WuQMacroMouseEventInfo::WuQMacroMouseEventInfo(const WuQMacroMouseEventTypeEnum::Enum mouseEventType, + const uint32_t mouseButton, + const uint32_t mouseButtonsMask, + const uint32_t keyboardModifiersMask, + const int32_t widgetWidth, + const int32_t widgetHeight) +: CaretObject(), +m_mouseEventType(mouseEventType), +m_mouseButton(mouseButton), +m_mouseButtonsMask(mouseButtonsMask), +m_keyboardModifiersMask(keyboardModifiersMask), +m_widgetWidth(widgetWidth), +m_widgetHeight(widgetHeight) +{ +} + +/** + * Destructor. + */ +WuQMacroMouseEventInfo::~WuQMacroMouseEventInfo() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +WuQMacroMouseEventInfo::WuQMacroMouseEventInfo(const WuQMacroMouseEventInfo& obj) +: CaretObject(obj) +{ + this->copyHelperWuQMacroMouseEventInfo(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +WuQMacroMouseEventInfo& +WuQMacroMouseEventInfo::operator=(const WuQMacroMouseEventInfo& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperWuQMacroMouseEventInfo(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +WuQMacroMouseEventInfo::copyHelperWuQMacroMouseEventInfo(const WuQMacroMouseEventInfo& obj) +{ + m_mouseEventType = obj.m_mouseEventType; + m_localXY = obj.m_localXY; + m_mouseButton = obj.m_mouseButton; + m_mouseButtonsMask = obj.m_mouseButtonsMask; + m_keyboardModifiersMask = obj.m_keyboardModifiersMask; + m_widgetWidth = obj.m_widgetWidth; + m_widgetHeight = obj.m_widgetHeight; +} + +/** + * Widget size may change so scale the x and y position to fit new widget size + * + * @param newWidth + * Current width of widget + * @param newHeight + * Current height of widget + * @param localX + * Local X position + * @param localY + * Local Y position + * @param xLocalOut + * Output with adjusted local-X position + * @param yLocalOut + * Output with adjusted local-Y position + */ +void +WuQMacroMouseEventInfo::getLocalPositionRescaledToWidgetSize(const int32_t newWidth, + const int32_t newHeight, + const int32_t localX, + const int32_t localY, + int32_t& xLocalOut, + int32_t& yLocalOut) const +{ + xLocalOut = localX; + yLocalOut = localY; + + if ((newWidth != m_widgetWidth) + || (newHeight != m_widgetHeight)) { + const float normalizedWidth = (static_cast(localX) + / static_cast(m_widgetWidth)); + const float normalizedHeight = (static_cast(localY) + / static_cast(m_widgetHeight)); + + xLocalOut = (newWidth * normalizedWidth); + yLocalOut = (newHeight * normalizedHeight); + } +} + +/** + * @return Type of the mouse event + */ +WuQMacroMouseEventTypeEnum::Enum +WuQMacroMouseEventInfo::getMouseEventType() const +{ + return m_mouseEventType; +} + +/** + * Append local mouse X/Y coordinates + * + * @param localX + * The local X-coordinate + * @param localY + * The local Y-coordinate + */ +void +WuQMacroMouseEventInfo::addLocalXY(const int32_t localX, + const int32_t localY) +{ + m_localXY.push_back(localX); + m_localXY.push_back(localY); +} + +int32_t +WuQMacroMouseEventInfo::getNumberOfLocalXY() const +{ + const int32_t num = (m_localXY.size() / 2); + return num; +} + +/** + * @return X-coordinate of mouse relative to widget at the given index + * + * @param index + * Index of the coordinate + */ +int32_t +WuQMacroMouseEventInfo::getLocalX(const int32_t index) const +{ + const int32_t offset = (index * 2); + CaretAssertVectorIndex(m_localXY, offset); + return m_localXY[offset]; +} + +/** + * @return Y-coordinate of mouse relative to widget at the given index + * + * @param index + * Index of the coordinate + */ +int32_t +WuQMacroMouseEventInfo::getLocalY(const int32_t index) const +{ + const int32_t offset = (index * 2) + 1; + CaretAssertVectorIndex(m_localXY, offset); + return m_localXY[offset]; +} + +/** + * @return Button that caused the event + */ +uint32_t +WuQMacroMouseEventInfo::getMouseButton() const +{ + return m_mouseButton; +} + +/** + * @return Mask with buttons down during mouse event + */ +uint32_t WuQMacroMouseEventInfo::getMouseButtonsMask() const +{ + return m_mouseButtonsMask; +} + +/** + * @@return Mask with any keys down during mouse event + */ +uint32_t +WuQMacroMouseEventInfo::getKeyboardModifiersMask() const +{ + return m_keyboardModifiersMask; +} + +/** + * @return Width of widget where mouse event occurred + */ +int32_t +WuQMacroMouseEventInfo::getWidgetWidth() const +{ + return m_widgetWidth; +} + +/** + * @return Width of widget where mouse event occurred + */ +int32_t +WuQMacroMouseEventInfo::getWidgetHeight() const +{ + return m_widgetHeight; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +WuQMacroMouseEventInfo::toString() const +{ + return "WuQMacroMouseEventInfo"; +} + diff --git a/src/Common/WuQMacroMouseEventInfo.h b/src/Common/WuQMacroMouseEventInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..d381c9e0b9cf3364ca8a8e40ddc0ff4212f97998 --- /dev/null +++ b/src/Common/WuQMacroMouseEventInfo.h @@ -0,0 +1,117 @@ +#ifndef __WU_Q_MACRO_MOUSE_EVENT_INFO_H__ +#define __WU_Q_MACRO_MOUSE_EVENT_INFO_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" +#include "WuQMacroMouseEventTypeEnum.h" + + +namespace caret { + + class WuQMacroMouseEventInfo : public CaretObject { + + public: + WuQMacroMouseEventInfo(const WuQMacroMouseEventTypeEnum::Enum mouseEventType, + const uint32_t mouseButton, + const uint32_t mouseButtonsMask, + const uint32_t keyboardModifiersMask, + const int32_t widgetWidth, + const int32_t widgetHeight); + + virtual ~WuQMacroMouseEventInfo(); + + WuQMacroMouseEventInfo(const WuQMacroMouseEventInfo&); + + WuQMacroMouseEventInfo& operator=(const WuQMacroMouseEventInfo&); + + void getLocalPositionRescaledToWidgetSize(const int32_t widgetWidth, + const int32_t widgetHeight, + const int32_t localX, + const int32_t localY, + int32_t& xOut, + int32_t& yOut) const; + + WuQMacroMouseEventTypeEnum::Enum getMouseEventType() const; + + void addLocalXY(const int32_t localX, + const int32_t localY); + + int32_t getNumberOfLocalXY() const; + + int32_t getLocalX(const int32_t index) const; + + int32_t getLocalY(const int32_t index) const; + + uint32_t getMouseButton() const; + + uint32_t getMouseButtonsMask() const; + + uint32_t getKeyboardModifiersMask() const; + + int32_t getWidgetWidth() const; + + int32_t getWidgetHeight() const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperWuQMacroMouseEventInfo(const WuQMacroMouseEventInfo& obj); + + /** Type of mouse event */ + WuQMacroMouseEventTypeEnum::Enum m_mouseEventType; + + /** Positions of mouse relative to widget */ + std::vector m_localXY; + + /** Button that caused the event */ + uint32_t m_mouseButton; + + /** Mask with buttons down during mouse event */ + uint32_t m_mouseButtonsMask; + + /** Mask with any keys down during mouse event */ + uint32_t m_keyboardModifiersMask; + + /** Width of widget where mouse event occurred */ + int32_t m_widgetWidth; + + /** Width of widget where mouse event occurred */ + int32_t m_widgetHeight; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ + // +#endif // __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_MOUSE_EVENT_INFO_H__ + diff --git a/src/Common/WuQMacroMouseEventTypeEnum.cxx b/src/Common/WuQMacroMouseEventTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a2294319b378f837fe41f1e808d2c640c783bba3 --- /dev/null +++ b/src/Common/WuQMacroMouseEventTypeEnum.cxx @@ -0,0 +1,380 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ +#include "WuQMacroMouseEventTypeEnum.h" +#undef __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroMouseEventTypeEnum + * \brief Types of mouse events + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_wuQMacroMouseEventTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void wuQMacroMouseEventTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WuQMacroMouseEventTypeEnum.h" + * + * Instatiate: + * m_wuQMacroMouseEventTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_wuQMacroMouseEventTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_wuQMacroMouseEventTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(wuQMacroMouseEventTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_wuQMacroMouseEventTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WuQMacroMouseEventTypeEnum::Enum VARIABLE = m_wuQMacroMouseEventTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WuQMacroMouseEventTypeEnum::WuQMacroMouseEventTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WuQMacroMouseEventTypeEnum::~WuQMacroMouseEventTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WuQMacroMouseEventTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WuQMacroMouseEventTypeEnum(BUTTON_PRESS, + "BUTTON_PRESS", + "Button-Press")); + + enumData.push_back(WuQMacroMouseEventTypeEnum(BUTTON_RELEASE, + "BUTTON_RELEASE", + "Button-Release")); + + enumData.push_back(WuQMacroMouseEventTypeEnum(DOUBLE_CLICKED, + "DOUBLE_CLICKED", + "Double-Clicked")); + + enumData.push_back(WuQMacroMouseEventTypeEnum(MOVE, + "MOVE", + "Move")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WuQMacroMouseEventTypeEnum* +WuQMacroMouseEventTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WuQMacroMouseEventTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroMouseEventTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroMouseEventTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroMouseEventTypeEnum::Enum +WuQMacroMouseEventTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroMouseEventTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroMouseEventTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroMouseEventTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroMouseEventTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroMouseEventTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroMouseEventTypeEnum::Enum +WuQMacroMouseEventTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroMouseEventTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroMouseEventTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroMouseEventTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WuQMacroMouseEventTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WuQMacroMouseEventTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WuQMacroMouseEventTypeEnum::Enum +WuQMacroMouseEventTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroMouseEventTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroMouseEventTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroMouseEventTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WuQMacroMouseEventTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroMouseEventTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WuQMacroMouseEventTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroMouseEventTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WuQMacroMouseEventTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/WuQMacroMouseEventTypeEnum.h b/src/Common/WuQMacroMouseEventTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..36bff2b4917a0dee544c4c15d7c5cc1f5a048af4 --- /dev/null +++ b/src/Common/WuQMacroMouseEventTypeEnum.h @@ -0,0 +1,108 @@ +#ifndef __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_H__ +#define __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WuQMacroMouseEventTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Mouse button is pressed */ + BUTTON_PRESS, + /** Mouse button is released */ + BUTTON_RELEASE, + /** Mouse is double-clicked */ + DOUBLE_CLICKED, + /** Mouse is moved */ + MOVE + }; + + + ~WuQMacroMouseEventTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WuQMacroMouseEventTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WuQMacroMouseEventTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ +std::vector WuQMacroMouseEventTypeEnum::enumData; +bool WuQMacroMouseEventTypeEnum::initializedFlag = false; +int32_t WuQMacroMouseEventTypeEnum::integerCodeCounter = 0; +#endif // __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_H__ diff --git a/src/Common/WuQMacroShortCutKeyEnum.cxx b/src/Common/WuQMacroShortCutKeyEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ea1955de07377026aa50f4ffdc38847c3ed83d11 --- /dev/null +++ b/src/Common/WuQMacroShortCutKeyEnum.cxx @@ -0,0 +1,549 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ +#include "WuQMacroShortCutKeyEnum.h" +#undef __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroShortCutKeyEnum + * \brief Shortcut keys for running macros + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_wuQMacroShortCutKeyEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void wuQMacroShortCutKeyEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WuQMacroShortCutKeyEnum.h" + * + * Instatiate: + * m_wuQMacroShortCutKeyEnumComboBox = new EnumComboBoxTemplate(this); + * m_wuQMacroShortCutKeyEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_wuQMacroShortCutKeyEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(wuQMacroShortCutKeyEnumComboBoxItemActivated())); + * + * Update the selection: + * m_wuQMacroShortCutKeyEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WuQMacroShortCutKeyEnum::Enum VARIABLE = m_wuQMacroShortCutKeyEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WuQMacroShortCutKeyEnum::WuQMacroShortCutKeyEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WuQMacroShortCutKeyEnum::~WuQMacroShortCutKeyEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WuQMacroShortCutKeyEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_None, + "Key_None", + "None")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_A, + "Key_A", + "A")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_B, + "Key_B", + "B")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_C, + "Key_C", + "C")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_D, + "Key_D", + "D")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_E, + "Key_E", + "E")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_F, + "Key_F", + "F")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_G, + "Key_G", + "G")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_H, + "Key_H", + "H")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_I, + "Key_I", + "I")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_J, + "Key_J", + "J")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_K, + "Key_K", + "K")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_L, + "Key_L", + "L")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_M, + "Key_M", + "M")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_N, + "Key_N", + "N")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_O, + "Key_O", + "O")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_P, + "Key_P", + "P")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_Q, + "Key_Q", + "Q")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_R, + "Key_R", + "R")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_S, + "Key_S", + "S")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_T, + "Key_T", + "T")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_U, + "Key_U", + "U")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_V, + "Key_V", + "V")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_W, + "Key_W", + "W")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_X, + "Key_X", + "X")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_Y, + "Key_Y", + "Y")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_Z, + "Key_Z", + "Z")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_0, + "Key_0", + "0")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_1, + "Key_1", + "1")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_2, + "Key_2", + "2")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_3, + "Key_3", + "3")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_4, + "Key_4", + "4")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_5, + "Key_5", + "5")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_6, + "Key_6", + "6")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_7, + "Key_7", + "7")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_8, + "Key_8", + "8")); + + enumData.push_back(WuQMacroShortCutKeyEnum(Key_9, + "Key_9", + "9")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WuQMacroShortCutKeyEnum* +WuQMacroShortCutKeyEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WuQMacroShortCutKeyEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroShortCutKeyEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroShortCutKeyEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroShortCutKeyEnum::Enum +WuQMacroShortCutKeyEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroShortCutKeyEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroShortCutKeyEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroShortCutKeyEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroShortCutKeyEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroShortCutKeyEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroShortCutKeyEnum::Enum +WuQMacroShortCutKeyEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroShortCutKeyEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroShortCutKeyEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroShortCutKeyEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WuQMacroShortCutKeyEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WuQMacroShortCutKeyEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WuQMacroShortCutKeyEnum::Enum +WuQMacroShortCutKeyEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroShortCutKeyEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroShortCutKeyEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroShortCutKeyEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WuQMacroShortCutKeyEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroShortCutKeyEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WuQMacroShortCutKeyEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroShortCutKeyEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WuQMacroShortCutKeyEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + +/** + * Find the data type corresponding to a Qt::Key enum value. + * If not valid, the none key (Key_None) is returned. + * + * @param qtKeyEnum + * The Qt::Key enum value + * @return + * Enum for integer code. + */ +WuQMacroShortCutKeyEnum::Enum +WuQMacroShortCutKeyEnum::fromQtKeyEnum(const int32_t qtKeyEnum) +{ + if (initializedFlag == false) initialize(); + + int32_t shortCutKeyInteger = -1; + if ((qtKeyEnum >= Qt::Key_A) + && (qtKeyEnum <= Qt::Key_Z)) { + shortCutKeyInteger = (WuQMacroShortCutKeyEnum::toIntegerCode(Key_A) + + (qtKeyEnum - (int)Qt::Key_A)); + } + else if ((qtKeyEnum >= Qt::Key_0) + && (qtKeyEnum <= Qt::Key_9)) { + shortCutKeyInteger = (WuQMacroShortCutKeyEnum::toIntegerCode(Key_0) + + (qtKeyEnum - (int)Qt::Key_0)); + } + else { + shortCutKeyInteger = WuQMacroShortCutKeyEnum::toIntegerCode(Key_None); + } + + bool validFlag = false; + const Enum enumValue = WuQMacroShortCutKeyEnum::fromIntegerCode(shortCutKeyInteger, + &validFlag); + CaretAssert(validFlag); + + return enumValue; +} diff --git a/src/Common/WuQMacroShortCutKeyEnum.h b/src/Common/WuQMacroShortCutKeyEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..47e65e18ab68fce1c0f782d244f433501efcacc7 --- /dev/null +++ b/src/Common/WuQMacroShortCutKeyEnum.h @@ -0,0 +1,176 @@ +#ifndef __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_H__ +#define __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WuQMacroShortCutKeyEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** No Key */ + Key_None, + /** */ + Key_A, + /** */ + Key_B, + /** */ + Key_C, + /** */ + Key_D, + /** */ + Key_E, + /** */ + Key_F, + /** */ + Key_G, + /** */ + Key_H, + /** */ + Key_I, + /** */ + Key_J, + /** */ + Key_K, + /** */ + Key_L, + /** */ + Key_M, + /** */ + Key_N, + /** */ + Key_O, + /** */ + Key_P, + /** */ + Key_Q, + /** */ + Key_R, + /** */ + Key_S, + /** */ + Key_T, + /** */ + Key_U, + /** */ + Key_V, + /** */ + Key_W, + /** */ + Key_X, + /** */ + Key_Y, + /** */ + Key_Z, + /** */ + Key_0, + /** */ + Key_1, + /** */ + Key_2, + /** */ + Key_3, + /** */ + Key_4, + /** */ + Key_5, + /** */ + Key_6, + /** */ + Key_7, + /** */ + Key_8, + /** */ + Key_9 + }; + + + ~WuQMacroShortCutKeyEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + + static Enum fromQtKeyEnum(const int32_t qtKeyEnum); + +private: + WuQMacroShortCutKeyEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WuQMacroShortCutKeyEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ +std::vector WuQMacroShortCutKeyEnum::enumData; +bool WuQMacroShortCutKeyEnum::initializedFlag = false; +int32_t WuQMacroShortCutKeyEnum::integerCodeCounter = 0; +#endif // __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_SHORT_CUT_KEY_ENUM_H__ diff --git a/src/Common/WuQMacroStandardItemTypeEnum.cxx b/src/Common/WuQMacroStandardItemTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4003763b0809f690b96768e6a404422ed155548a --- /dev/null +++ b/src/Common/WuQMacroStandardItemTypeEnum.cxx @@ -0,0 +1,396 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ +#include "WuQMacroStandardItemTypeEnum.h" +#undef __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ + +#include + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroStandardItemTypeEnum + * \brief Enumerated type for macro items in a QStandardItemModel + * + * Macros and macro command are displayed in the GUI using a + * QStandardItem. The QStandardItem documentation recommends + * overriding the type() method and returning a value greater + * than or equal to UserType. This enumerated type provides + * these values. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_wuQMacroStandardItemTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void wuQMacroStandardItemTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WuQMacroStandardItemTypeEnum.h" + * + * Instatiate: + * m_wuQMacroStandardItemTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_wuQMacroStandardItemTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_wuQMacroStandardItemTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(wuQMacroStandardItemTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_wuQMacroStandardItemTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WuQMacroStandardItemTypeEnum::Enum VARIABLE = m_wuQMacroStandardItemTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param integerCode + * Integer code for this enumerated value. + * + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WuQMacroStandardItemTypeEnum::WuQMacroStandardItemTypeEnum(const Enum enumValue, + const int32_t integerCode, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCode; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WuQMacroStandardItemTypeEnum::~WuQMacroStandardItemTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WuQMacroStandardItemTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + int32_t typeOffset = QStandardItem::UserType + 1; + const int32_t invalidType(typeOffset++); + const int32_t macroType(typeOffset++); + const int32_t macroCommandType(typeOffset++); + + enumData.push_back(WuQMacroStandardItemTypeEnum(INVALID, + invalidType, + "INVALID", + "Invalid")); + + enumData.push_back(WuQMacroStandardItemTypeEnum(MACRO, + macroType, + "MACRO", + "Macro")); + + enumData.push_back(WuQMacroStandardItemTypeEnum(MACRO_COMMAND, + macroCommandType, + "MACRO_COMMAND", + "Macro Command")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WuQMacroStandardItemTypeEnum* +WuQMacroStandardItemTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WuQMacroStandardItemTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroStandardItemTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroStandardItemTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroStandardItemTypeEnum::Enum +WuQMacroStandardItemTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroStandardItemTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroStandardItemTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroStandardItemTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroStandardItemTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroStandardItemTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroStandardItemTypeEnum::Enum +WuQMacroStandardItemTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroStandardItemTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroStandardItemTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroStandardItemTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WuQMacroStandardItemTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WuQMacroStandardItemTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WuQMacroStandardItemTypeEnum::Enum +WuQMacroStandardItemTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroStandardItemTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroStandardItemTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroStandardItemTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WuQMacroStandardItemTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroStandardItemTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WuQMacroStandardItemTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroStandardItemTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WuQMacroStandardItemTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/WuQMacroStandardItemTypeEnum.h b/src/Common/WuQMacroStandardItemTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..120b8f5392361e24a4ec221200b4f7685e503953 --- /dev/null +++ b/src/Common/WuQMacroStandardItemTypeEnum.h @@ -0,0 +1,103 @@ +#ifndef __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_H__ +#define __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WuQMacroStandardItemTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Type that is invalid */ + INVALID, + /** Type for a macro */ + MACRO, + /** Type for a macro command */ + MACRO_COMMAND + }; + + + ~WuQMacroStandardItemTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WuQMacroStandardItemTypeEnum(const Enum enumValue, + const int32_t integerCode, + const AString& name, + const AString& guiName); + + static const WuQMacroStandardItemTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ +std::vector WuQMacroStandardItemTypeEnum::enumData; +bool WuQMacroStandardItemTypeEnum::initializedFlag = false; +#endif // __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_H__ diff --git a/src/Common/WuQMacroWidgetTypeEnum.cxx b/src/Common/WuQMacroWidgetTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d45ea0a8769f24223b1f99df777b52509fc4b9b8 --- /dev/null +++ b/src/Common/WuQMacroWidgetTypeEnum.cxx @@ -0,0 +1,476 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ +#include "WuQMacroWidgetTypeEnum.h" +#undef __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroWidgetTypeEnum + * \brief Enumerated type for widgets in a macro command + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_WuQMacroWidgetTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void WuQMacroWidgetTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WuQMacroWidgetTypeEnum.h" + * + * Instatiate: + * m_WuQMacroWidgetTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_WuQMacroWidgetTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_WuQMacroWidgetTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(WuQMacroWidgetTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_WuQMacroWidgetTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WuQMacroWidgetTypeEnum::Enum VARIABLE = m_WuQMacroWidgetTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WuQMacroWidgetTypeEnum::WuQMacroWidgetTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WuQMacroWidgetTypeEnum::~WuQMacroWidgetTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WuQMacroWidgetTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WuQMacroWidgetTypeEnum(INVALID, + "INVALID", + "Invalid")); + + enumData.push_back(WuQMacroWidgetTypeEnum(ACTION, + "ACTION", + "QAction")); + + enumData.push_back(WuQMacroWidgetTypeEnum(ACTION_CHECKABLE, + "ACTION_CHECKABLE", + "QActionCheckable")); + + enumData.push_back(WuQMacroWidgetTypeEnum(ACTION_GROUP, + "ACTION_GROUP", + "QActionGroup")); + + enumData.push_back(WuQMacroWidgetTypeEnum(BUTTON_GROUP, + "BUTTON_GROUP", + "QButtonGroup")); + + enumData.push_back(WuQMacroWidgetTypeEnum(CHECK_BOX, + "CHECK_BOX", + "QCheckBox")); + + enumData.push_back(WuQMacroWidgetTypeEnum(COMBO_BOX, + "COMBO_BOX", + "QComboBox")); + + enumData.push_back(WuQMacroWidgetTypeEnum(DOUBLE_SPIN_BOX, + "DOUBLE_SPIN_BOX", + "QDoubleSpinBox")); + + enumData.push_back(WuQMacroWidgetTypeEnum(LINE_EDIT, + "LINE_EDIT", + "QLineEdit")); + + enumData.push_back(WuQMacroWidgetTypeEnum(LIST_WIDGET, + "LIST_WIDGET", + "QListWidget")); + + enumData.push_back(WuQMacroWidgetTypeEnum(MACRO_WIDGET_ACTION, + "MACRO_WIDGET_ACTION", + "caret::WuQMacroWidgetAction")); + + enumData.push_back(WuQMacroWidgetTypeEnum(MENU, + "MENU", + "QMenu")); + + enumData.push_back(WuQMacroWidgetTypeEnum(PUSH_BUTTON, + "PUSH_BUTTON", + "QPushButton")); + + enumData.push_back(WuQMacroWidgetTypeEnum(PUSH_BUTTON_CHECKABLE, + "PUSH_BUTTON_CHECKABLE", + "QPushButtonCheckable")); + + enumData.push_back(WuQMacroWidgetTypeEnum(RADIO_BUTTON, + "RADIO_BUTTON", + "QRadioButton")); + + enumData.push_back(WuQMacroWidgetTypeEnum(SLIDER, + "SLIDER", + "QSlider")); + + enumData.push_back(WuQMacroWidgetTypeEnum(SPIN_BOX, + "SPIN_BOX", + "QSpinBox")); + + enumData.push_back(WuQMacroWidgetTypeEnum(TAB_BAR, + "TAB_BAR", + "QTabBar")); + + enumData.push_back(WuQMacroWidgetTypeEnum(TAB_WIDGET, + "TAB_WIDGET", + "QTabWidget")); + + enumData.push_back(WuQMacroWidgetTypeEnum(TOOL_BUTTON, + "TOOL_BUTTON", + "QToolButton")); + + enumData.push_back(WuQMacroWidgetTypeEnum(TOOL_BUTTON_CHECKABLE, + "TOOL_BUTTON_CHECKABLE", + "QToolButtonCheckable")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WuQMacroWidgetTypeEnum* +WuQMacroWidgetTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WuQMacroWidgetTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroWidgetTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroWidgetTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroWidgetTypeEnum::Enum +WuQMacroWidgetTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroWidgetTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroWidgetTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroWidgetTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WuQMacroWidgetTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WuQMacroWidgetTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param guiNameIn + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WuQMacroWidgetTypeEnum::Enum +WuQMacroWidgetTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + /* + * Some widgets are extended from Qt Widgets and end with the Qt Name + */ + AString guiName(guiNameIn); + for (auto alias : s_widgetClassNameAliases) { + if (alias.second == guiName) { + guiName = alias.first; + break; + } + } + + bool validFlag = false; + Enum enumValue = WuQMacroWidgetTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroWidgetTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroWidgetTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WuQMacroWidgetTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WuQMacroWidgetTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WuQMacroWidgetTypeEnum::Enum +WuQMacroWidgetTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WuQMacroWidgetTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WuQMacroWidgetTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroWidgetTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WuQMacroWidgetTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroWidgetTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WuQMacroWidgetTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WuQMacroWidgetTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WuQMacroWidgetTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + +/** + * Add a widget alias for class names + * + * @param widgetName + * The name of a Qt widget class + * @param aliasWidgetName + * Name of class that is derived from Qt widget with name 'widgetName' + */ +void +WuQMacroWidgetTypeEnum::addWidgetClassNameAlias(const QString& widgetName, + const QString& aliasWidgetName) +{ + s_widgetClassNameAliases.push_back(std::make_pair(widgetName, + aliasWidgetName)); +} + + diff --git a/src/Common/WuQMacroWidgetTypeEnum.h b/src/Common/WuQMacroWidgetTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..e2951669ddb10b307e167fadafbb5db866eda5dc --- /dev/null +++ b/src/Common/WuQMacroWidgetTypeEnum.h @@ -0,0 +1,183 @@ +#ifndef __WU_Q_MACRO_WIDGET_TYPE_ENUM_H__ +#define __WU_Q_MACRO_WIDGET_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WuQMacroWidgetTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Invalid type */ + INVALID, + /** a QAction (not checkable) */ + ACTION, + /** a Checkable QAction */ + ACTION_CHECKABLE, + /** a QAction Group */ + ACTION_GROUP, + /** a QButtonGroup */ + BUTTON_GROUP, + /** a QCheckBox */ + CHECK_BOX, + /** a QComboBox */ + COMBO_BOX, + /** a QDoubleSpinBox */ + DOUBLE_SPIN_BOX, + /** a QLineEdit */ + LINE_EDIT, + /** a QListWidget */ + LIST_WIDGET, + /** a Macro Widget Action */ + MACRO_WIDGET_ACTION, + /** a QMenu */ + MENU, + /** a QPushButton(not checkable) */ + PUSH_BUTTON, + /** a Checkable QPushButton */ + PUSH_BUTTON_CHECKABLE, + /** a QRadioButton */ + RADIO_BUTTON, + /** a QSlider */ + SLIDER, + /** a QSpinBox */ + SPIN_BOX, + /** a QTabBar */ + TAB_BAR, + /** a QTabWidget */ + TAB_WIDGET, + /** a QToolButton (not checkable) */ + TOOL_BUTTON, + /** a Checkable QToolButton */ + TOOL_BUTTON_CHECKABLE + }; + +/* + switch (m_objectType) { + case WuQMacroWidgetTypeEnum::ACTION: + break; + case WuQMacroWidgetTypeEnum::CHECK_BOX: + break; + case WuQMacroWidgetTypeEnum::COMBO_BOX: + break; + case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: + break; + case WuQMacroWidgetTypeEnum::INVALID: + break; + case WuQMacroWidgetTypeEnum::LINE_EDIT: + break; + case WuQMacroWidgetTypeEnum::LIST_WIDGET: + break; + case WuQMacroWidgetTypeEnum::MENU: + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON: + break; + case WuQMacroWidgetTypeEnum::RADIO_BUTTON: + break; + case WuQMacroWidgetTypeEnum::SLIDER: + break; + case WuQMacroWidgetTypeEnum::SPIN_BOX: + break; + case WuQMacroWidgetTypeEnum::TAB_BAR: + break; + case WuQMacroWidgetTypeEnum::TAB_WIDGET: + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON: + break; + } + */ + + ~WuQMacroWidgetTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + + static void addWidgetClassNameAlias(const QString& widgetName, + const QString& aliasWidgetName); + +private: + WuQMacroWidgetTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WuQMacroWidgetTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; + + /** Aliases for widget 'first' is QWidget, 'second' is alias */ + static std::vector> s_widgetClassNameAliases; +}; + +#ifdef __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ + std::vector WuQMacroWidgetTypeEnum::enumData; + bool WuQMacroWidgetTypeEnum::initializedFlag = false; + int32_t WuQMacroWidgetTypeEnum::integerCodeCounter = 0; + std::vector> WuQMacroWidgetTypeEnum::s_widgetClassNameAliases; +#endif // __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_WIDGET_TYPE_ENUM_H__ diff --git a/src/Common/createMacroShortCutKeyEnum.sh b/src/Common/createMacroShortCutKeyEnum.sh new file mode 100755 index 0000000000000000000000000000000000000000..6eac9380dc9a8d4bedaf4cb86e187f29a2874e6a --- /dev/null +++ b/src/Common/createMacroShortCutKeyEnum.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +/mnt/myelin/distribution/caret7_distribution/workbench/bin_macosx64/wb_command \ + -class-create-enum WuQMacroShortCutKeyEnum 37 true \ + Key_None \ + Key_A \ + Key_B \ + Key_C \ + Key_D \ + Key_E \ + Key_F \ + Key_G \ + Key_H \ + Key_I \ + Key_J \ + Key_K \ + Key_L \ + Key_M \ + Key_N \ + Key_O \ + Key_P \ + Key_Q \ + Key_R \ + Key_S \ + Key_T \ + Key_U \ + Key_V \ + Key_W \ + Key_X \ + Key_Y \ + Key_Z \ + Key_0 \ + Key_1 \ + Key_2 \ + Key_3 \ + Key_4 \ + Key_5 \ + Key_6 \ + Key_7 \ + Key_8 \ + Key_9 + diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index 233e5cedff925646d18590937d959ef453c30fa2..cc8b7e457a95ebfaab20b29ead43b90a97d5908b 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -109,6 +109,7 @@ if(Qt5_FOUND) ${QT5_OPENGL_LIB_NAME} Qt5::PrintSupport Qt5::Test + ${WB_WEBKIT_LIBS} Qt5::Widgets Qt5::Xml) endif() @@ -235,8 +236,8 @@ IF (APPLE) SET (MACOSX_BUNDLE_GUI_IDENTIFIER workbench ) SET (MACOSX_BUNDLE_LONG_VERSION_STRING wb_view) SET (MACOSX_BUNDLE_BUNDLE_NAME wb_view) - SET (MACOSX_BUNDLE_SHORT_VERSION_STRING 1.3.2) - SET (MACOSX_BUNDLE_BUNDLE_VERSION 1.3.2) + SET (MACOSX_BUNDLE_SHORT_VERSION_STRING ${WB_VERSION}) + SET (MACOSX_BUNDLE_BUNDLE_VERSION ${WB_VERSION}) SET (MACOSX_BUNDLE_COPYRIGHT 2015 ) ADD_CUSTOM_COMMAND( diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index 68d5035bb8c65cf3585403628ee5a43e70272dd3..b6c7a923efdb719cdc68bd44ae02d3c0d3858442 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -342,7 +342,17 @@ main(int argc, char* argv[]) #else //CARET_OS_MACOSX QApplication app(argc, argv); #endif //CARET_OS_MACOSX - + + /* + * Create the GUI Manager. + * Moved here as part of WB-842. In OSX Mojave (10.14), + * the open file event appears to be delivered very quickly + * so the GUI manager need to be created sooner than + * before. + */ + GuiManager::createGuiManager(); + app.processEvents(); + ApplicationInformation applicationInformation; QApplication::addLibraryPath( @@ -433,11 +443,6 @@ main(int argc, char* argv[]) } } - /* - * Create the GUI Manager. - */ - GuiManager::createGuiManager(); - /* * Letting the App process events will allow the message for a * double-clicked spec file in Mac OSX to get processed. @@ -736,6 +741,14 @@ void printHelp(const AString& progName) cout << endl + << " -mac-menu-duplicate" << endl + << " MacOS Only - Adds menus to the top of the Browser Window " << endl + << " that duplicate the menu bar at the top of the window. " << endl + << " The menus are similar to that on Linux and Windows. " << endl + << " May be useful for creating tutorial images." << endl + << " This functionality is EXPERIMENTAL and subject to " << endl + << " removal in future versions of wb_view." << endl + << endl << " -no-splash" << endl << " disable all splash screens" << endl << endl @@ -812,6 +825,8 @@ void parseCommandLine(const AString& progName, ProgramParameters* myParams, Prog hasFatalError = true; } } + } else if (thisParam == "-mac-menu-duplicate") { + BrainBrowserWindow::setEnableMacDuplicateMenuBar(true); } else if (thisParam == "-no-splash") { myState.showSplash = false; } else if (thisParam == "-scene-load") { diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index 5660e4db30b24153d8cd3b22d5099c4e5390bff2..ac291f87ee841d8930491481ff56b70b5734baa7 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -44,7 +44,9 @@ #include "EventAnnotationGrouping.h" #include "EventAnnotationTextSubstitutionInvalidate.h" #include "EventBrowserTabDelete.h" +#include "EventBrowserTabNewClone.h" #include "EventManager.h" +#include "EventTileTabsConfigurationModification.h" #include "GiftiMetaData.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -221,7 +223,11 @@ AnnotationFile::initializeAnnotationFile() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GROUP_GET_WITH_KEY); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GROUPING); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); + + /* NEED THIS AFTER Tile Tabs have been modified */ + EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_TILE_TABS_MODIFICATION); + EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); + EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE); } /** @@ -237,10 +243,15 @@ AnnotationGroup* AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) { const AnnotationCoordinateSpaceEnum::Enum annotationSpace = annotation->getCoordinateSpace(); + SpacerTabIndex annotationSpacerTabIndex; + int32_t annotationTabOrWindowIndex = -1; switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + annotationSpacerTabIndex = annotation->getSpacerTabIndex(); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -267,6 +278,11 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) case AnnotationCoordinateSpaceEnum::SURFACE: return group; break; + case AnnotationCoordinateSpaceEnum::SPACER: + if (annotationSpacerTabIndex == group->getSpacerTabIndex()) { + return group; + } + break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; @@ -290,6 +306,8 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) CaretAssert((annotationTabOrWindowIndex >= 0) && (annotationTabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; @@ -303,7 +321,8 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) AnnotationGroupTypeEnum::SPACE, generateUniqueKey(), annotationSpace, - annotationTabOrWindowIndex); + annotationTabOrWindowIndex, + annotationSpacerTabIndex); group->setItemParent(this); m_annotationGroups.push_back(QSharedPointer(group)); @@ -445,9 +464,16 @@ AnnotationFile::receiveEvent(Event* event) CaretAssert(deleteEvent); const int32_t tabIndex = deleteEvent->getBrowserTabIndex(); - if (removeAnnotationsInTab(tabIndex)) { - deleteEvent->setEventProcessed(); - } + removeAnnotationsInTab(tabIndex); + } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE) { + EventBrowserTabNewClone* cloneTabEvent = dynamic_cast(event); + CaretAssert(cloneTabEvent); + + const int32_t cloneToTabIndex = cloneTabEvent->getNewBrowserTabIndex(); + const int32_t cloneFromTabIndex = cloneTabEvent->getIndexOfBrowserTabThatWasCloned(); + cloneAnnotationsFromTabToTab(cloneFromTabIndex, + cloneToTabIndex); } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE) { EventAnnotationTextSubstitutionInvalidate* textSubEvent = dynamic_cast(event); @@ -464,6 +490,11 @@ AnnotationFile::receiveEvent(Event* event) textSubEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_TILE_TABS_MODIFICATION) { + EventTileTabsConfigurationModification* modEvent = dynamic_cast(event); + CaretAssert(modEvent); + updateSpacerAnnotationsAfterTileTabsModification(modEvent); + } } /** @@ -638,6 +669,7 @@ void AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnum::Enum groupType, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const int32_t tabOrWindowIndex, + const SpacerTabIndex& spacerTabIndex, const int32_t uniqueKey, const std::vector& annotations) { @@ -654,6 +686,12 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + if ( ! spacerTabIndex.isValid()) { + throw DataFileException("Invalid spacer tab index for group while reading annotation file: " + + spacerTabIndex.toString()); + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -707,6 +745,15 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu + AnnotationCoordinateSpaceEnum::toGuiName(coordinateSpace) + ". Only one space group for each space is allowed."); break; + case AnnotationCoordinateSpaceEnum::SPACER: + if (spacerTabIndex == group->getSpacerTabIndex()) { + throw DataFileException("There is more than one annotation space group with space " + + AnnotationCoordinateSpaceEnum::toGuiName(coordinateSpace) + + " for spacer tab " + + spacerTabIndex.toString() + + ". Only one space group for each space is allowed."); + } + break; case AnnotationCoordinateSpaceEnum::TAB: if (tabOrWindowIndex == group->getTabOrWindowIndex()) { throw DataFileException("There is more than one annotation space group with space " @@ -738,7 +785,8 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu groupType, uniqueKey, coordinateSpace, - tabOrWindowIndex); + tabOrWindowIndex, + spacerTabIndex); for (std::vector::const_iterator annIter = annotations.begin(); annIter != annotations.end(); annIter++) { @@ -902,6 +950,50 @@ AnnotationFile::removeAnnotationPrivate(Annotation* annotation, return false; } +/** + * Clone annotations in 'fromTabIndex' to 'toTabIndex' + * + * @param fromTabIndex + * Clone annotations from this tab index + * @param toTabIndex + * Clone annotations into this tab index + * @return + * True if any annotations were cloned. + */ +bool +AnnotationFile::cloneAnnotationsFromTabToTab(const int32_t fromTabIndex, + const int32_t toTabIndex) +{ + /* + * Find annotation group(s) in tab space + * with the given tab index. + */ + bool annotationsWereClonedFlag(false); + for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); + groupIter != m_annotationGroups.end(); + groupIter++) { + QSharedPointer& group = *groupIter; + if (group->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { + if (group->getTabOrWindowIndex() == fromTabIndex) { + std::vector annotations; + group->getAllAnnotations(annotations); + + for (auto ann : annotations) { + CaretAssert(ann->getTabIndex() == fromTabIndex); + Annotation* newAnn = ann->clone(); + newAnn->setTabIndex(toTabIndex); + addAnnotationPrivate(newAnn, + generateUniqueKey()); + annotationsWereClonedFlag = true; + } + } + } + } + + return annotationsWereClonedFlag; +} + + /** * Remove all annotations in tab space in the given tab. * @@ -986,6 +1078,26 @@ AnnotationFile::getAllAnnotationGroups(std::vector& annotation } } +/** + * Does this file contain annotations in the given coordinate space? + * + * @param coordinateSpace + * The coordinate space. + * @return + * True if there are annotations in the given coordinate space, else false. + */ +bool +AnnotationFile::hasAnnotationsInCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordinateSpace) const +{ + for (const auto groupIter : m_annotationGroups) { + if (groupIter->getCoordinateSpace() == coordinateSpace) { + return true; + } + } + + return false; +} + /** * Group annotations. * @@ -1093,7 +1205,8 @@ AnnotationFile::processGroupingAnnotations(EventAnnotationGrouping* groupingEven AnnotationGroupTypeEnum::USER, generateUniqueKey(), spaceGroup->getCoordinateSpace(), - spaceGroup->getTabOrWindowIndex()); + spaceGroup->getTabOrWindowIndex(), + spaceGroup->getSpacerTabIndex()); for (std::vector >::iterator annPtrIter = movedAnnotations.begin(); annPtrIter != movedAnnotations.end(); @@ -1246,7 +1359,8 @@ AnnotationFile::processRegroupingAnnotations(EventAnnotationGrouping* groupingEv AnnotationGroupTypeEnum::USER, reuseUniqueKeyOrGenerateNewUniqueKey(userGroupUniqueKey), spaceGroup->getCoordinateSpace(), - spaceGroup->getTabOrWindowIndex()); + spaceGroup->getTabOrWindowIndex(), + spaceGroup->getSpacerTabIndex()); bool allValidFlag = true; std::vector > movedAnnotations; @@ -1545,6 +1659,15 @@ AnnotationFile::readFile(const AString& filename) void AnnotationFile::writeFile(const AString& filename) { + /* + * JWH, 11 Sep 2019 + * WB-866 removed the ".annot" extension for the annotation file. + * It is possible that a user may have a disk annotation file in + * multiple scenes. If this message caused the user to change + * the file extension from ".annot" to ".wb_annot", it could break + * other scenes if they are not updated. + * So, continue avoiding a log message if ".annot" extension is present. + */ if (!(filename.endsWith(".annot") || filename.endsWith(".wb_annot"))) { CaretLogWarning("annotation file '" + filename + "' should be saved ending in .annot"); @@ -1760,7 +1883,8 @@ AnnotationFile::appendContentFromDataFile(const DataFileContentCopyMoveParameter AnnotationGroupTypeEnum::USER, generateUniqueKey(), groupToCopy->getCoordinateSpace(), - groupToCopy->getTabOrWindowIndex()); + groupToCopy->getTabOrWindowIndex(), + groupToCopy->getSpacerTabIndex()); group->setItemParent(this); m_annotationGroups.push_back(QSharedPointer(group)); break; @@ -2040,3 +2164,228 @@ AnnotationFile::isItemSelectedForEditingInWindow(const int32_t /*windowIndex*/) return false; } +/** + * Update spacer annotations after tile tabs configuration is modified. + * + * @param modEvent + * The tile tabs modify event. + */ +void +AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsConfigurationModification* modEvent) +{ + const int32_t rowColumnIndex = modEvent->getRowColumnIndex(); + const bool rowFlag = (modEvent->getRowColumnType() == EventTileTabsConfigurationModification::RowColumnType::ROW); + + int32_t deleteIndex(-1); + int32_t shiftStartIndex(-1); + int32_t duplicateFromIndex(-1); + int32_t duplicateToIndex(-1); + int32_t moveOneIndex(-1); + int32_t moveTwoIndex(-1); + + switch (modEvent->getOperation()) { + case EventTileTabsConfigurationModification::Operation::DELETE_IT: + deleteIndex = rowColumnIndex; + shiftStartIndex = rowColumnIndex + 1; + break; + case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: + { + shiftStartIndex = rowColumnIndex + 1; + duplicateFromIndex = rowColumnIndex; + duplicateToIndex = rowColumnIndex + 1; + } + break; + case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + { + shiftStartIndex = rowColumnIndex; + duplicateFromIndex = rowColumnIndex + 1; + duplicateToIndex = rowColumnIndex; + } + break; + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: + shiftStartIndex = rowColumnIndex; + break; + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: + shiftStartIndex = rowColumnIndex + 1; + break; + case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: + moveOneIndex = rowColumnIndex; + moveTwoIndex = rowColumnIndex + 1; + break; + case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + moveOneIndex = rowColumnIndex; + moveTwoIndex = rowColumnIndex - 1; + break; + } + + std::vector deleteAnnotations; + std::vector duplicatedAnnotations; + std::vector, Annotation*>> modifiedAnnotations; + + std::set processedAnnotations; + + const int32_t windowIndex = modEvent->getWindowIndex(); + for (auto group : m_annotationGroups) { + std::vector> removeAnnotationsFromGroup; + + if (group->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SPACER) { + const int32_t numAnn = group->getNumberOfAnnotations(); + for (int32_t iAnn = 0; iAnn < numAnn; iAnn++) { + Annotation* ann = group->getAnnotation(iAnn); + CaretAssert(ann); + SpacerTabIndex spacerTabIndex = ann->getSpacerTabIndex(); + + if (spacerTabIndex.getWindowIndex() == windowIndex) { + int32_t rowIndex = spacerTabIndex.getRowIndex(); + int32_t columnIndex = spacerTabIndex.getColumnIndex(); + + switch (modEvent->getOperation()) { + case EventTileTabsConfigurationModification::Operation::DELETE_IT: + { + int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); + if (rcIndex == deleteIndex) { + deleteAnnotations.push_back(ann); + } + + /* + * Shift annotations + */ + if (rcIndex >= shiftStartIndex) { + rcIndex = rcIndex - 1; + + if (rowFlag) { + rowIndex = rcIndex; + } + else { + columnIndex = rcIndex; + } + } + } + break; + case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: + case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + { + int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); + /* + * Shift annotations + */ + if (rcIndex >= shiftStartIndex) { + rcIndex = rcIndex + 1; + } + + /* + * Then duplicate and yes, ok to use rowIndex even though it has changed + */ + if (rcIndex == duplicateFromIndex) { + Annotation* dupAnn = ann->clone(); + SpacerTabIndex dupAnnSTI = dupAnn->getSpacerTabIndex(); + if (rowFlag) { + dupAnnSTI.setRowIndex(duplicateToIndex); + } + else { + dupAnnSTI.setColumnIndex(duplicateToIndex); + } + dupAnn->setSpacerTabIndex(dupAnnSTI); + CaretLogFine("Copying from " + + AString::number(rcIndex) + " to " + AString::number(duplicateToIndex) + + " " + ann->toString()); + duplicatedAnnotations.push_back(dupAnn); + } + + if (rowFlag) { + rowIndex = rcIndex; + } + else { + columnIndex = rcIndex; + } + } + break; + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: + { + int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); + if (rcIndex >= shiftStartIndex) { + rcIndex = rcIndex + 1; + } + if (rowFlag) { + rowIndex = rcIndex; + } + else { + columnIndex = rcIndex; + } + } + break; + case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: + case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + { + int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); + int32_t newIndex(-1); + if (rcIndex == moveOneIndex) { + newIndex = moveTwoIndex; + } + else if (rcIndex == moveTwoIndex) { + newIndex = moveOneIndex; + } + if (newIndex >= 0) { + if (rowFlag) { + rowIndex = newIndex; + } + else { + columnIndex = newIndex; + } + } + } + break; + } + + if ((rowIndex != spacerTabIndex.getRowIndex()) + || (columnIndex != spacerTabIndex.getColumnIndex())) { + spacerTabIndex.setRowIndex(rowIndex); + spacerTabIndex.setColumnIndex(columnIndex); + ann->setSpacerTabIndex(spacerTabIndex); + CaretLogFine("Moved from " + + ann->getSpacerTabIndex().toString() + + " to " + spacerTabIndex.toString() + " " + ann->toString()); + modifiedAnnotations.push_back(std::make_pair(group, ann)); + } + } + } + } + + } + + /* + * Move modified annotations into correct annotation group. + */ + for (auto groupAndAnn : modifiedAnnotations) { + QSharedPointer group = groupAndAnn.first; + Annotation* ann = groupAndAnn.second; + + QSharedPointer annSharedPointer; + if (group->removeAnnotation(ann, + annSharedPointer)) { + addAnnotationPrivateSharedPointer(annSharedPointer, + ann->getUniqueKey()); + } + } + + /* + * Add duplicated anntotations. + */ + for (auto ann : duplicatedAnnotations) { + addAnnotationPrivate(ann, + generateUniqueKey()); + } + + /* + * Delete annotations + */ + for (auto ann : deleteAnnotations) { + const bool keepAnnotationForUndoRedoFlag(false); + removeAnnotationPrivate(ann, + keepAnnotationForUndoRedoFlag); + } +} + + + diff --git a/src/Files/AnnotationFile.h b/src/Files/AnnotationFile.h index 1bfde8e636d9e5a379cc3d67d75fe74e2aa77a2f..be344a6002db973ea96991fa3873ca258f2e58a5 100644 --- a/src/Files/AnnotationFile.h +++ b/src/Files/AnnotationFile.h @@ -33,6 +33,7 @@ #include "DisplayGroupAndTabItemInterface.h" #include "EventAnnotationGrouping.h" #include "EventListenerInterface.h" +#include "EventTileTabsConfigurationModification.h" namespace caret { @@ -40,6 +41,7 @@ namespace caret { class AnnotationGroup; class DisplayGroupAndTabItemHelper; class SceneClassAssistant; + class SpacerTabIndex; class AnnotationFile : public CaretDataFile, @@ -119,6 +121,8 @@ namespace caret { virtual DataFileContentCopyMoveInterface* newInstanceOfDataFile() const; + bool hasAnnotationsInCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordinateSpace) const; + // ADD_NEW_METHODS_HERE @@ -182,6 +186,7 @@ namespace caret { void addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnum::Enum groupType, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const int32_t tabOrWindowIndex, + const SpacerTabIndex& spacerTabIndex, const int32_t uniqueKey, const std::vector& annotations); @@ -200,6 +205,9 @@ namespace caret { bool removeAnnotationPrivate(Annotation* annotation, const bool keepAnnotationForUndoRedoFlag); + bool cloneAnnotationsFromTabToTab(const int32_t fromTabIndex, + const int32_t toTabIndex); + bool removeAnnotationsInTab(const int32_t tabIndex); int32_t generateUniqueKey(); @@ -210,6 +218,8 @@ namespace caret { AnnotationGroup* getSpaceAnnotationGroup(const Annotation* annotation); + void updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsConfigurationModification* modEvent); + const AnnotationFileSubType m_fileSubType; SceneClassAssistant* m_sceneAssistant; diff --git a/src/Files/AnnotationFileXmlFormatBase.h b/src/Files/AnnotationFileXmlFormatBase.h index 66e58272ba15b29119bb55566fe325dab52c9010..947e71b2ed9b67a588c1b1d0b412ca938fcf0145 100644 --- a/src/Files/AnnotationFileXmlFormatBase.h +++ b/src/Files/AnnotationFileXmlFormatBase.h @@ -92,6 +92,8 @@ namespace caret { static const QString ATTRIBUTE_ROTATION_ANGLE; + static const QString ATTRIBUTE_SPACER_TAB_INDEX; + static const QString ATTRIBUTE_TAB_INDEX; static const QString ATTRIBUTE_TAB_OR_WINDOW_INDEX; @@ -162,6 +164,8 @@ namespace caret { static const int32_t XML_VERSION_TWO; + static const int32_t XML_VERSION_THREE; + // ADD_NEW_MEMBERS_HERE }; @@ -212,6 +216,8 @@ namespace caret { const QString AnnotationFileXmlFormatBase::ATTRIBUTE_ROTATION_ANGLE = "rotationAngle"; + const QString AnnotationFileXmlFormatBase::ATTRIBUTE_SPACER_TAB_INDEX = "spacerTabIndex"; + const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TAB_INDEX = "tabIndex"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TAB_OR_WINDOW_INDEX = "tabOrWindowIndex"; @@ -282,6 +288,8 @@ namespace caret { const int32_t AnnotationFileXmlFormatBase::XML_VERSION_TWO = 2; + const int32_t AnnotationFileXmlFormatBase::XML_VERSION_THREE = 3; + #endif // __ANNOTATION_FILE_XML_FORMAT_BASE_DECLARE__ } // namespace diff --git a/src/Files/AnnotationFileXmlReader.cxx b/src/Files/AnnotationFileXmlReader.cxx index aab0fb224644e54831da56414eea28c1508ee5ad..4788b9cb42f45d46adfed7ba3c7865b716b61b6d 100644 --- a/src/Files/AnnotationFileXmlReader.cxx +++ b/src/Files/AnnotationFileXmlReader.cxx @@ -133,7 +133,7 @@ AnnotationFileXmlReader::readFileFromString(const QString& fileInString, */ m_stream.grabNew(new QXmlStreamReader(fileInString)); - readFileContentFromXmlStreamReader("SceneFileName", + readFileContentFromXmlStreamReader("AnnotationsInSceneFile", annotationFile); if (m_stream->hasError()) { @@ -198,6 +198,13 @@ AnnotationFileXmlReader::readFileContentFromXmlStreamReader(const QString& filen else if (m_fileVersionNumber == XML_VERSION_TWO) { readVersionTwo(annotationFile); } + else if (m_fileVersionNumber == XML_VERSION_THREE) { + /* + * NOTE: version 3 added new coordinate space "SPACER " + * and otherwise is the same as version 2 format + */ + readVersionTwo(annotationFile); + } else { m_streamHelper->throwDataFileException("File version number " + versionText.toString() @@ -567,6 +574,18 @@ AnnotationFileXmlReader::readAnnotationAttributes(Annotation* annotation, annotation->setWindowIndex(m_streamHelper->getRequiredAttributeIntValue(attributes, annotationElementName, ATTRIBUTE_WINDOW_INDEX)); + /* + * Spacer Tab Index added as part of WB-668 + */ + const AString spacerTabText = m_streamHelper->getOptionalAttributeStringValue(attributes, + annotationElementName, + ATTRIBUTE_SPACER_TAB_INDEX, + ""); + SpacerTabIndex spacerTabIndex; + if ( ! spacerTabText.isEmpty()) { + spacerTabIndex.setFromXmlAttributeText(spacerTabText); + } + annotation->setSpacerTabIndex(spacerTabIndex); /* * Unique Key @@ -669,6 +688,18 @@ AnnotationFileXmlReader::readGroup(AnnotationFile* annotationFile) ELEMENT_GROUP, ATTRIBUTE_TAB_OR_WINDOW_INDEX); + /* + * Spacer Tab Index added as part of WB-668 + */ + const AString spacerTabText = m_streamHelper->getOptionalAttributeStringValue(attributes, + ELEMENT_GROUP, + ATTRIBUTE_SPACER_TAB_INDEX, + ""); + SpacerTabIndex spacerTabIndex; + if ( ! spacerTabText.isEmpty()) { + spacerTabIndex.setFromXmlAttributeText(spacerTabText); + } + const int32_t uniqueKey = m_streamHelper->getRequiredAttributeIntValue(attributes, ELEMENT_GROUP, ATTRIBUTE_UNIQUE_KEY); @@ -745,6 +776,7 @@ AnnotationFileXmlReader::readGroup(AnnotationFile* annotationFile) annotationFile->addAnnotationGroupDuringFileReading(groupType, coordSpace, tabOrWindowIndex, + spacerTabIndex, uniqueKey, annotations); } diff --git a/src/Files/AnnotationFileXmlWriter.cxx b/src/Files/AnnotationFileXmlWriter.cxx index 3b0edb917d06c1acf7ec603f191b5a06d5e65e89..e3c2812a57ecc70f15cdbe93cba18b0cfe5e7668 100644 --- a/src/Files/AnnotationFileXmlWriter.cxx +++ b/src/Files/AnnotationFileXmlWriter.cxx @@ -167,8 +167,19 @@ AnnotationFileXmlWriter::writeFileContentToXmlStreamWriter(const AnnotationFile* m_stream->writeStartDocument(); m_stream->writeStartElement(ELEMENT_ANNOTATION_FILE); - m_stream->writeAttribute(ATTRIBUTE_VERSION, - AString::number(XML_VERSION_TWO)); + + /* + * To improve backward compatibility, only write version 3 if there + * are annotations in 'spacer' coordinate space. + */ + if (annotationFile->hasAnnotationsInCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER)) { + m_stream->writeAttribute(ATTRIBUTE_VERSION, + AString::number(XML_VERSION_THREE)); + } + else { + m_stream->writeAttribute(ATTRIBUTE_VERSION, + AString::number(XML_VERSION_TWO)); + } m_streamHelper->writeMetaData(annotationFile->getFileMetaData()); @@ -239,6 +250,9 @@ AnnotationFileXmlWriter::writeGroup(const AnnotationGroup* group) AnnotationGroupTypeEnum::toName(group->getGroupType())); m_stream->writeAttribute(ATTRIBUTE_TAB_OR_WINDOW_INDEX, QString::number(group->getTabOrWindowIndex())); + m_stream->writeAttribute(ATTRIBUTE_SPACER_TAB_INDEX, + group->getSpacerTabIndex().getXmlAttributeText()); + m_stream->writeAttribute(ATTRIBUTE_UNIQUE_KEY, QString::number(group->getUniqueKey())); @@ -500,6 +514,9 @@ AnnotationFileXmlWriter::getAnnotationPropertiesAsAttributes(const Annotation* a attributes.append(ATTRIBUTE_WINDOW_INDEX, QString::number(annotation->getWindowIndex())); + attributes.append(ATTRIBUTE_SPACER_TAB_INDEX, + annotation->getSpacerTabIndex().getXmlAttributeText()); + attributes.append(ATTRIBUTE_UNIQUE_KEY, QString::number(annotation->getUniqueKey())); } diff --git a/src/Files/BorderFile.cxx b/src/Files/BorderFile.cxx index 13c0bb7913d649b9b1f64415b1ff904062c9314e..f5908379289af1ec934fa5e7d8d9d87bed8e8bff 100644 --- a/src/Files/BorderFile.cxx +++ b/src/Files/BorderFile.cxx @@ -1475,6 +1475,7 @@ void BorderFile::writeFile(const AString& filename, const int& version) checkFileWritability(filename); setFileName(filename); + QFile::remove(filename);//delete it if it exists, to play better with file symlinks switch (version) { diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 0ffc8dc6f3fd4e8c2c0233c0f7b1e69b09f1fef4..0520e6a59d5b33e2ec6ab17d5ee72cbc04abbc11 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -109,6 +109,7 @@ LabelDrawingProperties.h LabelDrawingTypeEnum.h LabelFile.h MapYokingGroupEnum.h +MetricDynamicConnectivityFile.h MetricFile.h MetricSmoothingObject.h NodeAndVoxelColoring.h @@ -116,14 +117,19 @@ OxfordSparseThreeFile.h PaletteFile.h RgbaFile.h RibbonMappingHelper.h +SceneDataFileInfo.h SceneFile.h SceneFileSaxReader.h +SceneFileXmlStreamBase.h +SceneFileXmlStreamReader.h +SceneFileXmlStreamWriter.h SignedDistanceHelper.h SparseVolumeIndexer.h SpecFile.h SpecFileDataFileTypeGroup.h SpecFileDataFile.h SpecFileSaxReader.h +SceneFileXmlStreamFormatTester.h StudyMetaDataLink.h StudyMetaDataLinkSet.h StudyMetaDataLinkSetSaxReader.h @@ -141,6 +147,7 @@ SurfaceResamplingMethodEnum.h SurfaceTypeEnum.h TextFile.h TopologyHelper.h +VolumeDynamicConnectivityFile.h VolumeEditingModeEnum.h VolumeFile.h VolumeFileEditorDelegate.h @@ -237,6 +244,7 @@ LabelDrawingProperties.cxx LabelDrawingTypeEnum.cxx LabelFile.cxx MapYokingGroupEnum.cxx +MetricDynamicConnectivityFile.cxx MetricFile.cxx MetricSmoothingObject.cxx NodeAndVoxelColoring.cxx @@ -244,8 +252,13 @@ OxfordSparseThreeFile.cxx PaletteFile.cxx RgbaFile.cxx RibbonMappingHelper.cxx +SceneDataFileInfo.cxx SceneFile.cxx SceneFileSaxReader.cxx +SceneFileXmlStreamBase.cxx +SceneFileXmlStreamFormatTester.cxx +SceneFileXmlStreamReader.cxx +SceneFileXmlStreamWriter.cxx SignedDistanceHelper.cxx SparseVolumeIndexer.cxx SpecFile.cxx @@ -269,6 +282,7 @@ SurfaceResamplingMethodEnum.cxx SurfaceTypeEnum.cxx TextFile.cxx TopologyHelper.cxx +VolumeDynamicConnectivityFile.cxx VolumeEditingModeEnum.cxx VolumeFile.cxx VolumeFileEditorDelegate.cxx diff --git a/src/Files/CaretDataFileHelper.cxx b/src/Files/CaretDataFileHelper.cxx index d6817ab73053d07da2bd3a5ccc332d60e336a502..45255107205d9c5d2a8efa968cfe5b444056ae7b 100644 --- a/src/Files/CaretDataFileHelper.cxx +++ b/src/Files/CaretDataFileHelper.cxx @@ -368,6 +368,9 @@ CaretDataFileHelper::createCaretDataFileForFileType(const DataFileTypeEnum::Enum case DataFileTypeEnum::METRIC: caretDataFile = new MetricFile(); break; + case DataFileTypeEnum::METRIC_DYNAMIC: + CaretAssertMessage(0, "Never create a metric dynamic file"); + break; case DataFileTypeEnum::PALETTE: caretDataFile = new PaletteFile(); break; @@ -389,6 +392,9 @@ CaretDataFileHelper::createCaretDataFileForFileType(const DataFileTypeEnum::Enum case DataFileTypeEnum::VOLUME: caretDataFile = new VolumeFile(); break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + CaretAssertMessage(0, "Never create a Volume Dynamic file"); + break; } return caretDataFile; diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index b5a03a6e480490f99e11eabb2cca315f1da8ed4e..30fcb3e6be5a8f939e2065efce7af9a852448bb2 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -1473,3 +1473,51 @@ const CiftiXML CaretMappableDataFile::getCiftiXML() const return CiftiXML(); } +/** + * Get the identification information for a surface node in the given maps. + * + * @param mapIndices + * Indices of maps for which identification information is requested. + * @param structure + * Structure of the surface. + * @param nodeIndex + * Index of the node. + * @param numberOfNodes + * Number of nodes in the surface. + * @param textOut + * Output containing identification information. + */ +bool +CaretMappableDataFile::getSurfaceNodeIdentificationForMaps(const std::vector& /*mapIndices*/, + const StructureEnum::Enum /*structure*/, + const int /*nodeIndex*/, + const int32_t /*numberOfNodes*/, + AString& textOut) const +{ + textOut.clear(); + return false; +} + +/** + * Get the identification information for a surface node in the given maps. + * + * @param mapIndices + * Indices of maps for which identification information is requested. + * @param xyz + * Coordinate of voxel. + * @param ijkOut + * Voxel indices of value. + * @param textOut + * Output containing identification information. + */ +bool +CaretMappableDataFile::getVolumeVoxelIdentificationForMaps(const std::vector& /*mapIndices*/, + const float* /*xyz[3]*/, + int64_t* /*ijkOut[3]*/, + AString& textOut) const +{ + textOut.clear(); + return false; +} + + diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 6bf46d6a9d8a983d9f4234290f9963586075c903..a1b44eec6fc6502747a2ed64d2c91bf8b86042f6 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -504,6 +504,20 @@ namespace caret { */ virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const = 0; + virtual bool getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, + const StructureEnum::Enum structure, + const int nodeIndex, + const int32_t numberOfNodes, + AString& textOut) const; + + virtual bool getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, + const float xyz[3], + int64_t ijkOut[3], + AString& textOut) const; + + + void updateAfterFileDataChanges(); + protected: CaretMappableDataFile(const CaretMappableDataFile&); @@ -513,8 +527,6 @@ namespace caret { void helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; - void updateAfterFileDataChanges(); - virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); diff --git a/src/Files/CaretMappableDataFileAndMapSelectionModel.cxx b/src/Files/CaretMappableDataFileAndMapSelectionModel.cxx index 76aa917e834112934d5c07e929e0c397ef061b9f..d7ae9f173b7e4bf487a5577176ceb62accfee7b7 100644 --- a/src/Files/CaretMappableDataFileAndMapSelectionModel.cxx +++ b/src/Files/CaretMappableDataFileAndMapSelectionModel.cxx @@ -166,6 +166,9 @@ CaretMappableDataFileAndMapSelectionModel::validateDataFileTypes() case DataFileTypeEnum::METRIC: isMappableFile = true; break; + case DataFileTypeEnum::METRIC_DYNAMIC: + isMappableFile = true;; + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -182,6 +185,9 @@ CaretMappableDataFileAndMapSelectionModel::validateDataFileTypes() case DataFileTypeEnum::VOLUME: isMappableFile = true; break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + isMappableFile = true; + break; } CaretAssert(isMappableFile); diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index ec6f826a3d778c3b9d393ee835239dd76de6e309..03faab3301f78751ec9ba1cd435bb1c7db86a461 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -156,6 +156,9 @@ ChartableTwoFileDelegate::updateAfterFileChanged() histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; break; + case DataFileTypeEnum::METRIC_DYNAMIC: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -174,7 +177,9 @@ ChartableTwoFileDelegate::updateAfterFileChanged() lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; } break; - + case DataFileTypeEnum::VOLUME_DYNAMIC: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + break; } if (m_histogramCharting) { diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 1a93586edcd80e638af5ec4ed645c1dbfd4d9aa8..af1b89252e25c29923f22c031eab79d5803e1586 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -134,6 +134,8 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -148,6 +150,8 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } bool hasColumnParcelsFlag = false; diff --git a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx index fee8cbc5f50f969daa294bd32bc1b8427dffe7c1..6205019d218c5949d67665a10f8af05b7d8afbb6 100644 --- a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx +++ b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx @@ -62,7 +62,7 @@ CiftiMappableConnectivityMatrixDataFile::CiftiMappableConnectivityMatrixDataFile m_sceneAssistant->add("m_connectivityDataLoaded", "ConnectivityDataLoaded", m_connectivityDataLoaded); - m_sceneAssistant->add("m_dataLoadingEnabled", + m_sceneAssistant->add("+", &m_dataLoadingEnabled); } @@ -266,9 +266,9 @@ CiftiMappableConnectivityMatrixDataFile::getRowColumnIndexForNodeWhenLoading(con case CiftiMappingType::PARCELS: rowOrColumnIndex = ciftiXML.getParcelsMap(ciftiDirection).getIndexForNode(nodeIndex, structure); break; - case CIFTI_INDEX_TYPE_SCALARS: + case CiftiMappingType::SCALARS: break; - case CIFTI_INDEX_TYPE_TIME_POINTS: + case CiftiMappingType::SERIES: break; default: CaretAssert(0); @@ -462,7 +462,12 @@ CiftiMappableConnectivityMatrixDataFile::getRowColumnIndexForVoxelAtCoordinateWh } int64_t ijk[3]; - enclosingVoxel(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); + if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { + enclosingVoxel(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); + } + else { + enclosingVoxelForDataLoading(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); + } return getRowColumnIndexForVoxelIndexWhenLoading(ijk, rowIndexOut, columnIndexOut); @@ -504,12 +509,15 @@ CiftiMappableConnectivityMatrixDataFile::getRowColumnIndexForVoxelIndexWhenLoadi /* * Get the mapping type */ - if (indexValid(ijk[0], ijk[1], ijk[2])) { + const bool indexValidFlag = ((getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) + ? indexValid(ijk[0], ijk[1], ijk[2]) + : indexValidForDataLoading(ijk[0], ijk[1], ijk[2])); + if (indexValidFlag) { switch (rowMappingType) { - case CIFTI_INDEX_TYPE_BRAIN_MODELS: + case CiftiMappingType::BRAIN_MODELS: rowOrColumnIndex = ciftiXML.getBrainModelsMap(ciftiDirection).getIndexForVoxel(ijk); break; - case CIFTI_INDEX_TYPE_PARCELS: + case CiftiMappingType::PARCELS: rowOrColumnIndex = ciftiXML.getParcelsMap(ciftiDirection).getIndexForVoxel(ijk); break; default: diff --git a/src/Files/CiftiMappableConnectivityMatrixDataFile.h b/src/Files/CiftiMappableConnectivityMatrixDataFile.h index a14e5fb88fcd014b814084347e58af71062b8420..4b795411b8483daffc24fa02ad9855bd77ae2cc9 100644 --- a/src/Files/CiftiMappableConnectivityMatrixDataFile.h +++ b/src/Files/CiftiMappableConnectivityMatrixDataFile.h @@ -67,7 +67,7 @@ namespace caret { virtual bool loadMapAverageDataForVoxelIndices(const int32_t mapIndex, const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices); - + void loadDataForRowIndex(const int64_t rowIndex); void loadDataForColumnIndex(const int64_t rowIndex); diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 1bb252a5d67045558d0efb1ded2d21ec06b1b257..644cf8034d0532199c5e1a3ae746dcc48d1c3d29 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -44,6 +44,7 @@ #include "CiftiScalarDataSeriesFile.h" #include "CaretTemporaryFile.h" #include "CiftiXML.h" +#include "ConnectivityDataLoaded.h" #include "DataFileContentInformation.h" #include "EventManager.h" #include "EventCaretPreferencesGet.h" @@ -81,7 +82,8 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi : CaretMappableDataFile(dataFileType) { m_ciftiFile.grabNew(NULL); - m_voxelIndicesToOffset.grabNew(NULL); + m_voxelIndicesToOffsetForDataReading.grabNew(NULL); + m_voxelIndicesToOffsetForDataMapping.grabNew(NULL); m_classNameHierarchy.grabNew(NULL); m_fileDataReadingType = FILE_READ_DATA_ALL; @@ -230,6 +232,7 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi case DataFileTypeEnum::IMAGE: case DataFileTypeEnum::LABEL: case DataFileTypeEnum::METRIC: + case DataFileTypeEnum::METRIC_DYNAMIC: case DataFileTypeEnum::PALETTE: case DataFileTypeEnum::RGBA: case DataFileTypeEnum::SCENE: @@ -237,6 +240,7 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi case DataFileTypeEnum::SURFACE: case DataFileTypeEnum::UNKNOWN: case DataFileTypeEnum::VOLUME: + case DataFileTypeEnum::VOLUME_DYNAMIC: CaretAssertMessage(0, (DataFileTypeEnum::toGuiName(dataFileType) + " is not a CIFTI Mappable Data File.")); break; @@ -791,6 +795,7 @@ CiftiMappableDataFile::validateMappingTypes(const AString& filename) case DataFileTypeEnum::IMAGE: case DataFileTypeEnum::LABEL: case DataFileTypeEnum::METRIC: + case DataFileTypeEnum::METRIC_DYNAMIC: case DataFileTypeEnum::PALETTE: case DataFileTypeEnum::RGBA: case DataFileTypeEnum::SCENE: @@ -798,6 +803,7 @@ CiftiMappableDataFile::validateMappingTypes(const AString& filename) case DataFileTypeEnum::SURFACE: case DataFileTypeEnum::UNKNOWN: case DataFileTypeEnum::VOLUME: + case DataFileTypeEnum::VOLUME_DYNAMIC: throw DataFileException(filename, DataFileTypeEnum::toGuiName(dataFileType) + " is not a CIFTI Mappable Data File."); @@ -970,10 +976,10 @@ CiftiMappableDataFile::initializeAfterReading(const AString& filename) break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { - m_voxelIndicesToOffset.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN))); + m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN))); } else if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) { - m_voxelIndicesToOffset.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_COLUMN))); + m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_COLUMN))); } else { CaretAssertMessage(0, "Invalid mapping type for mapping data to brainordinates"); @@ -983,10 +989,10 @@ CiftiMappableDataFile::initializeAfterReading(const AString& filename) break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::BRAIN_MODELS) { - m_voxelIndicesToOffset.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_ROW))); + m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_ROW))); } else if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { - m_voxelIndicesToOffset.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_ROW))); + m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_ROW))); } else { CaretAssertMessage(0, "Invalid mapping type for mapping data to brainordinates"); @@ -996,6 +1002,36 @@ CiftiMappableDataFile::initializeAfterReading(const AString& filename) break; } + switch (m_dataReadingAccessMethod) { + case DATA_ACCESS_METHOD_INVALID: + CaretAssert(0); + break; + case DATA_ACCESS_NONE: + break; + case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: + if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { + m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN))); + } + else if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) { + m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_COLUMN))); + } + else { + m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer()); + } + break; + case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: + if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::BRAIN_MODELS) { + m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_ROW))); + } + else if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { + m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_ROW))); + } + else { + m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer()); + } + break; + } + /* * Special case for scalar data series that does NOT map to brainordinates */ @@ -1027,8 +1063,11 @@ CiftiMappableDataFile::initializeAfterReading(const AString& filename) /* * May not have mappings to voxels */ - if (m_voxelIndicesToOffset == NULL) { - m_voxelIndicesToOffset.grabNew(new SparseVolumeIndexer()); + if (m_voxelIndicesToOffsetForDataMapping == NULL) { + m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer()); + } + if (m_voxelIndicesToOffsetForDataReading == NULL) { + m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer()); } int32_t numberOfMaps = 0; @@ -1888,6 +1927,8 @@ CiftiMappableDataFile::getMatrixForChartingRGBA(int32_t& numberOfRowsOut, break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -1902,6 +1943,8 @@ CiftiMappableDataFile::getMatrixForChartingRGBA(int32_t& numberOfRowsOut, break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } if (( ! useMapFileHelperFlag) @@ -2682,6 +2725,96 @@ CiftiMappableDataFile::getDimensions(std::vector& dimsOut) const dimsOut[4] = dimComp; } +/** + * Get the dimensions of the volume for data loading + * + * @param dimOut1 + * First dimension (i) out. + * @param dimOut2 + * Second dimension (j) out. + * @param dimOut3 + * Third dimension (k) out. + * @param dimTimeOut + * Time dimensions out (number of maps) + * @param numComponentsOut + * Number of components per voxel. + */ +void +CiftiMappableDataFile::getDimensionsForDataLoading(int64_t& dimOut1, + int64_t& dimOut2, + int64_t& dimOut3, + int64_t& dimTimeOut, + int64_t& numComponentsOut) const +{ + CaretAssert(m_ciftiFile); + + dimOut1 = 0; + dimOut2 = 0; + dimOut3 = 0; + dimTimeOut = 0; + numComponentsOut = 0; + + if (m_dataReadingDirectionForCiftiXML != S_CIFTI_XML_ALONG_INVALID) { + switch (m_ciftiFile->getCiftiXML().getMappingType(m_dataReadingDirectionForCiftiXML)) + { + case CiftiMappingType::BRAIN_MODELS: + { + const CiftiBrainModelsMap& myDenseMap = m_ciftiFile->getCiftiXML().getBrainModelsMap(m_dataReadingDirectionForCiftiXML); + if (!myDenseMap.hasVolumeData()) return; + const VolumeSpace& mySpace = myDenseMap.getVolumeSpace(); + const int64_t* dims = mySpace.getDims(); + dimOut1 = dims[0]; + dimOut2 = dims[1]; + dimOut3 = dims[2]; + dimTimeOut = 1;//??? + numComponentsOut = 1; + break; + } + case CiftiMappingType::PARCELS: + { + const CiftiParcelsMap& myParcelMap = m_ciftiFile->getCiftiXML().getParcelsMap(m_dataReadingDirectionForCiftiXML); + if (!myParcelMap.hasVolumeData()) return; + const VolumeSpace& mySpace = myParcelMap.getVolumeSpace(); + const int64_t* dims = mySpace.getDims(); + dimOut1 = dims[0]; + dimOut2 = dims[1]; + dimOut3 = dims[2]; + dimTimeOut = 1;//??? + numComponentsOut = 1; + break; + } + default://nothing else has volume dimensions + break; + } + } +} + +/** + * Get the dimensions of the volume. + * + * @param dimsOut + * Will contain 5 elements: (0) X-dimension, (1) Y-dimension + * (2) Z-dimension, (3) time, (4) components. + */ +void +CiftiMappableDataFile::getDimensionsForDataLoading(std::vector& dimsOut) const +{ + dimsOut.resize(5); + + int64_t dimI, dimJ, dimK, dimTime, dimComp; + getDimensionsForDataLoading(dimI, + dimJ, + dimK, + dimTime, + dimComp); + + dimsOut[0] = dimI; + dimsOut[1] = dimJ; + dimsOut[2] = dimK; + dimsOut[3] = dimTime; + dimsOut[4] = dimComp; +} + /** * @return The number of componenents per voxel in the volume data. */ @@ -2723,8 +2856,8 @@ CiftiMappableDataFile::indexToSpace(const float& indexIn1, float& coordOut2, float& coordOut3) const { - CaretAssert(m_voxelIndicesToOffset); - m_voxelIndicesToOffset->indicesToCoordinate(indexIn1, + CaretAssert(m_voxelIndicesToOffsetForDataMapping); + m_voxelIndicesToOffsetForDataMapping->indicesToCoordinate(indexIn1, indexIn2, indexIn3, coordOut1, @@ -2750,8 +2883,8 @@ CiftiMappableDataFile::indexToSpace(const float& indexIn1, const float& indexIn3, float* coordOut) const { - CaretAssert(m_voxelIndicesToOffset); - m_voxelIndicesToOffset->indicesToCoordinate(indexIn1, + CaretAssert(m_voxelIndicesToOffsetForDataMapping); + m_voxelIndicesToOffsetForDataMapping->indicesToCoordinate(indexIn1, indexIn2, indexIn3, coordOut[0], @@ -2771,8 +2904,8 @@ void CiftiMappableDataFile::indexToSpace(const int64_t* indexIn, float* coordOut) const { - CaretAssert(m_voxelIndicesToOffset); - m_voxelIndicesToOffset->indicesToCoordinate(indexIn[0], + CaretAssert(m_voxelIndicesToOffsetForDataMapping); + m_voxelIndicesToOffsetForDataMapping->indicesToCoordinate(indexIn[0], indexIn[1], indexIn[2], coordOut[0], @@ -2805,8 +2938,8 @@ CiftiMappableDataFile::enclosingVoxel(const float& coordIn1, int64_t& indexOut2, int64_t& indexOut3) const { - CaretAssert(m_voxelIndicesToOffset); - m_voxelIndicesToOffset->coordinateToIndices(coordIn1, + CaretAssert(m_voxelIndicesToOffsetForDataMapping); + m_voxelIndicesToOffsetForDataMapping->coordinateToIndices(coordIn1, coordIn2, coordIn3, indexOut1, @@ -2814,6 +2947,41 @@ CiftiMappableDataFile::enclosingVoxel(const float& coordIn1, indexOut3); } +/** + * Use the method when LOADING data + * Convert a coordinate to indices. Note that output indices + * MAY NOT BE WITHIN THE VALID VOXEL DIMENSIONS. + * + * @param coordIn1 + * First (x) input coordinate. + * @param coordIn2 + * Second (y) input coordinate. + * @param coordIn3 + * Third (z) input coordinate. + * @param indexOut1 + * First output index (i). + * @param indexOut2 + * First output index (j). + * @param indexOut3 + * First output index (k). + */ +void +CiftiMappableDataFile::enclosingVoxelForDataLoading(const float& coordIn1, + const float& coordIn2, + const float& coordIn3, + int64_t& indexOut1, + int64_t& indexOut2, + int64_t& indexOut3) const +{ + CaretAssert(m_voxelIndicesToOffsetForDataReading); + m_voxelIndicesToOffsetForDataReading->coordinateToIndices(coordIn1, + coordIn2, + coordIn3, + indexOut1, + indexOut2, + indexOut3); +} + /** * Determine in the given voxel indices are valid (within the volume dimensions). * @@ -2852,10 +3020,48 @@ CiftiMappableDataFile::indexValid(const int64_t& indexIn1, return false; } +/** + * Determine in the given voxel indices are valid (within the volume dimensions). + * + * @param indexIn1 + * First dimension (i). + * @param indexIn2 + * Second dimension (j). + * @param indexIn3 + * Third dimension (k). + * @param coordOut1 + * Output first (x) coordinate. + * @param brickIndex + * Time/map index (default 0). + * @param component + * Voxel component (default 0). + */ +bool +CiftiMappableDataFile::indexValidForDataLoading(const int64_t& indexIn1, + const int64_t& indexIn2, + const int64_t& indexIn3, + const int64_t /*brickIndex*/, + const int64_t /*component*/) const +{ + std::vector volumeDimensions; + getDimensionsForDataLoading(volumeDimensions); + CaretAssertVectorIndex(volumeDimensions, 2); + if ((indexIn1 >= 0) + && (indexIn1 < volumeDimensions[0]) + && (indexIn2 >= 0) + && (indexIn2 < volumeDimensions[1]) + && (indexIn3 >= 0) + && (indexIn3 < volumeDimensions[2])) { + return true; + } + + return false; +} + const VolumeSpace& CiftiMappableDataFile::getVolumeSpace() const { - CaretAssert(m_voxelIndicesToOffset);//because this is where the other space functions get their volume space from, just roll with it for now - return m_voxelIndicesToOffset->getVolumeSpace(); + CaretAssert(m_voxelIndicesToOffsetForDataMapping);//because this is where the other space functions get their volume space from, just roll with it for now + return m_voxelIndicesToOffsetForDataMapping->getVolumeSpace(); } /** @@ -2867,7 +3073,7 @@ const VolumeSpace& CiftiMappableDataFile::getVolumeSpace() const void CiftiMappableDataFile::getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) const { - CaretAssert(m_voxelIndicesToOffset); + CaretAssert(m_voxelIndicesToOffsetForDataMapping); boundingBoxOut.resetForUpdate(); @@ -2875,7 +3081,7 @@ CiftiMappableDataFile::getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) con getDimensions(volumeDimensions); CaretAssertVectorIndex(volumeDimensions, 2); - if (m_voxelIndicesToOffset->isValid()) { + if (m_voxelIndicesToOffsetForDataMapping->isValid()) { float xyz[3]; indexToSpace(0, 0, @@ -2992,7 +3198,7 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; - CaretAssert(m_voxelIndicesToOffset); + CaretAssert(m_voxelIndicesToOffsetForDataMapping); /* * Data values are only needed when a label volume @@ -3021,7 +3227,7 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, case VolumeSliceViewPlaneEnum::AXIAL: for (int64_t j = 0; j < dimJ; j++) { for (int64_t i = 0; i < dimI; i++) { - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(i, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, j, sliceIndex); if (dataOffset >= 0) { @@ -3033,17 +3239,9 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; - /* - * A negative value for alpha indicates "do not draw". - * Since unsigned bytes do not have negative values, - * change the value to zero (which indicates "transparent"). - */ - float alpha = mapRGBA[dataOffset4+3]; - if (alpha < 0.0) { - alpha = 0.0; - } + uint8_t alpha = mapRGBA[dataOffset4+3]; - if (alpha > 0.0) { + if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. @@ -3057,17 +3255,17 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { - alpha = 0.0; + alpha = 0; } } } } - if (alpha > 0.0) { + if (alpha > 0) { ++validVoxelCount; } - rgbaOut[rgbaOffset+3] = (alpha * 255.0); + rgbaOut[rgbaOffset+3] = alpha; } } } @@ -3075,7 +3273,7 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, case VolumeSliceViewPlaneEnum::CORONAL: for (int64_t k = 0; k < dimK; k++) { for (int64_t i = 0; i < dimI; i++) { - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(i, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, sliceIndex, k); if (dataOffset >= 0) { @@ -3087,17 +3285,9 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; - /* - * A negative value for alpha indicates "do not draw". - * Since unsigned bytes do not have negative values, - * change the value to zero (which indicates "transparent"). - */ - float alpha = mapRGBA[dataOffset4+3]; - if (alpha < 0.0) { - alpha = 0.0; - } + uint8_t alpha = mapRGBA[dataOffset4+3]; - if (alpha > 0.0) { + if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. @@ -3111,17 +3301,17 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { - alpha = 0.0; + alpha = 0; } } } } - if (alpha > 0.0) { + if (alpha > 0) { ++validVoxelCount; } - rgbaOut[rgbaOffset+3] = (alpha * 255.0); + rgbaOut[rgbaOffset+3] = alpha; } } } @@ -3129,7 +3319,7 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, case VolumeSliceViewPlaneEnum::PARASAGITTAL: for (int64_t k = 0; k < dimK; k++) { for (int64_t j = 0; j < dimJ; j++) { - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(sliceIndex, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(sliceIndex, j, k); if (dataOffset >= 0) { @@ -3141,17 +3331,9 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; - /* - * A negative value for alpha indicates "do not draw". - * Since unsigned bytes do not have negative values, - * change the value to zero (which indicates "transparent"). - */ - float alpha = mapRGBA[dataOffset4+3]; - if (alpha < 0.0) { - alpha = 0.0; - } + uint8_t alpha = mapRGBA[dataOffset4+3]; - if (alpha > 0.0) { + if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. @@ -3165,17 +3347,17 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { - alpha = 0.0; + alpha = 0; } } } } - if (alpha > 0.0) { + if (alpha > 0) { ++validVoxelCount; } - rgbaOut[rgbaOffset+3] = (alpha * 255.0); + rgbaOut[rgbaOffset+3] = alpha; } } } @@ -3241,7 +3423,7 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; - CaretAssert(m_voxelIndicesToOffset); + CaretAssert(m_voxelIndicesToOffsetForDataMapping); /* * Data values are only needed when a label volume @@ -3270,7 +3452,7 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, for (int32_t iCol = 0; iCol < numberOfColumns; iCol++) { rgba[3] = 0; - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); @@ -3278,18 +3460,9 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, rgba[0] = mapRGBA[dataOffset4]; rgba[1] = mapRGBA[dataOffset4+1]; rgba[2] = mapRGBA[dataOffset4+2]; + uint8_t alpha = mapRGBA[dataOffset4+3]; - /* - * A negative value for alpha indicates "do not draw". - * Since unsigned bytes do not have negative values, - * change the value to zero (which indicates "transparent"). - */ - float alpha = mapRGBA[dataOffset4+3]; - if (alpha < 0.0) { - alpha = 0.0; - } - - if (alpha > 0.0) { + if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. @@ -3303,23 +3476,32 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { - alpha = 0.0; + alpha = 0; } } } } - if (alpha > 0.0) { + if (alpha > 0) { ++validVoxelCount; } - rgba[3] = (alpha * 255.0); + rgba[3] = alpha; } - rgbaOut[rgbaOutIndex4] = rgba[0]; - rgbaOut[rgbaOutIndex4+1] = rgba[1]; - rgbaOut[rgbaOutIndex4+2] = rgba[2]; - rgbaOut[rgbaOutIndex4+3] = rgba[3]; + if (rgba[3] > 0) { + rgbaOut[rgbaOutIndex4] = rgba[0]; + rgbaOut[rgbaOutIndex4+1] = rgba[1]; + rgbaOut[rgbaOutIndex4+2] = rgba[2]; + rgbaOut[rgbaOutIndex4+3] = rgba[3]; + } + else { + /* Fixes blending */ + rgbaOut[rgbaOutIndex4] = 0; + rgbaOut[rgbaOutIndex4+1] = 0; + rgbaOut[rgbaOutIndex4+2] = 0; + rgbaOut[rgbaOutIndex4+3] = 0; + } rgbaOutIndex4 += 4; if (rgba[3] > 0) { @@ -3457,7 +3639,7 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; - CaretAssert(m_voxelIndicesToOffset); + CaretAssert(m_voxelIndicesToOffsetForDataMapping); /* * Data values are only needed when a label volume @@ -3501,7 +3683,7 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, int64_t i = iStart; bool iLoopFlag = true; while (iLoopFlag) { - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(i, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, j, sliceIndex); if (dataOffset >= 0) { @@ -3512,17 +3694,9 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; - /* - * A negative value for alpha indicates "do not draw". - * Since unsigned bytes do not have negative values, - * change the value to zero (which indicates "transparent"). - */ - float alpha = mapRGBA[dataOffset4+3]; - if (alpha < 0.0) { - alpha = 0.0; - } + uint8_t alpha = mapRGBA[dataOffset4+3]; - if (alpha > 0.0) { + if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. @@ -3536,17 +3710,17 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { - alpha = 0.0; + alpha = 0; } } } } - if (alpha > 0.0) { + if (alpha > 0) { ++validVoxelCount; } - rgbaOut[rgbaOffset+3] = (alpha * 255.0); + rgbaOut[rgbaOffset+3] = alpha; } if (i == iEnd) { @@ -3581,7 +3755,7 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, bool iLoopFlag = true; while (iLoopFlag) { - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(i, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, sliceIndex, k); if (dataOffset >= 0) { @@ -3592,17 +3766,9 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; - /* - * A negative value for alpha indicates "do not draw". - * Since unsigned bytes do not have negative values, - * change the value to zero (which indicates "transparent"). - */ - float alpha = mapRGBA[dataOffset4+3]; - if (alpha < 0.0) { - alpha = 0.0; - } + uint8_t alpha = mapRGBA[dataOffset4+3]; - if (alpha > 0.0) { + if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. @@ -3616,17 +3782,17 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { - alpha = 0.0; + alpha = 0; } } } } - if (alpha > 0.0) { + if (alpha > 0) { ++validVoxelCount; } - rgbaOut[rgbaOffset+3] = (alpha * 255.0); + rgbaOut[rgbaOffset+3] = alpha; } @@ -3662,7 +3828,7 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, while (jLoopFlag) { - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(sliceIndex, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(sliceIndex, j, k); if (dataOffset >= 0) { @@ -3673,17 +3839,9 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; - /* - * A negative value for alpha indicates "do not draw". - * Since unsigned bytes do not have negative values, - * change the value to zero (which indicates "transparent"). - */ - float alpha = mapRGBA[dataOffset4+3]; - if (alpha < 0.0) { - alpha = 0.0; - } + uint8_t alpha = mapRGBA[dataOffset4+3]; - if (alpha > 0.0) { + if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. @@ -3697,17 +3855,17 @@ CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { - alpha = 0.0; + alpha = 0; } } } } - if (alpha > 0.0) { + if (alpha > 0) { ++validVoxelCount; } - rgbaOut[rgbaOffset+3] = (alpha * 255.0); + rgbaOut[rgbaOffset+3] = alpha; } if (j == jEnd) { @@ -3785,7 +3943,7 @@ CiftiMappableDataFile::getVoxelColorInMapForLabelData(const std::vector& const GiftiLabelTable* labelTable = getMapLabelTable(mapIndex); CaretAssert(labelTable); - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(indexIn1, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(indexIn1, indexIn2, indexIn3); if (dataOffset >= 0) { @@ -3801,7 +3959,7 @@ CiftiMappableDataFile::getVoxelColorInMapForLabelData(const std::vector& const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); if (item != NULL) { if (item->isSelected(displayGroup, tabIndex) == false) { - rgbaOut[3] = 0.0; + rgbaOut[3] = 0; } } } @@ -3849,7 +4007,7 @@ CiftiMappableDataFile::getVoxelColorInMap(const int64_t indexIn1, nonConstThis->updateScalarColoringForMap(mapIndex); } - CaretAssert(m_voxelIndicesToOffset); + CaretAssert(m_voxelIndicesToOffsetForDataMapping); const int64_t mapRgbaCount = m_mapContent[mapIndex]->m_rgba.size(); if (mapRgbaCount <= 0) { @@ -3857,7 +4015,7 @@ CiftiMappableDataFile::getVoxelColorInMap(const int64_t indexIn1, } const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(indexIn1, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(indexIn1, indexIn2, indexIn3); if (dataOffset >= 0) { @@ -4381,74 +4539,101 @@ CiftiMappableDataFile::getMapSurfaceNodeValues(const std::vector& mapIn break; case CiftiMappingType::PARCELS: { - int64_t parcelIndex = -1; - const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); - if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { - const std::vector& parcels = map.getParcels(); - parcelIndex = map.getIndexForNode(nodeIndex, - structure); - if ((parcelIndex >= 0) - && (parcelIndex < static_cast(parcels.size()))) { - textValueOut = parcels[parcelIndex].m_name; + + int32_t readingDataParcelIndex = -1; + const CiftiParcelsMap dataMap = ciftiXML.getParcelsMap(m_dataReadingDirectionForCiftiXML); + if (dataMap.getSurfaceNumberOfNodes(structure) == numberOfNodes) { + readingDataParcelIndex = dataMap.getIndexForNode(nodeIndex, structure); + } + + /* + * Special case for matrix type files + */ + const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(this); + if (matrixFile != NULL) { + const ConnectivityDataLoaded* dataLoaded = matrixFile->getConnectivityDataLoaded(); + switch (dataLoaded->getMode()) { + case ConnectivityDataLoaded::MODE_NONE: + return false; + break; + case ConnectivityDataLoaded::MODE_COLUMN: + case ConnectivityDataLoaded::MODE_ROW: + case ConnectivityDataLoaded::MODE_SURFACE_NODE: + case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: + case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: + case ConnectivityDataLoaded::MODE_VOXEL_XYZ: + { + int mappingDataParcelIndex(-1); + const CiftiParcelsMap& mappingMap = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); + if (mappingMap.getSurfaceNumberOfNodes(structure) == numberOfNodes) { + const std::vector& mappingParcels = mappingMap.getParcels(); + mappingDataParcelIndex = mappingMap.getIndexForNode(nodeIndex, + structure); + if ((mappingDataParcelIndex >= 0) + && (mappingDataParcelIndex < static_cast(mappingParcels.size()))) { + textValueOut = mappingParcels[mappingDataParcelIndex].m_name; + + std::vector dataLoaded; + matrixFile->getMapData(0, dataLoaded); + if ((mappingDataParcelIndex >= 0) + && (mappingDataParcelIndex < static_cast(dataLoaded.size()))) { + textValueOut += (" " + AString::number(dataLoaded[mappingDataParcelIndex])); + return true; + } + } + } + + } + break; + } + } + + int64_t mappingDataParcelIndex = -1; + if (readingDataParcelIndex >= 0) { + /* + * Only get parcel name if there is a row for reading + */ + const CiftiParcelsMap& mappingMap = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); + if (mappingMap.getSurfaceNumberOfNodes(structure) == numberOfNodes) { + const std::vector& mappingParcels = mappingMap.getParcels(); + mappingDataParcelIndex = mappingMap.getIndexForNode(nodeIndex, + structure); + if ((mappingDataParcelIndex >= 0) + && (mappingDataParcelIndex < static_cast(mappingParcels.size()))) { + textValueOut = mappingParcels[mappingDataParcelIndex].m_name; + } } } for (std::vector::const_iterator mapIter = mapIndices.begin(); mapIter != mapIndices.end(); mapIter++) { - const int32_t mapIndex = *mapIter; - - if (parcelIndex >= 0) { - int64_t itemIndex = -1; - switch (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML)) { - case CiftiMappingType::BRAIN_MODELS: + if ((mappingDataParcelIndex >= 0) + && (readingDataParcelIndex >= 0)) { + const int64_t numRows = m_ciftiFile->getNumberOfRows(); + const int64_t numCols = m_ciftiFile->getNumberOfColumns(); + + switch (m_dataReadingDirectionForCiftiXML) { + case CiftiXML::ALONG_COLUMN: { - const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataReadingDirectionForCiftiXML); - if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { - itemIndex = map.getIndexForNode(nodeIndex, - structure); - } + std::vector data; + data.resize(numCols); + CaretAssert(readingDataParcelIndex < numRows); + m_ciftiFile->getRow(&data[0], readingDataParcelIndex); + CaretAssertVectorIndex(data, mappingDataParcelIndex); + textValueOut += (" " + AString::number(data[mappingDataParcelIndex])); } break; - case CiftiMappingType::LABELS: - break; - case CiftiMappingType::PARCELS: - itemIndex = mapIndex; - break; - case CiftiMappingType::SCALARS: - itemIndex = mapIndex; - break; - case CiftiMappingType::SERIES: - itemIndex = mapIndex; - break; - } - if (itemIndex >= 0) { - const int64_t numRows = m_ciftiFile->getNumberOfRows(); - const int64_t numCols = m_ciftiFile->getNumberOfColumns(); - - switch (m_dataReadingDirectionForCiftiXML) { - case CiftiXML::ALONG_COLUMN: - { - std::vector data; - data.resize(numRows); - CaretAssert(parcelIndex < numCols); - m_ciftiFile->getColumn(&data[0], parcelIndex); - CaretAssertVectorIndex(data, itemIndex); - textValueOut += (" " + AString::number(data[itemIndex])); - } - break; - case CiftiXML::ALONG_ROW: - { - std::vector data; - data.resize(numCols); - CaretAssert(parcelIndex < numRows); - m_ciftiFile->getRow(&data[0], parcelIndex); - CaretAssertVectorIndex(data, itemIndex); - textValueOut += (" " + AString::number(data[itemIndex])); - } - break; + case CiftiXML::ALONG_ROW: + { + std::vector data; + data.resize(numRows); + CaretAssert(readingDataParcelIndex < numCols); + m_ciftiFile->getColumn(&data[0], readingDataParcelIndex); + CaretAssertVectorIndex(data, mappingDataParcelIndex); + textValueOut += (" " + AString::number(data[mappingDataParcelIndex])); } - + break; } } } @@ -4638,6 +4823,9 @@ CiftiMappableDataFile::getSurfaceNodeIdentificationForMaps(const std::vector(mapIndices.size()); @@ -5081,7 +5272,7 @@ CiftiMappableDataFile::getMapVolumeVoxelValue(const int32_t mapIndex, ijkOut[0] = ijk[0]; ijkOut[1] = ijk[1]; ijkOut[2] = ijk[2]; - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(ijk[0], + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); if (dataOffset >= 0) { @@ -5294,7 +5485,7 @@ CiftiMappableDataFile::getMapVolumeVoxelValues(const std::vector mapInd ijkOut[0] = ijk[0]; ijkOut[1] = ijk[1]; ijkOut[2] = ijk[2]; - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(ijk[0], + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); if (dataOffset >= 0) { @@ -5546,7 +5737,7 @@ CiftiMappableDataFile::getVoxelValue(const float coordinateX, voxelK, mapIndex, component)) { - const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(voxelI, + const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(voxelI, voxelJ, voxelK); if (dataOffset >= 0) { @@ -5600,7 +5791,7 @@ CiftiMappableDataFile::getMapDataOffsetForVoxelAtCoordinate(const float coordina voxelK, mapIndex, 0)) { - dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(voxelI, + dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(voxelI, voxelJ, voxelK); } diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index e75f13a0daddbab5144765b3b4defa8ed1c046ee..2fcbe0f4e253c95fc3d8d0fb993f9daa3f5dc3b3 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -261,6 +261,14 @@ namespace caret { virtual void getDimensions(std::vector& dimsOut) const override; + virtual void getDimensionsForDataLoading(int64_t& dimOut1, + int64_t& dimOut2, + int64_t& dimOut3, + int64_t& dimTimeOut, + int64_t& numComponents) const; + + virtual void getDimensionsForDataLoading(std::vector& dimsOut) const; + virtual void getMapDimensions(std::vector &dim) const; virtual const int64_t& getNumberOfComponents() const override; @@ -287,12 +295,25 @@ namespace caret { int64_t& indexOut2, int64_t& indexOut3) const override; + virtual void enclosingVoxelForDataLoading(const float& coordIn1, + const float& coordIn2, + const float& coordIn3, + int64_t& indexOut1, + int64_t& indexOut2, + int64_t& indexOut3) const; + virtual bool indexValid(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) const override; + virtual bool indexValidForDataLoading(const int64_t& indexIn1, + const int64_t& indexIn2, + const int64_t& indexIn3, + const int64_t brickIndex = 0, + const int64_t component = 0) const; + virtual const VolumeSpace& getVolumeSpace() const; virtual void getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) const override; @@ -401,7 +422,7 @@ namespace caret { const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, - AString& textOut) const; + AString& textOut) const override; int32_t getMappingSurfaceNumberOfNodes(const StructureEnum::Enum structure) const; @@ -777,7 +798,8 @@ namespace caret { bool m_fileHistogramLimitedValuesIncludeZeroValues; /** Fast conversion of IJK to data offset */ - CaretPointer m_voxelIndicesToOffset; + CaretPointer m_voxelIndicesToOffsetForDataMapping; + CaretPointer m_voxelIndicesToOffsetForDataReading; /** Holds class and name hierarchy used for display selection */ mutable CaretPointer m_classNameHierarchy; diff --git a/src/Files/FilePathNamePrefixCompactor.cxx b/src/Files/FilePathNamePrefixCompactor.cxx index d1b225c33c9eb518d86127fe2e0612f9654294cb..3fe874e7dc7fbbfcbcf1ab37cd6c640a4a6d0b12 100644 --- a/src/Files/FilePathNamePrefixCompactor.cxx +++ b/src/Files/FilePathNamePrefixCompactor.cxx @@ -102,18 +102,6 @@ FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(const st } removeMatchingPathPrefixFromCaretDataFiles(caretDataFiles, prefixRemovedNamesOut); - -// std::vector fileNames; -// for (std::vector::const_iterator iter = caretMappableDataFiles.begin(); -// iter != caretMappableDataFiles.end(); -// iter++) { -// const CaretDataFile* cdf = *iter; -// CaretAssert(cdf); -// fileNames.push_back(cdf->getFileName()); -// } -// -// removeMatchingPathPrefixFromFileNames(fileNames, -// prefixRemovedNamesOut); } /** @@ -137,6 +125,7 @@ void FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(const std::vector& caretDataFiles, std::vector& prefixRemovedNamesOut) { + std::vector filePathNames; std::vector fileNames; std::vector specialPrefixes; for (std::vector::const_iterator iter = caretDataFiles.begin(); @@ -145,21 +134,156 @@ FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(const st CaretDataFile* cdf = *iter; CaretAssert(cdf); - if (cdf->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { -// CiftiConnectivityMatrixDenseDynamicFile* denseDynFile = dynamic_cast(cdf); -// cdf = denseDynFile->getParentBrainordinateDataSeriesFile(); - specialPrefixes.push_back("dynconn - "); - } - else { - specialPrefixes.push_back(""); - } + AString fileSpecialPrefix; - fileNames.push_back(cdf->getFileName()); + switch (cdf->getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + fileSpecialPrefix = "dynconn - "; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + fileSpecialPrefix = "metricdynconn - "; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + fileSpecialPrefix = "voldynconn - "; + break; + } + specialPrefixes.push_back(fileSpecialPrefix); + + filePathNames.push_back(cdf->getFileName()); + fileNames.push_back(cdf->getFileNameNoPath()); } - removeMatchingPathPrefixFromFileNames(fileNames, - prefixRemovedNamesOut); + CaretAssert(filePathNames.size() == fileNames.size()); + CaretAssert(filePathNames.size() == specialPrefixes.size()); + const bool onlyFilesWithMatchingFileNamesFlag(true); + if (onlyFilesWithMatchingFileNamesFlag) { + const int32_t numFiles = static_cast(filePathNames.size()); + std::vector cleanedFlag(numFiles, false); + + /* + * Initialize output to just file names (no paths) + */ + prefixRemovedNamesOut = fileNames; + + for (int32_t i = 0; i < (numFiles - 1); i++) { + CaretAssertVectorIndex(cleanedFlag, i); + if (cleanedFlag[i]) { + continue; + } + + CaretAssertVectorIndex(fileNames, i); + const AString& name = fileNames[i]; + + std::vector duplicateFileIndices; + std::vector duplicateNameFiles; + duplicateFileIndices.push_back(i); + CaretAssertVectorIndex(filePathNames, i); + duplicateNameFiles.push_back(filePathNames[i]); + + /* + * Find files with same name (excluding path) + */ + for (int32_t j = i + 1; j < numFiles; j++) { + CaretAssertVectorIndex(cleanedFlag, j); + if (cleanedFlag[j]) { + continue; + } + + CaretAssertVectorIndex(fileNames, j); + if (name == fileNames[j]) { + duplicateFileIndices.push_back(j); + CaretAssertVectorIndex(filePathNames, j); + duplicateNameFiles.push_back(filePathNames[j]); + } + } + + /* + * If multiple files with same same, remove the matching paths + */ + std::vector cleanedFileNames; + if (duplicateNameFiles.size() > 1) { + removeMatchingPathPrefixFromFileNames(duplicateNameFiles, + cleanedFileNames); + + /* + * Update the name with prefix removed for output + */ + CaretAssert(duplicateFileIndices.size() == cleanedFileNames.size()); + const int32_t numCleanedFiles = static_cast(cleanedFileNames.size()); + for (int32_t m = 0; m < numCleanedFiles; m++) { + CaretAssertVectorIndex(duplicateFileIndices, m); + const int32_t indx = duplicateFileIndices[m]; + CaretAssertVectorIndex(cleanedFileNames, m); + prefixRemovedNamesOut[indx] = cleanedFileNames[m]; + CaretAssertVectorIndex(cleanedFlag, indx); + cleanedFlag[indx] = true; + } + } + } + } + else { + /* + * Running this will operate on all files as if all of the them have the same file name + */ + removeMatchingPathPrefixFromFileNames(filePathNames, + prefixRemovedNamesOut); + } + const int32_t numFiles = static_cast(prefixRemovedNamesOut.size()); CaretAssert(numFiles == static_cast(specialPrefixes.size())); for (int32_t i = 0; i < numFiles; i++) { @@ -167,39 +291,6 @@ FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(const st } } -/** - * Create names that show the filename followed by the path BUT remove - * any matching prefix from the paths for a group of CaretDataFiles. - * - * Example Input File Name: - * /mnt/myelin/data/subject2/rsfmri/activity.dscalar.nii - * /mnt/myelin/data/subject1/rsfmri/activity.dscalar.nii - * Output: - * actitivity.dscalar.nii (../subject2/rsfmri) - * actitivity.dscalar.nii (../subject1/rsfmri) - * - * @param caretDataFiles - * The caret data files from which names are obtained. - * @param prefixRemovedNamesOut - * Names of files with matching prefixes removed. Number of elements - * will match the number of elements in caretDataFiles. - */ -void -FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFile(const CaretDataFile* caretDataFile, - AString& prefixRemovedNameOut) -{ - std::vector nameVector; - nameVector.push_back(caretDataFile->getFileName()); - - std::vector prefixVector; - removeMatchingPathPrefixFromFileNames(nameVector, - prefixVector); - - CaretAssert(nameVector.size() == prefixVector.size()); - CaretAssert(prefixVector.size() == 1); - prefixRemovedNameOut = prefixVector[0]; -} - /** * Create names that show the filename followed by the path BUT remove * any matching prefix from the paths for a group of file names. diff --git a/src/Files/FilePathNamePrefixCompactor.h b/src/Files/FilePathNamePrefixCompactor.h index 2f8814e7b2684424d1d3b5c9c8512523a4197b2a..7c0ee16c12d47ee7fe3a1a6a8a9f19540de2f917 100644 --- a/src/Files/FilePathNamePrefixCompactor.h +++ b/src/Files/FilePathNamePrefixCompactor.h @@ -37,10 +37,7 @@ namespace caret { static void removeMatchingPathPrefixFromCaretDataFiles(const std::vector& caretDataFiles, std::vector& prefixRemovedNamesOut); - - static void removeMatchingPathPrefixFromCaretDataFile(const CaretDataFile* caretDataFile, - AString& prefixRemovedNameOut); - + private: FilePathNamePrefixCompactor(); diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index 67e9b15f2a8e187b6c04607b918777e13cf88f82..6de85ed84a8b49f8924f0b3cb80c4313f388dbe4 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -24,10 +24,15 @@ #include "FastStatistics.h" #include "GiftiDataArray.h" #include "GiftiFile.h" +#include "GiftiLabel.h" +#include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "GiftiTypeFile.h" #include "GiftiMetaDataXmlElements.h" #include "Histogram.h" +#include "LabelFile.h" +#include "MapFileDataSelector.h" +#include "MetricFile.h" #include "PaletteColorMapping.h" #include "PaletteColorMappingSaxReader.h" #include "SurfaceFile.h" @@ -809,10 +814,74 @@ GiftiTypeFile::getFileHistogram(const float mostPositiveValueInclusive, bool GiftiTypeFile::isMappedWithPalette() const { - if (this->getDataFileType() == DataFileTypeEnum::METRIC) { - return true; + bool paletteFlag(false); + + switch (getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + paletteFlag = true; + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + paletteFlag = true; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } - return false; + + return paletteFlag; } /** @@ -829,9 +898,70 @@ GiftiTypeFile::getPaletteNormalizationModesSupported(std::vector= 0) + && (mapIndex < getNumberOfMaps())) { + this->giftiFile->getDataArray(mapIndex)->invalidateHistograms(); + } } /** @@ -992,10 +1126,85 @@ GiftiTypeFile::addToDataFileContentInformation(DataFileContentInformation& dataF * Output with data. Will be empty if data does not support the map file data selector. */ void -GiftiTypeFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, +GiftiTypeFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const { dataOut.clear(); + + switch (mapFileDataSelector.getDataSelectionType()) { + case MapFileDataSelector::DataSelectionType::INVALID: + case MapFileDataSelector::DataSelectionType::COLUMN_DATA: + case MapFileDataSelector::DataSelectionType::ROW_DATA: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t numberOfNodes(-1); + int32_t nodeIndex(-1); + mapFileDataSelector.getSurfaceVertex(structure, numberOfNodes, nodeIndex); + if ((getStructure() == structure) + && (getNumberOfNodes() == numberOfNodes)) { + const int32_t numberOfMaps = getNumberOfMaps(); + if (isMappedWithLabelTable()) { + const LabelFile* lf = dynamic_cast(this); + CaretAssert(lf); + for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { + const int32_t key = lf->getLabelKey(nodeIndex, + mapIndex); + dataOut.push_back(key); + } + } + if (isMappedWithPalette()) { + const MetricFile* mf = dynamic_cast(this); + CaretAssert(mf); + for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { + const float value = mf->getValue(nodeIndex, + mapIndex); + dataOut.push_back(value); + } + } + } + } + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t numberOfNodes(-1); + std::vector nodeIndices; + mapFileDataSelector.getSurfaceVertexAverage(structure, numberOfNodes, nodeIndices); + if ((getStructure() == structure) + && (getNumberOfNodes() == numberOfNodes)) { + if (isMappedWithPalette()) { + const MetricFile* mf = dynamic_cast(this); + CaretAssert(mf); + const int32_t numberOfNodeIndices = static_cast(nodeIndices.size()); + if (numberOfNodeIndices > 0) { + const int32_t numberOfMaps = getNumberOfMaps(); + if (numberOfMaps > 0) { + for (int32_t iNode = 0; iNode < numberOfNodeIndices; iNode++) { + CaretAssertVectorIndex(nodeIndices, iNode); + const int32_t nodeIndex = nodeIndices[iNode]; + + float sum(0.0f); + for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { + const float value = mf->getValue(nodeIndex, + mapIndex); + sum += value; + } + + const float value = sum / numberOfMaps; + dataOut.push_back(value); + } + } + + } + } + } + } + break; + case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + break; + } } /** @@ -1058,6 +1267,9 @@ GiftiTypeFile::getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile case DataFileTypeEnum::METRIC: giftiFlag = true; break; + case DataFileTypeEnum::METRIC_DYNAMIC: + giftiFlag = true; + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -1074,6 +1286,8 @@ GiftiTypeFile::getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } if (giftiFlag) { @@ -1088,4 +1302,132 @@ GiftiTypeFile::getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile return BrainordinateMappingMatch::NO; } +/** + * Get the identification information for a surface node in the given maps. + * + * @param mapIndices + * Indices of maps for which identification information is requested. + * @param structure + * Structure of the surface. + * @param nodeIndex + * Index of the node. + * @param numberOfNodes + * Number of nodes in the surface. + * @param textOut + * Output containing identification information. + */ +bool +GiftiTypeFile::getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, + const StructureEnum::Enum structure, + const int nodeIndex, + const int32_t numberOfNodes, + AString& textOut) const +{ + textOut.clear(); + + if ((getStructure() == structure) + && (getNumberOfNodes() == numberOfNodes)) { + switch (getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + { + const LabelFile* lf = dynamic_cast(this); + CaretAssert(lf); + const GiftiLabelTable* labelTable = lf->getLabelTable(); + AString valuesText; + for (const auto mapIndex : mapIndices) { + const int32_t key = lf->getLabelKey(nodeIndex, + mapIndex); + if (key >= 0) { + if ( ! valuesText.isEmpty()) { + valuesText.append(", "); + } + valuesText.append(labelTable->getLabel(key)->getName()); + } + } + + if ( ! valuesText.isEmpty()) { + textOut = valuesText; + } + } + break; + case DataFileTypeEnum::METRIC: + case DataFileTypeEnum::METRIC_DYNAMIC: // subclass of METRIC + { + const MetricFile* mf = dynamic_cast(this); + CaretAssert(mf); + AString valuesText; + for (const auto mapIndex : mapIndices) { + const float value = mf->getValue(nodeIndex, + mapIndex); + if ( ! valuesText.isEmpty()) { + valuesText.append(", "); + } + valuesText.append(AString::number(value, 'f', 3)); + } + + if ( ! valuesText.isEmpty()) { + textOut = valuesText; + } + } + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; + } + } + + return ( ! textOut.isEmpty()); +} + diff --git a/src/Files/GiftiTypeFile.h b/src/Files/GiftiTypeFile.h index aef32ce515b688b6d7e486fef1113ae1c7714cb6..b534902e4ce30c000684f946d3ef7ea359b0340d 100644 --- a/src/Files/GiftiTypeFile.h +++ b/src/Files/GiftiTypeFile.h @@ -170,6 +170,12 @@ namespace caret { virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const override; + virtual bool getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, + const StructureEnum::Enum structure, + const int nodeIndex, + const int32_t numberOfNodes, + AString& textOut) const; + private: void copyHelperGiftiTypeFile(const GiftiTypeFile& gtf); diff --git a/src/Files/ImageCaptureSettings.cxx b/src/Files/ImageCaptureSettings.cxx index c1c71a0a6066df44330c6305a4849b21066ddcea..fab933ec4e772507104f649e6e738c850f5030cf 100644 --- a/src/Files/ImageCaptureSettings.cxx +++ b/src/Files/ImageCaptureSettings.cxx @@ -65,6 +65,14 @@ SceneableInterface() setPixelWidthAndHeight(512, 512); + /* WB-868 Defautl Custom, 300 DPI, 7.5 inches width, copy to clipboard OFF, save to file ON, no file name*/ + m_dimensionsMode = ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM; + setImageResolutionInSelectedUnits(300.0); + setSpatialWidth(7.5); + m_saveToFileEnabled = true; + m_copyToClipboardEnabled = false; + m_imageFileName = ""; + m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_pixelWidth", diff --git a/src/Files/ImageFile.cxx b/src/Files/ImageFile.cxx index 45261135afc7c91321586606893e69ffc9d0cfe5..3e4932082fb6c088f028709c84eadcb67e5cfd58 100644 --- a/src/Files/ImageFile.cxx +++ b/src/Files/ImageFile.cxx @@ -775,6 +775,99 @@ ImageFile::insertImage(const QImage& insertThisImage, } } +/** + * Scale the given image to the given width and height while preserving + * the aspect ratio. If the + * + * @param image + * The image + * @param width + * Width of the image + * @param height + * Height of the image + * @param fillColor + * If not NULL, padded region is this color + * @return + * Image that will be the requested width and height or + * a null image (.isNull()) if error. + */ +QImage +ImageFile::scaleToSizeWithPadding(const QImage& image, + const int width, + const int height, + const QColor* fillColor) +{ + /* + * Invalid image tests + */ + if (image.isNull()) { + return image; + } + if ((image.width() <= 0) + || (image.height() <= 0)) { + return QImage(); + } + + /* + * Nothing to do if image is correct size + */ + if ((image.width() == width) + && (image.height() == height)) { + return image; + } + + const QImage scaledImage = image.scaled(width, + height, + Qt::KeepAspectRatio, + Qt::SmoothTransformation); + const int scaledWidth = scaledImage.width(); + const int scaledHeight = scaledImage.height(); + if ((scaledWidth == width) + && (scaledHeight == height)) { + return scaledImage; + } + else if (scaledWidth > width) { + CaretLogSevere("Image scale width was made larger=" + + QString::number(scaledWidth) + + " than requested=" + + QString::number(width)); + return QImage(); + } + else if (scaledHeight > height) { + CaretLogSevere("Image scale height was made larger=" + + QString::number(scaledHeight) + + " than requested=" + + QString::number(height)); + return QImage(); + } + + QImage outputImage(width, + height, + image.format()); + if (fillColor != NULL) { + outputImage.fill(*fillColor); + } + else { + outputImage.fill(Qt::black); + } + + const int insertX = (width - scaledWidth) / 2; + const int insertY = (height - scaledHeight) / 2; + + try { + ImageFile::insertImage(scaledImage, + outputImage, + insertX, + insertY); + } + catch (const DataFileException& dfe) { + CaretLogSevere(dfe.whatString()); + outputImage = QImage(); + } + + return outputImage; +} + /** * Compare a file for unit testing (tolerance ignored). * diff --git a/src/Files/ImageFile.h b/src/Files/ImageFile.h index fd64cf4caa40dc36b9dac5fe6518f398612a0177..0a833d541b682b792fc927e5373ddd43c5b95b5a 100644 --- a/src/Files/ImageFile.h +++ b/src/Files/ImageFile.h @@ -24,6 +24,7 @@ #include "CaretDataFile.h" #include "CaretPointer.h" +class QColor; class QImage; namespace caret { @@ -196,6 +197,11 @@ public: static void getImageFileFilters(std::vector& imageFileFilters, AString& defaultFilter); + static QImage scaleToSizeWithPadding(const QImage& image, + const int width, + const int height, + const QColor* fillColor = NULL); + VolumeFile* convertToVolumeFile(const CONVERT_TO_VOLUME_COLOR_MODE colorMode, AString& errorMessageOut) const; diff --git a/src/Files/MetricDynamicConnectivityFile.cxx b/src/Files/MetricDynamicConnectivityFile.cxx new file mode 100644 index 0000000000000000000000000000000000000000..050eb5b07132de4fd7421b73d99bd1a520d7d11b --- /dev/null +++ b/src/Files/MetricDynamicConnectivityFile.cxx @@ -0,0 +1,683 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ +#include "MetricDynamicConnectivityFile.h" +#undef __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "ConnectivityCorrelation.h" +#include "ConnectivityDataLoaded.h" +#include "DataFileException.h" +#include "FileInformation.h" +#include "SceneClassAssistant.h" +using namespace caret; + + + +/** + * \class caret::MetricDynamicConnectivityFile + * \brief Dynamic connectivity from metric file + * \ingroup Files + */ + +/** + * Constructor. + * @param parentMetricFile + * The parent metric file. + */ +MetricDynamicConnectivityFile::MetricDynamicConnectivityFile(MetricFile* parentMetricFile) +: MetricFile(DataFileTypeEnum::METRIC_DYNAMIC), +m_parentMetricFile(parentMetricFile) +{ + CaretAssert(m_parentMetricFile); + + m_connectivityDataLoaded.reset(new ConnectivityDataLoaded()); + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_dataLoadingEnabledFlag", + &m_dataLoadingEnabledFlag); + m_sceneAssistant->add("m_enabledAsLayer", + &m_enabledAsLayer); + m_sceneAssistant->add("m_connectivityDataLoaded", + "ConnectivityDataLoaded", + m_connectivityDataLoaded.get()); +} + +/** + * Destructor. + */ +MetricDynamicConnectivityFile::~MetricDynamicConnectivityFile() +{ +} + +/** + * Clear the file. + */ +void +MetricDynamicConnectivityFile::clear() +{ + MetricFile::clear(); + clearPrivateData(); +} + +/** + * Clear the file. + */ +void +MetricDynamicConnectivityFile::clearPrivateData() +{ + m_numberOfVertices = 0; + m_validDataFlag = false; + m_enabledAsLayer = false; + m_connectivityCorrelation.reset(); + m_connectivityDataLoaded->reset(); +} + +/** + * @return Pointer to the information about last loaded connectivity data. + */ +const ConnectivityDataLoaded* +MetricDynamicConnectivityFile::getConnectivityDataLoaded() const +{ + return m_connectivityDataLoaded.get(); +} + +/** + * @return True if enabled as a layer. + */ +bool +MetricDynamicConnectivityFile::isEnabledAsLayer() const +{ + return m_enabledAsLayer; +} + +/** + * Set enabled as a layer. + * + * @param True if enabled as a layer. + */ +void +MetricDynamicConnectivityFile::setEnabledAsLayer(const bool enabled) +{ + m_enabledAsLayer = enabled; +} + +/** + * @return True if data loading enabled. + */ +bool +MetricDynamicConnectivityFile::isDataLoadingEnabled() const +{ + return m_dataLoadingEnabledFlag; +} + +/** + * Set data loading enabled. + * + * @param True if data loading enabled. + */ +void +MetricDynamicConnectivityFile::setDataLoadingEnabled(const bool enabled) +{ + m_dataLoadingEnabledFlag = enabled; +} + +/** + * Initialize the file using information from parent volume file + */ +void +MetricDynamicConnectivityFile::initializeFile() +{ + clearPrivateData(); + + CaretAssert(m_parentMetricFile); + m_numberOfVertices = m_parentMetricFile->getNumberOfNodes(); + const int32_t numberOfMaps = 1; + setNumberOfNodesAndColumns(m_numberOfVertices, + numberOfMaps); + setStructure(m_parentMetricFile->getStructure()); + + CaretAssert(getNumberOfNodes() == m_numberOfVertices); + CaretAssert(getNumberOfMaps() == numberOfMaps); + + AString path, nameNoExt, ext; + FileInformation fileInfo(m_parentMetricFile->getFileName()); + fileInfo.getFileComponents(path, nameNoExt, ext); + setFileName(FileInformation::assembleFileComponents(path, + nameNoExt, + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::METRIC_DYNAMIC))); + clearVertexValues(); + clearModified(); + + m_validDataFlag = true; +} + +/** + * @return True if this file type supports writing, else false. + * + * Dense files do NOT support writing. + */ +bool +MetricDynamicConnectivityFile::supportsWriting() const +{ + return false; +} + +/** + * @return The parent volume file + */ +MetricFile* +MetricDynamicConnectivityFile::getParentMetricFile() +{ + return const_cast(m_parentMetricFile); +} + +/** + * @return The parent metric file (const method) + */ +const MetricFile* +MetricDynamicConnectivityFile::getParentMetricFile() const +{ + return m_parentMetricFile; +} + +/** + * @return True if the data is valid + */ +bool +MetricDynamicConnectivityFile::isDataValid() const +{ + return m_validDataFlag; +} + +/** + * Add information about the file to the data file information. + * + * @param dataFileInformation + * Consolidates information about a data file. + */ +void +MetricDynamicConnectivityFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) +{ + MetricFile::addToDataFileContentInformation(dataFileInformation); +} + +/** + * Read the file with the given name. + * + * @param filename + * Name of file + * @throws DataFileException + * If error occurs + */ +void +MetricDynamicConnectivityFile::readFile(const AString& /*filename*/) +{ + throw DataFileException("Read of Metric Dynamic Connectivity File is not allowed"); +} + +/** + * Read the file with the given name. + * + * @param filename + * Name of file + * @throws DataFileException + * If error occurs + */ +void +MetricDynamicConnectivityFile::writeFile(const AString& /*filename*/) +{ + throw DataFileException("Writing of Metric Dynamic Connectivity File is not allowed"); +} + +/** + * Clear voxels in this volume + */ +void +MetricDynamicConnectivityFile::clearVertexValues() +{ + CaretAssert(getNumberOfMaps() == 1); + const int32_t mapIndex(0); + const float value(0.0f); + initializeColumn(mapIndex, + value); + m_dataLoadedName = ""; +} + +/** + * Load connectivity data for the surface's node. + * + * @param surfaceNumberOfNodes + * Number of nodes in surface. + * @param structure + * Surface's structure. + * @param nodeIndex + * Index of node number. + * @return + * True if data was loaded, else false. + */ +bool +MetricDynamicConnectivityFile::loadDataForSurfaceNode(const int32_t surfaceNumberOfNodes, + const StructureEnum::Enum structure, + const int32_t nodeIndex) +{ + bool validFlag(false); + + if ( ! isDataValid()) { + return validFlag; + } + if ( ! m_dataLoadingEnabledFlag) { + return validFlag; + } + if (getStructure() != structure) { + return validFlag; + } + if (getNumberOfNodes() != surfaceNumberOfNodes) { + return validFlag; + } + + clearVertexValues(); + m_connectivityDataLoaded->reset(); + + std::vector data; + if (getConnectivityForVertexIndex(nodeIndex, data)) { + CaretAssert(m_numberOfVertices == static_cast(data.size())); + float* dataPointer = const_cast(getValuePointerForColumn(0)); + CaretAssert(dataPointer); + std::copy(data.begin(), + data.end(), + dataPointer); + + validFlag = true; + + m_connectivityDataLoaded->setSurfaceNodeLoading(getStructure(), + getNumberOfNodes(), + nodeIndex, + -1, - + 1); + } + + const int32_t mapIndex(0); + const AString mapName("Vertex_Index_" + + AString::number(nodeIndex) + + "_Structure_" + + StructureEnum::toGuiName(structure)); + setMapName(mapIndex, + mapName); + m_dataLoadedName = mapName; + + updateAfterFileDataChanges(); + updateScalarColoringForMap(0); + + return validFlag; +} + + + +/** + * Load connectivity data for the surface's nodes and then average the data. + * + * @param surfaceNumberOfNodes + * Number of nodes in surface. + * @param structure + * Surface's structure. + * @param nodeIndices + * Indices of nodes. + * @return + * True if data was loaded, else false. + */ +bool +MetricDynamicConnectivityFile::loadAverageDataForSurfaceNodes(const int32_t surfaceNumberOfNodes, + const StructureEnum::Enum structure, + const std::vector& nodeIndices) +{ + bool validFlag(false); + + if ( ! isDataValid()) { + return validFlag; + } + if ( ! m_dataLoadingEnabledFlag) { + return validFlag; + } + if (getStructure() != structure) { + return validFlag; + } + if (getNumberOfNodes() != surfaceNumberOfNodes) { + return validFlag; + } + if (nodeIndices.size() < 2) { + return validFlag; + } + + ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); + if (connCorrelation == NULL) { + return validFlag; + } + + clearVertexValues(); + m_connectivityDataLoaded->reset(); + + float* dataPointer = const_cast(getValuePointerForColumn(0)); + CaretAssert(dataPointer); + + std::vector nodeIndices64(nodeIndices.begin(), nodeIndices.end()); + std::vector data(getNumberOfNodes()); + connCorrelation->getCorrelationForBrainordinateROI(nodeIndices64, + data); + const int64_t numData = static_cast(data.size()); + validFlag = (numData == getNumberOfNodes()); + if (validFlag) { + for (int64_t i = 0; i < numData; i++) { + dataPointer[i] = data[i]; + } + } + + + m_connectivityDataLoaded->setSurfaceAverageNodeLoading(getStructure(), + getNumberOfNodes(), + nodeIndices); + + const AString mapName("Average_Vertex_Count_" + + AString::number(static_cast(nodeIndices.size()))); + m_dataLoadedName = mapName; + const int32_t mapIndex(0); + setMapName(mapIndex, + mapName); + + updateAfterFileDataChanges(); + updateScalarColoringForMap(0); + + return validFlag; +} + +/** + * Get the connectivity for the given vertex index. + * If the vertex index is invalid, zeros are loaded into all voxels. + * + * @param vertexIndex + * The vertex index. + * @param vertexDataOut + * Output containing vertex data + * @return + * True if data was loaded. + */ +bool +MetricDynamicConnectivityFile::getConnectivityForVertexIndex(const int32_t vertexIndex, + std::vector& vertexDataOut) +{ + bool validFlag(false); + if ((vertexIndex >= 0) + && (vertexIndex < getNumberOfNodes())) { + ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); + + if (connCorrelation) { + connCorrelation->getCorrelationForBrainordinate(vertexIndex, + vertexDataOut); + CaretAssert(m_numberOfVertices == static_cast(vertexDataOut.size())); + validFlag = true; + } + } + + if ( ! validFlag) { + vertexDataOut.resize(m_numberOfVertices); + std::fill(vertexDataOut.begin(), vertexDataOut.end(), + 0.0f); + } + + updateAfterFileDataChanges(); + invalidateHistogramChartColoring(); + + return validFlag; +} + +/** + * @return Pointer to connectivity correlation or NULL if not valid + */ +ConnectivityCorrelation* +MetricDynamicConnectivityFile::getConnectivityCorrelation() +{ + if ( ! m_connectivityCorrelationFailedFlag) { + if (m_connectivityCorrelation == NULL) { + /* + * Need data and timepoint count from parent file + */ + CaretAssert(m_parentMetricFile); + const int32_t numberOfTimePoints = m_parentMetricFile->getNumberOfMaps(); + CaretAssert(numberOfTimePoints >= 2); + std::vector timePointData; + for (int32_t i = 0; i < numberOfTimePoints; i++) { + const float* dataPtr = m_parentMetricFile->getValuePointerForColumn(i); + CaretAssert(dataPtr); + timePointData.push_back(dataPtr); + } + const int64_t brainordinateStride(1); + AString errorMessage; + ConnectivityCorrelation* cc = ConnectivityCorrelation::newInstanceTimePoints(timePointData, + m_numberOfVertices, + brainordinateStride, + errorMessage); + if (cc != NULL) { + m_connectivityCorrelation.reset(cc); + } + else { + m_connectivityCorrelationFailedFlag = true; + CaretLogSevere("Failed to create connectvity correlation for " + + m_parentMetricFile->getFileNameNoPath()); + } + } + } + + return m_connectivityCorrelation.get(); +} + +/** + * @return A metric file using the loaded data (will return NULL if there is an error). + * + * @param directoryName + * Directory for file + * @param errorMessageOut + * Contains error information + */ +MetricFile* +MetricDynamicConnectivityFile::newMetricFileFromLoadedData(const AString& directoryName, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + bool validDataFlag(false); + switch (m_connectivityDataLoaded->getMode()) { + case ConnectivityDataLoaded::MODE_COLUMN: + break; + case ConnectivityDataLoaded::MODE_NONE: + break; + case ConnectivityDataLoaded::MODE_ROW: + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE: + validDataFlag = true; + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: + validDataFlag = true; + break; + case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: + break; + case ConnectivityDataLoaded::MODE_VOXEL_XYZ: + break; + } + + if ( ! validDataFlag) { + errorMessageOut = "No metric connectivity data is loaded"; + return NULL; + } + + MetricFile* mf(NULL); + + try { + const int32_t numVertices = getNumberOfNodes(); + mf = new MetricFile(); + mf->setStructure(getStructure()); + mf->setNumberOfNodesAndColumns(numVertices, + 1); + mf->setValuesForColumn(0, this->getValuePointerForColumn(0)); + + /* + * May need to convert a remote path to a local path + */ + FileInformation fileNameInfo(getFileName()); + const AString metricFileName = fileNameInfo.getAsLocalAbsoluteFilePath(directoryName, + mf->getDataFileType()); + + /* + * Create name of metric file data loaded information + */ + FileInformation metricFileInfo(metricFileName); + AString thePath, theName, theExtension; + metricFileInfo.getFileComponents(thePath, + theName, + theExtension); + theName.append("_" + m_dataLoadedName); + AString newFileName = FileInformation::assembleFileComponents(thePath, + theName, + theExtension); + mf->setFileName(newFileName); + mf->setMapName(0, m_dataLoadedName); + + /* + * Need to copy color palette since it may be the default + */ + PaletteColorMapping* metricPalette = mf->getMapPaletteColorMapping(0); + CaretAssert(metricPalette); + const PaletteColorMapping* myPalette = getMapPaletteColorMapping(0); + CaretAssert(myPalette); + metricPalette->copy(*myPalette, + true); + + mf->updateAfterFileDataChanges(); + mf->updateScalarColoringForMap(0); + mf->setModified(); + } + catch (const DataFileException& dfe) { + errorMessageOut = dfe.whatString(); + if (mf != NULL) { + delete mf; + mf = NULL; + } + } + + return mf; +} + + +/** + * Save data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +MetricDynamicConnectivityFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + MetricFile::saveFileDataToScene(sceneAttributes, + sceneClass); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +MetricDynamicConnectivityFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + m_connectivityDataLoaded->reset(); + + MetricFile::restoreFileDataFromScene(sceneAttributes, + sceneClass); + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + + switch (m_connectivityDataLoaded->getMode()) { + case ConnectivityDataLoaded::MODE_COLUMN: + break; + case ConnectivityDataLoaded::MODE_NONE: + break; + case ConnectivityDataLoaded::MODE_ROW: + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE: + { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t surfaceNumberOfVertices(-1); + int32_t vertexIndex(-1); + int64_t rowIndex(-1); + int64_t columnIndex(-1); + m_connectivityDataLoaded->getSurfaceNodeLoading(structure, + surfaceNumberOfVertices, + vertexIndex, + rowIndex, + columnIndex); + if (vertexIndex >= 0) { + loadDataForSurfaceNode(surfaceNumberOfVertices, + structure, + vertexIndex); + } + } + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: + { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t surfaceNumberOfVertices(-1); + std::vector vertexIndices; + m_connectivityDataLoaded->getSurfaceAverageNodeLoading(structure, + surfaceNumberOfVertices, + vertexIndices); + if ( ! vertexIndices.empty()) { + loadAverageDataForSurfaceNodes(surfaceNumberOfVertices, + structure, + vertexIndices); + } + } + break; + case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: + break; + case ConnectivityDataLoaded::MODE_VOXEL_XYZ: + break; + } +} + diff --git a/src/Files/MetricDynamicConnectivityFile.h b/src/Files/MetricDynamicConnectivityFile.h new file mode 100644 index 0000000000000000000000000000000000000000..5c36adbfb97153378c966e5c87260cda731e34d5 --- /dev/null +++ b/src/Files/MetricDynamicConnectivityFile.h @@ -0,0 +1,140 @@ +#ifndef __METRIC_DYNAMIC_CONNECTIVITY_FILE_H__ +#define __METRIC_DYNAMIC_CONNECTIVITY_FILE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "MetricFile.h" + + + +namespace caret { + + class ConnectivityCorrelation; + class ConnectivityDataLoaded; + + class MetricDynamicConnectivityFile : public MetricFile { + + public: + MetricDynamicConnectivityFile(MetricFile* parentMetricFile); + + virtual ~MetricDynamicConnectivityFile(); + + MetricDynamicConnectivityFile(const MetricDynamicConnectivityFile&) = delete; + + MetricDynamicConnectivityFile& operator=(const MetricDynamicConnectivityFile&) = delete; + + void initializeFile(); + + virtual void clear() override; + + virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) override; + + virtual void readFile(const AString& filename) override; + + virtual void writeFile(const AString& filename) override; + + virtual bool supportsWriting() const override; + + MetricFile* getParentMetricFile(); + + const MetricFile* getParentMetricFile() const; + + bool isDataValid() const; + + bool isEnabledAsLayer() const; + + void setEnabledAsLayer(const bool enabled); + + bool loadConnectivityForVoxelXYZ(const float xyz[3]); + + bool loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], + const std::vector& voxelIndices); + + bool isDataLoadingEnabled() const; + + void setDataLoadingEnabled(const bool enabled); + + const ConnectivityDataLoaded* getConnectivityDataLoaded() const; + + bool loadDataForSurfaceNode(const int32_t surfaceNumberOfNodes, + const StructureEnum::Enum structure, + const int32_t nodeIndex); + + bool loadAverageDataForSurfaceNodes(const int32_t surfaceNumberOfNodes, + const StructureEnum::Enum structure, + const std::vector& nodeIndices); + + MetricFile* newMetricFileFromLoadedData(const AString& directoryName, + AString& errorMessageOut); + + // ADD_NEW_METHODS_HERE + + protected: + virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) override; + + virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) override; + + private: + void clearPrivateData(); + + void clearVertexValues(); + + bool getConnectivityForVertexIndex(const int32_t vertexIndex, + std::vector& vertexDataOut); + + ConnectivityCorrelation* getConnectivityCorrelation(); + + const MetricFile* m_parentMetricFile; + + std::unique_ptr m_sceneAssistant; + + std::unique_ptr m_connectivityCorrelation; + + AString m_dataLoadedName; + + int32_t m_numberOfVertices = 0; + + bool m_validDataFlag = false; + + bool m_enabledAsLayer = true; + + bool m_dataLoadingEnabledFlag = true; + + std::unique_ptr m_connectivityDataLoaded; + + bool m_connectivityCorrelationFailedFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ + // +#endif // __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ + +} // namespace +#endif //__METRIC_DYNAMIC_CONNECTIVITY_FILE_H__ diff --git a/src/Files/MetricFile.cxx b/src/Files/MetricFile.cxx index c7892b114b594c2ec3ccc0e1ce804eb5cb66e145..53df0d2ad742add670608af0b3b2b8c5f6e97c7b 100644 --- a/src/Files/MetricFile.cxx +++ b/src/Files/MetricFile.cxx @@ -27,6 +27,7 @@ #include "GiftiFile.h" #include "MapFileDataSelector.h" #include "MathFunctions.h" +#include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "NiftiEnums.h" #include "PaletteColorMapping.h" @@ -36,6 +37,8 @@ using namespace caret; +const AString MetricFile::s_paletteColorMappingNameInMetaData = "__DYNAMIC_FILE_PALETTE_COLOR_MAPPING__"; + /** * Constructor. */ @@ -45,6 +48,18 @@ MetricFile::MetricFile() this->initializeMembersMetricFile(); } +/** + * Constructor for subclasses + * + * @param dataFileType + * Filetype for subclass + */ +MetricFile::MetricFile(const DataFileTypeEnum::Enum dataFileType) +: GiftiTypeFile(dataFileType) +{ + this->initializeMembersMetricFile(); +} + /** * Copy constructor. * @@ -92,6 +107,21 @@ void MetricFile::writeFile(const AString& filename) { CaretLogWarning("metric file '" + filename + "' should be saved ending in .func.gii or .shape.gii, see wb_command -gifti-help"); } + /* + * Put the child dynamic data-series file's palette in the file's metadata. + */ + if (m_lazyInitializedDynamicConnectivityFile != NULL) { + GiftiMetaData* fileMetaData = m_lazyInitializedDynamicConnectivityFile->getCiftiXML().getFileMetaData(); + CaretAssert(fileMetaData); + if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { + fileMetaData->set(s_paletteColorMappingNameInMetaData, + m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0)->encodeInXML()); + } + else { + fileMetaData->remove(s_paletteColorMappingNameInMetaData); + } + } + caret::GiftiTypeFile::writeFile(filename); } @@ -740,6 +770,11 @@ MetricFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); + + if (m_lazyInitializedDynamicConnectivityFile != NULL) { + sceneClass->addClass(m_lazyInitializedDynamicConnectivityFile->saveToScene(sceneAttributes, + "m_lazyInitializedDynamicConnectivityFile")); + } } /** @@ -774,6 +809,62 @@ MetricFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, m_chartingEnabledForTab[i] = false; } } + + const SceneClass* dynamicFileSceneClass = sceneClass->getClass("m_lazyInitializedDynamicConnectivityFile"); + if (dynamicFileSceneClass != NULL) { + MetricDynamicConnectivityFile* denseDynamicFile = getMetricDynamicConnectivityFile(); + denseDynamicFile->restoreFromScene(sceneAttributes, + dynamicFileSceneClass); + } +} + +/** + * @return The volume dynamic connectivity file for a data-series (functional) file + * that contains at least two time points. Note that some files may + * have type anatomy but still contain functional data. + * Will return NULL for other types. + */ +const MetricDynamicConnectivityFile* +MetricFile::getMetricDynamicConnectivityFile() const +{ + MetricFile* nonConstThis = const_cast(this); + return nonConstThis->getMetricDynamicConnectivityFile(); +} + +/** + * @return The volume dynamic connectivity file for a data-series (functional) file + * that contains at least two time points. Note that some files may + * have type anatomy but still contain functional data. + * Will return NULL for other types. + */ +MetricDynamicConnectivityFile* +MetricFile::getMetricDynamicConnectivityFile() +{ + if (m_lazyInitializedDynamicConnectivityFile == NULL) { + const int32_t minimumNumberOfTimePoints(8); + if (getNumberOfMaps() >= minimumNumberOfTimePoints) { + m_lazyInitializedDynamicConnectivityFile.reset(new MetricDynamicConnectivityFile(this)); + + m_lazyInitializedDynamicConnectivityFile->initializeFile(); + + /* + * Palette for dynamic file is in file metadata + */ + GiftiMetaData* fileMetaData = getFileMetaData(); + const AString encodedPaletteColorMappingString = fileMetaData->get(s_paletteColorMappingNameInMetaData); + if ( ! encodedPaletteColorMappingString.isEmpty()) { + if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { + PaletteColorMapping* pcm = m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0); + CaretAssert(pcm); + pcm->decodeFromStringXML(encodedPaletteColorMappingString); + } + } + + m_lazyInitializedDynamicConnectivityFile->clearModified(); + } + } + + return m_lazyInitializedDynamicConnectivityFile.get(); } diff --git a/src/Files/MetricFile.h b/src/Files/MetricFile.h index b22298dda1125bff1f641eba7a7e138dba5fb495..dc00ae2a7d87935c3b99c70f34e2121f2efa421d 100644 --- a/src/Files/MetricFile.h +++ b/src/Files/MetricFile.h @@ -22,6 +22,8 @@ */ /*LICENSE_END*/ +#include + #include #include @@ -32,6 +34,7 @@ namespace caret { class GiftiDataArray; + class MetricDynamicConnectivityFile; /** * \brief A Metric data file. @@ -99,7 +102,13 @@ namespace caret { //override writeFile in order to check filename against type of file virtual void writeFile(const AString& filename); + MetricDynamicConnectivityFile* getMetricDynamicConnectivityFile(); + + const MetricDynamicConnectivityFile* getMetricDynamicConnectivityFile() const; + protected: + MetricFile(const DataFileTypeEnum::Enum dataFileType); + /** * Validate the contents of the file after it * has been read such as correct number of @@ -121,7 +130,12 @@ namespace caret { /** Points to actual data in each Gifti Data Array */ std::vector columnDataPointers; + std::unique_ptr m_lazyInitializedDynamicConnectivityFile; + bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + static const AString s_paletteColorMappingNameInMetaData; + }; } // namespace diff --git a/src/Files/PaletteFile.cxx b/src/Files/PaletteFile.cxx index d9bc82b1946d7a6212fa9c3e2f07a576e6e95fe9..06f12de848e6139ee23642651ff80e73dc56bd66 100644 --- a/src/Files/PaletteFile.cxx +++ b/src/Files/PaletteFile.cxx @@ -1679,6 +1679,8 @@ PaletteFile::setDefaultPaletteColorMapping(PaletteColorMapping* paletteColorMapp case DataFileTypeEnum::METRIC: checkShapeFile = true; break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: invalid = true; break; @@ -1700,6 +1702,8 @@ PaletteFile::setDefaultPaletteColorMapping(PaletteColorMapping* paletteColorMapp case DataFileTypeEnum::VOLUME: checkVolume = true; break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } if (invalid) { @@ -1780,14 +1784,14 @@ PaletteFile::setDefaultPaletteColorMapping(PaletteColorMapping* paletteColorMapp // paletteColorMapping->setUserScaleNegativeMinimum(0.0); // paletteColorMapping->setUserScalePositiveMinimum(0.0); // paletteColorMapping->setUserScalePositiveMaximum(1.5); - paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); + paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMaximum(98.0); } else { - paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); + paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); @@ -1803,7 +1807,7 @@ PaletteFile::setDefaultPaletteColorMapping(PaletteColorMapping* paletteColorMapp paletteColorMapping->setSelectedPaletteName("videen-style"); paletteColorMapping->setSelectedPaletteName("ROY-BIG-BL"); paletteColorMapping->setInterpolatePaletteFlag(true); - paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); + paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); @@ -1817,7 +1821,7 @@ PaletteFile::setDefaultPaletteColorMapping(PaletteColorMapping* paletteColorMapp paletteColorMapping->setSelectedPaletteName("videen-style"); paletteColorMapping->setSelectedPaletteName("ROY-BIG-BL"); paletteColorMapping->setInterpolatePaletteFlag(true); - paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); + paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); diff --git a/src/Files/SceneDataFileInfo.cxx b/src/Files/SceneDataFileInfo.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e1618a783c632bc3157690417d811ee8413365dd --- /dev/null +++ b/src/Files/SceneDataFileInfo.cxx @@ -0,0 +1,314 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_DATA_FILE_INFO_DECLARE__ +#include "SceneDataFileInfo.h" +#undef __SCENE_DATA_FILE_INFO_DECLARE__ + +#include "CaretAssert.h" +#include "FileInformation.h" +using namespace caret; + + + +/** + * \class caret::SceneDataFileInfo + * \brief Information about data files in a scene file + * \ingroup Files + */ + +/** + * Constructor. + * + * @param absoluteDataFilePathAndName + * Absolute path and file name of the data file + * @param absoluteBasePath + * The absolute base path + * @param absoluteSceneFilePathAndName + * Absolute path and name of the scene file + * @param sceneIndex + * Index of scene using this data file. + */ +SceneDataFileInfo::SceneDataFileInfo(const AString& absoluteDataFilePathAndName, + const AString& absoluteBasePath, + const AString& absoluteSceneFilePathAndName, + const std::vector& sceneIndices) +: CaretObject() +{ + FileInformation fileInfo(absoluteDataFilePathAndName); + m_remoteFlag = fileInfo.isRemoteFile(); + if ( ! m_remoteFlag) { + m_missingFlag = ( ! fileInfo.exists()); + } + + m_absolutePath = fileInfo.getAbsolutePath(); + + m_dataFileName = fileInfo.getFileName(); + + FileInformation sceneFileInfo(absoluteSceneFilePathAndName); + m_relativePathToSceneFile = SystemUtilities::relativePath(m_absolutePath, + sceneFileInfo.getAbsolutePath()); + + m_relativePathToBasePath = SystemUtilities::relativePath(m_absolutePath, + absoluteBasePath); + + m_sceneIndices.insert(sceneIndices.begin(), + sceneIndices.end()); +} + +/** + * Destructor. + */ +SceneDataFileInfo::~SceneDataFileInfo() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +SceneDataFileInfo::SceneDataFileInfo(const SceneDataFileInfo& obj) +: CaretObject(obj) +{ + this->copyHelperSceneDataFileInfo(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +SceneDataFileInfo& +SceneDataFileInfo::operator=(const SceneDataFileInfo& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperSceneDataFileInfo(obj); + } + return *this; +} + +/** + * Less-than operator. + * + * @param rhs + * Other instance for comparison + * @return + * True if this instance is 'less-than' the other instance. + */ +bool +SceneDataFileInfo::operator<(const SceneDataFileInfo& rhs) const { + if (m_absolutePath == rhs.m_absolutePath) { + return (m_dataFileName < rhs.m_dataFileName); + } + return (m_absolutePath < rhs.m_absolutePath); +} + +/** + * Add a scene index that uses this data file. + * + * @param sceneIndex + * Additional scene index. + */ +void +SceneDataFileInfo::addSceneIndex(const int32_t sceneIndex) const +{ + m_sceneIndices.insert(sceneIndex); +} + +/** + * @return The scene indices as a string + */ +AString +SceneDataFileInfo::getSceneIndicesAsString() const +{ + std::vector indicesVector(m_sceneIndices.begin(), + m_sceneIndices.end()); + return AString::fromNumbers(indicesVector, ","); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +SceneDataFileInfo::copyHelperSceneDataFileInfo(const SceneDataFileInfo& obj) +{ + m_absolutePath = obj.m_absolutePath; + m_dataFileName = obj.m_dataFileName; + m_relativePathToBasePath = obj.m_relativePathToBasePath; + m_relativePathToSceneFile = obj.m_relativePathToSceneFile; + m_sceneIndices = obj.m_sceneIndices; +} + +/** + * @return + */ +AString +SceneDataFileInfo::getAbsolutePath() const +{ + return m_absolutePath; +} + +/** + * @return + */ +AString +SceneDataFileInfo::getAbsolutePathAndFileName() const +{ + if (m_absolutePath.isEmpty()) { + return m_dataFileName; + } + const AString s(m_absolutePath + + "/" + + m_dataFileName); + return s; +} + +/** + * @return + */ +AString +SceneDataFileInfo::getDataFileName() const +{ + return m_dataFileName; +} + +/** + * @return + */ +AString +SceneDataFileInfo::getRelativePathToBasePath() const +{ + return m_relativePathToBasePath; +} + +/** + * @return + */ +AString +SceneDataFileInfo::getRelativePathToSceneFile() const +{ + return m_relativePathToSceneFile; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +SceneDataFileInfo::toString() const +{ + return "SceneDataFileInfo"; +} + +/** + * @return True if the file is remote. + */ +bool +SceneDataFileInfo::isRemote() const +{ + return m_remoteFlag; +} + +/** + * @return True if this file is missing. + * Note: Remote file is never missing. + */ +bool +SceneDataFileInfo::isMissing() const +{ + if (isRemote()) { + return false; + } + + return m_missingFlag; +} + +/** + * Sort a vector of SceneDataFileInfo objects using the given sort mode + * + * @param sceneDataFileInfo + * Vector of object that is sorted. + * @param sortMode + * Mode for sorting. + */ +void +SceneDataFileInfo::sort(std::vector& sceneDataFileInfo, + const SortMode sortMode) +{ + switch (sortMode) { + case SortMode::AbsolutePath: + break; + case SortMode::RelativeToBasePath: + break; + case SortMode::RelativeToSceneFilePath: + break; + } + + std::sort(sceneDataFileInfo.begin(), + sceneDataFileInfo.end(), + [&sortMode] (const SceneDataFileInfo& lhs, const SceneDataFileInfo& rhs) { + AString lhsPath; + AString rhsPath; + + switch (sortMode) { + case SortMode::AbsolutePath: + lhsPath = lhs.m_absolutePath; + rhsPath = rhs.m_absolutePath; + break; + case SortMode::RelativeToBasePath: + lhsPath = lhs.m_relativePathToBasePath; + rhsPath = rhs.m_relativePathToBasePath; + break; + case SortMode::RelativeToSceneFilePath: + lhsPath = lhs.m_relativePathToSceneFile; + rhsPath = rhs.m_relativePathToSceneFile; + break; + } + + if (lhsPath == rhsPath) { + return (lhs.m_dataFileName < rhs.m_dataFileName); + } + return (lhsPath < rhsPath); + }); + + /*print (sceneDataFileInfo);*/ +} + +/** + * Print the vector of file information. + * + * @param sceneDataFileInfo + * Information that is printed. + */ +void +SceneDataFileInfo::print(const std::vector& sceneDataFileInfo) +{ + for (const auto sdfi : sceneDataFileInfo) { + std::cout << sdfi.getAbsolutePathAndFileName() << std::endl; + } +} + diff --git a/src/Files/SceneDataFileInfo.h b/src/Files/SceneDataFileInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..6550fc9499e18b922151ea466ec78c8e07a9daf4 --- /dev/null +++ b/src/Files/SceneDataFileInfo.h @@ -0,0 +1,115 @@ +#ifndef __SCENE_DATA_FILE_INFO_H__ +#define __SCENE_DATA_FILE_INFO_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include +#include + +#include "CaretObject.h" + + + +namespace caret { + + class SceneDataFileInfo : public CaretObject { + + public: + /** + * Mode for sorting + */ + enum class SortMode { + /* Sort by file's absolute path and then data file name */ + AbsolutePath, + /* Sort by path relative to base path and then data file name */ + RelativeToBasePath, + /* Sort by path relative to scene file path and then data file name */ + RelativeToSceneFilePath + }; + + SceneDataFileInfo(const AString& absoluteDataFilePathAndName, + const AString& absoluteBasePath, + const AString& absoluteSceneFilePathAndName, + const std::vector& sceneIndices); + + virtual ~SceneDataFileInfo(); + + SceneDataFileInfo(const SceneDataFileInfo& obj); + + SceneDataFileInfo& operator=(const SceneDataFileInfo& obj); + + bool operator<(const SceneDataFileInfo& rhs) const; + + void addSceneIndex(const int32_t sceneIndex) const; + + AString getSceneIndicesAsString() const; + + AString getAbsolutePath() const; + + AString getAbsolutePathAndFileName() const; + + AString getDataFileName() const; + + AString getRelativePathToBasePath() const; + + AString getRelativePathToSceneFile() const; + + bool isRemote() const; + + bool isMissing() const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + static void sort(std::vector& sceneDataFileInfo, + const SortMode sortMode); + + static void print(const std::vector& sceneDataFileInfo); + + private: + void copyHelperSceneDataFileInfo(const SceneDataFileInfo& obj); + + AString m_absolutePath; + + AString m_dataFileName; + + AString m_relativePathToBasePath; + + AString m_relativePathToSceneFile; + + bool m_remoteFlag = false; + + bool m_missingFlag = false; + + mutable std::set m_sceneIndices; + + // ADD_NEW_MEMBERS_HERE and DON'T FORGET TO UPDATE COPY COPY METHOD + + }; + +#ifdef __SCENE_DATA_FILE_INFO_DECLARE__ + // +#endif // __SCENE_DATA_FILE_INFO_DECLARE__ + +} // namespace +#endif //__SCENE_DATA_FILE_INFO_H__ diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 4f1669be2da073704c002dbaa8957a40f09798ba..e41f7901e9594556b13cb541615fa9779753cbb2 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -34,6 +34,7 @@ #include "CaretLogger.h" #include "DataFileContentInformation.h" #include "DataFileException.h" +#include "DeveloperFlagsEnum.h" #include "FileAdapter.h" #include "FileInformation.h" #include "GiftiMetaData.h" @@ -45,10 +46,14 @@ #include "SceneInfo.h" #include "ScenePathName.h" #include "SceneXmlElements.h" +#include "SceneFileXmlStreamReader.h" +#include "SceneFileXmlStreamWriter.h" #include "SceneWriterXml.h" #include "SpecFile.h" #include "SystemUtilities.h" +#include "WuQMacroGroup.h" #include "XmlSaxParser.h" +#include "XmlUtilities.h" #include "XmlWriter.h" using namespace caret; @@ -570,6 +575,17 @@ void SceneFile::setBasePathType(const SceneFileBasePathTypeEnum::Enum basePathTy } } +/** + * Set the name of the file. + * + * @param filename + * New name of file + */ +void +SceneFile::setFileName(const AString& filename) +{ + CaretDataFile::setFileName(filename); +} /** * Read the scene file. @@ -591,9 +607,88 @@ SceneFile::readFile(const AString& filenameIn) checkFileReadability(filename); this->setFileName(filename); + + /* + * Stream reader is newer and supports macro in scene file. + * Stream reader is also faster than sax reader. + */ + const bool useStreamReaderFlag(true); + if (useStreamReaderFlag) { + try { + SceneFileXmlStreamReader streamReader; + streamReader.readFile(filename, + this); + } + catch (const DataFileException& e) { + DataFileException dfe(filename, + e.whatString()); + CaretLogThrowing(dfe); + throw dfe; + } + + } + else { + SceneFileSaxReader saxReader(this, + filename); + std::auto_ptr parser(XmlSaxParser::createXmlParser()); + try { + parser->parseFile(filename, &saxReader); + } + catch (const XmlSaxParserException& e) { + clear(); + this->setFileName(""); + + int lineNum = e.getLineNumber(); + int colNum = e.getColumnNumber(); + + AString msg = "Parse Error while reading:"; + + if ((lineNum >= 0) && (colNum >= 0)) { + msg += (" line/col (" + + AString::number(e.getLineNumber()) + + "/" + + AString::number(e.getColumnNumber()) + + ")"); + } + + msg += (": " + e.whatString()); + + DataFileException dfe(filenameIn, + msg); + CaretLogThrowing(dfe); + throw dfe; + } + } + + this->setFileName(filename); + + this->clearModified(); +} + +/** + * Read the scene file use the old SAX parser + * @param filenameIn + * Name of scene file. + * @throws DataFileException + * If there is an error reading the file. + */ +void +SceneFile::readFileSaxReader(const AString& filenameIn) +{ + clear(); + + AString filename = filenameIn; + if (DataFile::isFileOnNetwork(filename) == false) { + FileInformation specInfo(filename); + filename = specInfo.getAbsoluteFilePath(); + } + checkFileReadability(filename); + + this->setFileName(filename); + SceneFileSaxReader saxReader(this, filename); - std::auto_ptr parser(XmlSaxParser::createXmlParser()); + std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } @@ -621,12 +716,51 @@ SceneFile::readFile(const AString& filenameIn) CaretLogThrowing(dfe); throw dfe; } + + this->setFileName(filename); + + this->clearModified(); +} + +/** + * Read the scene file using the new Stream parser + * @param filenameIn + * Name of scene file. + * @throws DataFileException + * If there is an error reading the file. + */ +void +SceneFile::readFileStreamReader(const AString& filenameIn) +{ + clear(); + + AString filename = filenameIn; + if (DataFile::isFileOnNetwork(filename) == false) { + FileInformation specInfo(filename); + filename = specInfo.getAbsoluteFilePath(); + } + checkFileReadability(filename); this->setFileName(filename); + + try { + SceneFileXmlStreamReader streamReader; + streamReader.readFile(filename, + this); + } + catch (const DataFileException& e) { + DataFileException dfe(filename, + e.whatString()); + CaretLogThrowing(dfe); + throw dfe; + } + this->setFileName(filename); + this->clearModified(); } + /** * Write the scene file. * @param filename @@ -645,13 +779,60 @@ SceneFile::writeFile(const AString& filename) this->setFileName(filename); + try { - // - // Format the version string so that it ends with at most one zero - // - const AString versionString = AString::number(SceneFile::getFileVersion(), - 'f', - 1); + /* + * Stream Writer is newer and supports macros in scene file + */ + const bool useStreamWriterFlag(true); + if (useStreamWriterFlag) { + SceneFileXmlStreamWriter xmlStreamWriter; + xmlStreamWriter.writeFile(this); + } + else { + writeFileSaxWriter(filename); + } + + this->clearModified(); + } + catch (const GiftiException& e) { + throw DataFileException(e); + } + catch (const XmlException& e) { + throw DataFileException(e); + } +} + +/** + * Write the scene file using the (not exactly) sax writer + * @param filename + * Name of scene file. + * @throws DataFileException + * If there is an error writing the file. + */ +void +SceneFile::writeFileSaxWriter(const AString& filename) +{ + if (!(filename.endsWith(".scene") || filename.endsWith(".wb_scene"))) + { + CaretLogWarning("scene file '" + filename + "' should be saved ending in .scene"); + } + + for (const auto s : m_scenes) { + if ( ! s->getMacroGroup()->isEmpty()) { + throw DataFileException("OLD scene writer does not support scene files containing macros. Use stream writer"); + } + } + + checkFileWritability(filename); + + this->setFileName(filename); + + try { + /* + * This writes an old file format that does not support macros + */ + const AString versionString = AString::number(getSceneFileVersionBeforeMacros()); // // Open the file @@ -695,9 +876,9 @@ SceneFile::writeFile(const AString& filename) if (m_metadata != NULL) { m_metadata->writeAsXML(xmlWriter); } - + const int32_t numScenes = this->getNumberOfScenes(); - + /* * Write the scene info directory */ @@ -756,7 +937,7 @@ SceneFile::writeFile(const AString& filename) SceneWriterXml sceneWriter(xmlWriter, this->getFileName()); for (int32_t i = 0; i < numScenes; i++) { - sceneWriter.writeScene(*m_scenes[i], + sceneWriter.writeScene(*m_scenes[i], i); } @@ -764,7 +945,39 @@ SceneFile::writeFile(const AString& filename) xmlWriter.writeEndDocument(); file.close(); - + + this->clearModified(); + } + catch (const GiftiException& e) { + throw DataFileException(e); + } + catch (const XmlException& e) { + throw DataFileException(e); + } +} + +/** + * Write the scene file stream writer + * @param filename + * Name of scene file. + * @throws DataFileException + * If there is an error writing the file. + */ +void +SceneFile::writeFileStreamWriter(const AString& filename) +{ + if (!(filename.endsWith(".scene") || filename.endsWith(".wb_scene"))) + { + CaretLogWarning("scene file '" + filename + "' should be saved ending in .scene"); + } + checkFileWritability(filename); + + this->setFileName(filename); + + try { + SceneFileXmlStreamWriter xmlStreamWriter; + xmlStreamWriter.writeFile(this); + this->clearModified(); } catch (const GiftiException& e) { @@ -891,7 +1104,7 @@ SceneFile::findBaseDirectoryForDataFiles(AString& baseDirectoryOut, const AString directorySeparator("/"); std::vector allFileNames; - std::set filesFromScenes = getAllDataFileNamesFromAllScenes(); + std::set filesFromScenes = getAllDataFileNamesFromAllScenes(); for (const auto& nameInfo : filesFromScenes) { allFileNames.push_back(nameInfo.m_dataFileName); } @@ -1041,12 +1254,12 @@ SceneFile::getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCo /** * @return A vector containing the names of all data files from all scenes. */ -std::set +std::set SceneFile::getAllDataFileNamesFromAllScenes() const { const bool includeSpecFileFlag = false; - std::set fileInfoOut; + std::set fileInfoOut; /** * Find all 'path name' elements from ALL scenes @@ -1079,7 +1292,7 @@ SceneFile::getAllDataFileNamesFromAllScenes() const } if (useNameFlag) { AString pathName = scenePathName->stringValue().trimmed(); - + if ( ! pathName.isEmpty()) { bool validExtensionFlag = false; const DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromFileExtension(pathName, @@ -1131,6 +1344,9 @@ SceneFile::getAllDataFileNamesFromAllScenes() const break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + validDiskFileFlag = false; + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -1143,14 +1359,18 @@ SceneFile::getAllDataFileNamesFromAllScenes() const break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + validDiskFileFlag = false; + break; case DataFileTypeEnum::UNKNOWN: + validDiskFileFlag = false; break; } } if (validDiskFileFlag) { - QFileInfo fileInfo(pathName); - const QString absPathName = fileInfo.absoluteFilePath(); + FileInformation fileInfo(pathName); + const QString absPathName = fileInfo.getAbsoluteFilePath(); if ( ! absPathName.isEmpty()) { pathName = absPathName; } @@ -1168,8 +1388,8 @@ SceneFile::getAllDataFileNamesFromAllScenes() const } if ( ! foundFlag) { - fileInfoOut.insert(SceneDataFileInfo(pathName, - sceneIndex)); + fileInfoOut.insert(FileAndSceneIndicesInfo(pathName, + sceneIndex)); } } } @@ -1182,6 +1402,36 @@ SceneFile::getAllDataFileNamesFromAllScenes() const return fileInfoOut; } +/** + * @return File info for all files in the scene file. + */ +std::vector +SceneFile::getAllDataFileInfoFromAllScenes() const +{ + const std::set allNamesAndIndices = getAllDataFileNamesFromAllScenes(); + + AString basePath; + AString errorMessage; + std::vector missingFiles; + const bool validFlag = findBaseDirectoryForDataFiles(basePath, missingFiles, errorMessage); + if ( ! validFlag) { + CaretLogSevere("Failed to find the base path for scene file: " + + getFileName()); + } + + std::vector fileInfoOut; + + for (const auto nameAndIndices : allNamesAndIndices) { + fileInfoOut.emplace_back(nameAndIndices.m_dataFileName, + basePath, + getFileName(), + nameAndIndices.m_sceneIndices); + } + + return fileInfoOut; +} + + /** * @return Default name for a ZIP file containing the scene file and its data files. */ @@ -1246,3 +1496,46 @@ SceneFile::clearModified() scene->clearModified(); } } + +/** + * @return The version number to use when writing + * an instance of a scene. This number returned + * may version depending upon the content of the scene + * and may allow older versions of wb_view to read + * the scene file when it does not contain new stuff. + */ +int32_t +SceneFile::getSceneFileVersionForWriting() const +{ + int32_t version = s_sceneFileVersionBeforeMacros; + + for (const auto s : m_scenes) { + if ( ! s->getMacroGroup()->isEmpty()) { + version = s_sceneFileVersionContainingMacros; + break; + } + } + return version; +} + +/** + * @return The maximum scene file version supported + * by the scene file. + */ +int32_t +SceneFile::getMaxiumSupportedSceneFileVersion() +{ + return s_sceneFileVersionContainingMacros; +} + +/** + * @return The scene file version before macros were added. + */ +int32_t +SceneFile::getSceneFileVersionBeforeMacros() +{ + return s_sceneFileVersionBeforeMacros; +} + + + diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index b61e69e20686f549365df2f2b3a410635d136c87..84411b25fc486843bb9a9a074c8c656e99562a71 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -21,9 +21,11 @@ */ /*LICENSE_END*/ +#include #include #include "CaretDataFile.h" +#include "SceneDataFileInfo.h" #include "SceneFileBasePathTypeEnum.h" namespace caret { @@ -48,10 +50,20 @@ namespace caret { void clear(); + virtual void setFileName(const AString& filename) override; + void readFile(const AString& filename); + void readFileSaxReader(const AString& filename); + + void readFileStreamReader(const AString& filename); + void writeFile(const AString& filename); + void writeFileSaxWriter(const AString& filename); + + void writeFileStreamWriter(const AString& filename); + bool isEmpty() const; void addScene(Scene* scene); @@ -107,20 +119,20 @@ namespace caret { std::vector getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount = 25); - class SceneDataFileInfo { + class FileAndSceneIndicesInfo { public: - SceneDataFileInfo(const AString& dataFileName, - const int32_t sceneIndex) + FileAndSceneIndicesInfo(const AString& dataFileName, + const int32_t sceneIndex) : m_dataFileName(dataFileName) { - m_sceneIndices.push_back(sceneIndex); + m_sceneIndices.push_back(sceneIndex + 1); } - bool operator<(const SceneDataFileInfo& rhs) const { + bool operator<(const FileAndSceneIndicesInfo& rhs) const { return m_dataFileName < rhs.m_dataFileName; } void addSceneIndex(const int32_t sceneIndex) const { - m_sceneIndices.push_back(sceneIndex); + m_sceneIndices.push_back(sceneIndex + 1); } AString getSceneIndices() const { @@ -132,7 +144,9 @@ namespace caret { mutable std::vector m_sceneIndices; }; - std::set getAllDataFileNamesFromAllScenes() const; + std::set getAllDataFileNamesFromAllScenes() const; + + std::vector getAllDataFileInfoFromAllScenes() const; void reorderScenes(std::vector& orderedScenes); @@ -154,8 +168,11 @@ namespace caret { // ADD_NEW_METHODS_HERE - /** Version of file */ - static float getFileVersion() { return s_sceneFileVersion; } + int32_t getSceneFileVersionForWriting() const; + + static int32_t getSceneFileVersionBeforeMacros(); + + static int32_t getMaxiumSupportedSceneFileVersion(); /** XML Tag for scene file */ static const AString XML_TAG_SCENE_FILE; @@ -193,15 +210,26 @@ namespace caret { // ADD_NEW_MEMBERS_HERE - /** Version of this SceneFile */ - static const float s_sceneFileVersion; + /** Version of this SceneFile before addition of macros */ + static const int32_t s_sceneFileVersionBeforeMacros; + + /** Version of this SceneFile containing macros */ + static const int32_t s_sceneFileVersionContainingMacros; }; #ifdef __SCENE_FILE_DECLARE__ const AString SceneFile::XML_TAG_SCENE_FILE = "SceneFile"; const AString SceneFile::XML_ATTRIBUTE_VERSION = "Version"; const AString SceneFile::XML_TAG_SCENE_INFO_DIRECTORY_TAG = "SceneInfoDirectory"; - const float SceneFile::s_sceneFileVersion = 3.0; + + /* + * NOTE: If these scene file versions change, getSupportedSceneFileVersion() + * will need to be updated with the maximum scene file version that + * can be read + */ + const int32_t SceneFile::s_sceneFileVersionBeforeMacros = 3; + const int32_t SceneFile::s_sceneFileVersionContainingMacros = 4; + #endif // __SCENE_FILE_DECLARE__ } // namespace diff --git a/src/Files/SceneFileSaxReader.cxx b/src/Files/SceneFileSaxReader.cxx index ed8f8a27db69ad27c6e04112e63be03186b8741d..dd0b7f31fffff9696112293c462a2deb97a03aac 100644 --- a/src/Files/SceneFileSaxReader.cxx +++ b/src/Files/SceneFileSaxReader.cxx @@ -32,7 +32,6 @@ #include "SceneInfoSaxReader.h" #include "ScenePathName.h" #include "SceneXmlElements.h" - #include "XmlAttributes.h" #include "XmlException.h" #include "XmlUtilities.h" @@ -104,9 +103,10 @@ SceneFileSaxReader::startElement(const AString& namespaceURI, // // Check version of file being read // - const float version = attributes.getValueAsFloat(SceneFile::XML_ATTRIBUTE_VERSION); - if (version > SceneFile::getFileVersion()) { - AString msg = XmlUtilities::createInvalidVersionMessage(SceneFile::getFileVersion(), + const float versionFloat = attributes.getValueAsFloat(SceneFile::XML_ATTRIBUTE_VERSION); + const int32_t version = static_cast(versionFloat); + if (version > SceneFile::getSceneFileVersionBeforeMacros()) { + AString msg = XmlUtilities::createInvalidVersionMessage(SceneFile::getSceneFileVersionBeforeMacros(), version); XmlSaxParserException e(msg); CaretLogThrowing(e); diff --git a/src/Files/SceneFileXmlStreamBase.cxx b/src/Files/SceneFileXmlStreamBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9b0a191f87a8aa627eb3cbd4ccad023a5d901526 --- /dev/null +++ b/src/Files/SceneFileXmlStreamBase.cxx @@ -0,0 +1,62 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_FILE_XML_STREAM_BASE_DECLARE__ +#include "SceneFileXmlStreamBase.h" +#undef __SCENE_FILE_XML_STREAM_BASE_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SceneFileXmlStreamBase + * \brief Base class for Scene File XML Stream Reader and Writer + * \ingroup Files + */ + +/** + * Constructor. + */ +SceneFileXmlStreamBase::SceneFileXmlStreamBase() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +SceneFileXmlStreamBase::~SceneFileXmlStreamBase() +{ +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +SceneFileXmlStreamBase::toString() const +{ + return "SceneFileXmlStreamBase"; +} + diff --git a/src/Files/SceneFileXmlStreamBase.h b/src/Files/SceneFileXmlStreamBase.h new file mode 100644 index 0000000000000000000000000000000000000000..9b75437596fada2ba3c910bc0e2d88bd649e3afe --- /dev/null +++ b/src/Files/SceneFileXmlStreamBase.h @@ -0,0 +1,89 @@ +#ifndef __SCENE_FILE_XML_STREAM_BASE_H__ +#define __SCENE_FILE_XML_STREAM_BASE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class SceneFileXmlStreamBase : public CaretObject { + + public: + SceneFileXmlStreamBase(); + + virtual ~SceneFileXmlStreamBase(); + + SceneFileXmlStreamBase(const SceneFileXmlStreamBase&) = delete; + + SceneFileXmlStreamBase& operator=(const SceneFileXmlStreamBase&) = delete; + + static const QString ELEMENT_SCENE_FILE; + + static const QString ATTRIBUTE_SCENE_FILE_VERSION; + + static const QString ELEMENT_SCENE_FILE_INFO_DIRECTORY; + + static const QString ELEMENT_SCENE_FILE_BALSA_STUDY_ID; + + static const QString ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE; + + static const QString ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY; + + static const QString ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY; + + static const QString ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_FILE_XML_STREAM_BASE_DECLARE__ + const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE = "SceneFile"; + + const QString SceneFileXmlStreamBase::ATTRIBUTE_SCENE_FILE_VERSION = "Version"; + + const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_INFO_DIRECTORY = "SceneInfoDirectory"; + + const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_STUDY_ID = "BalsaStudyID"; + + const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE = "BalsaStudyTitle"; + + const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY = "BalsaBaseDirectory"; + + const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY = "BalsaExtractToDirectory"; + + const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE = "BasePathType"; +#endif // __SCENE_FILE_XML_STREAM_BASE_DECLARE__ + +} // namespace +#endif //__SCENE_FILE_XML_STREAM_BASE_H__ diff --git a/src/Files/SceneFileXmlStreamFormatTester.cxx b/src/Files/SceneFileXmlStreamFormatTester.cxx new file mode 100644 index 0000000000000000000000000000000000000000..27c6dc8de824ae2c208b050f312390b038285fe3 --- /dev/null +++ b/src/Files/SceneFileXmlStreamFormatTester.cxx @@ -0,0 +1,328 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include + +#define __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ +#include "SceneFileXmlStreamFormatTester.h" +#undef __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ + +#include "CaretAssert.h" +#include "DataFileException.h" +#include "DataFileTypeEnum.h" +#include "ElapsedTimer.h" +#include "FileInformation.h" +#include "SceneFile.h" +#include "SystemUtilities.h" + +using namespace caret; + +/** + * \class caret::SceneFileXmlStreamFormatTester + * \brief Test new XML Stream Reader and Writer + * \ingroup Files + */ + +/** + * Constructor. + */ +SceneFileXmlStreamFormatTester::SceneFileXmlStreamFormatTester() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +SceneFileXmlStreamFormatTester::~SceneFileXmlStreamFormatTester() +{ +} + +bool +SceneFileXmlStreamFormatTester::testReadingAndWritingInDirectory(const QString& directoryName, + const bool printResultsFlag) +{ + bool allSuccessfulFlag(false); + + QStringList extensions; + for (auto ext : DataFileTypeEnum::getAllFileExtensions(DataFileTypeEnum::SCENE)) { + extensions.append("*." + ext); + } + + QDir directory(directoryName); + QStringList sceneFileList = directory.entryList(extensions, + QDir::Files, + QDir::Name); + + QStringListIterator iter(sceneFileList); + while (iter.hasNext()) { + const QString filename = iter.next(); + const bool passFlag = testReadingAndWriting(filename, + printResultsFlag); + std::cout << (passFlag ? "OK: " : "FAILED: ") << filename << std::endl; + } + return allSuccessfulFlag; +} + +bool +SceneFileXmlStreamFormatTester::testReadingAndWriting(const QString& filename, + const bool printResultsFlag) +{ + const bool readFlag = testReading(filename, + printResultsFlag); + const bool writeFlag = testWriting(filename, + printResultsFlag); + const bool successFlag = (readFlag + && writeFlag); + if (printResultsFlag) { + if (successFlag) { + std::cout << "Success " << std::endl; + } + else { + if ( ! readFlag) { + std::cout << "Read FAILED" << std::endl; + } + if ( ! writeFlag) { + std::cout << "Write FAILED" << std::endl; + } + } + } + + return successFlag; +} + +/** + * Test reading of XML Stream Reader + * + * @param filename + * Name of file + */ +bool +SceneFileXmlStreamFormatTester::testReading(const QString& filename, + const bool printResultsFlag) +{ + try { + QString originalReWrittenFileName; + QString intermediateFileName; + QString finalFileName; + getTempFileNames(filename, + "Read", + originalReWrittenFileName, + intermediateFileName, + finalFileName); + + /* + * Save original format file since some changes to writing + * may have been made since original file was last written + * (perhaps CDATA added) + */ + SceneFile sceneFileUpdated; + sceneFileUpdated.readFileSaxReader(filename); + sceneFileUpdated.writeFileSaxWriter(originalReWrittenFileName); + + SceneFile sceneFile; + sceneFile.readFileStreamReader(originalReWrittenFileName); + + sceneFile.writeFileSaxWriter(finalFileName); + + FileInformation origFileInfo(filename); + FileInformation origReWrittenFileInfo(originalReWrittenFileName); + FileInformation finalFileInfo(finalFileName); + + const bool successFlag(origReWrittenFileInfo.size() == finalFileInfo.size()); + + if (printResultsFlag) { + const QString resultString(successFlag + ? "READING MATCHED" + : "FAILED"); + std::cout << resultString << std::endl; + std::cout << " Original File: " << origFileInfo.getFileName() << std::endl; + std::cout << " Original File (rewritten): " << origReWrittenFileInfo.getFileName() << std::endl; + std::cout << " Test output file name: " << finalFileInfo.getFileName() << std::endl; + std::cout << " Sizes (orig) " << origReWrittenFileInfo.size() + << " (output) " << finalFileInfo.size() << std::endl; + std::cout << " sdiff -s " << origReWrittenFileInfo.getFileName() + << " " << finalFileInfo.getFileName() << std::endl; + std::cout << std::endl; + } + + return successFlag; + } + catch (const DataFileException& dfe) { + if (printResultsFlag) { + std::cout << "Failed: " << dfe.whatString() << std::endl; + } + return false; + } +} + +bool +SceneFileXmlStreamFormatTester::testWriting(const QString& filename, + const bool printResultsFlag) +{ + try { + QString originalReWrittenFileName; + QString intermediateFileName; + QString finalFileName; + getTempFileNames(filename, + "Write", + originalReWrittenFileName, + intermediateFileName, + finalFileName); + + /* + * Read with old reader and write with old reader since + * writing may have changed since file was originally written + */ + SceneFile sceneFileUpdated; + sceneFileUpdated.readFileSaxReader(filename); + sceneFileUpdated.writeFileSaxWriter(originalReWrittenFileName); + + /* + * Write with new reader + */ + sceneFileUpdated.writeFileSaxWriter(intermediateFileName); + + /* + * Read file with old reader and write with + * old reader. + */ + SceneFile sceneFile; + sceneFile.readFileSaxReader(intermediateFileName); + sceneFile.writeFileSaxWriter(finalFileName); + + FileInformation origFileInfo(filename); + FileInformation rewrittenFileInfo(originalReWrittenFileName); + FileInformation intermediateFileInfo(intermediateFileName); + FileInformation finalFileInfo(finalFileName); + + /* + * If 'original re-written' matches final then + * the intermediate writing with new writer was + * successful + */ + const bool successFlag(rewrittenFileInfo.size() == finalFileInfo.size()); + + if (printResultsFlag) { + const QString resultString(successFlag + ? "WRITING MATCHED" + : "FAILED"); + std::cout << resultString << std::endl; + std::cout << " Original File: " << origFileInfo.getFileName() << std::endl; + std::cout << " Old Reritten File: " << rewrittenFileInfo.getFileName() << std::endl; + std::cout << " New Writer File: " << intermediateFileInfo.getFileName() << std::endl; + std::cout << " Final file: " << finalFileInfo.getFileName() << std::endl; + std::cout << " Sizes (re-written) " << rewrittenFileInfo.size() + << " (final) " << finalFileInfo.size() << std::endl; + std::cout << " sdiff -s " << rewrittenFileInfo.getFileName() + << " " << finalFileInfo.getFileName() << std::endl; + std::cout << std::endl; + } + + return successFlag; + } + catch (const DataFileException& dfe) { + if (printResultsFlag) { + std::cout << "Failed: " << dfe.whatString() << std::endl; + } + return false; + } +} + +void +SceneFileXmlStreamFormatTester::getTempFileNames(const QString& filename, + const QString& prefixName, + QString& originalFileReWrittenOut, + QString& intermediateFileNameOut, + QString& finalFileNameOut) +{ + + FileInformation fileInfo(filename); + AString absPath, nameNoExt, extNoDot; + fileInfo.getFileComponents(absPath, nameNoExt, extNoDot); + + const AString path = fileInfo.getAbsolutePath(); + const AString name = fileInfo.getFileName(); + + originalFileReWrittenOut = FileInformation::assembleFileComponents(absPath, prefixName + "TestOriginalReWritten", extNoDot); + intermediateFileNameOut = FileInformation::assembleFileComponents(absPath, + prefixName + "TestItermediate", + extNoDot); + + finalFileNameOut = FileInformation::assembleFileComponents(absPath, + prefixName + "TestFinal", + extNoDot); +} + +bool +SceneFileXmlStreamFormatTester::timeReadingAndWriting(const QString& filename) +{ + const bool successFlag(false); + + + AString path, name, ext; + FileInformation fileInfo(filename); + fileInfo.getFileComponents(path, name, ext); + + std::cout << "Timing (seconds) for " << fileInfo.getFileName() << std::endl; + + try { + SceneFile sceneFile; + ElapsedTimer timer; + timer.start(); + sceneFile.readFileSaxReader(filename); + std::cout << " Read OLD: " << timer.getElapsedTimeSeconds() << std::endl; + + timer.reset(); + + QString tempName(FileInformation::assembleFileComponents(QDir::tempPath(), "TestRead", ext)); + + timer.start(); + sceneFile.writeFileSaxWriter(tempName); + std::cout << " Write OLD: " << timer.getElapsedTimeSeconds() << std::endl; + } + catch (const DataFileException& dfe) { + std::cout << "Test OLD Failed: " << dfe.whatString() << std::endl; + } + + try { + SceneFile sceneFile; + ElapsedTimer timer; + timer.start(); + sceneFile.readFileStreamReader(filename); + std::cout << " Read NEW: " << timer.getElapsedTimeSeconds() << std::endl; + + timer.reset(); + + QString tempName(FileInformation::assembleFileComponents(QDir::tempPath(), "TestWrite", ext)); + + timer.start(); + sceneFile.writeFileStreamWriter(tempName); + std::cout << " Write NEW: " << timer.getElapsedTimeSeconds() << std::endl; + } + catch (const DataFileException& dfe) { + std::cout << "Test New Failed: " << dfe.whatString() << std::endl; + } + + return successFlag; +} diff --git a/src/Files/SceneFileXmlStreamFormatTester.h b/src/Files/SceneFileXmlStreamFormatTester.h new file mode 100644 index 0000000000000000000000000000000000000000..fa578a80e84083ee2bec319e8f7f34de40ec0408 --- /dev/null +++ b/src/Files/SceneFileXmlStreamFormatTester.h @@ -0,0 +1,77 @@ +#ifndef __SCENE_FILE_XML_STREAM_FORMAT_TESTER_H__ +#define __SCENE_FILE_XML_STREAM_FORMAT_TESTER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class SceneFileXmlStreamFormatTester : public CaretObject { + + public: + SceneFileXmlStreamFormatTester(); + + virtual ~SceneFileXmlStreamFormatTester(); + + SceneFileXmlStreamFormatTester(const SceneFileXmlStreamFormatTester&) = delete; + + SceneFileXmlStreamFormatTester& operator=(const SceneFileXmlStreamFormatTester&) = delete; + + static bool testReadingAndWriting(const QString& filename, + const bool printResultsFlag); + + static bool testReading(const QString& filename, + const bool printResultsFlag); + + static bool testWriting(const QString& filename, + const bool printResultsFlag); + + static bool timeReadingAndWriting(const QString& filename); + + static bool testReadingAndWritingInDirectory(const QString& directoryName, + const bool printResultsFlag); + + // ADD_NEW_METHODS_HERE + + private: + static void getTempFileNames(const QString& filename, + const QString& prefixName, + QString& originalFileReWrittenOut, + QString& intermediateFileNameOut, + QString& finalFileNameOut); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ + // +#endif // __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ + +} // namespace +#endif //__SCENE_FILE_XML_STREAM_FORMAT_TESTER_H__ diff --git a/src/Files/SceneFileXmlStreamReader.cxx b/src/Files/SceneFileXmlStreamReader.cxx new file mode 100644 index 0000000000000000000000000000000000000000..853eeda5f7f01991a111518d0ce8a701a2cc0a8b --- /dev/null +++ b/src/Files/SceneFileXmlStreamReader.cxx @@ -0,0 +1,304 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include +#include + +#define __SCENE_FILE_XML_STREAM_READER_DECLARE__ +#include "SceneFileXmlStreamReader.h" +#undef __SCENE_FILE_XML_STREAM_READER_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "DataFileException.h" +#include "GiftiMetaData.h" +#include "GiftiXmlElements.h" +#include "Scene.h" +#include "SceneFile.h" +#include "SceneInfo.h" +#include "SceneInfoXmlStreamReader.h" +#include "SceneTypeEnum.h" +#include "SceneXmlStreamReader.h" + +using namespace caret; + + + +/** + * \class caret::SceneFileXmlStreamReader + * \brief XML Stream Writer for Scene File + * \ingroup Files + */ + +/** + * Constructor. + */ +SceneFileXmlStreamReader::SceneFileXmlStreamReader() +: SceneFileXmlStreamBase() +{ + +} + +/** + * Destructor. + */ +SceneFileXmlStreamReader::~SceneFileXmlStreamReader() +{ +} + +/** + * Read into the given scene file from the file with the given name + * + * @param filename + * Name of the scene file + * @param sceneFile + * Name of the scene file + * @throws + * Data file exception + */ +void +SceneFileXmlStreamReader::readFile(const AString& filename, + SceneFile* sceneFile) +{ + CaretAssert(sceneFile); + if (sceneFile == NULL) { + throw DataFileException("Scene file is invalid (NULL)."); + } + + if (filename.isEmpty()) { + throw DataFileException("Scene file name is empty"); + } + + m_filename = filename; + + QFile file(m_filename); + if ( ! file.open(QFile::ReadOnly)) { + throw DataFileException("Unable to open for reading: " + + m_filename + + " Reason: " + + file.errorString()); + } + + QXmlStreamReader xmlReader(&file); + readFileContent(xmlReader, + sceneFile); + + AString errorMessage; + if (xmlReader.hasError()) { + errorMessage = xmlReader.errorString(); + errorMessage.appendWithNewLine("Line " + + AString::number(xmlReader.lineNumber()) + + " column " + + AString::number(xmlReader.columnNumber())); + } + + file.close(); + + if ( ! errorMessage.isEmpty()) { + throw DataFileException(errorMessage); + } +} + +/** + * Read the file's content + * + * @param xmlReader + * The XML stream reader + * @param sceneFile + * Into this scene file + */ +void +SceneFileXmlStreamReader::readFileContent(QXmlStreamReader& xmlReader, + SceneFile* sceneFile) +{ + CaretAssert(sceneFile); + + if (xmlReader.atEnd()) { + xmlReader.raiseError("At end of file when starting to read. Is file empty?"); + return; + } + + xmlReader.readNextStartElement(); + if (xmlReader.name() != ELEMENT_SCENE_FILE) { + xmlReader.raiseError("First element is \"" + + xmlReader.name().toString() + + "\" but should be " + + ELEMENT_SCENE_FILE); + return; + } + + const QXmlStreamAttributes atts = xmlReader.attributes(); + const QStringRef versionAtt = atts.value(ATTRIBUTE_SCENE_FILE_VERSION); + m_fileVersion = 1; + if ( ! versionAtt.isEmpty()) { + /* + * Note: version was float in previous versions, so get as float and convert to int + */ + m_fileVersion = static_cast(versionAtt.toFloat()); + } + + /* + * Set when ending scene file element is found + */ + bool endElementFound(false); + + while ( ( ! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + switch (xmlReader.tokenType()) { + case QXmlStreamReader::StartElement: + if (xmlReader.name() == GiftiXmlElements::TAG_METADATA) { + GiftiMetaData* metaData = sceneFile->getFileMetaData(); + metaData->readSceneFile3(xmlReader); + } + else if (xmlReader.name() == ELEMENT_SCENE_FILE_INFO_DIRECTORY) { + readSceneInfoDirectory(xmlReader, + sceneFile); + } + else if (xmlReader.name() == SceneXmlStreamReader::ELEMENT_SCENE) { + const QXmlStreamAttributes attributes = xmlReader.attributes(); + const QStringRef typeString = attributes.value(SceneXmlStreamReader::ATTRIBUTE_SCENE_TYPE); + bool valid(false); + SceneTypeEnum::Enum sceneType = SceneTypeEnum::fromName(typeString.toString(), + &valid); + + const QStringRef indexString = attributes.value(SceneXmlStreamReader::ATTRIBUTE_SCENE_INDEX); + const int32_t sceneIndex = indexString.toInt(); + + Scene* scene = new Scene(sceneType); + SceneXmlStreamReader sceneReader; + sceneReader.readScene(xmlReader, + scene, + m_filename); + if ( ! xmlReader.hasError()) { + auto mapIter = m_sceneInfoMap.find(sceneIndex); + SceneInfo* sceneInfo = ((mapIter != m_sceneInfoMap.end()) + ? mapIter->second + : NULL); + scene->setSceneInfo(sceneInfo); + sceneFile->addScene(scene); + } + } + else { + m_unexpectedXmlElements.insert(xmlReader.name().toString()); + xmlReader.skipCurrentElement(); + } + break; + case QXmlStreamReader::EndElement: + if (xmlReader.name() == ELEMENT_SCENE_FILE) { + endElementFound = true; + } + break; + default: + break; + } + } +} + +/** + * Read the scene info directory + * + * @param xmlReader + * The XML stream reader + * @param sceneFile + * Into this scene file + */ +void +SceneFileXmlStreamReader::readSceneInfoDirectory(QXmlStreamReader& xmlReader, + SceneFile* sceneFile) +{ + /* + * Gets set when ending scene info directory element is read + */ + bool endElementFound(false); + + while ( (! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + switch (xmlReader.tokenType()) { + case QXmlStreamReader::StartElement: +// { +// std::cout << "Start Element " << xmlReader.name().toString() +// << " characters " << xmlReader.readElementText() +// << " CDATA" << (xmlReader.isCDATA() ? " Yes" : " No") << std::endl; +// +// } + if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_STUDY_ID) { + sceneFile->setBalsaStudyID(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE) { + sceneFile->setBalsaStudyTitle(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY) { + sceneFile->setBalsaCustomBaseDirectory(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY) { + sceneFile->setBalsaExtractToDirectoryName(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE) { + const AString name = xmlReader.readElementText(); + bool valid(false); + const SceneFileBasePathTypeEnum::Enum basePathType = SceneFileBasePathTypeEnum::fromName(name, + &valid); + if (valid) { + sceneFile->setBasePathType(basePathType); + } + else { + sceneFile->setBasePathType(SceneFileBasePathTypeEnum::AUTOMATIC); + CaretLogWarning(m_filename + + "has invalid base path type: " + + name); + } + + } + else if (xmlReader.name() == SceneInfoXmlStreamReader::ELEMENT_SCENE_INFO) { + const QXmlStreamAttributes attributes = xmlReader.attributes(); + const QStringRef indexAttribute = attributes.value(SceneInfoXmlStreamReader::ATTRIBUTE_SCENE_INDEX); + if ( ! indexAttribute.isEmpty()) { + const int32_t sceneIndex = indexAttribute.toInt(); + SceneInfoXmlStreamReader infoReader; + SceneInfo* sceneInfo = new SceneInfo(); + infoReader.readSceneInfo(xmlReader, + sceneInfo); + + if ( ! xmlReader.hasError()) { + m_sceneInfoMap.insert(std::make_pair(sceneIndex, + sceneInfo)); + } + } + } + else { + m_unexpectedXmlElements.insert(xmlReader.name().toString()); + xmlReader.skipCurrentElement(); + } + break; + case QXmlStreamReader::EndElement: + if (xmlReader.name() == ELEMENT_SCENE_FILE_INFO_DIRECTORY) { + endElementFound = true; + } + break; + default: + break; + } + } +} + diff --git a/src/Files/SceneFileXmlStreamReader.h b/src/Files/SceneFileXmlStreamReader.h new file mode 100644 index 0000000000000000000000000000000000000000..6246d45299293c3660cd7c341fc880b4b3caa4c8 --- /dev/null +++ b/src/Files/SceneFileXmlStreamReader.h @@ -0,0 +1,78 @@ +#ifndef __SCENE_FILE_XML_STREAM_READER_H__ +#define __SCENE_FILE_XML_STREAM_READER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include +#include + +#include "SceneFileXmlStreamBase.h" + +class QXmlStreamReader; + +namespace caret { + + class SceneFile; + class SceneInfo; + + class SceneFileXmlStreamReader : public SceneFileXmlStreamBase { + + public: + SceneFileXmlStreamReader(); + + virtual ~SceneFileXmlStreamReader(); + + SceneFileXmlStreamReader(const SceneFileXmlStreamReader&) = delete; + + SceneFileXmlStreamReader& operator=(const SceneFileXmlStreamReader&) = delete; + + void readFile(const AString& filename, + SceneFile* sceneFile); + + // ADD_NEW_METHODS_HERE + + private: + void readFileContent(QXmlStreamReader& xmlReader, + SceneFile* sceneFile); + + void readSceneInfoDirectory(QXmlStreamReader& xmlReader, + SceneFile* sceneFile); + + AString m_filename; + + int32_t m_fileVersion = -1; + + std::set m_unexpectedXmlElements; + + std::map m_sceneInfoMap; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_FILE_XML_STREAM_READER_DECLARE__ + // +#endif // __SCENE_FILE_XML_STREAM_READER_DECLARE__ + +} // namespace +#endif //__SCENE_FILE_XML_STREAM_READER_H__ diff --git a/src/Files/SceneFileXmlStreamWriter.cxx b/src/Files/SceneFileXmlStreamWriter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5fae42fac70380c4a5aef311d0e914821c4bc25a --- /dev/null +++ b/src/Files/SceneFileXmlStreamWriter.cxx @@ -0,0 +1,220 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ +#include "SceneFileXmlStreamWriter.h" +#undef __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +#include "DataFileException.h" +#include "FileInformation.h" +#include "GiftiMetaData.h" +#include "Scene.h" +#include "SceneFile.h" +#include "SceneInfoXmlStreamWriter.h" +#include "ScenePathName.h" +#include "SceneXmlStreamWriter.h" + +using namespace caret; + + + +/** + * \class caret::SceneFileXmlStreamWriter + * \brief XML Stream reader for Scene File + * \ingroup Files + */ + +/** + * Constructor. + */ +SceneFileXmlStreamWriter::SceneFileXmlStreamWriter() +: SceneFileXmlStreamBase() +{ + +} + +/** + * Destructor. + */ +SceneFileXmlStreamWriter::~SceneFileXmlStreamWriter() +{ +} + +/** + * Write the given Scene File in XML format. Name of the file + * is obtained from the file. + * + * @param sceneFile + * Scene File written in XML format. + * @throws + * DataFileException if there is an error writing the file. + */ +void +SceneFileXmlStreamWriter::writeFile(const SceneFile* sceneFile) +{ + CaretAssert(sceneFile); + + const QString filename = sceneFile->getFileName(); + if (filename.isEmpty()) { + throw DataFileException("Name for writing annotation file is empty."); + } + + QFile file(filename); + if ( ! file.open(QFile::WriteOnly)) { + throw DataFileException(filename, + "Error opening for writing: " + + file.errorString()); + } + + QXmlStreamWriter xmlWriter(&file); + writeFileContentToXmlStreamWriter(xmlWriter, + sceneFile, + filename); + + file.close(); + + if (xmlWriter.hasError()) { + throw DataFileException(filename, + ("Unknown error writing file " + + sceneFile->getFileNameNoPath())); + } +} + +/** + * Write the scene files content to the XML stream. + * + * @param xmlWriter + * The XML stream writer + * @param sceneFile + * The scene file + * @param sceneFileName + * Name of the file. + */ +void +SceneFileXmlStreamWriter::writeFileContentToXmlStreamWriter(QXmlStreamWriter& xmlWriter, + const SceneFile* sceneFile, + const AString& sceneFileName) +{ + CaretAssert(sceneFile); + + const AString versionString = AString::number(sceneFile->getSceneFileVersionForWriting()); + + xmlWriter.setAutoFormatting(true); + + xmlWriter.writeStartDocument(); + + xmlWriter.writeStartElement(ELEMENT_SCENE_FILE); + xmlWriter.writeAttribute(ATTRIBUTE_SCENE_FILE_VERSION, + versionString); + + const GiftiMetaData* metaData = sceneFile->getFileMetaData(); + if ( ! metaData->isEmpty()) { + metaData->writeSceneFile3(xmlWriter); + } + + writeSceneInfoDirectory(xmlWriter, + sceneFile, + sceneFileName); + + const int32_t numberOfScenes = sceneFile->getNumberOfScenes(); + for (int32_t sceneIndex = 0; sceneIndex < numberOfScenes; sceneIndex++) { + SceneXmlStreamWriter sceneXmlWriter; + sceneXmlWriter.writeXML(&xmlWriter, + sceneFile->getSceneAtIndex(sceneIndex), + sceneIndex, + sceneFileName); + } + + xmlWriter.writeEndElement(); + + xmlWriter.writeEndDocument(); +} + +/** + * Write the scene info directory to the XML stream + * + * @param xmlWriter + * The XML stream writer + * @param sceneFile + * The scene file + * @param sceneFileName + * Name of the file. + */ +void +SceneFileXmlStreamWriter::writeSceneInfoDirectory(QXmlStreamWriter& xmlWriter, + const SceneFile* sceneFile, + const AString& sceneFileName) +{ + xmlWriter.writeStartElement(ELEMENT_SCENE_FILE_INFO_DIRECTORY); + + xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_STUDY_ID, + sceneFile->getBalsaStudyID()); + xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE, + sceneFile->getBalsaStudyTitle()); + + AString relativeBasePath(""); + switch (sceneFile->getBasePathType()) { + case SceneFileBasePathTypeEnum::AUTOMATIC: + break; + case SceneFileBasePathTypeEnum::CUSTOM: + { + /* + * Write base path as a path RELATIVE to the scene file + * but only when base path type is CUSTOM + * Note: we do not use FileInformation::getCanonicalFilePath() + * because it returns an empty string if the file DOES NOT exist + * and this may occur since the file may be new and has not + * been closed. + */ + if ( ! sceneFile->getBalsaCustomBaseDirectory().isEmpty()) { + const AString baseDirAbsPath = FileInformation(sceneFile->getBalsaCustomBaseDirectory()).getAbsoluteFilePath(); + const AString sceneFileAbsPath = FileInformation(sceneFileName).getAbsoluteFilePath(); + ScenePathName basePathName("basePathName", + baseDirAbsPath); + + relativeBasePath = basePathName.getRelativePathToSceneFile(sceneFileAbsPath); + } + } + break; + } + xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY, + relativeBasePath); + + + xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY, + sceneFile->getBalsaExtractToDirectoryName()); + xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE, + SceneFileBasePathTypeEnum::toName(sceneFile->getBasePathType())); + + const int32_t numberOfScenes = sceneFile->getNumberOfScenes(); + for (int32_t sceneIndex = 0; sceneIndex < numberOfScenes; sceneIndex++) { + SceneInfoXmlStreamWriter infoXmlWriter; + infoXmlWriter.writeXML(&xmlWriter, + sceneFile->getSceneAtIndex(sceneIndex)->getSceneInfo(), + sceneIndex); + } + + xmlWriter.writeEndElement(); +} diff --git a/src/Files/SceneFileXmlStreamWriter.h b/src/Files/SceneFileXmlStreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..73a123af4a0a75ba2a916b7ed5ec1dc67281c89f --- /dev/null +++ b/src/Files/SceneFileXmlStreamWriter.h @@ -0,0 +1,68 @@ +#ifndef __SCENE_FILE_XML_STREAM_WRITER_H__ +#define __SCENE_FILE_XML_STREAM_WRITER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "SceneFileXmlStreamBase.h" + +class QXmlStreamWriter; + +namespace caret { + class SceneFile; + + class SceneFileXmlStreamWriter : public SceneFileXmlStreamBase { + + public: + SceneFileXmlStreamWriter(); + + virtual ~SceneFileXmlStreamWriter(); + + SceneFileXmlStreamWriter(const SceneFileXmlStreamWriter&) = delete; + + SceneFileXmlStreamWriter& operator=(const SceneFileXmlStreamWriter&) = delete; + + void writeFile(const SceneFile* sceneFile); + + // ADD_NEW_METHODS_HERE + + private: + void writeFileContentToXmlStreamWriter(QXmlStreamWriter& xmlWriter, + const SceneFile* sceneFile, + const AString& sceneFileName); + + void writeSceneInfoDirectory(QXmlStreamWriter& xmlWriter, + const SceneFile* sceneFile, + const AString& sceneFileName); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ + // +#endif // __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ + +} // namespace +#endif //__SCENE_FILE_XML_STREAM_WRITER_H__ diff --git a/src/Files/SpecFile.cxx b/src/Files/SpecFile.cxx index e5ec858634ea88b30ccd836257f221d319209e8f..bd98ddcebfdc7621862022002c9d9ec3e0d14e0a 100644 --- a/src/Files/SpecFile.cxx +++ b/src/Files/SpecFile.cxx @@ -1775,11 +1775,75 @@ SpecFile::addToDataFileContentInformation(DataFileContentInformation& dataFileIn bool SpecFile::isDataFileTypeAllowedInSpecFile(const DataFileTypeEnum::Enum dataFileType) { - if (dataFileType == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { - return false; + bool allowedFlag(true); + + switch (dataFileType) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + allowedFlag = false; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + allowedFlag = false; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + allowedFlag = false; + break; } - return true; + return allowedFlag; } diff --git a/src/Files/SurfaceFile.cxx b/src/Files/SurfaceFile.cxx index f7b5c7aea64e117b060c983bd01925ac8d2c0856..29f513ddc7ce9de8e6ff28312a028ad53368e752 100644 --- a/src/Files/SurfaceFile.cxx +++ b/src/Files/SurfaceFile.cxx @@ -18,6 +18,8 @@ */ /*LICENSE_END*/ +#include +#include #include #include @@ -556,6 +558,25 @@ SurfaceFile::getNormalVector(const int32_t nodeIndex) const return &(this->normalVectors[offset]); } +/** + * Get a normal vector for a coordinate. + * + * @param nodeIndex + * Index of coordinate. + * @param normalVectorOut + * Output containing the normal vector for the node. + */ +void +SurfaceFile::getNormalVector(const int32_t nodeIndex, + float normalVectorOut[3]) const +{ + const int32_t offset = nodeIndex * 3; + CaretAssertVectorIndex(this->normalVectors, offset+2); + normalVectorOut[0] = this->normalVectors[offset]; + normalVectorOut[1] = this->normalVectors[offset+1]; + normalVectorOut[2] = this->normalVectors[offset+2]; +} + const float* SurfaceFile::getNormalData() const { return normalVectors.data(); @@ -909,9 +930,200 @@ SurfaceFile::getBoundingBox() const return this->boundingBox; } +/** + * Match the surface to the given anatomical surface. If this + * surface is an anatomical or raw surface, no action is taken. + * + * @param anatomicalSurfaceFile + * Match to this anatomical surface file. + * @param matchStatus + * The match status + */ +void +SurfaceFile::matchToAnatomicalSurface(const SurfaceFile* anatomicalSurfaceFile, + const bool matchStatus) +{ + CaretAssert(anatomicalSurfaceFile); + if (anatomicalSurfaceFile == NULL) { + return; + } + if (this == anatomicalSurfaceFile) { + return; + } + + if (matchStatus) { + bool sphereMatchFlag(false); + bool matchFlag(false); + switch (getSurfaceType()) { + case SurfaceTypeEnum::ANATOMICAL: + break; + case SurfaceTypeEnum::ELLIPSOID: + break; + case SurfaceTypeEnum::FLAT: + matchFlag = true; + break; + case SurfaceTypeEnum::HULL: + break; + case SurfaceTypeEnum::INFLATED: + matchFlag = true; + break; + case SurfaceTypeEnum::RECONSTRUCTION: + break; + case SurfaceTypeEnum::SEMI_SPHERICAL: + break; + case SurfaceTypeEnum::SPHERICAL: + sphereMatchFlag = true; + break; + case SurfaceTypeEnum::UNKNOWN: + break; + case SurfaceTypeEnum::VERY_INFLATED: + matchFlag = true; + break; + } + + if (matchFlag + || sphereMatchFlag) { + /* + * Save the unmatched coordinates + */ + const int32_t numXYZ = getNumberOfNodes() * 3; + m_unmatchedCoordinates.resize(numXYZ); + CaretAssert(this->coordinatePointer); + std::copy_n(this->coordinatePointer, + numXYZ, + m_unmatchedCoordinates.begin()); + + const bool modStatus(isModified()); + if (sphereMatchFlag) { + matchSphereToSurface(anatomicalSurfaceFile); + if ( ! modStatus) { + clearModified(); + } + } + else if (matchFlag) { + matchSurfaceBoundingBox(anatomicalSurfaceFile); + if ( ! modStatus) { + clearModified(); + } + } + } + } + else { + /* + * Restore the unmatched coordinates + */ + const int32_t numXYZ = getNumberOfNodes() * 3; + if (static_cast(m_unmatchedCoordinates.size()) == numXYZ) { + CaretAssert(this->coordinatePointer); + std::copy_n(m_unmatchedCoordinates.begin(), + numXYZ, + this->coordinatePointer); + } + m_unmatchedCoordinates.clear(); + } +} + + +/** + * Match a sphere to the given surface while retaining the spherical + * shape. The center of gravity of the sphere will be the same as the center of gravity of + * the match surface and the radius of the sphere will be the + * distance furthest from the origin in the match surface. + * + * @param matchSurfaceFile + * Match to this surface file. + */ +void +SurfaceFile::matchSphereToSurface(const SurfaceFile* matchSurfaceFile) +{ + CaretAssert(matchSurfaceFile); + + const float oldRadius = getSphericalRadius(); + if (oldRadius <= 0.0) { + CaretLogWarning("Match sphere has invalid radius"); + return; + } + + /* + * Find match surface vertex distance furthest from origin (0,0,0) + * This value will become the radius of the sphere + */ + CaretPointer matchTH = matchSurfaceFile->getTopologyHelper(); + const int32_t numMatchVertices = matchSurfaceFile->getNumberOfNodes(); + float newRadius = 0.0; + for (int32_t i = 0; i < numMatchVertices; i++) { + if (matchTH->getNodeHasNeighbors(i)) { + const float* xyz = matchSurfaceFile->getCoordinate(i); + const float dist = ((xyz[0]*xyz[0]) + + (xyz[1]*xyz[1]) + + (xyz[2]*xyz[2])); + if (dist > newRadius) { + newRadius = dist; + } + } + } + newRadius = std::sqrt(newRadius); + + float myCOG[3]; + getCenterOfGravity(myCOG); + + float matchCOG[3]; + matchSurfaceFile->getCenterOfGravity(matchCOG); + + + Matrix4x4 matrix; + + /* + * Scale to new radius + */ + const float scale = newRadius / oldRadius; + matrix.scale(scale, + scale, + scale); + + applyMatrix(matrix); +} + +/** + * Get the center of gravity (average coordinate) of the surface. + * + * param cogOut + * Output containing center of gravity. + */ +void +SurfaceFile::getCenterOfGravity(float cogOut[3]) const +{ + cogOut[0] = 0.0; + cogOut[1] = 0.0; + cogOut[2] = 0.0; + + const int32_t numberOfNodes = getNumberOfNodes(); + CaretPointer th = this->getTopologyHelper(); + + double numberOfNodesWithNeighbors = 0.0; + + double cx(0.0), cy(0.0), cz(0.0); + for (int32_t i = 0; i < numberOfNodes; i++) { + if (th->getNodeHasNeighbors(i)) { + const float* xyz = getCoordinate(i); + + cx += xyz[0]; + cy += xyz[1]; + cz += xyz[2]; + numberOfNodesWithNeighbors += 1.0; + } + } + + if (numberOfNodesWithNeighbors > 0.0) { + cogOut[0] = cx / numberOfNodesWithNeighbors; + cogOut[1] = cy / numberOfNodesWithNeighbors; + cogOut[2] = cz / numberOfNodesWithNeighbors; + } +} + /** * Match this surface to the given surface. That is, after this - * method is called, this surface and the given surface will + * method is called, this surface and the given surface will * fit within the same bounding box. * @param surfaceFile * Match to this surface file. @@ -930,18 +1142,18 @@ SurfaceFile::matchSurfaceBoundingBox(const SurfaceFile* surfaceFile) * Translate min x/y/z to origin */ matrix.translate(-myBoundingBox->getMinX(), - -myBoundingBox->getMinY(), - -myBoundingBox->getMinZ()); + -myBoundingBox->getMinY(), + -myBoundingBox->getMinZ()); /* * Scale to match size of match surface */ float scaleX = (targetBoundingBox->getDifferenceX() - / myBoundingBox->getDifferenceX()); + / myBoundingBox->getDifferenceX()); float scaleY = (targetBoundingBox->getDifferenceY() - / myBoundingBox->getDifferenceY()); + / myBoundingBox->getDifferenceY()); float scaleZ = (targetBoundingBox->getDifferenceZ() - / myBoundingBox->getDifferenceZ()); + / myBoundingBox->getDifferenceZ()); if (getSurfaceType() == SurfaceTypeEnum::FLAT) { /* @@ -957,16 +1169,16 @@ SurfaceFile::matchSurfaceBoundingBox(const SurfaceFile* surfaceFile) } matrix.scale(scaleX, - scaleY, - scaleZ); + scaleY, + scaleZ); /* * Translate to min x/y/z of match surface so that * the two surfaces are now within the same "shoebox". */ matrix.translate(targetBoundingBox->getMinX(), - targetBoundingBox->getMinY(), - targetBoundingBox->getMinZ()); + targetBoundingBox->getMinY(), + targetBoundingBox->getMinZ()); applyMatrix(matrix); } diff --git a/src/Files/SurfaceFile.h b/src/Files/SurfaceFile.h index 1bd8377d682c9fd6cc8fe9e957bcc0c1d04b4fd9..7347a18662785f8fc18c9f9fe8578305cd2ab836 100644 --- a/src/Files/SurfaceFile.h +++ b/src/Files/SurfaceFile.h @@ -91,6 +91,9 @@ namespace caret { const float* getNormalVector(const int32_t nodeIndex) const; + void getNormalVector(const int32_t nodeIndex, + float normalVectorOut[3]) const; + const float* getNormalData() const; int getNumberOfTriangles() const; @@ -144,6 +147,13 @@ namespace caret { void matchSurfaceBoundingBox(const SurfaceFile* surfaceFile); + void matchSphereToSurface(const SurfaceFile* surfaceFile); + + void matchToAnatomicalSurface(const SurfaceFile* anatomicalSurfaceFile, + const bool matchStatus); + + void getCenterOfGravity(float cogOut[3]) const; + void applyMatrix(const Matrix4x4& matrix); void getNodesSpacingStatistics(DescriptiveStatistics& statsOut) const; @@ -258,6 +268,9 @@ namespace caret { /** surface normal vectors. */ std::vector normalVectors; + /** Coordinates before matching surface to anatomical */ + std::vector m_unmatchedCoordinates; + bool m_normalsComputed; bool m_skipSanityCheck; diff --git a/src/Files/VolumeDynamicConnectivityFile.cxx b/src/Files/VolumeDynamicConnectivityFile.cxx new file mode 100644 index 0000000000000000000000000000000000000000..72111b9c45a26de7c5f23fd00ee8900b5ecf5e5e --- /dev/null +++ b/src/Files/VolumeDynamicConnectivityFile.cxx @@ -0,0 +1,774 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#define __VOLUME_DYNN_CONN_FILE_DECLARE__ +#include "VolumeDynamicConnectivityFile.h" +#undef __VOLUME_DYNN_CONN_FILE_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "ConnectivityCorrelation.h" +#include "ConnectivityDataLoaded.h" +#include "DataFileException.h" +#include "FileInformation.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::VolumeDynamicConnectivityFile + * \brief Dynamic connectivity volume file + * \ingroup Files + */ + +/** + * Constructor. + */ +VolumeDynamicConnectivityFile::VolumeDynamicConnectivityFile(const VolumeFile* parentVolumeFile) +: VolumeFile(DataFileTypeEnum::VOLUME_DYNAMIC), +m_parentVolumeFile(parentVolumeFile) +{ + CaretAssert(m_parentVolumeFile); + + m_connectivityDataLoaded.reset(new ConnectivityDataLoaded()); + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_dataLoadingEnabledFlag", + &m_dataLoadingEnabledFlag); + m_sceneAssistant->add("m_enabledAsLayer", + &m_enabledAsLayer); + m_sceneAssistant->add("m_connectivityDataLoaded", + "ConnectivityDataLoaded", + m_connectivityDataLoaded.get()); +} + +/** + * Destructor. + */ +VolumeDynamicConnectivityFile::~VolumeDynamicConnectivityFile() +{ +} + +/** + * Clear the file. + */ +void +VolumeDynamicConnectivityFile::clear() +{ + VolumeFile::clear(); + clearPrivateData(); +} + +/** + * Clear the file. + */ +void +VolumeDynamicConnectivityFile::clearPrivateData() +{ + m_voxelData = NULL; + m_numberOfVoxels = 0; + m_validDataFlag = false; + m_enabledAsLayer = false; + m_connectivityCorrelation.reset(); + m_connectivityDataLoaded->reset(); +} + +/** + * @return Pointer to the information about last loaded connectivity data. + */ +const ConnectivityDataLoaded* +VolumeDynamicConnectivityFile::getConnectivityDataLoaded() const +{ + return m_connectivityDataLoaded.get(); +} + +/** + * @return True if enabled as a layer. + */ +bool +VolumeDynamicConnectivityFile::isEnabledAsLayer() const +{ + return m_enabledAsLayer; +} + +/** + * Set enabled as a layer. + * + * @param True if enabled as a layer. + */ +void +VolumeDynamicConnectivityFile::setEnabledAsLayer(const bool enabled) +{ + m_enabledAsLayer = enabled; +} + +/** + * @return True if data loading enabled. + */ +bool +VolumeDynamicConnectivityFile::isDataLoadingEnabled() const +{ + return m_dataLoadingEnabledFlag; +} + +/** + * Set data loading enabled. + * + * @param True if data loading enabled. + */ +void +VolumeDynamicConnectivityFile::setDataLoadingEnabled(const bool enabled) +{ + m_dataLoadingEnabledFlag = enabled; +} + +/** + * Initialize the file using information from parent volume file + */ +void +VolumeDynamicConnectivityFile::initializeFile() +{ + clearPrivateData(); + + CaretAssert(m_parentVolumeFile); + const int64_t numberOfFrames(1); + const int32_t numberOfComponents(1); + + reinitialize(m_parentVolumeFile->getVolumeSpace(), + numberOfFrames, + numberOfComponents, + SubvolumeAttributes::FUNCTIONAL, + m_parentVolumeFile->m_header); + + AString path, nameNoExt, ext; + FileInformation fileInfo(m_parentVolumeFile->getFileName()); + fileInfo.getFileComponents(path, nameNoExt, ext); + setFileName(FileInformation::assembleFileComponents(path, + nameNoExt, + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::VOLUME_DYNAMIC))); + + std::vector dims; + getDimensions(dims); + m_numberOfVoxels = (dims[0] * dims[1] * dims[2]); + m_dimI = dims[0]; + m_dimJ = dims[1]; + m_dimK = dims[2]; + m_dimTime = dims[3]; + CaretAssert(m_dimTime == 1); + if (m_numberOfVoxels > 0) { + m_voxelData = const_cast(getFrame(0)); + m_sliceStride = m_dimI * m_dimJ; + m_timePointIndexStride = m_numberOfVoxels; + } + + clearVoxels(); + + m_validDataFlag = true; +} + +/** + * @return True if this file type supports writing, else false. + * + * Dense files do NOT support writing. + */ +bool +VolumeDynamicConnectivityFile::supportsWriting() const +{ + return false; +} + +/** + * @return The parent volume file + */ +VolumeFile* +VolumeDynamicConnectivityFile::getParentVolumeFile() +{ + return const_cast(m_parentVolumeFile); +} + +/** + * @return The parent volume file (const method) + */ +const VolumeFile* +VolumeDynamicConnectivityFile::getParentVolumeFile() const +{ + return m_parentVolumeFile; +} + +/** + * @return True if the data is valid + */ +bool +VolumeDynamicConnectivityFile::isDataValid() const +{ + return m_validDataFlag; +} + +/** + * Add information about the file to the data file information. + * + * @param dataFileInformation + * Consolidates information about a data file. + */ +void +VolumeDynamicConnectivityFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) +{ + VolumeFile::addToDataFileContentInformation(dataFileInformation); +} + +/** + * Read the file with the given name. + * + * @param filename + * Name of file + * @throws DataFileException + * If error occurs + */ +void +VolumeDynamicConnectivityFile::readFile(const AString& /*filename*/) +{ + throw DataFileException("Read of Volume Dynamic Connectivity File is not allowed"); +} + +/** + * Read the file with the given name. + * + * @param filename + * Name of file + * @throws DataFileException + * If error occurs + */ +void +VolumeDynamicConnectivityFile::writeFile(const AString& /*filename*/) +{ + throw DataFileException("Writing of Volume Dynamic Connectivity File is not allowed"); +} + +/** + * Clear voxels in this volume + */ +void +VolumeDynamicConnectivityFile::clearVoxels() +{ + if (m_voxelData != NULL) { + std::fill(m_voxelData, m_voxelData + m_numberOfVoxels, 0.0f); + updateScalarColoringForMap(0); + m_connectivityDataLoaded->reset(); + } + m_dataLoadedName = ""; +} + +/** + * Get the timepoints for a given voxel + * + * @param i + * index "I" + * @param j + * index "J" + * @param k + * index "K" + * @param dataOut + * Output with time points + */ +void +VolumeDynamicConnectivityFile::getTimePointsForVoxel(const int64_t i, + const int64_t j, + const int64_t k, + std::vector& dataOut) const +{ + CaretAssert(indexValid(i, j, k)); + + const int64_t ijk[3] { i, j, k }; + const int64_t componentIndex(0); + + dataOut.resize(m_dimTime); + for (int64_t iTime = 0; iTime < m_dimTime; iTime++) { + dataOut[iTime] = m_parentVolumeFile->getValue(ijk, + iTime, + componentIndex); + } +} + +/** + * Load connectivity data for the voxel indices and then average the data. + * + * @param volumeDimensionIJK + * Dimensions of the volume. + * @param voxelIndices + * Indices of voxels. + * @return + * True if data was loaded, else false + */ +bool +VolumeDynamicConnectivityFile::loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], + const std::vector& voxelIndices) +{ + /* + * Loading of data disabled? + */ + if ( ! isDataValid()) { + return false; + } + if ( ! isDataLoadingEnabled()) { + return false; + } + + if ( ! matchesDimensions(volumeDimensionIJK[0], + volumeDimensionIJK[1], + volumeDimensionIJK[2])) { + return false; + } + + ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); + if (connCorrelation == NULL) { + return false; + } + + /* + * Zero out here so that data only gets cleared when data + * is to be loaded. + */ + clearVoxels(); + + std::vector brainordinateIndices; + for (auto voxel : voxelIndices) { + const int64_t offset = getVoxelOffset(voxel.m_ijk[0], voxel.m_ijk[1], voxel.m_ijk[2], 0); + brainordinateIndices.push_back(offset); + } + std::vector data(m_numberOfVoxels); + connCorrelation->getCorrelationForBrainordinateROI(brainordinateIndices, + data); + if (m_numberOfVoxels == static_cast(data.size())) { + for (int64_t i = 0; i < m_numberOfVoxels; i++) { + m_voxelData[i] = data[i]; + } + + const int32_t mapIndex(0); + const int64_t validDataCount(static_cast(brainordinateIndices.size())); + setMapName(mapIndex, + ("Average Voxel Count: " + + AString::number(validDataCount, 'f', 0))); + m_dataLoadedName = ("Average_Voxel_Count_" + + AString::number(validDataCount, 'f', 0)); + + updateScalarColoringForMap(mapIndex); + + return true; + } + + return false; +} + +/** + * Load the connectivity for the voxel at the given coordinate. + * The loaded data will be in the voxels inside this volume. + * If the voxel index at the coordinate is invalid, zeros are loaded into all voxels. + * + * @param xyz + * The voxel XYZ. + * @return + * True if data was loaded, else false. + */ +bool +VolumeDynamicConnectivityFile::loadConnectivityForVoxelXYZ(const float xyz[3]) +{ + float indicesFloat[3]; + spaceToIndex(xyz, + indicesFloat); + const int64_t ijk[3] { + static_cast(indicesFloat[0]), + static_cast(indicesFloat[1]), + static_cast(indicesFloat[2]) + }; + + if (loadConnectivityForVoxelIndex(ijk)) { + const int32_t invalidRowColumnIndex(-1); + m_connectivityDataLoaded->setVolumeXYZLoading(xyz, + invalidRowColumnIndex, + invalidRowColumnIndex); + setMapName(0, + ("Voxel XYZ: (" + + AString::fromNumbers(xyz, 3, ",") + + ")")); + m_dataLoadedName = ("Voxel_x" + + AString::number(static_cast(xyz[0])) + + "_y" + + AString::number(static_cast(xyz[1])) + + "_z" + + AString::number(static_cast(xyz[2]))); + + return true; + } + + return false; +} + + +/** + * Load the connectivity for the given voxel. + * The loaded data will be in the voxels inside this volume. + * If the voxel index is invalid, zeros are loaded into all voxels. + * + * @param ijk + * The voxel index. + */ +bool +VolumeDynamicConnectivityFile::loadConnectivityForVoxelIndex(const int64_t ijk[3]) +{ + bool validFlag(false); + + if ( ! isDataValid()) { + return validFlag; + } + if ( ! m_dataLoadingEnabledFlag) { + return validFlag; + } + + clearVoxels(); + + std::vector data; + if (getConnectivityForVoxelIndex(ijk, data)) { + CaretAssert(m_numberOfVoxels == static_cast(data.size())); + std::copy(data.begin(), + data.end(), + m_voxelData); + + validFlag = true; + } + + const int32_t mapIndex(0); + updateScalarColoringForMap(mapIndex); + + return validFlag; +} + +/** + * Get the connectivity for the given voxel. + * If the voxel index is invalid, zeros are loaded into all voxels. + * + * @param ijk + * The voxel index. + * @param voxelsOut + * Output containing voxel data + * @return + * True if data was loaded. + */ +bool +VolumeDynamicConnectivityFile::getConnectivityForVoxelIndex(const int64_t ijk[3], + std::vector& voxelsOut) +{ + bool validFlag(false); + + ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); + if (connCorrelation != NULL) { + if (indexValid(ijk)) { + const int64_t voxelCount(m_dimI * m_dimJ * m_dimK); + + if (connCorrelation) { + const int64_t myTimePointOffset = getVoxelOffset(ijk[0], ijk[1], ijk[2], 0); + connCorrelation->getCorrelationForBrainordinate(myTimePointOffset, + voxelsOut); + CaretAssert(voxelCount == static_cast(voxelsOut.size())); + validFlag = true; + } + } + } + + if ( ! validFlag) { + voxelsOut.resize(m_numberOfVoxels); + std::fill(voxelsOut.begin(), voxelsOut.end(), + 0.0f); + } + + return validFlag; +} + +/** + * @return Pointer to connectivity correlation or NULL if not valid + */ +ConnectivityCorrelation* +VolumeDynamicConnectivityFile::getConnectivityCorrelation() +{ + if ( ! m_connectivityCorrelationFailedFlag) { + if (m_voxelData != NULL) { + if (m_connectivityCorrelation == NULL) { + /* + * Need data and timepoint count from parent volume + * IJK dimensions are same in this and parent volume + */ + CaretAssert(m_parentVolumeFile); + const float* parentVoxels = m_parentVolumeFile->getFrame(0); + CaretAssert(parentVoxels); + std::vector parentVolumeDimensions; + m_parentVolumeFile->getDimensions(parentVolumeDimensions); + CaretAssert(parentVolumeDimensions.size() >= 4); + const int64_t timePointCount = parentVolumeDimensions[3]; + + const int64_t voxelCount(m_dimI * m_dimJ * m_dimK); + const int64_t numberOfBrainordinates(voxelCount); // Each IJK voxel is a group + const int64_t nextBrainordinateStride(1); // All groups have one element in each 'brick' + const int64_t numberOfTimePoints(timePointCount); // Each group contains timepoints + const int64_t nextTimePointStride(voxelCount); // Each group element is in separate IJK 'brick' + + AString errorMessage; + ConnectivityCorrelation* cc = ConnectivityCorrelation::newInstance(parentVoxels, + numberOfBrainordinates, + nextBrainordinateStride, + numberOfTimePoints, + nextTimePointStride, + errorMessage); + if (cc != NULL) { + m_connectivityCorrelation.reset(cc); + } + else { + m_connectivityCorrelationFailedFlag = true; + CaretLogSevere("Failed to create connectvity correlation for " + + m_parentVolumeFile->getFileNameNoPath()); + } + } + } + } + + return m_connectivityCorrelation.get(); +} + +/** + * @return True if this matches the given dimensions + * + * @param dimI + * I dimension + * @param dimJ + * J dimension + * @param dimK + * K dimension + */ +bool +VolumeDynamicConnectivityFile::matchesDimensions(const int64_t dimI, + const int64_t dimJ, + const int64_t dimK) const +{ + if ((dimI == m_dimI) + && (dimJ == m_dimJ) + && (dimK == m_dimK)) { + return true; + } + + return false; +} + +/** + * @return A volume file using the loaded data (will return NULL if there is an error). + * + * @param directoryName + * Directory for file + * @param errorMessageOut + * Contains error information + */ +VolumeFile* +VolumeDynamicConnectivityFile::newVolumeFileFromLoadedData(const AString& directoryName, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + bool validDataFlag(false); + switch (m_connectivityDataLoaded->getMode()) { + case ConnectivityDataLoaded::MODE_COLUMN: + break; + case ConnectivityDataLoaded::MODE_NONE: + break; + case ConnectivityDataLoaded::MODE_ROW: + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE: + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: + break; + case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: + validDataFlag = true; + break; + case ConnectivityDataLoaded::MODE_VOXEL_XYZ: + validDataFlag = true; + break; + } + + if ( ! validDataFlag) { + errorMessageOut = "No voxel connectivity data is loaded"; + return NULL; + } + + VolumeFile* vf(NULL); + + try { + std::vector dimensions; + dimensions.push_back(m_dimI); + dimensions.push_back(m_dimJ); + dimensions.push_back(m_dimK); + dimensions.push_back(1); + dimensions.push_back(1); + + const VolumeSpace vs = getVolumeSpace(); + vf = new VolumeFile(dimensions, + vs.getSform(), + 1, + SubvolumeAttributes::FUNCTIONAL, + m_header); + + float* voxelData = const_cast(vf->getFrame(0)); + std::copy(m_voxelData, m_voxelData + m_numberOfVoxels, + voxelData); + + /* + * May need to convert a remote path to a local path + */ + FileInformation fileNameInfo(getFileName()); + const AString volumeFileName = fileNameInfo.getAsLocalAbsoluteFilePath(directoryName, + vf->getDataFileType()); + + /* + * Create name of volume file data loaded information + */ + FileInformation volumeFileInfo(volumeFileName); + AString thePath, theName, theExtension; + volumeFileInfo.getFileComponents(thePath, + theName, + theExtension); + theName.append("_" + m_dataLoadedName); + AString newFileName = FileInformation::assembleFileComponents(thePath, + theName, + theExtension); + if (newFileName.endsWith(".nii")) { + newFileName.append(".gz"); + } + vf->setFileName(newFileName); + + + /* + * Need to copy color palette since it may be the default + */ + PaletteColorMapping* volumePalette = vf->getMapPaletteColorMapping(0); + CaretAssert(volumePalette); + const PaletteColorMapping* myPalette = getMapPaletteColorMapping(0); + CaretAssert(myPalette); + volumePalette->copy(*myPalette, + true); + + vf->updateAfterFileDataChanges(); + vf->updateScalarColoringForMap(0); + vf->setModified(); + } + catch (const DataFileException& dfe) { + errorMessageOut = dfe.whatString(); + if (vf != NULL) { + delete vf; + vf = NULL; + } + } + + return vf; +} + + +/** + * Save data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +VolumeDynamicConnectivityFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + VolumeFile::saveFileDataToScene(sceneAttributes, + sceneClass); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +VolumeDynamicConnectivityFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + m_connectivityDataLoaded->reset(); + + VolumeFile::restoreFileDataFromScene(sceneAttributes, + sceneClass); + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + + switch (m_connectivityDataLoaded->getMode()) { + case ConnectivityDataLoaded::MODE_COLUMN: + break; + case ConnectivityDataLoaded::MODE_NONE: + break; + case ConnectivityDataLoaded::MODE_ROW: + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE: + break; + case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: + break; + case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: + { + int64_t dimIJK[3]; + std::vector voxelIJKs; + m_connectivityDataLoaded->getVolumeAverageVoxelLoading(dimIJK, + voxelIJKs); + loadMapAverageDataForVoxelIndices(dimIJK, + voxelIJKs); + } + break; + case ConnectivityDataLoaded::MODE_VOXEL_XYZ: + { + float xyz[3]; + int64_t rowIndex(-1); + int64_t columnIndex(-1); + + m_connectivityDataLoaded->getVolumeXYZLoading(xyz, + rowIndex, + columnIndex); + loadConnectivityForVoxelXYZ(xyz); + } + break; + } +} + diff --git a/src/Files/VolumeDynamicConnectivityFile.h b/src/Files/VolumeDynamicConnectivityFile.h new file mode 100644 index 0000000000000000000000000000000000000000..250bdd927d0ee05126d250d0a5a15998bcdfe549 --- /dev/null +++ b/src/Files/VolumeDynamicConnectivityFile.h @@ -0,0 +1,173 @@ +#ifndef __VOLUME_DYNN_CONN_FILE_H__ +#define __VOLUME_DYNN_CONN_FILE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "VolumeFile.h" + + + +namespace caret { + class ConnectivityCorrelation; + class ConnectivityDataLoaded; + + class VolumeDynamicConnectivityFile : public VolumeFile { + + public: + VolumeDynamicConnectivityFile(const VolumeFile* parentVolumeFile); + + virtual ~VolumeDynamicConnectivityFile(); + + VolumeDynamicConnectivityFile(const VolumeDynamicConnectivityFile&) = delete; + + VolumeDynamicConnectivityFile& operator=(const VolumeDynamicConnectivityFile&) = delete; + + void initializeFile(); + + virtual void clear() override; + + virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) override; + + virtual void readFile(const AString& filename) override; + + virtual void writeFile(const AString& filename) override; + + virtual bool supportsWriting() const override; + + VolumeFile* getParentVolumeFile(); + + const VolumeFile* getParentVolumeFile() const; + + bool isDataValid() const; + + bool isEnabledAsLayer() const; + + void setEnabledAsLayer(const bool enabled); + + bool loadConnectivityForVoxelXYZ(const float xyz[3]); + + bool loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], + const std::vector& voxelIndices); + + bool isDataLoadingEnabled() const; + + void setDataLoadingEnabled(const bool enabled); + + const ConnectivityDataLoaded* getConnectivityDataLoaded() const; + + bool matchesDimensions(const int64_t dimI, + const int64_t dimJ, + const int64_t dimK) const; + + VolumeFile* newVolumeFileFromLoadedData(const AString& directoryName, + AString& errorMessageOut); + + // ADD_NEW_METHODS_HERE + + + + + + + protected: + virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) override; + + virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) override; + + private: + void clearPrivateData(); + + void clearVoxels(); + + void getTimePointsForVoxel(const int64_t i, + const int64_t j, + const int64_t k, + std::vector& dataOut) const; + + inline int64_t getVoxelOffset(const int64_t i, + const int64_t j, + const int64_t k, + const int64_t timePointIndex) const { + const int64_t offset = (i + + (j * m_dimI) + + (k * m_sliceStride) + + (timePointIndex * m_timePointIndexStride)); + return offset; + } + + bool loadConnectivityForVoxelIndex(const int64_t ijk[3]); + + bool getConnectivityForVoxelIndex(const int64_t ijk[3], + std::vector& voxelsOut) ; + + ConnectivityCorrelation* getConnectivityCorrelation(); + + + const VolumeFile* m_parentVolumeFile; + + std::unique_ptr m_sceneAssistant; + + std::unique_ptr m_connectivityCorrelation; + + bool m_connectivityCorrelationFailedFlag = false; + + float* m_voxelData = NULL; + + int64_t m_numberOfVoxels = 0; + + int64_t m_sliceStride = 0; + + int64_t m_timePointIndexStride = 0; + + int64_t m_dimI = 0; + + int64_t m_dimJ = 0; + + int64_t m_dimK = 0; + + int64_t m_dimTime = 0; + + AString m_dataLoadedName; + + bool m_validDataFlag = false; + + bool m_enabledAsLayer = true; + + bool m_dataLoadingEnabledFlag = true; + + std::unique_ptr m_connectivityDataLoaded; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __VOLUME_DYNN_CONN_FILE_DECLARE__ + // +#endif // __VOLUME_DYNN_CONN_FILE_DECLARE__ + +} // namespace +#endif //__VOLUME_DYNN_CONN_FILE_H__ diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index a2c20f513d63884c87cbd3a24f4dccfa51a299fe..360abbe5617ea34fc38a37676ec3f90226a7bbc0 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -17,6 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ + +#include #include #include #include @@ -33,6 +35,7 @@ #include "DataFileContentInformation.h" #include "ElapsedTimer.h" #include "EventManager.h" +#include "GiftiLabel.h" #include "GroupAndNameHierarchyModel.h" #include "FastStatistics.h" #include "Histogram.h" @@ -41,6 +44,7 @@ #include "NiftiIO.h" #include "Palette.h" #include "SceneClass.h" +#include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "VolumeFileEditorDelegate.h" #include "VolumeFileVoxelColorizer.h" @@ -53,6 +57,7 @@ using namespace std; const float VolumeFile::INVALID_INTERP_VALUE = 0.0f;//we may want NaN or something more obvious bool VolumeFile::s_voxelColoringEnabled = true; +const AString VolumeFile::s_paletteColorMappingNameInMetaData = "__DYNAMIC_FILE_PALETTE_COLOR_MAPPING__"; /** * Static method that sets the status of voxel coloring. Coloring may take @@ -74,6 +79,19 @@ VolumeFile::setVoxelColoringEnabled(const bool enabled) : "Volume coloring is disabled.")); } +/** protected, used by dynamic volume file */ +VolumeFile::VolumeFile(const DataFileTypeEnum::Enum dataFileType) +: VolumeBase(), CaretMappableDataFile(dataFileType) +{//CaretPointers initialize to NULL, and this isn't an operator= + CaretAssert((dataFileType == DataFileTypeEnum::VOLUME) + || (dataFileType == DataFileTypeEnum::VOLUME_DYNAMIC)); + m_forceUpdateOfGroupAndNameHierarchy = true; + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_chartingEnabledForTab[i] = false; + } + validateMembers(); +} + VolumeFile::VolumeFile() : VolumeBase(), CaretMappableDataFile(DataFileTypeEnum::VOLUME) @@ -196,6 +214,7 @@ VolumeFile::clear() VolumeBase::clear(); m_volumeFileEditorDelegate->clear(); + m_lazyInitializedDynamicConnectivityFile.reset(); } void VolumeFile::readFile(const AString& filename) @@ -332,6 +351,22 @@ VolumeFile::writeFile(const AString& filename) throw DataFileException(filename, "writing multi-component volumes is not currently supported");//its a hassle, and uncommon, and there is only one 3-component type, restricted to 0-255 } + + /* + * Put the child dynamic data-series file's palette in the file's metadata. + */ + if (m_lazyInitializedDynamicConnectivityFile != NULL) { + GiftiMetaData* fileMetaData = m_lazyInitializedDynamicConnectivityFile->getCiftiXML().getFileMetaData(); + CaretAssert(fileMetaData); + if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { + fileMetaData->set(s_paletteColorMappingNameInMetaData, + m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0)->encodeInXML()); + } + else { + fileMetaData->remove(s_paletteColorMappingNameInMetaData); + } + } + updateCaretExtension(); NiftiHeader outHeader;//begin nifti-specific code @@ -405,8 +440,13 @@ float VolumeFile::interpolateValue(const float coordIn1, const float coordIn2, c int64_t ind3high = ind3low + 1; if (!indexValid(ind1low, ind2low, ind3low, brickIndex, component) || !indexValid(ind1high, ind2high, ind3high, brickIndex, component)) { - if (validOut != NULL) *validOut = false; - return INVALID_INTERP_VALUE;//check for valid coord before deconvolving the frame + if (validOut != NULL) *validOut = false;//check for valid coord before deconvolving the frame + if (getType() == SubvolumeAttributes::LABEL) + { + return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); + } else { + return INVALID_INTERP_VALUE; + } } int64_t whichFrame = component * dimensions[3] + brickIndex; validateSpline(brickIndex, component); @@ -426,7 +466,12 @@ float VolumeFile::interpolateValue(const float coordIn1, const float coordIn2, c if (!indexValid(ind1low, ind2low, ind3low, brickIndex, component) || !indexValid(ind1high, ind2high, ind3high, brickIndex, component)) { if (validOut != NULL) *validOut = false; - return INVALID_INTERP_VALUE; + if (getType() == SubvolumeAttributes::LABEL) + { + return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); + } else { + return INVALID_INTERP_VALUE; + } } float xhighWeight = index1 - ind1low; float xlowWeight = 1.0f - xhighWeight; @@ -457,13 +502,23 @@ float VolumeFile::interpolateValue(const float coordIn1, const float coordIn2, c return getValue(index1, index2, index3, brickIndex, component); } else { if (validOut != NULL) *validOut = false; - return INVALID_INTERP_VALUE; + if (getType() == SubvolumeAttributes::LABEL) + { + return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); + } else { + return INVALID_INTERP_VALUE; + } } } break; } - if (validOut != NULL) *validOut = false; - return INVALID_INTERP_VALUE; + if (validOut != NULL) *validOut = false;//this shouldn't be reached unless the enum value is invalid + if (getType() == SubvolumeAttributes::LABEL) + { + return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); + } else { + return INVALID_INTERP_VALUE; + } } void VolumeFile::validateSpline(const int64_t brickIndex, const int64_t component) const @@ -675,17 +730,17 @@ void VolumeFile::validateMembers() if (m_caretVolExt.m_attributes[i]->m_palette == NULL) { m_caretVolExt.m_attributes[i]->m_palette.grabNew(new PaletteColorMapping()); - if (theType == SubvolumeAttributes::ANATOMY) + m_caretVolExt.m_attributes[i]->m_palette->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); + if ((theType == SubvolumeAttributes::ANATOMY) && (numMaps == 1)) { m_caretVolExt.m_attributes[i]->m_palette->setSelectedPaletteName(Palette::GRAY_INTERP_POSITIVE_PALETTE_NAME); - m_caretVolExt.m_attributes[i]->m_palette->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); + } else { + m_caretVolExt.m_attributes[i]->m_palette->setSelectedPaletteName(Palette::ROY_BIG_BL_PALETTE_NAME); } } } } - //setPaletteNormalizationMode(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); - m_singleSliceFlag = false; if ((dimensions[0] == 1) || (dimensions[1] == 1) @@ -755,6 +810,10 @@ VolumeFile::clearModified() for (int32_t i = 0; i < numMaps; i++) { getMapMetaData(i)->clearModified(); } + + if (m_lazyInitializedDynamicConnectivityFile != NULL) { + m_lazyInitializedDynamicConnectivityFile->clearModified(); + } } /** @@ -1255,8 +1314,13 @@ VolumeFile::getPaletteNormalizationModesSupported(std::vectoraddClass(m_classNameHierarchy->saveToScene(sceneAttributes, "m_classNameHierarchy")); } + if (m_lazyInitializedDynamicConnectivityFile != NULL) { + sceneClass->addClass(m_lazyInitializedDynamicConnectivityFile->saveToScene(sceneAttributes, + "m_lazyInitializedDynamicConnectivityFile")); + } } /** @@ -1954,6 +2022,13 @@ VolumeFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, sc); m_forceUpdateOfGroupAndNameHierarchy = false; } + + const SceneClass* dynamicFileSceneClass = sceneClass->getClass("m_lazyInitializedDynamicConnectivityFile"); + if (dynamicFileSceneClass != NULL) { + VolumeDynamicConnectivityFile* denseDynamicFile = getVolumeDynamicConnectivityFile(); + denseDynamicFile->restoreFromScene(sceneAttributes, + dynamicFileSceneClass); + } } /** @@ -1989,18 +2064,55 @@ VolumeFile::addToDataFileContentInformation(DataFileContentInformation& dataFile dimString += AString::number(dims[i]); } dataFileInformation.addNameAndValue("Dimensions", dimString); - const int64_t zero64 = 0; - if (indexValid(zero64, zero64, zero64)) { - float x, y, z; - indexToSpace(zero64, zero64, zero64, x, y, z); - dataFileInformation.addNameAndValue("IJK = (0,0,0)", - ("XYZ = (" - + AString::number(x) - + ", " - + AString::number(y) - + ", " - + AString::number(z) - + ")")); + + if (dims.size() >= 3) { + const int64_t maxI((dims[0] > 1) ? dims[0] - 1 : 0); + const int64_t maxJ((dims[1] > 1) ? dims[1] - 1 : 0); + const int64_t maxK((dims[2] > 1) ? dims[2] - 1 : 0); + int64_t corners[8][3] = { + { 0, 0, 0 }, + { maxI, 0, 0 }, + { maxI, maxJ, 0 }, + { 0, maxJ, 0}, + { 0, 0, maxK }, + { maxI, 0, maxK }, + { maxI, maxJ, maxK }, + { 0, maxJ, maxK} + }; + for (int32_t m = 0; m < 8; m++) { + const int64_t i(corners[m][0]); + const int64_t j(corners[m][1]); + const int64_t k(corners[m][2]); + if (indexValid(i, j, k)) { + float x, y, z; + indexToSpace(i, j, k, x, y, z); + dataFileInformation.addNameAndValue("IJK = (" + + AString::number(i) + + "," + + AString::number(j) + + "," + + AString::number(k) + + ")", + ("XYZ = (" + + AString::number(x) + + ", " + + AString::number(y) + + ", " + + AString::number(z) + + ")")); + } + } + } + + const std::vector>& sform = getVolumeSpace().getSform(); + QString sformName("sform"); + for (const auto& row : sform) { + AString s; + for (const auto element : row) { + s.append(AString::number(element, 'f', 6) + " "); + } + dataFileInformation.addNameAndValue(sformName, s); + sformName.clear(); } BoundingBox boundingBox; @@ -2277,4 +2389,259 @@ VolumeFile::getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) c return BrainordinateMappingMatch::NO; } +/** + * Get the identification information for a surface node in the given maps. + * + * @param mapIndices + * Indices of maps for which identification information is requested. + * @param xyz + * Coordinate of voxel. + * @param ijkOut + * Voxel indices of value. + * @param textOut + * Output containing identification information. + */ +bool +VolumeFile::getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, + const float xyz[3], + int64_t ijkOut[3], + AString& textOut) const +{ + float floatIJK[3]; + spaceToIndex(xyz, floatIJK); + + ijkOut[0] = floatIJK[0]; + ijkOut[1] = floatIJK[1]; + ijkOut[2] = floatIJK[2]; + + bool anyValidFlag = false; + AString valuesText; + for (const auto mapIndex : mapIndices) { + if ( ! valuesText.isEmpty()) { + valuesText.append(", "); + } + bool validFlag(false); + const float value = getVoxelValue(xyz, + &validFlag, + mapIndex); + if (validFlag) { + anyValidFlag = true; + if (isMappedWithLabelTable()) { + const GiftiLabelTable* labelTable = getMapLabelTable(mapIndex); + CaretAssert(labelTable); + const int32_t key = static_cast(value); + const GiftiLabel* label = labelTable->getLabel(key); + if (label != NULL) { + valuesText.append(label->getName()); + } + else { + valuesText.append("?"); + } + } + else { + valuesText.append(AString::number(value, 'f', 3)); + } + } + else { + valuesText.append("invalid"); + } + } + + if (anyValidFlag) { + textOut = valuesText; + return true; + } + + return false; +} + + +/** + * @return The units for the 'interval' between two consecutive maps. + */ +NiftiTimeUnitsEnum::Enum +VolumeFile::getMapIntervalUnits() const +{ + NiftiTimeUnitsEnum::Enum units = NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN; + + if (m_header != NULL && m_header->getType() == AbstractHeader::NIFTI) { + const NiftiHeader& myHeader = *((NiftiHeader*)m_header.getPointer()); + + std::vector dims; + getDimensions(dims); + if (dims.size() >= 4) { + if (dims[3] > 1) { + /* + * Timestep from NiftiHeader is always seconds + */ + const float timeStep = myHeader.getTimeStep(); + if (timeStep > 0.0) { + units = NiftiTimeUnitsEnum::NIFTI_UNITS_SEC; + } + } + } + } + + return units; +} + +/** + * Get the units value for the first map and the + * quantity of units between consecutive maps. If the + * units for the maps is unknown, value of one (1) are + * returned for both output values. + * + * @param firstMapUnitsValueOut + * Output containing units value for first map. + * @param mapIntervalStepValueOut + * Output containing number of units between consecutive maps. + */ +void +VolumeFile::getMapIntervalStartAndStep(float& firstMapUnitsValueOut, + float& mapIntervalStepValueOut) const +{ + firstMapUnitsValueOut = 0.0; + mapIntervalStepValueOut = 1.0; + + if (m_header != NULL && m_header->getType() == AbstractHeader::NIFTI) { + const NiftiHeader& myHeader = *((NiftiHeader*)m_header.getPointer()); + + std::vector dims; + getDimensions(dims); + if (dims.size() >= 4) { + if (dims[3] > 1) { + /* + * Timestep from NiftiHeader is always seconds + */ + const float timeStep = myHeader.getTimeStep(); + if (timeStep > 0.0) { + mapIntervalStepValueOut = timeStep; + } + } + } + } +} + +/** + * @return The volume dynamic connectivity file for a data-series (functional) file + * that contains at least two time points. Note that some files may + * have type anatomy but still contain functional data. + * Will return NULL for other types. + */ +const VolumeDynamicConnectivityFile* +VolumeFile::getVolumeDynamicConnectivityFile() const +{ + VolumeFile* nonConstThis = const_cast(this); + return nonConstThis->getVolumeDynamicConnectivityFile(); +} + +/** + * @return The volume dynamic connectivity file for a data-series (functional) file + * that contains at least two time points. Note that some files may + * have type anatomy but still contain functional data. + * Will return NULL for other types. + */ +VolumeDynamicConnectivityFile* +VolumeFile::getVolumeDynamicConnectivityFile() +{ + if (m_lazyInitializedDynamicConnectivityFile == NULL) { + if ((getType() == SubvolumeAttributes::ANATOMY) + || (getType() == SubvolumeAttributes::FUNCTIONAL)) { + std::vector dims; + getDimensions(dims); + if (dims.size() >= 4) { + const int64_t minimumNumberOfTimePoints(8); + if (dims[3] > minimumNumberOfTimePoints) { + m_lazyInitializedDynamicConnectivityFile.reset(new VolumeDynamicConnectivityFile(this)); + + m_lazyInitializedDynamicConnectivityFile->initializeFile(); + + /* + * Palette for dynamic file is in file metadata + */ + GiftiMetaData* fileMetaData = getFileMetaData(); + const AString encodedPaletteColorMappingString = fileMetaData->get(s_paletteColorMappingNameInMetaData); + if ( ! encodedPaletteColorMappingString.isEmpty()) { + if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { + PaletteColorMapping* pcm = m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0); + CaretAssert(pcm); + pcm->decodeFromStringXML(encodedPaletteColorMappingString); + } + } + + m_lazyInitializedDynamicConnectivityFile->clearModified(); + } + } + } + } + + return m_lazyInitializedDynamicConnectivityFile.get(); +} + +/** + * @return True if any of the maps in this file contain a + * color mapping that possesses a modified status. + */ +bool +VolumeFile::isModifiedPaletteColorMapping() const +{ + /* + * This method is override because we need to know if the + * encapsulated dynamic dense file has a modified palette. + * When restoring a scene, a file with any type of modification + * must be reloaded to remove any modifications. Note that + * when a scene is restored, files that are not modified and + * are in the new scene are NOT reloaded to save time. + */ + if (CaretMappableDataFile::isModifiedPaletteColorMapping()) { + return true; + } + + if (m_lazyInitializedDynamicConnectivityFile != NULL) { + if (m_lazyInitializedDynamicConnectivityFile->isModifiedPaletteColorMapping()) { + return true; + } + } + + return false; +} + +/** + * @return The modified status for aall palettes in this file. + * Note that 'modified' overrides any 'modified by show scene'. + */ +PaletteModifiedStatusEnum::Enum +VolumeFile::getPaletteColorMappingModifiedStatus() const +{ + const std::array fileModStatus = { { + CaretMappableDataFile::getPaletteColorMappingModifiedStatus(), + ((m_lazyInitializedDynamicConnectivityFile != NULL) + ? m_lazyInitializedDynamicConnectivityFile->getPaletteColorMappingModifiedStatus() + : PaletteModifiedStatusEnum::UNMODIFIED) + } }; + + PaletteModifiedStatusEnum::Enum modStatus = PaletteModifiedStatusEnum::UNMODIFIED; + for (auto status : fileModStatus) { + switch (status) { + case PaletteModifiedStatusEnum::MODIFIED: + modStatus = PaletteModifiedStatusEnum::MODIFIED; + break; + case PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE: + modStatus = PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE; + break; + case PaletteModifiedStatusEnum::UNMODIFIED: + break; + } + + if (modStatus == PaletteModifiedStatusEnum::MODIFIED) { + /* + * 'MODIFIED' overrides 'MODIFIED_BY_SHOW_SCENE' + * so no need to continue loop + */ + break; + } + } + + return modStatus; +} diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index b53a6accbcda107e6f1c1c8a083bdff1187908f4..3a8e488c64cc636e7cfe4b5cd2f9e5bf1c8b37bd 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -37,6 +37,7 @@ namespace caret { class GroupAndNameHierarchyModel; + class VolumeDynamicConnectivityFile; class VolumeFileEditorDelegate; class VolumeFileVoxelColorizer; class VolumeSpline; @@ -96,6 +97,8 @@ namespace caret { /** Performs coloring of voxels. Will be NULL if coloring is disabled. */ CaretPointer m_voxelColorizer; + std::unique_ptr m_lazyInitializedDynamicConnectivityFile; + /** True if the volume is a single slice, needed by interpolateValue() methods */ bool m_singleSliceFlag; @@ -123,7 +126,11 @@ namespace caret { CaretPointer m_volumeFileEditorDelegate; + static const AString s_paletteColorMappingNameInMetaData; + protected: + VolumeFile(const DataFileTypeEnum::Enum dataFileType); + virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); @@ -189,9 +196,9 @@ namespace caret { ///returns true if volume space matches in spatial dimensions and sform bool matchesVolumeSpace(const int64_t dims[3], const std::vector >& sform) const; - void readFile(const AString& filename); + virtual void readFile(const AString& filename); - void writeFile(const AString& filename); + virtual void writeFile(const AString& filename); bool isEmpty() const { return VolumeBase::isEmpty(); } @@ -369,6 +376,25 @@ namespace caret { std::vector& dataOut) const override; virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const override; + + virtual bool getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, + const float xyz[3], + int64_t ijkOut[3], + AString& textOut) const; + + virtual NiftiTimeUnitsEnum::Enum getMapIntervalUnits() const override; + + virtual void getMapIntervalStartAndStep(float& firstMapUnitsValueOut, + float& mapIntervalStepValueOut) const override; + + VolumeDynamicConnectivityFile* getVolumeDynamicConnectivityFile(); + + const VolumeDynamicConnectivityFile* getVolumeDynamicConnectivityFile() const; + + virtual bool isModifiedPaletteColorMapping() const override; + + virtual PaletteModifiedStatusEnum::Enum getPaletteColorMappingModifiedStatus() const override; + }; } diff --git a/src/Files/VolumePaddingHelper.cxx b/src/Files/VolumePaddingHelper.cxx index 5cdeecda519d7119e48f618741fc26d96e35f418..4022ad2298989339de4e44f9f9c57cce14c6da98 100644 --- a/src/Files/VolumePaddingHelper.cxx +++ b/src/Files/VolumePaddingHelper.cxx @@ -70,14 +70,14 @@ VolumePaddingHelper VolumePaddingHelper::padMM(const VolumeFile* orig, const flo return padVoxels(orig, ipad, jpad, kpad); } -void VolumePaddingHelper::doPadding(const VolumeFile* orig, VolumeFile* padded, const float& padval) +void VolumePaddingHelper::doPadding(const VolumeFile* orig, VolumeFile* padded, const float& padval) const { CaretAssert(padded != orig); + bool labelMode = (orig->getType() == SubvolumeAttributes::LABEL); if (!orig->matchesVolumeSpace(m_origDims.data(), m_origSform)) throw CaretException("attempted to pad a volume that doesn't match the one initialized with"); vector newdims = m_paddedDims, curdims = orig->getOriginalDimensions(); while (newdims.size() < curdims.size()) newdims.push_back(curdims[newdims.size()]);//add the nonspatial dimensions from orig padded->reinitialize(newdims, m_paddedSform, orig->getNumberOfComponents(), orig->getType()); - vector padframe(m_paddedDims[0] * m_paddedDims[1] * m_paddedDims[2], padval); vector loopdims; orig->getDimensions(loopdims); for (int c = 0; c < loopdims[4]; ++c) @@ -86,7 +86,7 @@ void VolumePaddingHelper::doPadding(const VolumeFile* orig, VolumeFile* padded, { if (c == 0) { - if (orig->getType() == SubvolumeAttributes::LABEL) + if (labelMode) { *(padded->getMapLabelTable(s)) = *(orig->getMapLabelTable(s)); } else { @@ -94,6 +94,9 @@ void VolumePaddingHelper::doPadding(const VolumeFile* orig, VolumeFile* padded, } padded->setMapName(s, orig->getMapName(s)); } + float mypadval = padval; + if (labelMode) mypadval = orig->getMapLabelTable(s)->getUnassignedLabelKey(); + vector padframe(m_paddedDims[0] * m_paddedDims[1] * m_paddedDims[2], mypadval); int64_t ijk[3], inIndex = 0;//we scan the frame linearly, so we can do this const float* inFrame = orig->getFrame(s, c); for (ijk[2] = 0; ijk[2] < m_origDims[2]; ++ijk[2]) @@ -113,7 +116,7 @@ void VolumePaddingHelper::doPadding(const VolumeFile* orig, VolumeFile* padded, } } -void VolumePaddingHelper::undoPadding(const VolumeFile* padded, VolumeFile* orig) +void VolumePaddingHelper::undoPadding(const VolumeFile* padded, VolumeFile* orig) const { CaretAssert(orig != padded); if (!padded->matchesVolumeSpace(m_paddedDims.data(), m_paddedSform)) throw CaretException("attempted to unpad a volume that doesn't match padding"); diff --git a/src/Files/VolumePaddingHelper.h b/src/Files/VolumePaddingHelper.h index 3104913f9bb0341a3f4e60767dd918cf7d889c2a..b4d3542b5e5eb42e0de6095e81d8fd6261edd28b 100644 --- a/src/Files/VolumePaddingHelper.h +++ b/src/Files/VolumePaddingHelper.h @@ -37,8 +37,9 @@ namespace caret { VolumePaddingHelper() { } static VolumePaddingHelper padMM(const VolumeFile* orig, const float& mmpad); static VolumePaddingHelper padVoxels(const VolumeFile* orig, const int& ipad, const int& jpad, const int& kpad); - void doPadding(const VolumeFile* orig, VolumeFile* padded, const float& padval = 0.0f); - void undoPadding(const VolumeFile* padded, VolumeFile* orig); + void getPadding(int& ipad, int& jpad, int& kpad) const { ipad = m_ipad; jpad = m_jpad; kpad = m_kpad; } + void doPadding(const VolumeFile* orig, VolumeFile* padded, const float& padval = 0.0f) const; + void undoPadding(const VolumeFile* padded, VolumeFile* orig) const; }; } diff --git a/src/FilesBase/GiftiMetaData.cxx b/src/FilesBase/GiftiMetaData.cxx index fd7747b41498c7283487ad3df0c0142405601203..ca67eac6ff7b25ea3a76ef30935e1e6d494495cc 100644 --- a/src/FilesBase/GiftiMetaData.cxx +++ b/src/FilesBase/GiftiMetaData.cxx @@ -557,6 +557,11 @@ void GiftiMetaData::writeBorderFileXML3(QXmlStreamWriter& xmlWriter) const writeCiftiXML1(xmlWriter); } +void GiftiMetaData::writeSceneFile3(QXmlStreamWriter& xmlWriter) const +{ + writeCiftiXML1(xmlWriter); +} + void GiftiMetaData::readCiftiXML1(QXmlStreamReader& xml) { clear(false); @@ -593,6 +598,11 @@ void GiftiMetaData::readBorderFileXML3(QXmlStreamReader& xml) readCiftiXML1(xml); } +void GiftiMetaData::readSceneFile3(QXmlStreamReader& xml) +{ + readCiftiXML1(xml); +} + void GiftiMetaData::readEntry(QXmlStreamReader& xml) { AString key, value; diff --git a/src/FilesBase/GiftiMetaData.h b/src/FilesBase/GiftiMetaData.h index a98f3724c16b0edb78060a142e7d438d07573e11..1076fd73d5359978bd676ed94097141c76780f2c 100644 --- a/src/FilesBase/GiftiMetaData.h +++ b/src/FilesBase/GiftiMetaData.h @@ -121,6 +121,9 @@ public: void readBorderFileXML1(QXmlStreamReader& xml); void readBorderFileXML3(QXmlStreamReader& xml); + void readSceneFile3(QXmlStreamReader& xml); + void writeSceneFile3(QXmlStreamWriter& xmlWriter) const; + void setModified(); void clearModified(); diff --git a/src/FilesBase/VolumeSpace.h b/src/FilesBase/VolumeSpace.h index 0afc6be39f9f3339701efc8f6207e6bb109370a4..40b512cd3bbf87d930bd9cb4c869c3d0b69d7de4 100644 --- a/src/FilesBase/VolumeSpace.h +++ b/src/FilesBase/VolumeSpace.h @@ -24,6 +24,7 @@ #include "CaretAssert.h" #include "Vector3D.h" +#include "VoxelIJK.h" #include #include @@ -86,6 +87,21 @@ namespace caret inline void indexToSpace(const T* indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const { indexToSpace(indexIn[0], indexIn[1], indexIn[2], coordOut1, coordOut2, coordOut3); } + ///output a Vector3D for three indices + template + inline Vector3D indexToSpace(const T& indexIn1, const T& indexIn2, const T& indexIn3) const + { Vector3D coords; indexToSpace(indexIn1, indexIn2, indexIn3, coords); return coords; } + + ///output a Vector3D for an index triplet + template + inline Vector3D indexToSpace(const T* indexIn) const + { Vector3D coords; indexToSpace(indexIn, coords); return coords; } + + ///convenience methods to use VoxelIJK without .m_ijk + inline Vector3D indexToSpace(const VoxelIJK indexIn) const { return indexToSpace(indexIn.m_ijk); } + inline void indexToSpace(const VoxelIJK indexIn, float* coordOut) const { indexToSpace(indexIn.m_ijk, coordOut); } + inline void indexToSpace(const VoxelIJK indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const { indexToSpace(indexIn.m_ijk, coordOut1, coordOut2, coordOut3); } + ///returns three coordinates of three indices template void indexToSpace(const T& indexIn1, const T& indexIn2, const T& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const; diff --git a/src/GLMath/glm/CMakeLists.txt b/src/GLMath/glm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..032340d47a5d9743b2004b20e1eada692fff765f --- /dev/null +++ b/src/GLMath/glm/CMakeLists.txt @@ -0,0 +1,66 @@ +file(GLOB ROOT_SOURCE *.cpp) +file(GLOB ROOT_INLINE *.inl) +file(GLOB ROOT_HEADER *.hpp) +file(GLOB ROOT_TEXT ../*.txt) +file(GLOB ROOT_MD ../*.md) +file(GLOB ROOT_NAT ../util/glm.natvis) + +file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp) +file(GLOB_RECURSE CORE_INLINE ./detail/*.inl) +file(GLOB_RECURSE CORE_HEADER ./detail/*.hpp) + +file(GLOB_RECURSE EXT_SOURCE ./ext/*.cpp) +file(GLOB_RECURSE EXT_INLINE ./ext/*.inl) +file(GLOB_RECURSE EXT_HEADER ./ext/*.hpp) + +file(GLOB_RECURSE GTC_SOURCE ./gtc/*.cpp) +file(GLOB_RECURSE GTC_INLINE ./gtc/*.inl) +file(GLOB_RECURSE GTC_HEADER ./gtc/*.hpp) + +file(GLOB_RECURSE GTX_SOURCE ./gtx/*.cpp) +file(GLOB_RECURSE GTX_INLINE ./gtx/*.inl) +file(GLOB_RECURSE GTX_HEADER ./gtx/*.hpp) + +file(GLOB_RECURSE SIMD_SOURCE ./simd/*.cpp) +file(GLOB_RECURSE SIMD_INLINE ./simd/*.inl) +file(GLOB_RECURSE SIMD_HEADER ./simd/*.h) + +source_group("Text Files" FILES ${ROOT_TEXT} ${ROOT_MD}) +source_group("Core Files" FILES ${CORE_SOURCE}) +source_group("Core Files" FILES ${CORE_INLINE}) +source_group("Core Files" FILES ${CORE_HEADER}) +source_group("EXT Files" FILES ${EXT_SOURCE}) +source_group("EXT Files" FILES ${EXT_INLINE}) +source_group("EXT Files" FILES ${EXT_HEADER}) +source_group("GTC Files" FILES ${GTC_SOURCE}) +source_group("GTC Files" FILES ${GTC_INLINE}) +source_group("GTC Files" FILES ${GTC_HEADER}) +source_group("GTX Files" FILES ${GTX_SOURCE}) +source_group("GTX Files" FILES ${GTX_INLINE}) +source_group("GTX Files" FILES ${GTX_HEADER}) +source_group("SIMD Files" FILES ${SIMD_SOURCE}) +source_group("SIMD Files" FILES ${SIMD_INLINE}) +source_group("SIMD Files" FILES ${SIMD_HEADER}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +if(BUILD_STATIC_LIBS) +add_library(glm_static STATIC ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} + ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} + ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} + ${EXT_SOURCE} ${EXT_INLINE} ${EXT_HEADER} + ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} + ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} + ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) +endif() + +if(BUILD_SHARED_LIBS) +add_library(glm_shared SHARED ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} + ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} + ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} + ${EXT_SOURCE} ${EXT_INLINE} ${EXT_HEADER} + ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} + ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} + ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) +endif() + diff --git a/src/GLMath/glm/common.hpp b/src/GLMath/glm/common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1f923aac2ae9cb1e5ed62b2a093843a3fccb5c46 --- /dev/null +++ b/src/GLMath/glm/common.hpp @@ -0,0 +1,539 @@ +/// @ref core +/// @file glm/common.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.3 Common Functions +/// +/// @defgroup core_func_common Common functions +/// @ingroup core +/// +/// Provides GLSL common functions +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/qualifier.hpp" +#include "detail/_fixes.hpp" + +namespace glm +{ + /// @addtogroup core_func_common + /// @{ + + /// Returns x if x >= 0; otherwise, it returns -x. + /// + /// @tparam genType floating-point or signed integer; scalar or vector types. + /// + /// @see GLSL abs man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType abs(genType x); + + /// Returns x if x >= 0; otherwise, it returns -x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL abs man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec abs(vec const& x); + + /// Returns 1.0 if x > 0, 0.0 if x == 0, or -1.0 if x < 0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sign man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec sign(vec const& x); + + /// Returns a value equal to the nearest integer that is less then or equal to x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floor man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floor(vec const& x); + + /// Returns a value equal to the nearest integer to x + /// whose absolute value is not larger than the absolute value of x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL trunc man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec trunc(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// This includes the possibility that round(x) returns the + /// same value as roundEven(x) for all values of x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL round man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec round(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// A fractional part of 0.5 will round toward the nearest even + /// integer. (Both 3.5 and 4.5 for x will return 4.0.) + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL roundEven man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// @see New round to even technique + template + GLM_FUNC_DECL vec roundEven(vec const& x); + + /// Returns a value equal to the nearest integer + /// that is greater than or equal to x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL ceil man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec ceil(vec const& x); + + /// Return x - floor(x). + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL fract man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType fract(genType x); + + /// Return x - floor(x). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL fract man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec fract(vec const& x); + + template + GLM_FUNC_DECL genType mod(genType x, genType y); + + template + GLM_FUNC_DECL vec mod(vec const& x, T y); + + /// Modulus. Returns x - y * floor(x / y) + /// for each component in x using the floating point value y. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types, include glm/gtc/integer for integer scalar types support + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL mod man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec mod(vec const& x, vec const& y); + + /// Returns the fractional part of x and sets i to the integer + /// part (as a whole number floating point value). Both the + /// return value and the output parameter will have the same + /// sign as x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL modf man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType modf(genType x, genType& i); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType min(genType x, genType y); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, T y); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, vec const& y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType max(genType x, genType y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, T y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal); + + /// If genTypeU is a floating scalar or vector: + /// Returns x * (1.0 - a) + y * a, i.e., the linear blend of + /// x and y using the floating-point value a. + /// The value for a is not restricted to the range [0, 1]. + /// + /// If genTypeU is a boolean scalar or vector: + /// Selects which vector each returned component comes + /// from. For a component of 'a' that is false, the + /// corresponding component of 'x' is returned. For a + /// component of 'a' that is true, the corresponding + /// component of 'y' is returned. Components of 'x' and 'y' that + /// are not selected are allowed to be invalid floating point + /// values and will have no effect on the results. Thus, this + /// provides different functionality than + /// genType mix(genType x, genType y, genType(a)) + /// where a is a Boolean vector. + /// + /// @see GLSL mix man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// + /// @param[in] x Value to interpolate. + /// @param[in] y Value to interpolate. + /// @param[in] a Interpolant. + /// + /// @tparam genTypeT Floating point scalar or vector. + /// @tparam genTypeU Floating point or boolean scalar or vector. It can't be a vector if it is the length of genTypeT. + /// + /// @code + /// #include + /// ... + /// float a; + /// bool b; + /// glm::dvec3 e; + /// glm::dvec3 f; + /// glm::vec4 g; + /// glm::vec4 h; + /// ... + /// glm::vec4 r = glm::mix(g, h, a); // Interpolate with a floating-point scalar two vectors. + /// glm::vec4 s = glm::mix(g, h, b); // Returns g or h; + /// glm::dvec3 t = glm::mix(e, f, a); // Types of the third parameter is not required to match with the first and the second. + /// glm::vec4 u = glm::mix(g, h, r); // Interpolations can be perform per component with a vector for the last parameter. + /// @endcode + template + GLM_FUNC_DECL genTypeT mix(genTypeT x, genTypeT y, genTypeU a); + + template + GLM_FUNC_DECL vec mix(vec const& x, vec const& y, vec const& a); + + template + GLM_FUNC_DECL vec mix(vec const& x, vec const& y, U a); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a genType. + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType step(genType edge, genType x); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec step(T edge, vec const& x); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec step(vec const& edge, vec const& x); + + /// Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and + /// performs smooth Hermite interpolation between 0 and 1 + /// when edge0 < x < edge1. This is useful in cases where + /// you would want a threshold function with a smooth + /// transition. This is equivalent to: + /// genType t; + /// t = clamp ((x - edge0) / (edge1 - edge0), 0, 1); + /// return t * t * (3 - 2 * t); + /// Results are undefined if edge0 >= edge1. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL smoothstep man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType smoothstep(genType edge0, genType edge1, genType x); + + template + GLM_FUNC_DECL vec smoothstep(T edge0, T edge1, vec const& x); + + template + GLM_FUNC_DECL vec smoothstep(vec const& edge0, vec const& edge1, vec const& x); + + /// Returns true if x holds a NaN (not a number) + /// representation in the underlying implementation's set of + /// floating point representations. Returns false otherwise, + /// including for implementations with no NaN + /// representations. + /// + /// /!\ When using compiler fast math, this function may fail. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL isnan man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec isnan(vec const& x); + + /// Returns true if x holds a positive infinity or negative + /// infinity representation in the underlying implementation's + /// set of floating point representations. Returns false + /// otherwise, including for implementations with no infinity + /// representations. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL isinf man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec isinf(vec const& x); + + /// Returns a signed integer value representing + /// the encoding of a floating-point value. The floating-point + /// value's bit-level representation is preserved. + /// + /// @see GLSL floatBitsToInt man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL int floatBitsToInt(float const& v); + + /// Returns a signed integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floatBitsToInt man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floatBitsToInt(vec const& v); + + /// Returns a unsigned integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @see GLSL floatBitsToUint man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL uint floatBitsToUint(float const& v); + + /// Returns a unsigned integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floatBitsToUint man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floatBitsToUint(vec const& v); + + /// Returns a floating-point value corresponding to a signed + /// integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @see GLSL intBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL float intBitsToFloat(int const& v); + + /// Returns a floating-point value corresponding to a signed + /// integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL intBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec intBitsToFloat(vec const& v); + + /// Returns a floating-point value corresponding to a + /// unsigned integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @see GLSL uintBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL float uintBitsToFloat(uint const& v); + + /// Returns a floating-point value corresponding to a + /// unsigned integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL uintBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec uintBitsToFloat(vec const& v); + + /// Computes and returns a * b + c. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL fma man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType fma(genType const& a, genType const& b, genType const& c); + + /// Splits x into a floating-point significand in the range + /// [0.5, 1.0) and an integral exponent of two, such that: + /// x = significand * exp(2, exponent) + /// + /// The significand is returned by the function and the + /// exponent is returned in the parameter exp. For a + /// floating-point value of zero, the significant and exponent + /// are both zero. For a floating-point value that is an + /// infinity or is not a number, the results are undefined. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL frexp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType frexp(genType const& x, genIType& exp); + + template + GLM_FUNC_DECL vec frexp(vec const& v, vec& exp); + + /// Builds a floating-point number from x and the + /// corresponding integral exponent of two in exp, returning: + /// significand * exp(2, exponent) + /// + /// If this product is too large to be represented in the + /// floating-point type, the result is undefined. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL ldexp man page; + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType ldexp(genType const& x, genIType const& exp); + + template + GLM_FUNC_DECL vec ldexp(vec const& v, vec const& exp); + + /// @} +}//namespace glm + +#include "detail/func_common.inl" + diff --git a/src/GLMath/glm/detail/_features.hpp b/src/GLMath/glm/detail/_features.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b0cbe9ff02cf50fc8a2e298998efabe59a9b07ea --- /dev/null +++ b/src/GLMath/glm/detail/_features.hpp @@ -0,0 +1,394 @@ +#pragma once + +// #define GLM_CXX98_EXCEPTIONS +// #define GLM_CXX98_RTTI + +// #define GLM_CXX11_RVALUE_REFERENCES +// Rvalue references - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html + +// GLM_CXX11_TRAILING_RETURN +// Rvalue references for *this - GCC not supported +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Initialization of class objects by rvalues - GCC any +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Non-static data member initializers - GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm + +// #define GLM_CXX11_VARIADIC_TEMPLATE +// Variadic templates - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf + +// +// Extending variadic template template parameters - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf + +// #define GLM_CXX11_GENERALIZED_INITIALIZERS +// Initializer lists - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm + +// #define GLM_CXX11_STATIC_ASSERT +// Static assertions - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html + +// #define GLM_CXX11_AUTO_TYPE +// auto-typed variables - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Multi-declarator auto - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Removal of auto as a storage-class specifier - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm + +// #define GLM_CXX11_AUTO_TYPE +// New function declarator syntax - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm + +// #define GLM_CXX11_LAMBDAS +// New wording for C++0x lambdas - GCC 4.5 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf + +// #define GLM_CXX11_DECLTYPE +// Declared type of an expression - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf + +// +// Right angle brackets - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html + +// +// Default template arguments for function templates DR226 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226 + +// +// Solving the SFINAE problem for expressions DR339 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html + +// #define GLM_CXX11_ALIAS_TEMPLATE +// Template aliases N2258 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf + +// +// Extern templates N1987 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm + +// #define GLM_CXX11_NULLPTR +// Null pointer constant N2431 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf + +// #define GLM_CXX11_STRONG_ENUMS +// Strongly-typed enums N2347 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf + +// +// Forward declarations for enums N2764 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf + +// +// Generalized attributes N2761 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf + +// +// Generalized constant expressions N2235 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf + +// +// Alignment support N2341 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf + +// #define GLM_CXX11_DELEGATING_CONSTRUCTORS +// Delegating constructors N1986 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf + +// +// Inheriting constructors N2540 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm + +// #define GLM_CXX11_EXPLICIT_CONVERSIONS +// Explicit conversion operators N2437 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf + +// +// New character types N2249 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html + +// +// Unicode string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Raw string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Universal character name literals N2170 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html + +// #define GLM_CXX11_USER_LITERALS +// User-defined literals N2765 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf + +// +// Standard Layout Types N2342 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm + +// #define GLM_CXX11_DEFAULTED_FUNCTIONS +// #define GLM_CXX11_DELETED_FUNCTIONS +// Defaulted and deleted functions N2346 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm + +// +// Extended friend declarations N1791 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf + +// +// Extending sizeof N2253 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html + +// #define GLM_CXX11_INLINE_NAMESPACES +// Inline namespaces N2535 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm + +// #define GLM_CXX11_UNRESTRICTED_UNIONS +// Unrestricted unions N2544 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + +// #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +// Local and unnamed types as template arguments N2657 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm + +// #define GLM_CXX11_RANGE_FOR +// Range-based for N2930 GCC 4.6 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html + +// #define GLM_CXX11_OVERRIDE_CONTROL +// Explicit virtual overrides N2928 N3206 N3272 GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm + +// +// Minimal support for garbage collection and reachability-based leak detection N2670 No +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm + +// #define GLM_CXX11_NOEXCEPT +// Allowing move constructors to throw [noexcept] N3050 GCC 4.6 (core language only) +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html + +// +// Defining move special member functions N3053 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html + +// +// Sequence points N2239 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Atomic operations N2427 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Strong Compare and Exchange N2748 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html + +// +// Bidirectional Fences N2752 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm + +// +// Memory model N2429 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm + +// +// Data-dependency ordering: atomics and memory model N2664 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm + +// +// Propagating exceptions N2179 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html + +// +// Abandoning a process and at_quick_exit N2440 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm + +// +// Allow atomics use in signal handlers N2547 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm + +// +// Thread-local storage N2659 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm + +// +// Dynamic initialization and destruction with concurrency N2660 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm + +// +// __func__ predefined identifier N2340 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm + +// +// C99 preprocessor N1653 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm + +// +// long long N1811 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf + +// +// Extended integral types N1988 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf + +#if(GLM_COMPILER & GLM_COMPILER_GCC) + +# define GLM_CXX11_STATIC_ASSERT + +#elif(GLM_COMPILER & GLM_COMPILER_CLANG) +# if(__has_feature(cxx_exceptions)) +# define GLM_CXX98_EXCEPTIONS +# endif + +# if(__has_feature(cxx_rtti)) +# define GLM_CXX98_RTTI +# endif + +# if(__has_feature(cxx_access_control_sfinae)) +# define GLM_CXX11_ACCESS_CONTROL_SFINAE +# endif + +# if(__has_feature(cxx_alias_templates)) +# define GLM_CXX11_ALIAS_TEMPLATE +# endif + +# if(__has_feature(cxx_alignas)) +# define GLM_CXX11_ALIGNAS +# endif + +# if(__has_feature(cxx_attributes)) +# define GLM_CXX11_ATTRIBUTES +# endif + +# if(__has_feature(cxx_constexpr)) +# define GLM_CXX11_CONSTEXPR +# endif + +# if(__has_feature(cxx_decltype)) +# define GLM_CXX11_DECLTYPE +# endif + +# if(__has_feature(cxx_default_function_template_args)) +# define GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_defaulted_functions)) +# define GLM_CXX11_DEFAULTED_FUNCTIONS +# endif + +# if(__has_feature(cxx_delegating_constructors)) +# define GLM_CXX11_DELEGATING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_deleted_functions)) +# define GLM_CXX11_DELETED_FUNCTIONS +# endif + +# if(__has_feature(cxx_explicit_conversions)) +# define GLM_CXX11_EXPLICIT_CONVERSIONS +# endif + +# if(__has_feature(cxx_generalized_initializers)) +# define GLM_CXX11_GENERALIZED_INITIALIZERS +# endif + +# if(__has_feature(cxx_implicit_moves)) +# define GLM_CXX11_IMPLICIT_MOVES +# endif + +# if(__has_feature(cxx_inheriting_constructors)) +# define GLM_CXX11_INHERITING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_inline_namespaces)) +# define GLM_CXX11_INLINE_NAMESPACES +# endif + +# if(__has_feature(cxx_lambdas)) +# define GLM_CXX11_LAMBDAS +# endif + +# if(__has_feature(cxx_local_type_template_args)) +# define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_noexcept)) +# define GLM_CXX11_NOEXCEPT +# endif + +# if(__has_feature(cxx_nonstatic_member_init)) +# define GLM_CXX11_NONSTATIC_MEMBER_INIT +# endif + +# if(__has_feature(cxx_nullptr)) +# define GLM_CXX11_NULLPTR +# endif + +# if(__has_feature(cxx_override_control)) +# define GLM_CXX11_OVERRIDE_CONTROL +# endif + +# if(__has_feature(cxx_reference_qualified_functions)) +# define GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS +# endif + +# if(__has_feature(cxx_range_for)) +# define GLM_CXX11_RANGE_FOR +# endif + +# if(__has_feature(cxx_raw_string_literals)) +# define GLM_CXX11_RAW_STRING_LITERALS +# endif + +# if(__has_feature(cxx_rvalue_references)) +# define GLM_CXX11_RVALUE_REFERENCES +# endif + +# if(__has_feature(cxx_static_assert)) +# define GLM_CXX11_STATIC_ASSERT +# endif + +# if(__has_feature(cxx_auto_type)) +# define GLM_CXX11_AUTO_TYPE +# endif + +# if(__has_feature(cxx_strong_enums)) +# define GLM_CXX11_STRONG_ENUMS +# endif + +# if(__has_feature(cxx_trailing_return)) +# define GLM_CXX11_TRAILING_RETURN +# endif + +# if(__has_feature(cxx_unicode_literals)) +# define GLM_CXX11_UNICODE_LITERALS +# endif + +# if(__has_feature(cxx_unrestricted_unions)) +# define GLM_CXX11_UNRESTRICTED_UNIONS +# endif + +# if(__has_feature(cxx_user_literals)) +# define GLM_CXX11_USER_LITERALS +# endif + +# if(__has_feature(cxx_variadic_templates)) +# define GLM_CXX11_VARIADIC_TEMPLATES +# endif + +#endif//(GLM_COMPILER & GLM_COMPILER_CLANG) diff --git a/src/GLMath/glm/detail/_fixes.hpp b/src/GLMath/glm/detail/_fixes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a503c7c0d041a9df14c88e391fee1b26b615f2c7 --- /dev/null +++ b/src/GLMath/glm/detail/_fixes.hpp @@ -0,0 +1,27 @@ +#include + +//! Workaround for compatibility with other libraries +#ifdef max +#undef max +#endif + +//! Workaround for compatibility with other libraries +#ifdef min +#undef min +#endif + +//! Workaround for Android +#ifdef isnan +#undef isnan +#endif + +//! Workaround for Android +#ifdef isinf +#undef isinf +#endif + +//! Workaround for Chrone Native Client +#ifdef log2 +#undef log2 +#endif + diff --git a/src/GLMath/glm/detail/_noise.hpp b/src/GLMath/glm/detail/_noise.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5a874a02221f1c5eaa0ed393d9f24aec3be898c5 --- /dev/null +++ b/src/GLMath/glm/detail/_noise.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "../common.hpp" + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER T mod289(T const& x) + { + return x - floor(x * (static_cast(1.0) / static_cast(289.0))) * static_cast(289.0); + } + + template + GLM_FUNC_QUALIFIER T permute(T const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> permute(vec<2, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> permute(vec<3, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> permute(vec<4, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER T taylorInvSqrt(T const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> taylorInvSqrt(vec<2, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> taylorInvSqrt(vec<3, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> taylorInvSqrt(vec<4, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> fade(vec<2, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> fade(vec<3, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> fade(vec<4, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } +}//namespace detail +}//namespace glm + diff --git a/src/GLMath/glm/detail/_swizzle.hpp b/src/GLMath/glm/detail/_swizzle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..87896ef4f6f25e5d336a74c98b8369adea378e80 --- /dev/null +++ b/src/GLMath/glm/detail/_swizzle.hpp @@ -0,0 +1,804 @@ +#pragma once + +namespace glm{ +namespace detail +{ + // Internal class for implementing swizzle operators + template + struct _swizzle_base0 + { + protected: + GLM_FUNC_QUALIFIER T& elem(size_t i){ return (reinterpret_cast(_buffer))[i]; } + GLM_FUNC_QUALIFIER T const& elem(size_t i) const{ return (reinterpret_cast(_buffer))[i]; } + + // Use an opaque buffer to *ensure* the compiler doesn't call a constructor. + // The size 1 buffer is assumed to aligned to the actual members so that the + // elem() + char _buffer[1]; + }; + + template + struct _swizzle_base1 : public _swizzle_base0 + { + }; + + template + struct _swizzle_base1<2, T, Q, E0,E1,-1,-2, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<2, T, Q> operator ()() const { return vec<2, T, Q>(this->elem(E0), this->elem(E1)); } + }; + + template + struct _swizzle_base1<3, T, Q, E0,E1,E2,-1, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<3, T, Q> operator ()() const { return vec<3, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2)); } + }; + + template + struct _swizzle_base1<4, T, Q, E0,E1,E2,E3, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, T, Q> operator ()() const { return vec<4, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2), this->elem(E3)); } + }; + + // Internal class for implementing swizzle operators + /* + Template parameters: + + T = type of scalar values (e.g. float, double) + N = number of components in the vector (e.g. 3) + E0...3 = what index the n-th element of this swizzle refers to in the unswizzled vec + + DUPLICATE_ELEMENTS = 1 if there is a repeated element, 0 otherwise (used to specialize swizzles + containing duplicate elements so that they cannot be used as r-values). + */ + template + struct _swizzle_base2 : public _swizzle_base1::value> + { + struct op_equal + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e = t; } + }; + + struct op_minus + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e -= t; } + }; + + struct op_plus + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e += t; } + }; + + struct op_mul + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e *= t; } + }; + + struct op_div + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e /= t; } + }; + + public: + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (const T& t) + { + for (int i = 0; i < N; ++i) + (*this)[i] = t; + return *this; + } + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (vec const& that) + { + _apply_op(that, op_equal()); + return *this; + } + + GLM_FUNC_QUALIFIER void operator -= (vec const& that) + { + _apply_op(that, op_minus()); + } + + GLM_FUNC_QUALIFIER void operator += (vec const& that) + { + _apply_op(that, op_plus()); + } + + GLM_FUNC_QUALIFIER void operator *= (vec const& that) + { + _apply_op(that, op_mul()); + } + + GLM_FUNC_QUALIFIER void operator /= (vec const& that) + { + _apply_op(that, op_div()); + } + + GLM_FUNC_QUALIFIER T& operator[](size_t i) + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + GLM_FUNC_QUALIFIER T operator[](size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + + protected: + template + GLM_FUNC_QUALIFIER void _apply_op(vec const& that, const U& op) + { + // Make a copy of the data in this == &that. + // The copier should optimize out the copy in cases where the function is + // properly inlined and the copy is not necessary. + T t[N]; + for (int i = 0; i < N; ++i) + t[i] = that[i]; + for (int i = 0; i < N; ++i) + op( (*this)[i], t[i] ); + } + }; + + // Specialization for swizzles containing duplicate elements. These cannot be modified. + template + struct _swizzle_base2 : public _swizzle_base1::value> + { + struct Stub {}; + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (Stub const&) { return *this; } + + GLM_FUNC_QUALIFIER T operator[] (size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + }; + + template + struct _swizzle : public _swizzle_base2 + { + typedef _swizzle_base2 base_type; + + using base_type::operator=; + + GLM_FUNC_QUALIFIER operator vec () const { return (*this)(); } + }; + +// +// To prevent the C++ syntax from getting entirely overwhelming, define some alias macros +// +#define GLM_SWIZZLE_TEMPLATE1 template +#define GLM_SWIZZLE_TEMPLATE2 template +#define GLM_SWIZZLE_TYPE1 _swizzle +#define GLM_SWIZZLE_TYPE2 _swizzle + +// +// Wrapper for a binary operator (e.g. u.yy + v.zy) +// +#define GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ + { \ + return a() OPERAND b(); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const vec& b) \ + { \ + return a() OPERAND b; \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const vec& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Wrapper for a operand between a swizzle and a binary (e.g. 1.0f - u.xyz) +// +#define GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const T& b) \ + { \ + return a() OPERAND b; \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const T& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Macro for wrapping a function taking one argument (e.g. abs()) +// +#define GLM_SWIZZLE_FUNCTION_1_ARGS(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a) \ + { \ + return FUNCTION(a()); \ + } + +// +// Macro for wrapping a function taking two vector arguments (e.g. dot()). +// +#define GLM_SWIZZLE_FUNCTION_2_ARGS(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename V& b) \ + { \ + return FUNCTION(a(), b); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const V& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a, b()); \ + } + +// +// Macro for wrapping a function take 2 vec arguments followed by a scalar (e.g. mix()). +// +#define GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename S0::vec_type& b, const T& c)\ + { \ + return FUNCTION(a(), b, c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const typename V& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a, b(), c); \ + } + +}//namespace detail +}//namespace glm + +namespace glm +{ + namespace detail + { + GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(-) + GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(*) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(+) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(-) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(*) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(/) + } + + // + // Swizzles are distinct types from the unswizzled type. The below macros will + // provide template specializations for the swizzle types for the given functions + // so that the compiler does not have any ambiguity to choosing how to handle + // the function. + // + // The alternative is to use the operator()() when calling the function in order + // to explicitly convert the swizzled type to the unswizzled type. + // + + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, abs); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acos); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acosh); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, all); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, any); + + //GLM_SWIZZLE_FUNCTION_2_ARGS(value_type, dot); + //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, cross); + //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, step); + //GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(vec_type, mix); +} + +#define GLM_SWIZZLE2_2_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<2, T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2, T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2, T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2, T, Q, 1,1,-1,-2> E1 ## E1; }; + +#define GLM_SWIZZLE2_3_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<3,T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; + +#define GLM_SWIZZLE2_4_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; + +#define GLM_SWIZZLE3_2_MEMBERS(T, Q, E0,E1,E2) \ + struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; + +#define GLM_SWIZZLE3_3_MEMBERS(T, Q ,E0,E1,E2) \ + struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; + +#define GLM_SWIZZLE3_4_MEMBERS(T, Q, E0,E1,E2) \ + struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; + +#define GLM_SWIZZLE4_2_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 0,3,-1,-2> E0 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 1,3,-1,-2> E1 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 2,3,-1,-2> E2 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 3,0,-1,-2> E3 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 3,1,-1,-2> E3 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 3,2,-1,-2> E3 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 3,3,-1,-2> E3 ## E3; }; + +#define GLM_SWIZZLE4_3_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,3,-1> E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,3,-1> E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,3,-1> E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,0,-1> E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,1,-1> E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,2,-1> E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,3,-1> E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,3,-1> E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,3,-1> E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,3,-1> E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,0,-1> E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,1,-1> E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,2,-1> E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,3,-1> E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,3,-1> E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,3,-1> E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,3,-1> E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,0,-1> E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,1,-1> E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,2,-1> E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,3,-1> E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,0,-1> E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,1,-1> E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,2,-1> E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,3,-1> E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,0,-1> E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,1,-1> E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,2,-1> E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,3,-1> E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,0,-1> E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,1,-1> E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,2,-1> E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,3,-1> E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,0,-1> E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,1,-1> E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,2,-1> E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,3,-1> E3 ## E3 ## E3; }; + +#define GLM_SWIZZLE4_4_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<4, T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,3> E0 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,3> E0 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,3> E0 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,0> E0 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,1> E0 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,2> E0 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,3> E0 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,3> E0 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,3> E0 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,3> E0 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,0> E0 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,1> E0 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,2> E0 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,3> E0 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,3> E0 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,3> E0 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,3> E0 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,0> E0 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,1> E0 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,2> E0 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,3> E0 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,0> E0 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,1> E0 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,2> E0 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,3> E0 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,0> E0 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,1> E0 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,2> E0 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,3> E0 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,0> E0 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,1> E0 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,2> E0 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,3> E0 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,0> E0 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,1> E0 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,2> E0 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,3> E0 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,3> E1 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,3> E1 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,3> E1 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,0> E1 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,1> E1 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,2> E1 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,3> E1 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,3> E1 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,3> E1 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,3> E1 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,0> E1 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,1> E1 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,2> E1 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,3> E1 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,3> E1 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,3> E1 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,3> E1 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,0> E1 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,1> E1 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,2> E1 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,3> E1 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,0> E1 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,1> E1 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,2> E1 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,3> E1 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,0> E1 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,1> E1 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,2> E1 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,3> E1 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,0> E1 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,1> E1 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,2> E1 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,3> E1 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,0> E1 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,1> E1 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,2> E1 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,3> E1 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,3> E2 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,3> E2 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,3> E2 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,0> E2 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,1> E2 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,2> E2 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,3> E2 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,3> E2 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,3> E2 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,3> E2 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,0> E2 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,1> E2 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,2> E2 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,3> E2 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,3> E2 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,3> E2 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,3> E2 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,0> E2 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,1> E2 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,2> E2 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,3> E2 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,0> E2 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,1> E2 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,2> E2 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,3> E2 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,0> E2 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,1> E2 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,2> E2 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,3> E2 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,0> E2 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,1> E2 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,2> E2 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,3> E2 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,0> E2 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,1> E2 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,2> E2 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,3> E2 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,0> E3 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,1> E3 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,2> E3 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,3> E3 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,0> E3 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,1> E3 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,2> E3 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,3> E3 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,0> E3 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,1> E3 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,2> E3 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,3> E3 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,0> E3 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,1> E3 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,2> E3 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,3> E3 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,0> E3 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,1> E3 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,2> E3 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,3> E3 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,0> E3 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,1> E3 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,2> E3 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,3> E3 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,0> E3 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,1> E3 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,2> E3 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,3> E3 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,0> E3 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,1> E3 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,2> E3 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,3> E3 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,0> E3 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,1> E3 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,2> E3 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,3> E3 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,0> E3 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,1> E3 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,2> E3 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,3> E3 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,0> E3 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,1> E3 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,2> E3 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,3> E3 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,0> E3 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,1> E3 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,2> E3 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,3> E3 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,0> E3 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,1> E3 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,2> E3 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,3> E3 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,0> E3 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,1> E3 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,2> E3 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,3> E3 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,0> E3 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,1> E3 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,2> E3 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,3> E3 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,0> E3 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,1> E3 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,2> E3 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,3> E3 ## E3 ## E3 ## E3; }; diff --git a/src/GLMath/glm/detail/_swizzle_func.hpp b/src/GLMath/glm/detail/_swizzle_func.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d93c6afd5b79aeda66f5e96077503625519888fa --- /dev/null +++ b/src/GLMath/glm/detail/_swizzle_func.hpp @@ -0,0 +1,682 @@ +#pragma once + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, CONST, A, B) \ + vec<2, T, Q> A ## B() CONST \ + { \ + return vec<2, T, Q>(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, CONST, A, B, C) \ + vec<3, T, Q> A ## B ## C() CONST \ + { \ + return vec<3, T, Q>(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, CONST, A, B, C, D) \ + vec<4, T, Q> A ## B ## C ## D() CONST \ + { \ + return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ + } + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY_DEF(T, P, L, CONST, A, B) \ + template \ + vec vec::A ## B() CONST \ + { \ + return vec<2, T, Q>(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(T, P, L, CONST, A, B, C) \ + template \ + vec<3, T, Q> vec::A ## B ## C() CONST \ + { \ + return vec<3, T, Q>(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY_DEF(T, P, L, CONST, A, B, C, D) \ + template \ + vec<4, T, Q> vec::A ## B ## C ## D() CONST \ + { \ + return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ + } + +#define GLM_MUTABLE + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC2(T, P) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, x, y) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, r, g) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, s, t) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3(T, P) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, x, y, z) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, r, g, b) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, s, t, p) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, C) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, B) + +#define GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, C, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4(T, P) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, x, y, z, w) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, r, g, b, a) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, s, t, p, q) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, x, y) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, r, g) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, s, t) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, x, y, z) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, r, g, b) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, s, t, p) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, D) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, x, y, z, w) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, r, g, b, a) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, s, t, p, q) + diff --git a/src/GLMath/glm/detail/_vectorize.hpp b/src/GLMath/glm/detail/_vectorize.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ba7fd85c808a5f92f4b1c691d5fa442aaee748ca --- /dev/null +++ b/src/GLMath/glm/detail/_vectorize.hpp @@ -0,0 +1,123 @@ +#pragma once + +namespace glm{ +namespace detail +{ + template class vec, length_t L, typename R, typename T, qualifier Q> + struct functor1{}; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<1, R, Q> call(R (*Func) (T x), vec<1, T, Q> const& v) + { + return vec<1, R, Q>(Func(v.x)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<2, R, Q> call(R (*Func) (T x), vec<2, T, Q> const& v) + { + return vec<2, R, Q>(Func(v.x), Func(v.y)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<3, R, Q> call(R (*Func) (T x), vec<3, T, Q> const& v) + { + return vec<3, R, Q>(Func(v.x), Func(v.y), Func(v.z)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, R, Q> call(R (*Func) (T x), vec<4, T, Q> const& v) + { + return vec<4, R, Q>(Func(v.x), Func(v.y), Func(v.z), Func(v.w)); + } + }; + + template class vec, length_t L, typename T, qualifier Q> + struct functor2{}; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, vec<1, T, Q> const& b) + { + return vec<1, T, Q>(Func(a.x, b.x)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, vec<2, T, Q> const& b) + { + return vec<2, T, Q>(Func(a.x, b.x), Func(a.y, b.y)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return vec<3, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); + } + }; + + template class vec, length_t L, typename T, qualifier Q> + struct functor2_vec_sca{}; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, T b) + { + return vec<1, T, Q>(Func(a.x, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, T b) + { + return vec<2, T, Q>(Func(a.x, b), Func(a.y, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, T b) + { + return vec<3, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, T b) + { + return vec<4, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b)); + } + }; +}//namespace detail +}//namespace glm diff --git a/src/GLMath/glm/detail/compute_common.hpp b/src/GLMath/glm/detail/compute_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cc24b9e62f50cd2fe6d54c2b82335c76fd70bac8 --- /dev/null +++ b/src/GLMath/glm/detail/compute_common.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "setup.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_abs + {}; + + template + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || std::numeric_limits::is_signed, + "'abs' only accept floating-point and integer scalar or vector inputs"); + + return x >= genFIType(0) ? x : -x; + // TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff; + } + }; + +#if GLM_COMPILER & GLM_COMPILER_CUDA + template<> + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static float call(float x) + { + return fabsf(x); + } + }; +#endif + + template + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) + { + GLM_STATIC_ASSERT( + (!std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'abs' only accept floating-point and integer scalar or vector inputs"); + return x; + } + }; +}//namespace detail +}//namespace glm diff --git a/src/GLMath/glm/detail/compute_vector_relational.hpp b/src/GLMath/glm/detail/compute_vector_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..167b6345dd398e3822c772a113dab5864470f64e --- /dev/null +++ b/src/GLMath/glm/detail/compute_vector_relational.hpp @@ -0,0 +1,30 @@ +#pragma once + +//#include "compute_common.hpp" +#include "setup.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) + { + return a == b; + } + }; +/* + template + struct compute_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) + { + return detail::compute_abs::is_signed>::call(b - a) <= static_cast(0); + //return std::memcmp(&a, &b, sizeof(T)) == 0; + } + }; +*/ +}//namespace detail +}//namespace glm diff --git a/src/GLMath/glm/detail/func_common.inl b/src/GLMath/glm/detail/func_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..b987de63fab7bc17288ce14e39340298e75a819d --- /dev/null +++ b/src/GLMath/glm/detail/func_common.inl @@ -0,0 +1,787 @@ +/// @ref core +/// @file glm/detail/func_common.inl + +#include "../vector_relational.hpp" +#include "compute_common.hpp" +#include "type_vec1.hpp" +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include "_vectorize.hpp" +#include + +namespace glm +{ + // min + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType min(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return (y < x) ? y : x; + } + + // max + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType max(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + + return (x < y) ? y : x; + } + + // abs + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR int abs(int x) + { + int const y = x >> (sizeof(int) * 8 - 1); + return (x ^ y) - y; + } + + // round +# if GLM_HAS_CXX11_STL + using ::std::round; +# else + template + GLM_FUNC_QUALIFIER genType round(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); + + return x < static_cast(0) ? static_cast(int(x - static_cast(0.5))) : static_cast(int(x + static_cast(0.5))); + } +# endif + + // trunc +# if GLM_HAS_CXX11_STL + using ::std::trunc; +# else + template + GLM_FUNC_QUALIFIER genType trunc(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); + + return x < static_cast(0) ? -std::floor(-x) : std::floor(x); + } +# endif + +}//namespace glm + +namespace glm{ +namespace detail +{ + template + struct compute_abs_vector + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec call(vec const& x) + { + return detail::functor1::call(abs, x); + } + }; + + template + struct compute_mix_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); + } + }; + + template + struct compute_mix_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) + { + vec Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = a[i] ? y[i] : x[i]; + return Result; + } + }; + + template + struct compute_mix_scalar + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, U const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); + } + }; + + template + struct compute_mix_scalar + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, bool const& a) + { + return a ? y : x; + } + }; + + template + struct compute_mix + { + GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, U const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return static_cast(static_cast(x) * (static_cast(1) - a) + static_cast(y) * a); + } + }; + + template + struct compute_mix + { + GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, bool const& a) + { + return a ? y : x; + } + }; + + template + struct compute_sign + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return vec(glm::lessThan(vec(0), x)) - vec(glm::lessThan(x, vec(0))); + } + }; + +# if GLM_ARCH == GLM_ARCH_X86 + template + struct compute_sign + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + T const Shift(static_cast(sizeof(T) * 8 - 1)); + vec const y(vec::type, Q>(-x) >> typename detail::make_unsigned::type(Shift)); + + return (x >> Shift) | y; + } + }; +# endif + + template + struct compute_floor + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::floor, x); + } + }; + + template + struct compute_ceil + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::ceil, x); + } + }; + + template + struct compute_fract + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return x - floor(x); + } + }; + + template + struct compute_trunc + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(trunc, x); + } + }; + + template + struct compute_round + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(round, x); + } + }; + + template + struct compute_mod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mod' only accept floating-point inputs. Include for integer inputs."); + return a - b * floor(a / b); + } + }; + + template + struct compute_min_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) + { + return detail::functor2::call(min, x, y); + } + }; + + template + struct compute_max_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) + { + return detail::functor2::call(max, x, y); + } + }; + + template + struct compute_clamp_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& minVal, vec const& maxVal) + { + return min(max(x, minVal), maxVal); + } + }; + + template + struct compute_step_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& edge, vec const& x) + { + return mix(vec(1), vec(0), glm::lessThan(x, edge)); + } + }; + + template + struct compute_smoothstep_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& edge0, vec const& edge1, vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'step' only accept floating-point inputs"); + vec const tmp(clamp((x - edge0) / (edge1 - edge0), static_cast(0), static_cast(1))); + return tmp * tmp * (static_cast(3) - static_cast(2) * tmp); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genFIType abs(genFIType x) + { + return detail::compute_abs::is_signed>::call(x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec abs(vec const& x) + { + return detail::compute_abs_vector::value>::call(x); + } + + // sign + // fast and works for any type + template + GLM_FUNC_QUALIFIER genFIType sign(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'sign' only accept signed inputs"); + + return detail::compute_sign<1, genFIType, defaultp, std::numeric_limits::is_iec559, highp>::call(vec<1, genFIType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec sign(vec const& x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'sign' only accept signed inputs"); + + return detail::compute_sign::is_iec559, detail::is_aligned::value>::call(x); + } + + // floor + using ::std::floor; + template + GLM_FUNC_QUALIFIER vec floor(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'floor' only accept floating-point inputs."); + return detail::compute_floor::value>::call(x); + } + + template + GLM_FUNC_QUALIFIER vec trunc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); + return detail::compute_trunc::value>::call(x); + } + + template + GLM_FUNC_QUALIFIER vec round(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); + return detail::compute_round::value>::call(x); + } + +/* + // roundEven + template + GLM_FUNC_QUALIFIER genType roundEven(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + + return genType(int(x + genType(int(x) % 2))); + } +*/ + + // roundEven + template + GLM_FUNC_QUALIFIER genType roundEven(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + + int Integer = static_cast(x); + genType IntegerPart = static_cast(Integer); + genType FractionalPart = fract(x); + + if(FractionalPart > static_cast(0.5) || FractionalPart < static_cast(0.5)) + { + return round(x); + } + else if((Integer % 2) == 0) + { + return IntegerPart; + } + else if(x <= static_cast(0)) // Work around... + { + return IntegerPart - static_cast(1); + } + else + { + return IntegerPart + static_cast(1); + } + //else // Bug on MinGW 4.5.2 + //{ + // return mix(IntegerPart + genType(-1), IntegerPart + genType(1), x <= genType(0)); + //} + } + + template + GLM_FUNC_QUALIFIER vec roundEven(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + return detail::functor1::call(roundEven, x); + } + + // ceil + using ::std::ceil; + template + GLM_FUNC_QUALIFIER vec ceil(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ceil' only accept floating-point inputs"); + return detail::compute_ceil::value>::call(x); + } + + // fract + template + GLM_FUNC_QUALIFIER genType fract(genType x) + { + return fract(vec<1, genType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec fract(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fract' only accept floating-point inputs"); + return detail::compute_fract::value>::call(x); + } + + // mod + template + GLM_FUNC_QUALIFIER genType mod(genType x, genType y) + { +# if GLM_COMPILER & GLM_COMPILER_CUDA + // Another Cuda compiler bug https://github.com/g-truc/glm/issues/530 + vec<1, genType, defaultp> Result(mod(vec<1, genType, defaultp>(x), y)); + return Result.x; +# else + return mod(vec<1, genType, defaultp>(x), y).x; +# endif + } + + template + GLM_FUNC_QUALIFIER vec mod(vec const& x, T y) + { + return detail::compute_mod::value>::call(x, vec(y)); + } + + template + GLM_FUNC_QUALIFIER vec mod(vec const& x, vec const& y) + { + return detail::compute_mod::value>::call(x, y); + } + + // modf + template + GLM_FUNC_QUALIFIER genType modf(genType x, genType & i) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'modf' only accept floating-point inputs"); + return std::modf(x, &i); + } + + template + GLM_FUNC_QUALIFIER vec<1, T, Q> modf(vec<1, T, Q> const& x, vec<1, T, Q> & i) + { + return vec<1, T, Q>( + modf(x.x, i.x)); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> modf(vec<2, T, Q> const& x, vec<2, T, Q> & i) + { + return vec<2, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> modf(vec<3, T, Q> const& x, vec<3, T, Q> & i) + { + return vec<3, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y), + modf(x.z, i.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> modf(vec<4, T, Q> const& x, vec<4, T, Q> & i) + { + return vec<4, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y), + modf(x.z, i.z), + modf(x.w, i.w)); + } + + //// Only valid if (INT_MIN <= x-y <= INT_MAX) + //// min(x,y) + //r = y + ((x - y) & ((x - y) >> (sizeof(int) * + //CHAR_BIT - 1))); + //// max(x,y) + //r = x - ((x - y) & ((x - y) >> (sizeof(int) * + //CHAR_BIT - 1))); + + // min + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return detail::compute_min_vector::value>::call(a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, vec const& b) + { + return detail::compute_min_vector::value>::call(a, b); + } + + // max + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + return detail::compute_max_vector::value>::call(a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, vec const& b) + { + return detail::compute_max_vector::value>::call(a, b); + } + + // clamp + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return min(max(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return detail::compute_clamp_vector::value>::call(x, vec(minVal), vec(maxVal)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return detail::compute_clamp_vector::value>::call(x, minVal, maxVal); + } + + template + GLM_FUNC_QUALIFIER genTypeT mix(genTypeT x, genTypeT y, genTypeU a) + { + return detail::compute_mix::call(x, y, a); + } + + template + GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, U a) + { + return detail::compute_mix_scalar::value>::call(x, y, a); + } + + template + GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, vec const& a) + { + return detail::compute_mix_vector::value>::call(x, y, a); + } + + // step + template + GLM_FUNC_QUALIFIER genType step(genType edge, genType x) + { + return mix(static_cast(1), static_cast(0), x < edge); + } + + template + GLM_FUNC_QUALIFIER vec step(T edge, vec const& x) + { + return detail::compute_step_vector::value>::call(vec(edge), x); + } + + template + GLM_FUNC_QUALIFIER vec step(vec const& edge, vec const& x) + { + return detail::compute_step_vector::value>::call(edge, x); + } + + // smoothstep + template + GLM_FUNC_QUALIFIER genType smoothstep(genType edge0, genType edge1, genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs"); + + genType const tmp(clamp((x - edge0) / (edge1 - edge0), genType(0), genType(1))); + return tmp * tmp * (genType(3) - genType(2) * tmp); + } + + template + GLM_FUNC_QUALIFIER vec smoothstep(T edge0, T edge1, vec const& x) + { + return detail::compute_smoothstep_vector::value>::call(vec(edge0), vec(edge1), x); + } + + template + GLM_FUNC_QUALIFIER vec smoothstep(vec const& edge0, vec const& edge1, vec const& x) + { + return detail::compute_smoothstep_vector::value>::call(edge0, edge1, x); + } + +# if GLM_HAS_CXX11_STL + using std::isnan; +# else + template + GLM_FUNC_QUALIFIER bool isnan(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::isnan(x); +# elif GLM_COMPILER & GLM_COMPILER_VC + return _isnan(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# if GLM_PLATFORM & GLM_PLATFORM_WINDOWS + return _isnan(x) != 0; +# else + return ::isnan(x) != 0; +# endif +# elif (GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)) && (GLM_PLATFORM & GLM_PLATFORM_ANDROID) && __cplusplus < 201103L + return _isnan(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_CUDA + return ::isnan(x) != 0; +# else + return std::isnan(x); +# endif + } +# endif + + template + GLM_FUNC_QUALIFIER vec isnan(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = glm::isnan(v[l]); + return Result; + } + +# if GLM_HAS_CXX11_STL + using std::isinf; +# else + template + GLM_FUNC_QUALIFIER bool isinf(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::isinf(x); +# elif GLM_COMPILER & (GLM_COMPILER_INTEL | GLM_COMPILER_VC) +# if(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) + return _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF; +# else + return ::isinf(x); +# endif +# elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) +# if(GLM_PLATFORM & GLM_PLATFORM_ANDROID && __cplusplus < 201103L) + return _isinf(x) != 0; +# else + return std::isinf(x); +# endif +# elif GLM_COMPILER & GLM_COMPILER_CUDA + // http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/docs/online/group__CUDA__MATH__DOUBLE_g13431dd2b40b51f9139cbb7f50c18fab.html#g13431dd2b40b51f9139cbb7f50c18fab + return ::isinf(double(x)) != 0; +# else + return std::isinf(x); +# endif + } +# endif + + template + GLM_FUNC_QUALIFIER vec isinf(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = glm::isinf(v[l]); + return Result; + } + + GLM_FUNC_QUALIFIER int floatBitsToInt(float const& v) + { + union + { + float in; + int out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec floatBitsToInt(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER uint floatBitsToUint(float const& v) + { + union + { + float in; + uint out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec floatBitsToUint(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER float intBitsToFloat(int const& v) + { + union + { + int in; + float out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec intBitsToFloat(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER float uintBitsToFloat(uint const& v) + { + union + { + uint in; + float out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec uintBitsToFloat(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + template + GLM_FUNC_QUALIFIER genType fma(genType const& a, genType const& b, genType const& c) + { + return a * b + c; + } + + template + GLM_FUNC_QUALIFIER genType frexp(genType x, int& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); + + return std::frexp(x, &exp); + } + + template + GLM_FUNC_QUALIFIER vec frexp(vec const& v, vec& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = std::frexp(v[l], &exp[l]); + return Result; + } + + template + GLM_FUNC_QUALIFIER genType ldexp(genType const& x, int const& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); + + return std::ldexp(x, exp); + } + + template + GLM_FUNC_QUALIFIER vec ldexp(vec const& v, vec const& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = std::ldexp(v[l], exp[l]); + return Result; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_common_simd.inl" +#endif diff --git a/src/GLMath/glm/detail/func_common_simd.inl b/src/GLMath/glm/detail/func_common_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..ce0032d33fefbf095f9d5eb38ba56c88d11dc3a7 --- /dev/null +++ b/src/GLMath/glm/detail/func_common_simd.inl @@ -0,0 +1,231 @@ +/// @ref core +/// @file glm/detail/func_common_simd.inl + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#include "../simd/common.h" + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_abs_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_abs(v.data); + return result; + } + }; + + template + struct compute_abs_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) + { + vec<4, int, Q> result; + result.data = glm_ivec4_abs(v.data); + return result; + } + }; + + template + struct compute_floor<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_floor(v.data); + return result; + } + }; + + template + struct compute_ceil<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_ceil(v.data); + return result; + } + }; + + template + struct compute_fract<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_fract(v.data); + return result; + } + }; + + template + struct compute_round<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_round(v.data); + return result; + } + }; + + template + struct compute_mod<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { + vec<4, float, Q> result; + result.data = glm_vec4_mod(x.data, y.data); + return result; + } + }; + + template + struct compute_min_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + vec<4, float, Q> result; + result.data = _mm_min_ps(v1.data, v2.data); + return result; + } + }; + + template + struct compute_min_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + vec<4, int, Q> result; + result.data = _mm_min_epi32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_min_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + vec<4, uint, Q> result; + result.data = _mm_min_epu32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + vec<4, float, Q> result; + result.data = _mm_max_ps(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + vec<4, int, Q> result; + result.data = _mm_max_epi32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + vec<4, uint, Q> result; + result.data = _mm_max_epu32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& minVal, vec<4, float, Q> const& maxVal) + { + vec<4, float, Q> result; + result.data = _mm_min_ps(_mm_max_ps(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& x, vec<4, int, Q> const& minVal, vec<4, int, Q> const& maxVal) + { + vec<4, int, Q> result; + result.data = _mm_min_epi32(_mm_max_epi32(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& x, vec<4, uint, Q> const& minVal, vec<4, uint, Q> const& maxVal) + { + vec<4, uint, Q> result; + result.data = _mm_min_epu32(_mm_max_epu32(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_mix_vector<4, float, bool, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y, vec<4, bool, Q> const& a) + { + __m128i const Load = _mm_set_epi32(-static_cast(a.w), -static_cast(a.z), -static_cast(a.y), -static_cast(a.x)); + __m128 const Mask = _mm_castsi128_ps(Load); + + vec<4, float, Q> Result; +# if 0 && GLM_ARCH & GLM_ARCH_AVX + Result.data = _mm_blendv_ps(x.data, y.data, Mask); +# else + Result.data = _mm_or_ps(_mm_and_ps(Mask, y.data), _mm_andnot_ps(Mask, x.data)); +# endif + return Result; + } + }; +/* FIXME + template + struct compute_step_vector + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge, vec<4, float, Q> const& x) + { + vec<4, float, Q> Result; + result.data = glm_vec4_step(edge.data, x.data); + return result; + } + }; +*/ + template + struct compute_smoothstep_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge0, vec<4, float, Q> const& edge1, vec<4, float, Q> const& x) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_smoothstep(edge0.data, edge1.data, x.data); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/detail/func_exponential.inl b/src/GLMath/glm/detail/func_exponential.inl new file mode 100644 index 0000000000000000000000000000000000000000..2040d41f8a3dfe17cc129601e0d25b7ba56a2e55 --- /dev/null +++ b/src/GLMath/glm/detail/func_exponential.inl @@ -0,0 +1,152 @@ +/// @ref core +/// @file glm/detail/func_exponential.inl + +#include "../vector_relational.hpp" +#include "_vectorize.hpp" +#include +#include +#include + +namespace glm{ +namespace detail +{ +# if GLM_HAS_CXX11_STL + using std::log2; +# else + template + genType log2(genType Value) + { + return std::log(Value) * static_cast(1.4426950408889634073599246810019); + } +# endif + + template + struct compute_log2 + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'log2' only accept floating-point inputs. Include for integer inputs."); + + return detail::functor1::call(log2, v); + } + }; + + template + struct compute_sqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::sqrt, x); + } + }; + + template + struct compute_inversesqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return static_cast(1) / sqrt(x); + } + }; + + template + struct compute_inversesqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + vec tmp(x); + vec xhalf(tmp * 0.5f); + vec* p = reinterpret_cast*>(const_cast*>(&x)); + vec i = vec(0x5f375a86) - (*p >> vec(1)); + vec* ptmp = reinterpret_cast*>(&i); + tmp = *ptmp; + tmp = tmp * (1.5f - xhalf * tmp * tmp); + return tmp; + } + }; +}//namespace detail + + // pow + using std::pow; + template + GLM_FUNC_QUALIFIER vec pow(vec const& base, vec const& exponent) + { + return detail::functor2::call(pow, base, exponent); + } + + // exp + using std::exp; + template + GLM_FUNC_QUALIFIER vec exp(vec const& x) + { + return detail::functor1::call(exp, x); + } + + // log + using std::log; + template + GLM_FUNC_QUALIFIER vec log(vec const& x) + { + return detail::functor1::call(log, x); + } + +# if GLM_HAS_CXX11_STL + using std::exp2; +# else + //exp2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType exp2(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'exp2' only accept floating-point inputs"); + + return std::exp(static_cast(0.69314718055994530941723212145818) * x); + } +# endif + + template + GLM_FUNC_QUALIFIER vec exp2(vec const& x) + { + return detail::functor1::call(exp2, x); + } + + // log2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType log2(genType x) + { + return log2(vec<1, genType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec log2(vec const& x) + { + return detail::compute_log2::is_iec559, detail::is_aligned::value>::call(x); + } + + // sqrt + using std::sqrt; + template + GLM_FUNC_QUALIFIER vec sqrt(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sqrt' only accept floating-point inputs"); + return detail::compute_sqrt::value>::call(x); + } + + // inversesqrt + template + GLM_FUNC_QUALIFIER genType inversesqrt(genType x) + { + return static_cast(1) / sqrt(x); + } + + template + GLM_FUNC_QUALIFIER vec inversesqrt(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'inversesqrt' only accept floating-point inputs"); + return detail::compute_inversesqrt::value>::call(x); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_exponential_simd.inl" +#endif + diff --git a/src/GLMath/glm/detail/func_exponential_simd.inl b/src/GLMath/glm/detail/func_exponential_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fb78951727f1c5e419418fbac9394322f579f1c4 --- /dev/null +++ b/src/GLMath/glm/detail/func_exponential_simd.inl @@ -0,0 +1,37 @@ +/// @ref core +/// @file glm/detail/func_exponential_simd.inl + +#include "../simd/exponential.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_sqrt<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> Result; + Result.data = _mm_sqrt_ps(v.data); + return Result; + } + }; + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + struct compute_sqrt<4, float, aligned_lowp, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& v) + { + vec<4, float, aligned_lowp> Result; + Result.data = glm_vec4_sqrt_lowp(v.data); + return Result; + } + }; +# endif +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/detail/func_geometric.inl b/src/GLMath/glm/detail/func_geometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..9cde28fed189636790ed32b285357442cb5ddf9a --- /dev/null +++ b/src/GLMath/glm/detail/func_geometric.inl @@ -0,0 +1,243 @@ +#include "../exponential.hpp" +#include "../common.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_length + { + GLM_FUNC_QUALIFIER static T call(vec const& v) + { + return sqrt(dot(v, v)); + } + }; + + template + struct compute_distance + { + GLM_FUNC_QUALIFIER static T call(vec const& p0, vec const& p1) + { + return length(p1 - p0); + } + }; + + template + struct compute_dot{}; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<1, T, Q> const& a, vec<1, T, Q> const& b) + { + return a.x * b.x; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& a, vec<2, T, Q> const& b) + { + vec<2, T, Q> tmp(a * b); + return tmp.x + tmp.y; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + vec<3, T, Q> tmp(a * b); + return tmp.x + tmp.y + tmp.z; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> tmp(a * b); + return (tmp.x + tmp.y) + (tmp.z + tmp.w); + } + }; + + template + struct compute_cross + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); + + return vec<3, T, Q>( + x.y * y.z - y.y * x.z, + x.z * y.x - y.z * x.x, + x.x * y.y - y.x * x.y); + } + }; + + template + struct compute_normalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return v * inversesqrt(dot(v, v)); + } + }; + + template + struct compute_faceforward + { + GLM_FUNC_QUALIFIER static vec call(vec const& N, vec const& I, vec const& Nref) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return dot(Nref, I) < static_cast(0) ? N : -N; + } + }; + + template + struct compute_reflect + { + GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N) + { + return I - N * dot(N, I) * static_cast(2); + } + }; + + template + struct compute_refract + { + GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N, T eta) + { + T const dotValue(dot(N, I)); + T const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); + vec const Result = + (k >= static_cast(0)) ? (eta * I - (eta * dotValue + std::sqrt(k)) * N) : vec(0); + return Result; + } + }; +}//namespace detail + + // length + template + GLM_FUNC_QUALIFIER genType length(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); + + return abs(x); + } + + template + GLM_FUNC_QUALIFIER T length(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); + + return detail::compute_length::value>::call(v); + } + + // distance + template + GLM_FUNC_QUALIFIER genType distance(genType const& p0, genType const& p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance' accepts only floating-point inputs"); + + return length(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T distance(vec const& p0, vec const& p1) + { + return detail::compute_distance::value>::call(p0, p1); + } + + // dot + template + GLM_FUNC_QUALIFIER T dot(T x, T y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return x * y; + } + + template + GLM_FUNC_QUALIFIER T dot(vec const& x, vec const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); + } + + // cross + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + return detail::compute_cross::value>::call(x, y); + } +/* + // normalize + template + GLM_FUNC_QUALIFIER genType normalize(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return x < genType(0) ? genType(-1) : genType(1); + } +*/ + template + GLM_FUNC_QUALIFIER vec normalize(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return detail::compute_normalize::value>::call(x); + } + + // faceforward + template + GLM_FUNC_QUALIFIER genType faceforward(genType const& N, genType const& I, genType const& Nref) + { + return dot(Nref, I) < static_cast(0) ? N : -N; + } + + template + GLM_FUNC_QUALIFIER vec faceforward(vec const& N, vec const& I, vec const& Nref) + { + return detail::compute_faceforward::value>::call(N, I, Nref); + } + + // reflect + template + GLM_FUNC_QUALIFIER genType reflect(genType const& I, genType const& N) + { + return I - N * dot(N, I) * genType(2); + } + + template + GLM_FUNC_QUALIFIER vec reflect(vec const& I, vec const& N) + { + return detail::compute_reflect::value>::call(I, N); + } + + // refract + template + GLM_FUNC_QUALIFIER genType refract(genType const& I, genType const& N, genType eta) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); + genType const dotValue(dot(N, I)); + genType const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); + return (eta * I - (eta * dotValue + sqrt(k)) * N) * static_cast(k >= static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER vec refract(vec const& I, vec const& N, T eta) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); + return detail::compute_refract::value>::call(I, N, eta); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_geometric_simd.inl" +#endif diff --git a/src/GLMath/glm/detail/func_geometric_simd.inl b/src/GLMath/glm/detail/func_geometric_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..e6c8d85f2b73595857595749d74f624297e4e5ca --- /dev/null +++ b/src/GLMath/glm/detail/func_geometric_simd.inl @@ -0,0 +1,99 @@ +/// @ref core +/// @file glm/detail/func_geometric_simd.inl + +#include "../simd/geometric.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_length<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v) + { + return _mm_cvtss_f32(glm_vec4_length(v.data)); + } + }; + + template + struct compute_distance<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1) + { + return _mm_cvtss_f32(glm_vec4_distance(p0.data, p1.data)); + } + }; + + template + struct compute_dot, float, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { + return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); + } + }; + + template + struct compute_cross + { + GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<3, float, Q> const& a, vec<3, float, Q> const& b) + { + __m128 const set0 = _mm_set_ps(0.0f, a.z, a.y, a.x); + __m128 const set1 = _mm_set_ps(0.0f, b.z, b.y, b.x); + __m128 const xpd0 = glm_vec4_cross(set0, set1); + + vec<4, float, Q> Result; + Result.data = xpd0; + return vec<3, float, Q>(Result); + } + }; + + template + struct compute_normalize<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_normalize(v.data); + return Result; + } + }; + + template + struct compute_faceforward<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& N, vec<4, float, Q> const& I, vec<4, float, Q> const& Nref) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_faceforward(N.data, I.data, Nref.data); + return Result; + } + }; + + template + struct compute_reflect<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_reflect(I.data, N.data); + return Result; + } + }; + + template + struct compute_refract<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N, float eta) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_refract(I.data, N.data, _mm_set1_ps(eta)); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/detail/func_integer.inl b/src/GLMath/glm/detail/func_integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..f4067ffccbc3eb084ca0e546a3ca21bacb773e05 --- /dev/null +++ b/src/GLMath/glm/detail/func_integer.inl @@ -0,0 +1,362 @@ +/// @ref core + +#include "_vectorize.hpp" +#if(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) +# include +# pragma intrinsic(_BitScanReverse) +#endif//(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) +#include + +#if !GLM_HAS_EXTENDED_INTEGER_TYPE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +# if (GLM_COMPILER & GLM_COMPILER_CLANG) +# pragma clang diagnostic ignored "-Wc++11-long-long" +# endif +#endif + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER T mask(T Bits) + { + return Bits >= static_cast(sizeof(T) * 8) ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); + } + + template + struct compute_bitfieldReverseStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) + { + return v; + } + }; + + template + struct compute_bitfieldReverseStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) + { + return (v & Mask) << Shift | (v & (~Mask)) >> Shift; + } + }; + + template + struct compute_bitfieldBitCountStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) + { + return v; + } + }; + + template + struct compute_bitfieldBitCountStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) + { + return (v & Mask) + ((v >> Shift) & Mask); + } + }; + + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + if(Value == 0) + return -1; + + return glm::bitCount(~Value & (Value - static_cast(1))); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanForward(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + }; + +# if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanForward64(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + }; +# endif +# endif//GLM_HAS_BITSCAN_WINDOWS + + template + struct compute_findMSB_step_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, T Shift) + { + return x | (x >> Shift); + } + }; + + template + struct compute_findMSB_step_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, T) + { + return x; + } + }; + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + vec x(v); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 1)); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 2)); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 4)); + x = compute_findMSB_step_vec= 16>::call(x, static_cast( 8)); + x = compute_findMSB_step_vec= 32>::call(x, static_cast(16)); + x = compute_findMSB_step_vec= 64>::call(x, static_cast(32)); + return vec(sizeof(T) * 8 - 1) - glm::bitCount(~x); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + GLM_FUNC_QUALIFIER int compute_findMSB_32(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanReverse(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(compute_findMSB_32, x); + } + }; + +# if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) + template + GLM_FUNC_QUALIFIER int compute_findMSB_64(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanReverse64(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(compute_findMSB_64, x); + } + }; +# endif +# endif//GLM_HAS_BITSCAN_WINDOWS +}//namespace detail + + // uaddCarry + GLM_FUNC_QUALIFIER uint uaddCarry(uint const& x, uint const& y, uint & Carry) + { + detail::uint64 const Value64(static_cast(x) + static_cast(y)); + detail::uint64 const Max32((static_cast(1) << static_cast(32)) - static_cast(1)); + Carry = Value64 > Max32 ? 1u : 0u; + return static_cast(Value64 % (Max32 + static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER vec uaddCarry(vec const& x, vec const& y, vec& Carry) + { + vec Value64(vec(x) + vec(y)); + vec Max32((static_cast(1) << static_cast(32)) - static_cast(1)); + Carry = mix(vec(0), vec(1), greaterThan(Value64, Max32)); + return vec(Value64 % (Max32 + static_cast(1))); + } + + // usubBorrow + GLM_FUNC_QUALIFIER uint usubBorrow(uint const& x, uint const& y, uint & Borrow) + { + Borrow = x >= y ? static_cast(0) : static_cast(1); + if(y >= x) + return y - x; + else + return static_cast((static_cast(1) << static_cast(32)) + (static_cast(y) - static_cast(x))); + } + + template + GLM_FUNC_QUALIFIER vec usubBorrow(vec const& x, vec const& y, vec& Borrow) + { + Borrow = mix(vec(1), vec(0), greaterThanEqual(x, y)); + vec const YgeX(y - x); + vec const XgeY(vec((static_cast(1) << static_cast(32)) + (vec(y) - vec(x)))); + return mix(XgeY, YgeX, greaterThanEqual(y, x)); + } + + // umulExtended + GLM_FUNC_QUALIFIER void umulExtended(uint const& x, uint const& y, uint & msb, uint & lsb) + { + detail::uint64 Value64 = static_cast(x) * static_cast(y); + msb = static_cast(Value64 >> static_cast(32)); + lsb = static_cast(Value64); + } + + template + GLM_FUNC_QUALIFIER void umulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) + { + vec Value64(vec(x) * vec(y)); + msb = vec(Value64 >> static_cast(32)); + lsb = vec(Value64); + } + + // imulExtended + GLM_FUNC_QUALIFIER void imulExtended(int x, int y, int& msb, int& lsb) + { + detail::int64 Value64 = static_cast(x) * static_cast(y); + msb = static_cast(Value64 >> static_cast(32)); + lsb = static_cast(Value64); + } + + template + GLM_FUNC_QUALIFIER void imulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) + { + vec Value64(vec(x) * vec(y)); + lsb = vec(Value64 & static_cast(0xFFFFFFFF)); + msb = vec((Value64 >> static_cast(32)) & static_cast(0xFFFFFFFF)); + } + + // bitfieldExtract + template + GLM_FUNC_QUALIFIER genIUType bitfieldExtract(genIUType Value, int Offset, int Bits) + { + return bitfieldExtract(vec<1, genIUType>(Value), Offset, Bits).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldExtract(vec const& Value, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldExtract' only accept integer inputs"); + + return (Value >> static_cast(Offset)) & static_cast(detail::mask(Bits)); + } + + // bitfieldInsert + template + GLM_FUNC_QUALIFIER genIUType bitfieldInsert(genIUType const& Base, genIUType const& Insert, int Offset, int Bits) + { + return bitfieldInsert(vec<1, genIUType>(Base), vec<1, genIUType>(Insert), Offset, Bits).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldInsert(vec const& Base, vec const& Insert, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); + + T const Mask = static_cast(detail::mask(Bits) << Offset); + return (Base & ~Mask) | ((Insert << static_cast(Offset)) & Mask); + } + + // bitfieldReverse + template + GLM_FUNC_QUALIFIER genType bitfieldReverse(genType x) + { + return bitfieldReverse(glm::vec<1, genType, glm::defaultp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldReverse(vec const& v) + { + vec x(v); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 2>::call(x, static_cast(0x5555555555555555ull), static_cast( 1)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 4>::call(x, static_cast(0x3333333333333333ull), static_cast( 2)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 8>::call(x, static_cast(0x0F0F0F0F0F0F0F0Full), static_cast( 4)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 16>::call(x, static_cast(0x00FF00FF00FF00FFull), static_cast( 8)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 32>::call(x, static_cast(0x0000FFFF0000FFFFull), static_cast(16)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 64>::call(x, static_cast(0x00000000FFFFFFFFull), static_cast(32)); + return x; + } + + // bitCount + template + GLM_FUNC_QUALIFIER int bitCount(genType x) + { + return bitCount(glm::vec<1, genType, glm::defaultp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec bitCount(vec const& v) + { +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable : 4310) //cast truncates constant value +# endif + + vec::type, Q> x(*reinterpret_cast::type, Q> const *>(&v)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 2>::call(x, typename detail::make_unsigned::type(0x5555555555555555ull), typename detail::make_unsigned::type( 1)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 4>::call(x, typename detail::make_unsigned::type(0x3333333333333333ull), typename detail::make_unsigned::type( 2)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 8>::call(x, typename detail::make_unsigned::type(0x0F0F0F0F0F0F0F0Full), typename detail::make_unsigned::type( 4)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 16>::call(x, typename detail::make_unsigned::type(0x00FF00FF00FF00FFull), typename detail::make_unsigned::type( 8)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 32>::call(x, typename detail::make_unsigned::type(0x0000FFFF0000FFFFull), typename detail::make_unsigned::type(16)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 64>::call(x, typename detail::make_unsigned::type(0x00000000FFFFFFFFull), typename detail::make_unsigned::type(32)); + return vec(x); + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif + } + + // findLSB + template + GLM_FUNC_QUALIFIER int findLSB(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + + return detail::compute_findLSB::call(Value); + } + + template + GLM_FUNC_QUALIFIER vec findLSB(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + + return detail::functor1::call(findLSB, x); + } + + // findMSB + template + GLM_FUNC_QUALIFIER int findMSB(genIUType v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + return findMSB(vec<1, genIUType>(v)).x; + } + + template + GLM_FUNC_QUALIFIER vec findMSB(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + return detail::compute_findMSB_vec::call(v); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_integer_simd.inl" +#endif + diff --git a/src/GLMath/glm/detail/func_integer_simd.inl b/src/GLMath/glm/detail/func_integer_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..8be6c9ce4dc143cedd3565899b6c44b7fea3bde8 --- /dev/null +++ b/src/GLMath/glm/detail/func_integer_simd.inl @@ -0,0 +1,65 @@ +#include "../simd/integer.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_bitfieldReverseStep<4, uint, Q, true, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) + { + __m128i const set0 = v.data; + + __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); + __m128i const and1 = _mm_and_si128(set0, set1); + __m128i const sft1 = _mm_slli_epi32(and1, Shift); + + __m128i const set2 = _mm_andnot_si128(set0, _mm_set1_epi32(-1)); + __m128i const and2 = _mm_and_si128(set0, set2); + __m128i const sft2 = _mm_srai_epi32(and2, Shift); + + __m128i const or0 = _mm_or_si128(sft1, sft2); + + return or0; + } + }; + + template + struct compute_bitfieldBitCountStep<4, uint, Q, true, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) + { + __m128i const set0 = v.data; + + __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); + __m128i const and0 = _mm_and_si128(set0, set1); + __m128i const sft0 = _mm_slli_epi32(set0, Shift); + __m128i const and1 = _mm_and_si128(sft0, set1); + __m128i const add0 = _mm_add_epi32(and0, and1); + + return add0; + } + }; +}//namespace detail + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template<> + GLM_FUNC_QUALIFIER int bitCount(uint x) + { + return _mm_popcnt_u32(x); + } + +# if(GLM_MODEL == GLM_MODEL_64) + template<> + GLM_FUNC_QUALIFIER int bitCount(detail::uint64 x) + { + return static_cast(_mm_popcnt_u64(x)); + } +# endif//GLM_MODEL +# endif//GLM_ARCH + +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/detail/func_matrix.inl b/src/GLMath/glm/detail/func_matrix.inl new file mode 100644 index 0000000000000000000000000000000000000000..d980c6d3888584d108f12f41def72c0ffda633ca --- /dev/null +++ b/src/GLMath/glm/detail/func_matrix.inl @@ -0,0 +1,398 @@ +#include "../geometric.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_matrixCompMult + { + GLM_FUNC_QUALIFIER static mat call(mat const& x, mat const& y) + { + mat Result; + for(length_t i = 0; i < Result.length(); ++i) + Result[i] = x[i] * y[i]; + return Result; + } + }; + + template + struct compute_transpose{}; + + template + struct compute_transpose<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) + { + mat<2, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + return Result; + } + }; + + template + struct compute_transpose<2, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 2, T, Q> call(mat<2, 3, T, Q> const& m) + { + mat<3,2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + return Result; + } + }; + + template + struct compute_transpose<2, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 2, T, Q> call(mat<2, 4, T, Q> const& m) + { + mat<4, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + return Result; + } + }; + + template + struct compute_transpose<3, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 3, T, Q> call(mat<3, 2, T, Q> const& m) + { + mat<2, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + return Result; + } + }; + + template + struct compute_transpose<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) + { + mat<3, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + return Result; + } + }; + + template + struct compute_transpose<3, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 3, T, Q> call(mat<3, 4, T, Q> const& m) + { + mat<4, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + return Result; + } + }; + + template + struct compute_transpose<4, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 4, T, Q> call(mat<4, 2, T, Q> const& m) + { + mat<2, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + return Result; + } + }; + + template + struct compute_transpose<4, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 4, T, Q> call(mat<4, 3, T, Q> const& m) + { + mat<3, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + return Result; + } + }; + + template + struct compute_transpose<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) + { + mat<4, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + Result[3][3] = m[3][3]; + return Result; + } + }; + + template + struct compute_determinant{}; + + template + struct compute_determinant<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<2, 2, T, Q> const& m) + { + return m[0][0] * m[1][1] - m[1][0] * m[0][1]; + } + }; + + template + struct compute_determinant<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<3, 3, T, Q> const& m) + { + return + + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]); + } + }; + + template + struct compute_determinant<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<4, 4, T, Q> const& m) + { + T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + vec<4, T, Q> DetCof( + + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + return + m[0][0] * DetCof[0] + m[0][1] * DetCof[1] + + m[0][2] * DetCof[2] + m[0][3] * DetCof[3]; + } + }; + + template + struct compute_inverse{}; + + template + struct compute_inverse<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) + { + T OneOverDeterminant = static_cast(1) / ( + + m[0][0] * m[1][1] + - m[1][0] * m[0][1]); + + mat<2, 2, T, Q> Inverse( + + m[1][1] * OneOverDeterminant, + - m[0][1] * OneOverDeterminant, + - m[1][0] * OneOverDeterminant, + + m[0][0] * OneOverDeterminant); + + return Inverse; + } + }; + + template + struct compute_inverse<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) + { + T OneOverDeterminant = static_cast(1) / ( + + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])); + + mat<3, 3, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant; + Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant; + Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant; + Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant; + Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant; + Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant; + Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant; + Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant; + Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant; + + return Inverse; + } + }; + + template + struct compute_inverse<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) + { + T Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + T Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + T Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + T Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + T Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + T Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + T Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + T Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + T Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + T Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + T Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + T Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + T Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + vec<4, T, Q> Fac0(Coef00, Coef00, Coef02, Coef03); + vec<4, T, Q> Fac1(Coef04, Coef04, Coef06, Coef07); + vec<4, T, Q> Fac2(Coef08, Coef08, Coef10, Coef11); + vec<4, T, Q> Fac3(Coef12, Coef12, Coef14, Coef15); + vec<4, T, Q> Fac4(Coef16, Coef16, Coef18, Coef19); + vec<4, T, Q> Fac5(Coef20, Coef20, Coef22, Coef23); + + vec<4, T, Q> Vec0(m[1][0], m[0][0], m[0][0], m[0][0]); + vec<4, T, Q> Vec1(m[1][1], m[0][1], m[0][1], m[0][1]); + vec<4, T, Q> Vec2(m[1][2], m[0][2], m[0][2], m[0][2]); + vec<4, T, Q> Vec3(m[1][3], m[0][3], m[0][3], m[0][3]); + + vec<4, T, Q> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2); + vec<4, T, Q> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4); + vec<4, T, Q> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5); + vec<4, T, Q> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5); + + vec<4, T, Q> SignA(+1, -1, +1, -1); + vec<4, T, Q> SignB(-1, +1, -1, +1); + mat<4, 4, T, Q> Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB); + + vec<4, T, Q> Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]); + + vec<4, T, Q> Dot0(m[0] * Row0); + T Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w); + + T OneOverDeterminant = static_cast(1) / Dot1; + + return Inverse * OneOverDeterminant; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER mat matrixCompMult(mat const& x, mat const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'matrixCompMult' only accept floating-point inputs"); + return detail::compute_matrixCompMult::value>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'outerProduct' only accept floating-point inputs"); + + typename detail::outerProduct_trait::type m; + for(length_t i = 0; i < m.length(); ++i) + m[i] = c * r[i]; + return m; + } + + template + GLM_FUNC_QUALIFIER typename mat::transpose_type transpose(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'transpose' only accept floating-point inputs"); + return detail::compute_transpose::value>::call(m); + } + + template + GLM_FUNC_QUALIFIER T determinant(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'determinant' only accept floating-point inputs"); + return detail::compute_determinant::value>::call(m); + } + + template + GLM_FUNC_QUALIFIER mat inverse(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'inverse' only accept floating-point inputs"); + return detail::compute_inverse::value>::call(m); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_matrix_simd.inl" +#endif + diff --git a/src/GLMath/glm/detail/func_matrix_simd.inl b/src/GLMath/glm/detail/func_matrix_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..f7337fe7585d7ddd6014159c0cd9ff5c89a61809 --- /dev/null +++ b/src/GLMath/glm/detail/func_matrix_simd.inl @@ -0,0 +1,94 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#include "type_mat4x4.hpp" +#include "../geometric.hpp" +#include "../simd/matrix.h" +#include + +namespace glm{ +namespace detail +{ +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template + struct compute_matrixCompMult<4, 4, float, Q, true> + { + GLM_STATIC_ASSERT(detail::is_aligned::value, "Specialization requires aligned"); + + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& x, mat<4, 4, float, Q> const& y) + { + mat<4, 4, float, Q> Result; + glm_mat4_matrixCompMult( + *static_cast(&x[0].data), + *static_cast(&y[0].data), + *static_cast(&Result[0].data)); + return Result; + } + }; +# endif + + template + struct compute_transpose<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + mat<4, 4, float, Q> Result; + glm_mat4_transpose(&m[0].data, &Result[0].data); + return Result; + } + }; + + template + struct compute_determinant<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(mat<4, 4, float, Q> const& m) + { + return _mm_cvtss_f32(glm_mat4_determinant(&m[0].data)); + } + }; + + template + struct compute_inverse<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + mat<4, 4, float, Q> Result; + glm_mat4_inverse(&m[0].data, &Result[0].data); + return Result; + } + }; +}//namespace detail + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_lowp> outerProduct<4, 4, float, aligned_lowp>(vec<4, float, aligned_lowp> const& c, vec<4, float, aligned_lowp> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_lowp> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } + + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_mediump> outerProduct<4, 4, float, aligned_mediump>(vec<4, float, aligned_mediump> const& c, vec<4, float, aligned_mediump> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_mediump> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } + + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_highp> outerProduct<4, 4, float, aligned_highp>(vec<4, float, aligned_highp> const& c, vec<4, float, aligned_highp> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_highp> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } +# endif +}//namespace glm + +#endif diff --git a/src/GLMath/glm/detail/func_packing.inl b/src/GLMath/glm/detail/func_packing.inl new file mode 100644 index 0000000000000000000000000000000000000000..234b093c081cc029ccf2094efbdb3d63b319431e --- /dev/null +++ b/src/GLMath/glm/detail/func_packing.inl @@ -0,0 +1,189 @@ +/// @ref core +/// @file glm/detail/func_packing.inl + +#include "../common.hpp" +#include "type_half.hpp" + +namespace glm +{ + GLM_FUNC_QUALIFIER uint packUnorm2x16(vec2 const& v) + { + union + { + unsigned short in[2]; + uint out; + } u; + + vec<2, unsigned short, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 65535.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x16(uint p) + { + union + { + uint in; + unsigned short out[2]; + } u; + + u.in = p; + + return vec2(u.out[0], u.out[1]) * 1.5259021896696421759365224689097e-5f; + } + + GLM_FUNC_QUALIFIER uint packSnorm2x16(vec2 const& v) + { + union + { + signed short in[2]; + uint out; + } u; + + vec<2, short, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 32767.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackSnorm2x16(uint p) + { + union + { + uint in; + signed short out[2]; + } u; + + u.in = p; + + return clamp(vec2(u.out[0], u.out[1]) * 3.0518509475997192297128208258309e-5f, -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint packUnorm4x8(vec4 const& v) + { + union + { + unsigned char in[4]; + uint out; + } u; + + vec<4, unsigned char, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + u.in[2] = result[2]; + u.in[3] = result[3]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x8(uint p) + { + union + { + uint in; + unsigned char out[4]; + } u; + + u.in = p; + + return vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0039215686274509803921568627451f; + } + + GLM_FUNC_QUALIFIER uint packSnorm4x8(vec4 const& v) + { + union + { + signed char in[4]; + uint out; + } u; + + vec<4, signed char, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 127.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + u.in[2] = result[2]; + u.in[3] = result[3]; + + return u.out; + } + + GLM_FUNC_QUALIFIER glm::vec4 unpackSnorm4x8(uint p) + { + union + { + uint in; + signed char out[4]; + } u; + + u.in = p; + + return clamp(vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0078740157480315f, -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER double packDouble2x32(uvec2 const& v) + { + union + { + uint in[2]; + double out; + } u; + + u.in[0] = v[0]; + u.in[1] = v[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER uvec2 unpackDouble2x32(double v) + { + union + { + double in; + uint out[2]; + } u; + + u.in = v; + + return uvec2(u.out[0], u.out[1]); + } + + GLM_FUNC_QUALIFIER uint packHalf2x16(vec2 const& v) + { + union + { + signed short in[2]; + uint out; + } u; + + u.in[0] = detail::toFloat16(v.x); + u.in[1] = detail::toFloat16(v.y); + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackHalf2x16(uint v) + { + union + { + uint in; + signed short out[2]; + } u; + + u.in = v; + + return vec2( + detail::toFloat32(u.out[0]), + detail::toFloat32(u.out[1])); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_packing_simd.inl" +#endif + diff --git a/src/GLMath/glm/detail/func_packing_simd.inl b/src/GLMath/glm/detail/func_packing_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fd0fe8b7d9b4a49f032fd678b7bd6a51624a6b53 --- /dev/null +++ b/src/GLMath/glm/detail/func_packing_simd.inl @@ -0,0 +1,6 @@ +namespace glm{ +namespace detail +{ + +}//namespace detail +}//namespace glm diff --git a/src/GLMath/glm/detail/func_trigonometric.inl b/src/GLMath/glm/detail/func_trigonometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..e129dceac5cb2ae09dd4154cf3356173317b9801 --- /dev/null +++ b/src/GLMath/glm/detail/func_trigonometric.inl @@ -0,0 +1,197 @@ +#include "_vectorize.hpp" +#include +#include + +namespace glm +{ + // radians + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType radians(genType degrees) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'radians' only accept floating-point input"); + + return degrees * static_cast(0.01745329251994329576923690768489); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec radians(vec const& v) + { + return detail::functor1::call(radians, v); + } + + // degrees + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType degrees(genType radians) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'degrees' only accept floating-point input"); + + return radians * static_cast(57.295779513082320876798154814105); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec degrees(vec const& v) + { + return detail::functor1::call(degrees, v); + } + + // sin + using ::std::sin; + + template + GLM_FUNC_QUALIFIER vec sin(vec const& v) + { + return detail::functor1::call(sin, v); + } + + // cos + using std::cos; + + template + GLM_FUNC_QUALIFIER vec cos(vec const& v) + { + return detail::functor1::call(cos, v); + } + + // tan + using std::tan; + + template + GLM_FUNC_QUALIFIER vec tan(vec const& v) + { + return detail::functor1::call(tan, v); + } + + // asin + using std::asin; + + template + GLM_FUNC_QUALIFIER vec asin(vec const& v) + { + return detail::functor1::call(asin, v); + } + + // acos + using std::acos; + + template + GLM_FUNC_QUALIFIER vec acos(vec const& v) + { + return detail::functor1::call(acos, v); + } + + // atan + template + GLM_FUNC_QUALIFIER genType atan(genType y, genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atan' only accept floating-point input"); + + return ::std::atan2(y, x); + } + + template + GLM_FUNC_QUALIFIER vec atan(vec const& a, vec const& b) + { + return detail::functor2::call(::std::atan2, a, b); + } + + using std::atan; + + template + GLM_FUNC_QUALIFIER vec atan(vec const& v) + { + return detail::functor1::call(atan, v); + } + + // sinh + using std::sinh; + + template + GLM_FUNC_QUALIFIER vec sinh(vec const& v) + { + return detail::functor1::call(sinh, v); + } + + // cosh + using std::cosh; + + template + GLM_FUNC_QUALIFIER vec cosh(vec const& v) + { + return detail::functor1::call(cosh, v); + } + + // tanh + using std::tanh; + + template + GLM_FUNC_QUALIFIER vec tanh(vec const& v) + { + return detail::functor1::call(tanh, v); + } + + // asinh +# if GLM_HAS_CXX11_STL + using std::asinh; +# else + template + GLM_FUNC_QUALIFIER genType asinh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asinh' only accept floating-point input"); + + return (x < static_cast(0) ? static_cast(-1) : (x > static_cast(0) ? static_cast(1) : static_cast(0))) * log(std::abs(x) + sqrt(static_cast(1) + x * x)); + } +# endif + + template + GLM_FUNC_QUALIFIER vec asinh(vec const& v) + { + return detail::functor1::call(asinh, v); + } + + // acosh +# if GLM_HAS_CXX11_STL + using std::acosh; +# else + template + GLM_FUNC_QUALIFIER genType acosh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acosh' only accept floating-point input"); + + if(x < static_cast(1)) + return static_cast(0); + return log(x + sqrt(x * x - static_cast(1))); + } +# endif + + template + GLM_FUNC_QUALIFIER vec acosh(vec const& v) + { + return detail::functor1::call(acosh, v); + } + + // atanh +# if GLM_HAS_CXX11_STL + using std::atanh; +# else + template + GLM_FUNC_QUALIFIER genType atanh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atanh' only accept floating-point input"); + + if(std::abs(x) >= static_cast(1)) + return 0; + return static_cast(0.5) * log((static_cast(1) + x) / (static_cast(1) - x)); + } +# endif + + template + GLM_FUNC_QUALIFIER vec atanh(vec const& v) + { + return detail::functor1::call(atanh, v); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_trigonometric_simd.inl" +#endif + diff --git a/src/GLMath/glm/detail/func_trigonometric_simd.inl b/src/GLMath/glm/detail/func_trigonometric_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/GLMath/glm/detail/func_vector_relational.inl b/src/GLMath/glm/detail/func_vector_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..80c9e87fcb97ea042c1aaf42fd6424ebc0bc6e32 --- /dev/null +++ b/src/GLMath/glm/detail/func_vector_relational.inl @@ -0,0 +1,87 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] < y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] <= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] > y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] >= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] == y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] != y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool any(vec const& v) + { + bool Result = false; + for(length_t i = 0; i < L; ++i) + Result = Result || v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool all(vec const& v) + { + bool Result = true; + for(length_t i = 0; i < L; ++i) + Result = Result && v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec not_(vec const& v) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = !v[i]; + return Result; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_vector_relational_simd.inl" +#endif diff --git a/src/GLMath/glm/detail/func_vector_relational_simd.inl b/src/GLMath/glm/detail/func_vector_relational_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fd0fe8b7d9b4a49f032fd678b7bd6a51624a6b53 --- /dev/null +++ b/src/GLMath/glm/detail/func_vector_relational_simd.inl @@ -0,0 +1,6 @@ +namespace glm{ +namespace detail +{ + +}//namespace detail +}//namespace glm diff --git a/src/GLMath/glm/detail/glm.cpp b/src/GLMath/glm/detail/glm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0755bd65d4675232490a4a9ff944506e632e5f5 --- /dev/null +++ b/src/GLMath/glm/detail/glm.cpp @@ -0,0 +1,263 @@ +/// @ref core +/// @file glm/glm.cpp + +#ifndef GLM_ENABLE_EXPERIMENTAL +#define GLM_ENABLE_EXPERIMENTAL +#endif +#include +#include +#include +#include +#include +#include + +namespace glm +{ +// tvec1 type explicit instantiation +template struct vec<1, uint8, lowp>; +template struct vec<1, uint16, lowp>; +template struct vec<1, uint32, lowp>; +template struct vec<1, uint64, lowp>; +template struct vec<1, int8, lowp>; +template struct vec<1, int16, lowp>; +template struct vec<1, int32, lowp>; +template struct vec<1, int64, lowp>; +template struct vec<1, float32, lowp>; +template struct vec<1, float64, lowp>; + +template struct vec<1, uint8, mediump>; +template struct vec<1, uint16, mediump>; +template struct vec<1, uint32, mediump>; +template struct vec<1, uint64, mediump>; +template struct vec<1, int8, mediump>; +template struct vec<1, int16, mediump>; +template struct vec<1, int32, mediump>; +template struct vec<1, int64, mediump>; +template struct vec<1, float32, mediump>; +template struct vec<1, float64, mediump>; + +template struct vec<1, uint8, highp>; +template struct vec<1, uint16, highp>; +template struct vec<1, uint32, highp>; +template struct vec<1, uint64, highp>; +template struct vec<1, int8, highp>; +template struct vec<1, int16, highp>; +template struct vec<1, int32, highp>; +template struct vec<1, int64, highp>; +template struct vec<1, float32, highp>; +template struct vec<1, float64, highp>; + +// tvec2 type explicit instantiation +template struct vec<2, uint8, lowp>; +template struct vec<2, uint16, lowp>; +template struct vec<2, uint32, lowp>; +template struct vec<2, uint64, lowp>; +template struct vec<2, int8, lowp>; +template struct vec<2, int16, lowp>; +template struct vec<2, int32, lowp>; +template struct vec<2, int64, lowp>; +template struct vec<2, float32, lowp>; +template struct vec<2, float64, lowp>; + +template struct vec<2, uint8, mediump>; +template struct vec<2, uint16, mediump>; +template struct vec<2, uint32, mediump>; +template struct vec<2, uint64, mediump>; +template struct vec<2, int8, mediump>; +template struct vec<2, int16, mediump>; +template struct vec<2, int32, mediump>; +template struct vec<2, int64, mediump>; +template struct vec<2, float32, mediump>; +template struct vec<2, float64, mediump>; + +template struct vec<2, uint8, highp>; +template struct vec<2, uint16, highp>; +template struct vec<2, uint32, highp>; +template struct vec<2, uint64, highp>; +template struct vec<2, int8, highp>; +template struct vec<2, int16, highp>; +template struct vec<2, int32, highp>; +template struct vec<2, int64, highp>; +template struct vec<2, float32, highp>; +template struct vec<2, float64, highp>; + +// tvec3 type explicit instantiation +template struct vec<3, uint8, lowp>; +template struct vec<3, uint16, lowp>; +template struct vec<3, uint32, lowp>; +template struct vec<3, uint64, lowp>; +template struct vec<3, int8, lowp>; +template struct vec<3, int16, lowp>; +template struct vec<3, int32, lowp>; +template struct vec<3, int64, lowp>; +template struct vec<3, float32, lowp>; +template struct vec<3, float64, lowp>; + +template struct vec<3, uint8, mediump>; +template struct vec<3, uint16, mediump>; +template struct vec<3, uint32, mediump>; +template struct vec<3, uint64, mediump>; +template struct vec<3, int8, mediump>; +template struct vec<3, int16, mediump>; +template struct vec<3, int32, mediump>; +template struct vec<3, int64, mediump>; +template struct vec<3, float32, mediump>; +template struct vec<3, float64, mediump>; + +template struct vec<3, uint8, highp>; +template struct vec<3, uint16, highp>; +template struct vec<3, uint32, highp>; +template struct vec<3, uint64, highp>; +template struct vec<3, int8, highp>; +template struct vec<3, int16, highp>; +template struct vec<3, int32, highp>; +template struct vec<3, int64, highp>; +template struct vec<3, float32, highp>; +template struct vec<3, float64, highp>; + +// tvec4 type explicit instantiation +template struct vec<4, uint8, lowp>; +template struct vec<4, uint16, lowp>; +template struct vec<4, uint32, lowp>; +template struct vec<4, uint64, lowp>; +template struct vec<4, int8, lowp>; +template struct vec<4, int16, lowp>; +template struct vec<4, int32, lowp>; +template struct vec<4, int64, lowp>; +template struct vec<4, float32, lowp>; +template struct vec<4, float64, lowp>; + +template struct vec<4, uint8, mediump>; +template struct vec<4, uint16, mediump>; +template struct vec<4, uint32, mediump>; +template struct vec<4, uint64, mediump>; +template struct vec<4, int8, mediump>; +template struct vec<4, int16, mediump>; +template struct vec<4, int32, mediump>; +template struct vec<4, int64, mediump>; +template struct vec<4, float32, mediump>; +template struct vec<4, float64, mediump>; + +template struct vec<4, uint8, highp>; +template struct vec<4, uint16, highp>; +template struct vec<4, uint32, highp>; +template struct vec<4, uint64, highp>; +template struct vec<4, int8, highp>; +template struct vec<4, int16, highp>; +template struct vec<4, int32, highp>; +template struct vec<4, int64, highp>; +template struct vec<4, float32, highp>; +template struct vec<4, float64, highp>; + +// tmat2x2 type explicit instantiation +template struct mat<2, 2, float32, lowp>; +template struct mat<2, 2, float64, lowp>; + +template struct mat<2, 2, float32, mediump>; +template struct mat<2, 2, float64, mediump>; + +template struct mat<2, 2, float32, highp>; +template struct mat<2, 2, float64, highp>; + +// tmat2x3 type explicit instantiation +template struct mat<2, 3, float32, lowp>; +template struct mat<2, 3, float64, lowp>; + +template struct mat<2, 3, float32, mediump>; +template struct mat<2, 3, float64, mediump>; + +template struct mat<2, 3, float32, highp>; +template struct mat<2, 3, float64, highp>; + +// tmat2x4 type explicit instantiation +template struct mat<2, 4, float32, lowp>; +template struct mat<2, 4, float64, lowp>; + +template struct mat<2, 4, float32, mediump>; +template struct mat<2, 4, float64, mediump>; + +template struct mat<2, 4, float32, highp>; +template struct mat<2, 4, float64, highp>; + +// tmat3x2 type explicit instantiation +template struct mat<3, 2, float32, lowp>; +template struct mat<3, 2, float64, lowp>; + +template struct mat<3, 2, float32, mediump>; +template struct mat<3, 2, float64, mediump>; + +template struct mat<3, 2, float32, highp>; +template struct mat<3, 2, float64, highp>; + +// tmat3x3 type explicit instantiation +template struct mat<3, 3, float32, lowp>; +template struct mat<3, 3, float64, lowp>; + +template struct mat<3, 3, float32, mediump>; +template struct mat<3, 3, float64, mediump>; + +template struct mat<3, 3, float32, highp>; +template struct mat<3, 3, float64, highp>; + +// tmat3x4 type explicit instantiation +template struct mat<3, 4, float32, lowp>; +template struct mat<3, 4, float64, lowp>; + +template struct mat<3, 4, float32, mediump>; +template struct mat<3, 4, float64, mediump>; + +template struct mat<3, 4, float32, highp>; +template struct mat<3, 4, float64, highp>; + +// tmat4x2 type explicit instantiation +template struct mat<4, 2, float32, lowp>; +template struct mat<4, 2, float64, lowp>; + +template struct mat<4, 2, float32, mediump>; +template struct mat<4, 2, float64, mediump>; + +template struct mat<4, 2, float32, highp>; +template struct mat<4, 2, float64, highp>; + +// tmat4x3 type explicit instantiation +template struct mat<4, 3, float32, lowp>; +template struct mat<4, 3, float64, lowp>; + +template struct mat<4, 3, float32, mediump>; +template struct mat<4, 3, float64, mediump>; + +template struct mat<4, 3, float32, highp>; +template struct mat<4, 3, float64, highp>; + +// tmat4x4 type explicit instantiation +template struct mat<4, 4, float32, lowp>; +template struct mat<4, 4, float64, lowp>; + +template struct mat<4, 4, float32, mediump>; +template struct mat<4, 4, float64, mediump>; + +template struct mat<4, 4, float32, highp>; +template struct mat<4, 4, float64, highp>; + +// tquat type explicit instantiation +template struct qua; +template struct qua; + +template struct qua; +template struct qua; + +template struct qua; +template struct qua; + +//tdualquat type explicit instantiation +template struct tdualquat; +template struct tdualquat; + +template struct tdualquat; +template struct tdualquat; + +template struct tdualquat; +template struct tdualquat; + +}//namespace glm + diff --git a/src/GLMath/glm/detail/qualifier.hpp b/src/GLMath/glm/detail/qualifier.hpp new file mode 100644 index 0000000000000000000000000000000000000000..115817f19ac6aabaa460223d87b09f47201e8419 --- /dev/null +++ b/src/GLMath/glm/detail/qualifier.hpp @@ -0,0 +1,210 @@ +#pragma once + +#include "setup.hpp" + +namespace glm +{ + /// Qualify GLM types in term of alignment (packed, aligned) and precision in term of ULPs (lowp, mediump, highp) + enum qualifier + { + packed_highp, ///< Typed data is tightly packed in memory and operations are executed with high precision in term of ULPs + packed_mediump, ///< Typed data is tightly packed in memory and operations are executed with medium precision in term of ULPs for higher performance + packed_lowp, ///< Typed data is tightly packed in memory and operations are executed with low precision in term of ULPs to maximize performance + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + aligned_highp, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs + aligned_mediump, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs for higher performance + aligned_lowp, // ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs to maximize performance + aligned = aligned_highp, ///< By default aligned qualifier is also high precision +# endif + + highp = packed_highp, ///< By default highp qualifier is also packed + mediump = packed_mediump, ///< By default mediump qualifier is also packed + lowp = packed_lowp, ///< By default lowp qualifier is also packed + packed = packed_highp, ///< By default packed qualifier is also high precision + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE && defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) + defaultp = aligned_highp +# else + defaultp = highp +# endif + }; + + typedef qualifier precision; + + template struct vec; + template struct mat; + template struct qua; + +# if GLM_HAS_TEMPLATE_ALIASES + template using tvec1 = vec<1, T, Q>; + template using tvec2 = vec<2, T, Q>; + template using tvec3 = vec<3, T, Q>; + template using tvec4 = vec<4, T, Q>; + template using tmat2x2 = mat<2, 2, T, Q>; + template using tmat2x3 = mat<2, 3, T, Q>; + template using tmat2x4 = mat<2, 4, T, Q>; + template using tmat3x2 = mat<3, 2, T, Q>; + template using tmat3x3 = mat<3, 3, T, Q>; + template using tmat3x4 = mat<3, 4, T, Q>; + template using tmat4x2 = mat<4, 2, T, Q>; + template using tmat4x3 = mat<4, 3, T, Q>; + template using tmat4x4 = mat<4, 4, T, Q>; + template using tquat = qua; +# endif + +namespace detail +{ + template + struct is_aligned + { + static const bool value = false; + }; + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + struct is_aligned + { + static const bool value = true; + }; + + template<> + struct is_aligned + { + static const bool value = true; + }; + + template<> + struct is_aligned + { + static const bool value = true; + }; +# endif + + template + struct storage + { + typedef struct type { + T data[L]; + } type; + }; + +# if GLM_HAS_ALIGNOF + template + struct storage + { + typedef struct alignas(L * sizeof(T)) type { + T data[L]; + } type; + }; + + template + struct storage<3, T, true> + { + typedef struct alignas(4 * sizeof(T)) type { + T data[4]; + } type; + }; +# endif + +# if GLM_ARCH & GLM_ARCH_SSE2_BIT + template<> + struct storage<4, float, true> + { + typedef glm_f32vec4 type; + }; + + template<> + struct storage<4, int, true> + { + typedef glm_i32vec4 type; + }; + + template<> + struct storage<4, unsigned int, true> + { + typedef glm_u32vec4 type; + }; + + template<> + struct storage<2, double, true> + { + typedef glm_f64vec2 type; + }; + + template<> + struct storage<2, detail::int64, true> + { + typedef glm_i64vec2 type; + }; + + template<> + struct storage<2, detail::uint64, true> + { + typedef glm_u64vec2 type; + }; +# endif + +# if (GLM_ARCH & GLM_ARCH_AVX_BIT) + template<> + struct storage<4, double, true> + { + typedef glm_f64vec4 type; + }; +# endif + +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) + template<> + struct storage<4, detail::int64, true> + { + typedef glm_i64vec4 type; + }; + + template<> + struct storage<4, detail::uint64, true> + { + typedef glm_u64vec4 type; + }; +# endif + + enum genTypeEnum + { + GENTYPE_VEC, + GENTYPE_MAT, + GENTYPE_QUAT + }; + + template + struct genTypeTrait + {}; + + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = GENTYPE_MAT; + }; + + template + struct init_gentype + { + }; + + template + struct init_gentype + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() + { + return genType(1, 0, 0, 0); + } + }; + + template + struct init_gentype + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() + { + return genType(1); + } + }; +}//namespace detail +}//namespace glm diff --git a/src/GLMath/glm/detail/setup.hpp b/src/GLMath/glm/detail/setup.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2983e71978ee5ff2845dcef7dbd46da9fced4b20 --- /dev/null +++ b/src/GLMath/glm/detail/setup.hpp @@ -0,0 +1,1086 @@ +#ifndef GLM_SETUP_INCLUDED + +#include +#include + +#define GLM_VERSION_MAJOR 0 +#define GLM_VERSION_MINOR 9 +#define GLM_VERSION_PATCH 9 +#define GLM_VERSION_REVISION 4 +#define GLM_VERSION 995 +#define GLM_VERSION_MESSAGE "GLM: version 0.9.9.5" + +#define GLM_SETUP_INCLUDED GLM_VERSION + +/////////////////////////////////////////////////////////////////////////////////// +// Active states + +#define GLM_DISABLE 0 +#define GLM_ENABLE 1 + +/////////////////////////////////////////////////////////////////////////////////// +// Messages + +#if defined(GLM_FORCE_MESSAGES) +# define GLM_MESSAGES GLM_ENABLE +#else +# define GLM_MESSAGES GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Detect the platform + +#include "../simd/platform.h" + +/////////////////////////////////////////////////////////////////////////////////// +// Build model + +#if defined(__arch64__) || defined(__LP64__) || defined(_M_X64) || defined(__ppc64__) || defined(__x86_64__) +# define GLM_MODEL GLM_MODEL_64 +#elif defined(__i386__) || defined(__ppc__) +# define GLM_MODEL GLM_MODEL_32 +#else +# define GLM_MODEL GLM_MODEL_32 +#endif// + +#if !defined(GLM_MODEL) && GLM_COMPILER != 0 +# error "GLM_MODEL undefined, your compiler may not be supported by GLM. Add #define GLM_MODEL 0 to ignore this message." +#endif//GLM_MODEL + +/////////////////////////////////////////////////////////////////////////////////// +// C++ Version + +// User defines: GLM_FORCE_CXX98, GLM_FORCE_CXX03, GLM_FORCE_CXX11, GLM_FORCE_CXX14, GLM_FORCE_CXX17, GLM_FORCE_CXX2A + +#define GLM_LANG_CXX98_FLAG (1 << 1) +#define GLM_LANG_CXX03_FLAG (1 << 2) +#define GLM_LANG_CXX0X_FLAG (1 << 3) +#define GLM_LANG_CXX11_FLAG (1 << 4) +#define GLM_LANG_CXX14_FLAG (1 << 5) +#define GLM_LANG_CXX17_FLAG (1 << 6) +#define GLM_LANG_CXX2A_FLAG (1 << 7) +#define GLM_LANG_CXXMS_FLAG (1 << 8) +#define GLM_LANG_CXXGNU_FLAG (1 << 9) + +#define GLM_LANG_CXX98 GLM_LANG_CXX98_FLAG +#define GLM_LANG_CXX03 (GLM_LANG_CXX98 | GLM_LANG_CXX03_FLAG) +#define GLM_LANG_CXX0X (GLM_LANG_CXX03 | GLM_LANG_CXX0X_FLAG) +#define GLM_LANG_CXX11 (GLM_LANG_CXX0X | GLM_LANG_CXX11_FLAG) +#define GLM_LANG_CXX14 (GLM_LANG_CXX11 | GLM_LANG_CXX14_FLAG) +#define GLM_LANG_CXX17 (GLM_LANG_CXX14 | GLM_LANG_CXX17_FLAG) +#define GLM_LANG_CXX2A (GLM_LANG_CXX17 | GLM_LANG_CXX2A_FLAG) +#define GLM_LANG_CXXMS GLM_LANG_CXXMS_FLAG +#define GLM_LANG_CXXGNU GLM_LANG_CXXGNU_FLAG + +#if (defined(_MSC_EXTENSIONS)) +# define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG +#elif ((GLM_COMPILER & (GLM_COMPILER_CLANG | GLM_COMPILER_GCC)) && (GLM_ARCH & GLM_ARCH_SIMD_BIT)) +# define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG +#else +# define GLM_LANG_EXT 0 +#endif + +#if (defined(GLM_FORCE_CXX_UNKNOWN)) +# define GLM_LANG 0 +#elif defined(GLM_FORCE_CXX2A) +# define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX17) +# define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX14) +# define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX11) +# define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX03) +# define GLM_LANG (GLM_LANG_CXX03 | GLM_LANG_EXT) +#elif defined(GLM_FORCE_CXX98) +# define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) +#else +# if GLM_COMPILER & GLM_COMPILER_VC && defined(_MSVC_LANG) +# if GLM_COMPILER >= GLM_COMPILER_VC15_7 +# define GLM_LANG_PLATFORM _MSVC_LANG +# elif GLM_COMPILER >= GLM_COMPILER_VC15 +# if _MSVC_LANG > 201402L +# define GLM_LANG_PLATFORM 201402L +# else +# define GLM_LANG_PLATFORM _MSVC_LANG +# endif +# else +# define GLM_LANG_PLATFORM 0 +# endif +# else +# define GLM_LANG_PLATFORM 0 +# endif + +# if __cplusplus > 201703L || GLM_LANG_PLATFORM > 201703L +# define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) +# elif __cplusplus == 201703L || GLM_LANG_PLATFORM == 201703L +# define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) +# elif __cplusplus == 201402L || GLM_LANG_PLATFORM == 201402L +# define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) +# elif __cplusplus == 201103L || GLM_LANG_PLATFORM == 201103L +# define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) +# elif defined(__INTEL_CXX11_MODE__) || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define GLM_LANG (GLM_LANG_CXX0X | GLM_LANG_EXT) +# elif __cplusplus == 199711L +# define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) +# else +# define GLM_LANG (0 | GLM_LANG_EXT) +# endif +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Has of C++ features + +// http://clang.llvm.org/cxx_status.html +// http://gcc.gnu.org/projects/cxx0x.html +// http://msdn.microsoft.com/en-us/library/vstudio/hh567368(v=vs.120).aspx + +// Android has multiple STLs but C++11 STL detection doesn't always work #284 #564 +#if GLM_PLATFORM == GLM_PLATFORM_ANDROID && !defined(GLM_LANG_STL11_FORCED) +# define GLM_HAS_CXX11_STL 0 +#elif GLM_COMPILER & GLM_COMPILER_CLANG +# if ((defined(_LIBCPP_VERSION) || defined(_MSC_VER)) && GLM_LANG & GLM_LANG_CXX11_FLAG) || \ + defined(GLM_LANG_STL11_FORCED) +# define GLM_HAS_CXX11_STL 1 +# else +# define GLM_HAS_CXX11_STL 0 +# endif +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_CXX11_STL 1 +#else +# define GLM_HAS_CXX11_STL ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_PLATFORM != GLM_PLATFORM_WINDOWS) && (GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)))) +#endif + +// N1720 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_STATIC_ASSERT __has_feature(cxx_static_assert) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_STATIC_ASSERT 1 +#else +# define GLM_HAS_STATIC_ASSERT ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC)))) +#endif + +// N1988 +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_EXTENDED_INTEGER_TYPE 1 +#else +# define GLM_HAS_EXTENDED_INTEGER_TYPE (\ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CLANG))) +#endif + +// N2672 Initializer lists http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_INITIALIZER_LISTS __has_feature(cxx_generalized_initializers) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_INITIALIZER_LISTS 1 +#else +# define GLM_HAS_INITIALIZER_LISTS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA75)))) +#endif + +// N2544 Unrestricted unions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_UNRESTRICTED_UNIONS __has_feature(cxx_unrestricted_unions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_UNRESTRICTED_UNIONS 1 +#else +# define GLM_HAS_UNRESTRICTED_UNIONS (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + (GLM_COMPILER & GLM_COMPILER_VC) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA75))) +#endif + +// N2346 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_DEFAULTED_FUNCTIONS __has_feature(cxx_defaulted_functions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_DEFAULTED_FUNCTIONS 1 +#else +# define GLM_HAS_DEFAULTED_FUNCTIONS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + (GLM_COMPILER & GLM_COMPILER_CUDA))) +#endif + +// N2118 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_RVALUE_REFERENCES __has_feature(cxx_rvalue_references) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_RVALUE_REFERENCES 1 +#else +# define GLM_HAS_RVALUE_REFERENCES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2437 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS __has_feature(cxx_explicit_conversions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 1 +#else +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2258 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_TEMPLATE_ALIASES __has_feature(cxx_alias_templates) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_TEMPLATE_ALIASES 1 +#else +# define GLM_HAS_TEMPLATE_ALIASES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2930 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2930.html +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_RANGE_FOR __has_feature(cxx_range_for) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_RANGE_FOR 1 +#else +# define GLM_HAS_RANGE_FOR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2341 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_ALIGNOF __has_feature(cxx_alignas) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_ALIGNOF 1 +#else +# define GLM_HAS_ALIGNOF ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA70)))) +#endif + +// N2235 Generalized Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf +// N3652 Extended Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html +#if (GLM_ARCH & GLM_ARCH_SIMD_BIT) // Compiler SIMD intrinsics don't support constexpr... +# define GLM_HAS_CONSTEXPR 0 +#elif (GLM_COMPILER & GLM_COMPILER_CLANG) +# define GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr) +#elif (GLM_LANG & GLM_LANG_CXX14_FLAG) +# define GLM_HAS_CONSTEXPR 1 +#else +# define GLM_HAS_CONSTEXPR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && GLM_HAS_INITIALIZER_LISTS && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL17)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)))) +#endif + +#if GLM_HAS_CONSTEXPR +# define GLM_CONSTEXPR constexpr +#else +# define GLM_CONSTEXPR +#endif + +// +#if GLM_HAS_CONSTEXPR +# if (GLM_COMPILER & GLM_COMPILER_CLANG) +# define GLM_HAS_IF_CONSTEXPR __has_feature(cxx_if_constexpr) +# elif (GLM_COMPILER & GLM_COMPILER_GCC) +# define GLM_HAS_IF_CONSTEXPR GLM_COMPILER >= GLM_COMPILER_GCC7 +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) +# define GLM_HAS_IF_CONSTEXPR 1 +# else +# define GLM_HAS_IF_CONSTEXPR 0 +# endif +#else +# define GLM_HAS_IF_CONSTEXPR 0 +#endif + +#if GLM_HAS_IF_CONSTEXPR +# define GLM_IF_CONSTEXPR if constexpr +#else +# define GLM_IF_CONSTEXPR if +#endif + +// +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_ASSIGNABLE 1 +#else +# define GLM_HAS_ASSIGNABLE ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ + ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC49)))) +#endif + +// +#define GLM_HAS_TRIVIAL_QUERIES 0 + +// +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_MAKE_SIGNED 1 +#else +# define GLM_HAS_MAKE_SIGNED ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// +#if defined(GLM_FORCE_INTRINSICS) +# define GLM_HAS_BITSCAN_WINDOWS ((GLM_PLATFORM & GLM_PLATFORM_WINDOWS) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14) && (GLM_ARCH & GLM_ARCH_X86_BIT)))) +#else +# define GLM_HAS_BITSCAN_WINDOWS 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// OpenMP +#ifdef _OPENMP +# if GLM_COMPILER & GLM_COMPILER_GCC +# if GLM_COMPILER >= GLM_COMPILER_GCC61 +# define GLM_HAS_OPENMP 45 +# elif GLM_COMPILER >= GLM_COMPILER_GCC49 +# define GLM_HAS_OPENMP 40 +# elif GLM_COMPILER >= GLM_COMPILER_GCC47 +# define GLM_HAS_OPENMP 31 +# else +# define GLM_HAS_OPENMP 0 +# endif +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# if GLM_COMPILER >= GLM_COMPILER_CLANG38 +# define GLM_HAS_OPENMP 31 +# else +# define GLM_HAS_OPENMP 0 +# endif +# elif GLM_COMPILER & GLM_COMPILER_VC +# define GLM_HAS_OPENMP 20 +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# if GLM_COMPILER >= GLM_COMPILER_INTEL16 +# define GLM_HAS_OPENMP 40 +# else +# define GLM_HAS_OPENMP 0 +# endif +# else +# define GLM_HAS_OPENMP 0 +# endif +#else +# define GLM_HAS_OPENMP 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// nullptr + +#if GLM_LANG & GLM_LANG_CXX0X_FLAG +# define GLM_CONFIG_NULLPTR GLM_ENABLE +#else +# define GLM_CONFIG_NULLPTR GLM_DISABLE +#endif + +#if GLM_CONFIG_NULLPTR == GLM_ENABLE +# define GLM_NULLPTR nullptr +#else +# define GLM_NULLPTR 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Static assert + +#if GLM_HAS_STATIC_ASSERT +# define GLM_STATIC_ASSERT(x, message) static_assert(x, message) +#elif GLM_COMPILER & GLM_COMPILER_VC +# define GLM_STATIC_ASSERT(x, message) typedef char __CASSERT__##__LINE__[(x) ? 1 : -1] +#else +# define GLM_STATIC_ASSERT(x, message) assert(x) +#endif//GLM_LANG + +/////////////////////////////////////////////////////////////////////////////////// +// Qualifiers + +#if GLM_COMPILER & GLM_COMPILER_CUDA +# define GLM_CUDA_FUNC_DEF __device__ __host__ +# define GLM_CUDA_FUNC_DECL __device__ __host__ +#else +# define GLM_CUDA_FUNC_DEF +# define GLM_CUDA_FUNC_DECL +#endif + +#if defined(GLM_FORCE_INLINE) +# if GLM_COMPILER & GLM_COMPILER_VC +# define GLM_INLINE __forceinline +# define GLM_NEVER_INLINE __declspec((noinline)) +# elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) +# define GLM_INLINE inline __attribute__((__always_inline__)) +# define GLM_NEVER_INLINE __attribute__((__noinline__)) +# elif GLM_COMPILER & GLM_COMPILER_CUDA +# define GLM_INLINE __forceinline__ +# define GLM_NEVER_INLINE __noinline__ +# else +# define GLM_INLINE inline +# define GLM_NEVER_INLINE +# endif//GLM_COMPILER +#else +# define GLM_INLINE inline +# define GLM_NEVER_INLINE +#endif//defined(GLM_FORCE_INLINE) + +#define GLM_FUNC_DECL GLM_CUDA_FUNC_DECL +#define GLM_FUNC_QUALIFIER GLM_CUDA_FUNC_DEF GLM_INLINE + +/////////////////////////////////////////////////////////////////////////////////// +// Swizzle operators + +// User defines: GLM_FORCE_SWIZZLE + +#define GLM_SWIZZLE_DISABLED 0 +#define GLM_SWIZZLE_OPERATOR 1 +#define GLM_SWIZZLE_FUNCTION 2 + +#if defined(GLM_FORCE_XYZW_ONLY) +# undef GLM_FORCE_SWIZZLE +#endif + +#if defined(GLM_SWIZZLE) +# pragma message("GLM: GLM_SWIZZLE is deprecated, use GLM_FORCE_SWIZZLE instead.") +# define GLM_FORCE_SWIZZLE +#endif + +#if defined(GLM_FORCE_SWIZZLE) && (GLM_LANG & GLM_LANG_CXXMS_FLAG) +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_OPERATOR +#elif defined(GLM_FORCE_SWIZZLE) +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_FUNCTION +#else +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_DISABLED +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Allows using not basic types as genType + +// #define GLM_FORCE_UNRESTRICTED_GENTYPE + +#ifdef GLM_FORCE_UNRESTRICTED_GENTYPE +# define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_ENABLE +#else +# define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Clip control, define GLM_FORCE_DEPTH_ZERO_TO_ONE before including GLM +// to use a clip space between 0 to 1. +// Coordinate system, define GLM_FORCE_LEFT_HANDED before including GLM +// to use left handed coordinate system by default. + +#define GLM_CLIP_CONTROL_ZO_BIT (1 << 0) // ZERO_TO_ONE +#define GLM_CLIP_CONTROL_NO_BIT (1 << 1) // NEGATIVE_ONE_TO_ONE +#define GLM_CLIP_CONTROL_LH_BIT (1 << 2) // LEFT_HANDED, For DirectX, Metal, Vulkan +#define GLM_CLIP_CONTROL_RH_BIT (1 << 3) // RIGHT_HANDED, For OpenGL, default in GLM + +#define GLM_CLIP_CONTROL_LH_ZO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_ZO_BIT) +#define GLM_CLIP_CONTROL_LH_NO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_NO_BIT) +#define GLM_CLIP_CONTROL_RH_ZO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_ZO_BIT) +#define GLM_CLIP_CONTROL_RH_NO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_NO_BIT) + +#ifdef GLM_FORCE_DEPTH_ZERO_TO_ONE +# ifdef GLM_FORCE_LEFT_HANDED +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_ZO +# else +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_ZO +# endif +#else +# ifdef GLM_FORCE_LEFT_HANDED +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_NO +# else +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_NO +# endif +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Qualifiers + +#if (GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)) +# define GLM_DEPRECATED __declspec(deprecated) +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef __declspec(align(alignment)) type name +#elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG | GLM_COMPILER_INTEL) +# define GLM_DEPRECATED __attribute__((__deprecated__)) +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __attribute__((aligned(alignment))) +#elif GLM_COMPILER & GLM_COMPILER_CUDA +# define GLM_DEPRECATED +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __align__(x) +#else +# define GLM_DEPRECATED +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name +#endif + +/////////////////////////////////////////////////////////////////////////////////// + +#ifdef GLM_FORCE_EXPLICIT_CTOR +# define GLM_EXPLICIT explicit +#else +# define GLM_EXPLICIT +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Length type: all length functions returns a length_t type. +// When GLM_FORCE_SIZE_T_LENGTH is defined, length_t is a typedef of size_t otherwise +// length_t is a typedef of int like GLSL defines it. + +#define GLM_LENGTH_INT 1 +#define GLM_LENGTH_SIZE_T 2 + +#ifdef GLM_FORCE_SIZE_T_LENGTH +# define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_SIZE_T +#else +# define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_INT +#endif + +namespace glm +{ + using std::size_t; +# if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T + typedef size_t length_t; +# else + typedef int length_t; +# endif +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// constexpr + +#if GLM_HAS_CONSTEXPR +# define GLM_CONFIG_CONSTEXP GLM_ENABLE + + namespace glm + { + template + constexpr std::size_t countof(T const (&)[N]) + { + return N; + } + }//namespace glm +# define GLM_COUNTOF(arr) glm::countof(arr) +#elif defined(_MSC_VER) +# define GLM_CONFIG_CONSTEXP GLM_DISABLE + +# define GLM_COUNTOF(arr) _countof(arr) +#else +# define GLM_CONFIG_CONSTEXP GLM_DISABLE + +# define GLM_COUNTOF(arr) sizeof(arr) / sizeof(arr[0]) +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// uint + +namespace glm{ +namespace detail +{ + template + struct is_int + { + enum test {value = 0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + typedef unsigned int uint; +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// 64-bit int + +#if GLM_HAS_EXTENDED_INTEGER_TYPE +# include +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::uint64_t uint64; + typedef std::int64_t int64; +# elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) // C99 detected, 64 bit types available + typedef uint64_t uint64; + typedef int64_t int64; +# elif GLM_COMPILER & GLM_COMPILER_VC + typedef unsigned __int64 uint64; + typedef signed __int64 int64; +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic ignored "-Wlong-long" + __extension__ typedef unsigned long long uint64; + __extension__ typedef signed long long int64; +# elif (GLM_COMPILER & GLM_COMPILER_CLANG) +# pragma clang diagnostic ignored "-Wc++11-long-long" + typedef unsigned long long uint64; + typedef signed long long int64; +# else//unknown compiler + typedef unsigned long long uint64; + typedef signed long long int64; +# endif +}//namespace detail +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// make_unsigned + +#if GLM_HAS_MAKE_SIGNED +# include + +namespace glm{ +namespace detail +{ + using std::make_unsigned; +}//namespace detail +}//namespace glm + +#else + +namespace glm{ +namespace detail +{ + template + struct make_unsigned + {}; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned short type; + }; + + template<> + struct make_unsigned + { + typedef unsigned int type; + }; + + template<> + struct make_unsigned + { + typedef unsigned long type; + }; + + template<> + struct make_unsigned + { + typedef uint64 type; + }; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned short type; + }; + + template<> + struct make_unsigned + { + typedef unsigned int type; + }; + + template<> + struct make_unsigned + { + typedef unsigned long type; + }; + + template<> + struct make_unsigned + { + typedef uint64 type; + }; +}//namespace detail +}//namespace glm +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Only use x, y, z, w as vector type components + +#ifdef GLM_FORCE_XYZW_ONLY +# define GLM_CONFIG_XYZW_ONLY GLM_ENABLE +#else +# define GLM_CONFIG_XYZW_ONLY GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of defaulted initialized types + +#define GLM_CTOR_INIT_DISABLE 0 +#define GLM_CTOR_INITIALIZER_LIST 1 +#define GLM_CTOR_INITIALISATION 2 + +#if defined(GLM_FORCE_CTOR_INIT) && GLM_HAS_INITIALIZER_LISTS +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALIZER_LIST +#elif defined(GLM_FORCE_CTOR_INIT) && !GLM_HAS_INITIALIZER_LISTS +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALISATION +#else +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INIT_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Use SIMD instruction sets + +#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (GLM_ARCH & GLM_ARCH_SIMD_BIT) +# define GLM_CONFIG_SIMD GLM_ENABLE +#else +# define GLM_CONFIG_SIMD GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of defaulted function + +#if GLM_HAS_DEFAULTED_FUNCTIONS && GLM_CONFIG_CTOR_INIT == GLM_CTOR_INIT_DISABLE +# define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_ENABLE +# define GLM_DEFAULT = default +#else +# define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_DISABLE +# define GLM_DEFAULT +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of aligned gentypes + +#ifdef GLM_FORCE_ALIGNED // Legacy define +# define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#endif + +#ifdef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +# define GLM_FORCE_ALIGNED_GENTYPES +#endif + +#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (defined(GLM_FORCE_ALIGNED_GENTYPES) || (GLM_CONFIG_SIMD == GLM_ENABLE)) +# define GLM_CONFIG_ALIGNED_GENTYPES GLM_ENABLE +#else +# define GLM_CONFIG_ALIGNED_GENTYPES GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of anonymous structure as implementation detail + +#if ((GLM_CONFIG_SIMD == GLM_ENABLE) || (GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR) || (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE)) +# define GLM_CONFIG_ANONYMOUS_STRUCT GLM_ENABLE +#else +# define GLM_CONFIG_ANONYMOUS_STRUCT GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Silent warnings + +#ifdef GLM_FORCE_SILENT_WARNINGS +# define GLM_SILENT_WARNINGS GLM_ENABLE +#else +# define GLM_SILENT_WARNINGS GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Precision + +#define GLM_HIGHP 1 +#define GLM_MEDIUMP 2 +#define GLM_LOWP 3 + +#if defined(GLM_FORCE_PRECISION_HIGHP_BOOL) || defined(GLM_PRECISION_HIGHP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_BOOL) || defined(GLM_PRECISION_MEDIUMP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_BOOL) || defined(GLM_PRECISION_LOWP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_INT) || defined(GLM_PRECISION_HIGHP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_INT) || defined(GLM_PRECISION_MEDIUMP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_INT) || defined(GLM_PRECISION_LOWP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_INT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_UINT) || defined(GLM_PRECISION_HIGHP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_UINT) || defined(GLM_PRECISION_MEDIUMP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_UINT) || defined(GLM_PRECISION_LOWP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_UINT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_FLOAT) || defined(GLM_PRECISION_HIGHP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_FLOAT) || defined(GLM_PRECISION_MEDIUMP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_FLOAT) || defined(GLM_PRECISION_LOWP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_DOUBLE) || defined(GLM_PRECISION_HIGHP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_DOUBLE) || defined(GLM_PRECISION_MEDIUMP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_DOUBLE) || defined(GLM_PRECISION_LOWP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Check inclusions of different versions of GLM + +#elif ((GLM_SETUP_INCLUDED != GLM_VERSION) && !defined(GLM_FORCE_IGNORE_VERSION)) +# error "GLM error: A different version of GLM is already included. Define GLM_FORCE_IGNORE_VERSION before including GLM headers to ignore this error." +#elif GLM_SETUP_INCLUDED == GLM_VERSION + +/////////////////////////////////////////////////////////////////////////////////// +// Messages + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_DISPLAYED) +# define GLM_MESSAGE_DISPLAYED +# define GLM_STR_HELPER(x) #x +# define GLM_STR(x) GLM_STR_HELPER(x) + + // Report GLM version +# pragma message (GLM_STR(GLM_VERSION_MESSAGE)) + + // Report C++ language +# if (GLM_LANG & GLM_LANG_CXX2A_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 2A with extensions") +# elif (GLM_LANG & GLM_LANG_CXX2A_FLAG) +# pragma message("GLM: C++ 2A") +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 17 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) +# pragma message("GLM: C++ 17") +# elif (GLM_LANG & GLM_LANG_CXX14_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 14 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX14_FLAG) +# pragma message("GLM: C++ 14") +# elif (GLM_LANG & GLM_LANG_CXX11_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 11 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX11_FLAG) +# pragma message("GLM: C++ 11") +# elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 0x with extensions") +# elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) +# pragma message("GLM: C++ 0x") +# elif (GLM_LANG & GLM_LANG_CXX03_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 03 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX03_FLAG) +# pragma message("GLM: C++ 03") +# elif (GLM_LANG & GLM_LANG_CXX98_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 98 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX98_FLAG) +# pragma message("GLM: C++ 98") +# else +# pragma message("GLM: C++ language undetected") +# endif//GLM_LANG + + // Report compiler detection +# if GLM_COMPILER & GLM_COMPILER_CUDA +# pragma message("GLM: CUDA compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma message("GLM: Visual C++ compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma message("GLM: Clang compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# pragma message("GLM: Intel Compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma message("GLM: GCC compiler detected") +# else +# pragma message("GLM: Compiler not detected") +# endif + + // Report build target +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with AVX2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with AVX2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with AVX instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with AVX instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE4.2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE4.2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE4.1 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE4.1 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSSE3 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSSE3 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE3 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE3 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: ARM 64 bits with Neon instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: ARM 32 bits with Neon instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: ARM 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: ARM 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: MIPS 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: MIPS 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: PowerPC 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: PowerPC 32 bits build target") +# else +# pragma message("GLM: Unknown build target") +# endif//GLM_ARCH + + // Report platform name +# if(GLM_PLATFORM & GLM_PLATFORM_QNXNTO) +# pragma message("GLM: QNX platform detected") +//# elif(GLM_PLATFORM & GLM_PLATFORM_IOS) +//# pragma message("GLM: iOS platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_APPLE) +# pragma message("GLM: Apple platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_WINCE) +# pragma message("GLM: WinCE platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) +# pragma message("GLM: Windows platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_CHROME_NACL) +# pragma message("GLM: Native Client detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) +# pragma message("GLM: Android platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_LINUX) +# pragma message("GLM: Linux platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_UNIX) +# pragma message("GLM: UNIX platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_UNKNOWN) +# pragma message("GLM: platform unknown") +# else +# pragma message("GLM: platform not detected") +# endif + + // Report whether only xyzw component are used +# if defined GLM_FORCE_XYZW_ONLY +# pragma message("GLM: GLM_FORCE_XYZW_ONLY is defined. Only x, y, z and w component are available in vector type. This define disables swizzle operators and SIMD instruction sets.") +# endif + + // Report swizzle operator support +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling operators enabled.") +# elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling functions enabled. Enable compiler C++ language extensions to enable swizzle operators.") +# else +# pragma message("GLM: GLM_FORCE_SWIZZLE is undefined. swizzling functions or operators are disabled.") +# endif + + // Report .length() type +# if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T +# pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is defined. .length() returns a glm::length_t, a typedef of std::size_t.") +# else +# pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is undefined. .length() returns a glm::length_t, a typedef of int following GLSL.") +# endif + +# if GLM_CONFIG_UNRESTRICTED_GENTYPE == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is defined. Removes GLSL restrictions on valid function genTypes.") +# else +# pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is undefined. Follows strictly GLSL on valid function genTypes.") +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is defined. Ignores C++ warnings from using C++ language extensions.") +# else +# pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is undefined. Shows C++ warnings from using C++ language extensions.") +# endif + +# ifdef GLM_FORCE_SINGLE_ONLY +# pragma message("GLM: GLM_FORCE_SINGLE_ONLY is defined. Using only single precision floating-point types.") +# endif + +# if defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE) +# undef GLM_FORCE_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined, allowing aligned types. This prevents the use of C++ constexpr.") +# elif defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) +# undef GLM_FORCE_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") +# endif + +# if defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE +# undef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") +# elif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined. All gentypes (e.g. vec3) will be aligned and padded by default.") +# endif +# endif + +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT +# pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is defined. Using zero to one depth clip space.") +# else +# pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is undefined. Using negative one to one depth clip space.") +# endif + +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT +# pragma message("GLM: GLM_FORCE_LEFT_HANDED is defined. Using left handed coordinate system.") +# else +# pragma message("GLM: GLM_FORCE_LEFT_HANDED is undefined. Using right handed coordinate system.") +# endif +#endif//GLM_MESSAGES + +#endif//GLM_SETUP_INCLUDED diff --git a/src/GLMath/glm/detail/type_float.hpp b/src/GLMath/glm/detail/type_float.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c8037ebd7aa265cb56e3b809cf19df8fa807bcf8 --- /dev/null +++ b/src/GLMath/glm/detail/type_float.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "setup.hpp" + +#if GLM_COMPILER == GLM_COMPILER_VC12 +# pragma warning(push) +# pragma warning(disable: 4512) // assignment operator could not be generated +#endif + +namespace glm{ +namespace detail +{ + template + union float_t + {}; + + // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + template <> + union float_t + { + typedef int int_type; + typedef float float_type; + + GLM_CONSTEXPR float_t(float_type Num = 0.0f) : f(Num) {} + + GLM_CONSTEXPR float_t& operator=(float_t const& x) + { + f = x.f; + return *this; + } + + // Portable extraction of components. + GLM_CONSTEXPR bool negative() const { return i < 0; } + GLM_CONSTEXPR int_type mantissa() const { return i & ((1 << 23) - 1); } + GLM_CONSTEXPR int_type exponent() const { return (i >> 23) & ((1 << 8) - 1); } + + int_type i; + float_type f; + }; + + template <> + union float_t + { + typedef detail::int64 int_type; + typedef double float_type; + + GLM_CONSTEXPR float_t(float_type Num = static_cast(0)) : f(Num) {} + + GLM_CONSTEXPR float_t& operator=(float_t const& x) + { + f = x.f; + return *this; + } + + // Portable extraction of components. + GLM_CONSTEXPR bool negative() const { return i < 0; } + GLM_CONSTEXPR int_type mantissa() const { return i & ((int_type(1) << 52) - 1); } + GLM_CONSTEXPR int_type exponent() const { return (i >> 52) & ((int_type(1) << 11) - 1); } + + int_type i; + float_type f; + }; +}//namespace detail +}//namespace glm + +#if GLM_COMPILER == GLM_COMPILER_VC12 +# pragma warning(pop) +#endif diff --git a/src/GLMath/glm/detail/type_half.hpp b/src/GLMath/glm/detail/type_half.hpp new file mode 100644 index 0000000000000000000000000000000000000000..40b8bec00d34143d2e1f0ff60a743aad9e30580f --- /dev/null +++ b/src/GLMath/glm/detail/type_half.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "setup.hpp" + +namespace glm{ +namespace detail +{ + typedef short hdata; + + GLM_FUNC_DECL float toFloat32(hdata value); + GLM_FUNC_DECL hdata toFloat16(float const& value); + +}//namespace detail +}//namespace glm + +#include "type_half.inl" diff --git a/src/GLMath/glm/detail/type_half.inl b/src/GLMath/glm/detail/type_half.inl new file mode 100644 index 0000000000000000000000000000000000000000..b0723e362d53ad724adee01a6fbb696162851e64 --- /dev/null +++ b/src/GLMath/glm/detail/type_half.inl @@ -0,0 +1,241 @@ +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER float overflow() + { + volatile float f = 1e10; + + for(int i = 0; i < 10; ++i) + f *= f; // this will overflow before the for loop terminates + return f; + } + + union uif32 + { + GLM_FUNC_QUALIFIER uif32() : + i(0) + {} + + GLM_FUNC_QUALIFIER uif32(float f_) : + f(f_) + {} + + GLM_FUNC_QUALIFIER uif32(unsigned int i_) : + i(i_) + {} + + float f; + unsigned int i; + }; + + GLM_FUNC_QUALIFIER float toFloat32(hdata value) + { + int s = (value >> 15) & 0x00000001; + int e = (value >> 10) & 0x0000001f; + int m = value & 0x000003ff; + + if(e == 0) + { + if(m == 0) + { + // + // Plus or minus zero + // + + detail::uif32 result; + result.i = static_cast(s << 31); + return result.f; + } + else + { + // + // Denormalized number -- renormalize it + // + + while(!(m & 0x00000400)) + { + m <<= 1; + e -= 1; + } + + e += 1; + m &= ~0x00000400; + } + } + else if(e == 31) + { + if(m == 0) + { + // + // Positive or negative infinity + // + + uif32 result; + result.i = static_cast((s << 31) | 0x7f800000); + return result.f; + } + else + { + // + // Nan -- preserve sign and significand bits + // + + uif32 result; + result.i = static_cast((s << 31) | 0x7f800000 | (m << 13)); + return result.f; + } + } + + // + // Normalized number + // + + e = e + (127 - 15); + m = m << 13; + + // + // Assemble s, e and m. + // + + uif32 Result; + Result.i = static_cast((s << 31) | (e << 23) | m); + return Result.f; + } + + GLM_FUNC_QUALIFIER hdata toFloat16(float const& f) + { + uif32 Entry; + Entry.f = f; + int i = static_cast(Entry.i); + + // + // Our floating point number, f, is represented by the bit + // pattern in integer i. Disassemble that bit pattern into + // the sign, s, the exponent, e, and the significand, m. + // Shift s into the position where it will go in the + // resulting half number. + // Adjust e, accounting for the different exponent bias + // of float and half (127 versus 15). + // + + int s = (i >> 16) & 0x00008000; + int e = ((i >> 23) & 0x000000ff) - (127 - 15); + int m = i & 0x007fffff; + + // + // Now reassemble s, e and m into a half: + // + + if(e <= 0) + { + if(e < -10) + { + // + // E is less than -10. The absolute value of f is + // less than half_MIN (f may be a small normalized + // float, a denormalized float or a zero). + // + // We convert f to a half zero. + // + + return hdata(s); + } + + // + // E is between -10 and 0. F is a normalized float, + // whose magnitude is less than __half_NRM_MIN. + // + // We convert f to a denormalized half. + // + + m = (m | 0x00800000) >> (1 - e); + + // + // Round to nearest, round "0.5" up. + // + // Rounding may cause the significand to overflow and make + // our number normalized. Because of the way a half's bits + // are laid out, we don't have to treat this case separately; + // the code below will handle it correctly. + // + + if(m & 0x00001000) + m += 0x00002000; + + // + // Assemble the half from s, e (zero) and m. + // + + return hdata(s | (m >> 13)); + } + else if(e == 0xff - (127 - 15)) + { + if(m == 0) + { + // + // F is an infinity; convert f to a half + // infinity with the same sign as f. + // + + return hdata(s | 0x7c00); + } + else + { + // + // F is a NAN; we produce a half NAN that preserves + // the sign bit and the 10 leftmost bits of the + // significand of f, with one exception: If the 10 + // leftmost bits are all zero, the NAN would turn + // into an infinity, so we have to set at least one + // bit in the significand. + // + + m >>= 13; + + return hdata(s | 0x7c00 | m | (m == 0)); + } + } + else + { + // + // E is greater than zero. F is a normalized float. + // We try to convert f to a normalized half. + // + + // + // Round to nearest, round "0.5" up + // + + if(m & 0x00001000) + { + m += 0x00002000; + + if(m & 0x00800000) + { + m = 0; // overflow in significand, + e += 1; // adjust exponent + } + } + + // + // Handle exponent overflow + // + + if (e > 30) + { + overflow(); // Cause a hardware floating point overflow; + + return hdata(s | 0x7c00); + // if this returns, the half becomes an + } // infinity with the same sign as f. + + // + // Assemble the half from s, e and m. + // + + return hdata(s | (e << 10) | (m >> 13)); + } + } + +}//namespace detail +}//namespace glm diff --git a/src/GLMath/glm/detail/type_mat2x2.hpp b/src/GLMath/glm/detail/type_mat2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..033908f4495b79a9061e79738049684981ccd7f3 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat2x2.hpp @@ -0,0 +1,177 @@ +/// @ref core +/// @file glm/detail/type_mat2x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 2, T, Q> type; + typedef mat<2, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x1, T const& y1, + T const& x2, T const& y2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + U const& x1, V const& y1, + M const& x2, N const& y2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, U, Q> const& v1, + vec<2, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(mat<2, 2, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator*(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator*(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); +} //namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x2.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat2x2.inl b/src/GLMath/glm/detail/type_mat2x2.inl new file mode 100644 index 0000000000000000000000000000000000000000..fe5d1aa313339cc82bb2992ce9237761de8dd667 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat2x2.inl @@ -0,0 +1,536 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{m[0], m[1]} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(T scalar) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(scalar, 0), col_type(0, scalar)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(scalar, 0); + this->value[1] = col_type(0, scalar); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat + ( + T const& x0, T const& y0, + T const& x1, T const& y1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{v0, v1} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; +# endif + } + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat + ( + X1 const& x1, Y1 const& y1, + X2 const& x2, Y2 const& y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(static_cast(x1), value_type(y1)), col_type(static_cast(x2), value_type(y2)) } +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(static_cast(x1), value_type(y1)); + this->value[1] = col_type(static_cast(x2), value_type(y2)); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- mat2x2 matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 2, T, Q>::col_type const& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator=(mat<2, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(U scalar) + { + this->value[0] += scalar; + this->value[1] += scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(mat<2, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(U scalar) + { + this->value[0] -= scalar; + this->value[1] -= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(mat<2, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(U scalar) + { + this->value[0] *= scalar; + this->value[1] *= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(mat<2, 2, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(U scalar) + { + this->value[0] /= scalar; + this->value[1] /= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(mat<2, 2, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator++(int) + { + mat<2, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator--(int) + { + mat<2, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + scalar - m[0], + scalar - m[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator* + ( + mat<2, 2, T, Q> const& m, + typename mat<2, 2, T, Q>::row_type const& v + ) + { + return vec<2, T, Q>( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator* + ( + typename mat<2, 2, T, Q>::col_type const& v, + mat<2, 2, T, Q> const& m + ) + { + return vec<2, T, Q>( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + mat<2, 2, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat2x3.hpp b/src/GLMath/glm/detail/type_mat2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d6596e469b8445cafd61b8b19971a60ef3b82ee8 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat2x3.hpp @@ -0,0 +1,159 @@ +/// @ref core +/// @file glm/detail/type_mat2x3.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 3, T, Q> type; + typedef mat<3, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, + T x1, T y1, T z1); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1); + + // -- Conversions -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, U, Q> const& v1, + vec<3, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 3, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 3, T, Q>::col_type operator*(mat<2, 3, T, Q> const& m, typename mat<2, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 3, T, Q>::row_type operator*(typename mat<2, 3, T, Q>::col_type const& v, mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x3.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat2x3.inl b/src/GLMath/glm/detail/type_mat2x3.inl new file mode 100644 index 0000000000000000000000000000000000000000..5fec17e5dbbc7b021628543715bda2a8e6bc70f3 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat2x3.inl @@ -0,0 +1,510 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{m.value[0], m.value[1]} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m.value[0]; + this->value[1] = m.value[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(T scalar) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(scalar, 0, 0), col_type(0, scalar, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(scalar, 0, 0); + this->value[1] = col_type(0, scalar, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat + ( + T x0, T y0, T z0, + T x1, T y1, T z1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1), col_type(x2, y2, z2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1); + this->value[1] = col_type(x2, y2, z2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type & mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 3, T, Q>::col_type const& mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator=(mat<2, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator+=(mat<2, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(mat<2, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator++(int) + { + mat<2, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator--(int) + { + mat<2, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type operator* + ( + mat<2, 3, T, Q> const& m, + typename mat<2, 3, T, Q>::row_type const& v) + { + return typename mat<2, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y, + m[0][2] * v.x + m[1][2] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::row_type operator* + ( + typename mat<2, 3, T, Q>::col_type const& v, + mat<2, 3, T, Q> const& m) + { + return typename mat<2, 3, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + T SrcA00 = m1[0][0]; + T SrcA01 = m1[0][1]; + T SrcA02 = m1[0][2]; + T SrcA10 = m1[1][0]; + T SrcA11 = m1[1][1]; + T SrcA12 = m1[1][2]; + + T SrcB00 = m2[0][0]; + T SrcB01 = m2[0][1]; + T SrcB10 = m2[1][0]; + T SrcB11 = m2[1][1]; + T SrcB20 = m2[2][0]; + T SrcB21 = m2[2][1]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat2x4.hpp b/src/GLMath/glm/detail/type_mat2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ff03e215e5e4da0d190c514461fd57c902643bbf --- /dev/null +++ b/src/GLMath/glm/detail/type_mat2x4.hpp @@ -0,0 +1,161 @@ +/// @ref core +/// @file glm/detail/type_mat2x4.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 4, T, Q> type; + typedef mat<4, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, U, Q> const& v1, + vec<4, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 4, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x4.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat2x4.inl b/src/GLMath/glm/detail/type_mat2x4.inl new file mode 100644 index 0000000000000000000000000000000000000000..b6d2b9ddfd13e42f12fa462d7be77b32aa2d8e8a --- /dev/null +++ b/src/GLMath/glm/detail/type_mat2x4.inl @@ -0,0 +1,520 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{m[0], m[1]} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat + ( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1, w1); + this->value[1] = col_type(x2, y2, z2, w2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type & mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 4, T, Q>::col_type const& mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator=(mat<2, 4, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(mat<2, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(mat<2, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> & mat<2, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator++(int) + { + mat<2, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator--(int) + { + mat<2, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v) + { + return typename mat<2, 4, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y, + m[0][2] * v.x + m[1][2] * v.y, + m[0][3] * v.x + m[1][3] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m) + { + return typename mat<2, 4, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + T SrcA00 = m1[0][0]; + T SrcA01 = m1[0][1]; + T SrcA02 = m1[0][2]; + T SrcA03 = m1[0][3]; + T SrcA10 = m1[1][0]; + T SrcA11 = m1[1][1]; + T SrcA12 = m1[1][2]; + T SrcA13 = m1[1][3]; + + T SrcB00 = m2[0][0]; + T SrcB01 = m2[0][1]; + T SrcB10 = m2[1][0]; + T SrcB11 = m2[1][1]; + T SrcB20 = m2[2][0]; + T SrcB21 = m2[2][1]; + T SrcB30 = m2[3][0]; + T SrcB31 = m2[3][1]; + + mat<4, 4, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; + Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; + Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; + Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21; + Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31; + Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31; + Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31; + Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat3x2.hpp b/src/GLMath/glm/detail/type_mat3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e16658131fd6400fde34299313a9ac92c2db4f7f --- /dev/null +++ b/src/GLMath/glm/detail/type_mat3x2.hpp @@ -0,0 +1,167 @@ +/// @ref core +/// @file glm/detail/type_mat3x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 2, T, Q> type; + typedef mat<2, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, + T x1, T y1, + T x2, T y2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, V1, Q> const& v1, + vec<2, V2, Q> const& v2, + vec<2, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<3, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x2.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat3x2.inl b/src/GLMath/glm/detail/type_mat3x2.inl new file mode 100644 index 0000000000000000000000000000000000000000..b4b948b72613eb48253a5e5543ac977ab90d44da --- /dev/null +++ b/src/GLMath/glm/detail/type_mat3x2.inl @@ -0,0 +1,532 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1), col_type(0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); + this->value[2] = col_type(0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0), col_type(0, s), col_type(0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0); + this->value[1] = col_type(0, s); + this->value[2] = col_type(0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat + ( + T x0, T y0, + T x1, T y1, + T x2, T y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat + ( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type & mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 2, T, Q>::col_type const& mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator=(mat<3, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(mat<3, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(mat<3, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> & mat<3, 2, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator++(int) + { + mat<3, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator--(int) + { + mat<3, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v) + { + return typename mat<3, 2, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m) + { + return typename mat<3, 2, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1], + v.x * m[2][0] + v.y * m[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + const T SrcA00 = m1[0][0]; + const T SrcA01 = m1[0][1]; + const T SrcA10 = m1[1][0]; + const T SrcA11 = m1[1][1]; + const T SrcA20 = m1[2][0]; + const T SrcA21 = m1[2][1]; + + const T SrcB00 = m2[0][0]; + const T SrcB01 = m2[0][1]; + const T SrcB02 = m2[0][2]; + const T SrcB10 = m2[1][0]; + const T SrcB11 = m2[1][1]; + const T SrcB12 = m2[1][2]; + + mat<2, 2, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat3x3.hpp b/src/GLMath/glm/detail/type_mat3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3174872eb7c1b93f7a10b5fd0d653a814c1ccf64 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat3x3.hpp @@ -0,0 +1,184 @@ +/// @ref core +/// @file glm/detail/type_mat3x3.hpp + +#pragma once + +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 3, T, Q> type; + typedef mat<3, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, + T x1, T y1, T z1, + T x2, T y2, T z2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2, + X3 x3, Y3 y3, Z3 z3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, V1, Q> const& v1, + vec<3, V2, Q> const& v2, + vec<3, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(mat<3, 3, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 3, T, Q> & operator++(); + GLM_FUNC_DECL mat<3, 3, T, Q> & operator--(); + GLM_FUNC_DECL mat<3, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x3.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat3x3.inl b/src/GLMath/glm/detail/type_mat3x3.inl new file mode 100644 index 0000000000000000000000000000000000000000..1ddaf99d5819c18df1809a046c1b7c87402a0ea4 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat3x3.inl @@ -0,0 +1,601 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); + this->value[2] = col_type(0, 0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0); + this->value[1] = col_type(0, s, 0); + this->value[2] = col_type(0, 0, s); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat + ( + T x0, T y0, T z0, + T x1, T y1, T z1, + T x2, T y2, T z2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2, + X3 x3, Y3 y3, Z3 z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1); + this->value[1] = col_type(x2, y2, z2); + this->value[2] = col_type(x3, y3, z3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type & mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 3, T, Q>::col_type const& mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator=(mat<3, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(mat<3, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(mat<3, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(mat<3, 3, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(mat<3, 3, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator++(int) + { + mat<3, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator--(int) + { + mat<3, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + scalar - m[0], + scalar - m[1], + scalar - m[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) + { + return typename mat<3, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) + { + return typename mat<3, 3, T, Q>::row_type( + m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z, + m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z, + m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA02 = m1[0][2]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA12 = m1[1][2]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA22 = m1[2][2]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB20 = m2[2][0]; + T const SrcB21 = m2[2][1]; + T const SrcB22 = m2[2][2]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + mat<3, 3, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat3x4.hpp b/src/GLMath/glm/detail/type_mat3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6e40b90305eb2bf55c5bac3f5b77f8cc33f2f538 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat3x4.hpp @@ -0,0 +1,166 @@ +/// @ref core +/// @file glm/detail/type_mat3x4.hpp + +#pragma once + +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 4, T, Q> type; + typedef mat<4, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1, + T x2, T y2, T z2, T w2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2, + X3 x3, Y3 y3, Z3 z3, W3 w3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, V1, Q> const& v1, + vec<4, V2, Q> const& v2, + vec<4, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 4, T, Q> & operator++(); + GLM_FUNC_DECL mat<3, 4, T, Q> & operator--(); + GLM_FUNC_DECL mat<3, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 4, T, Q>::col_type operator*(mat<3, 4, T, Q> const& m, typename mat<3, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 4, T, Q>::row_type operator*(typename mat<3, 4, T, Q>::col_type const& v, mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x4.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat3x4.inl b/src/GLMath/glm/detail/type_mat3x4.inl new file mode 100644 index 0000000000000000000000000000000000000000..6ee416cfd657f7e9ed1bcf27e4cddbac641f4979 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat3x4.inl @@ -0,0 +1,578 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); + this->value[2] = col_type(0, 0, s, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat + ( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1, + T x2, T y2, T z2, T w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, typename Z0, typename W0, + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat + ( + X0 x0, Y0 y0, Z0 z0, W0 w0, + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(vec<4, V1, Q> const& v0, vec<4, V2, Q> const& v1, vec<4, V3, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type & mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 4, T, Q>::col_type const& mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator=(mat<3, 4, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(mat<3, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(mat<3, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> & mat<3, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator++(int) + { + mat<3, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator--(int) + { + mat<3, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type operator* + ( + mat<3, 4, T, Q> const& m, + typename mat<3, 4, T, Q>::row_type const& v + ) + { + return typename mat<3, 4, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z, + m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::row_type operator* + ( + typename mat<3, 4, T, Q>::col_type const& v, + mat<3, 4, T, Q> const& m + ) + { + return typename mat<3, 4, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3], + v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + const T SrcA00 = m1[0][0]; + const T SrcA01 = m1[0][1]; + const T SrcA02 = m1[0][2]; + const T SrcA03 = m1[0][3]; + const T SrcA10 = m1[1][0]; + const T SrcA11 = m1[1][1]; + const T SrcA12 = m1[1][2]; + const T SrcA13 = m1[1][3]; + const T SrcA20 = m1[2][0]; + const T SrcA21 = m1[2][1]; + const T SrcA22 = m1[2][2]; + const T SrcA23 = m1[2][3]; + + const T SrcB00 = m2[0][0]; + const T SrcB01 = m2[0][1]; + const T SrcB02 = m2[0][2]; + const T SrcB10 = m2[1][0]; + const T SrcB11 = m2[1][1]; + const T SrcB12 = m2[1][2]; + const T SrcB20 = m2[2][0]; + const T SrcB21 = m2[2][1]; + const T SrcB22 = m2[2][2]; + const T SrcB30 = m2[3][0]; + const T SrcB31 = m2[3][1]; + const T SrcB32 = m2[3][2]; + + mat<4, 4, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; + Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01 + SrcA23 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; + Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11 + SrcA23 * SrcB12; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; + Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21 + SrcA23 * SrcB22; + Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31 + SrcA20 * SrcB32; + Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31 + SrcA21 * SrcB32; + Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31 + SrcA22 * SrcB32; + Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31 + SrcA23 * SrcB32; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat4x2.hpp b/src/GLMath/glm/detail/type_mat4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8d3435271114988183d12ae39c1a8577e0da3327 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat4x2.hpp @@ -0,0 +1,171 @@ +/// @ref core +/// @file glm/detail/type_mat4x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 2, T, Q> type; + typedef mat<2, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, + T x1, T y1, + T x2, T y2, + T x3, T y3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, V1, Q> const& v1, + vec<2, V2, Q> const& v2, + vec<2, V3, Q> const& v3, + vec<2, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<4, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x2.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat4x2.inl b/src/GLMath/glm/detail/type_mat4x2.inl new file mode 100644 index 0000000000000000000000000000000000000000..419c80c42cf105be007160d38ce37a81b60b833c --- /dev/null +++ b/src/GLMath/glm/detail/type_mat4x2.inl @@ -0,0 +1,574 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1), col_type(0, 0), col_type(0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); + this->value[2] = col_type(0, 0); + this->value[3] = col_type(0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0), col_type(0, s), col_type(0, 0), col_type(0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0); + this->value[1] = col_type(0, s); + this->value[2] = col_type(0, 0); + this->value[3] = col_type(0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat + ( + T x0, T y0, + T x1, T y1, + T x2, T y2, + T x3, T y3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); + this->value[3] = col_type(x3, y3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat + ( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); + this->value[3] = col_type(x3, y3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2, vec<2, V3, Q> const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); + this->value[3] = col_type(v3); +# endif + } + + // -- Conversion -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type & mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 2, T, Q>::col_type const& mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q>& mat<4, 2, T, Q>::operator=(mat<4, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(mat<4, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(mat<4, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator++(int) + { + mat<4, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator--(int) + { + mat<4, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar, + m[3] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar, + m[3] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar, + m[3] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar, + m[3] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v) + { + return typename mat<4, 2, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m) + { + return typename mat<4, 2, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1], + v.x * m[2][0] + v.y * m[2][1], + v.x * m[3][0] + v.y * m[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA30 = m1[3][0]; + T const SrcA31 = m1[3][1]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB03 = m2[0][3]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB13 = m2[1][3]; + + mat<2, 2, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar, + m[3] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2], + scalar / m[3]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat4x3.hpp b/src/GLMath/glm/detail/type_mat4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..16e42705185bccd57d5de38b57f0505666aa7031 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat4x3.hpp @@ -0,0 +1,171 @@ +/// @ref core +/// @file glm/detail/type_mat4x3.hpp + +#pragma once + +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 3, T, Q> type; + typedef mat<3, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x0, T const& y0, T const& z0, + T const& x1, T const& y1, T const& z1, + T const& x2, T const& y2, T const& z2, + T const& x3, T const& y3, T const& z3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3, + typename X4, typename Y4, typename Z4> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 const& x1, Y1 const& y1, Z1 const& z1, + X2 const& x2, Y2 const& y2, Z2 const& z2, + X3 const& x3, Y3 const& y3, Z3 const& z3, + X4 const& x4, Y4 const& y4, Z4 const& z4); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, V1, Q> const& v1, + vec<3, V2, Q> const& v2, + vec<3, V3, Q> const& v3, + vec<3, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 3, T, Q>& operator++(); + GLM_FUNC_DECL mat<4, 3, T, Q>& operator--(); + GLM_FUNC_DECL mat<4, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 3, T, Q>::col_type operator*(mat<4, 3, T, Q> const& m, typename mat<4, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 3, T, Q>::row_type operator*(typename mat<4, 3, T, Q>::col_type const& v, mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x3.inl" +#endif //GLM_EXTERNAL_TEMPLATE diff --git a/src/GLMath/glm/detail/type_mat4x3.inl b/src/GLMath/glm/detail/type_mat4x3.inl new file mode 100644 index 0000000000000000000000000000000000000000..11b1ee35d8a2d5a1d81f73eedc0b98c1456508d5 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat4x3.inl @@ -0,0 +1,598 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1), col_type(0, 0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0, 0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(T const& s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s), col_type(0, 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0); + this->value[1] = col_type(0, s, 0); + this->value[2] = col_type(0, 0, s); + this->value[3] = col_type(0, 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat + ( + T const& x0, T const& y0, T const& z0, + T const& x1, T const& y1, T const& z1, + T const& x2, T const& y2, T const& z2, + T const& x3, T const& y3, T const& z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); + this->value[3] = col_type(x3, y3, z3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, typename Z0, + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat + ( + X0 const& x0, Y0 const& y0, Z0 const& z0, + X1 const& x1, Y1 const& y1, Z1 const& z1, + X2 const& x2, Y2 const& y2, Z2 const& z2, + X3 const& x3, Y3 const& y3, Z3 const& z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); + this->value[3] = col_type(x3, y3, z3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3, vec<3, V4, Q> const& v4) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); + this->value[3] = col_type(v4); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(m[3], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); + this->value[3] = col_type(m[3], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type & mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 3, T, Q>::col_type const& mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q>& mat<4, 3, T, Q>::operator=(mat<4, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(mat<4, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(mat<4, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator++(int) + { + mat<4, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator--(int) + { + mat<4, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] - s, + m[1] - s, + m[2] - s, + m[3] - s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type operator* + ( + mat<4, 3, T, Q> const& m, + typename mat<4, 3, T, Q>::row_type const& v) + { + return typename mat<4, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::row_type operator* + ( + typename mat<4, 3, T, Q>::col_type const& v, + mat<4, 3, T, Q> const& m) + { + return typename mat<4, 3, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2], + v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2], + v.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA02 = m1[0][2]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA12 = m1[1][2]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA22 = m1[2][2]; + T const SrcA30 = m1[3][0]; + T const SrcA31 = m1[3][1]; + T const SrcA32 = m1[3][2]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB03 = m2[0][3]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB13 = m2[1][3]; + T const SrcB20 = m2[2][0]; + T const SrcB21 = m2[2][1]; + T const SrcB22 = m2[2][2]; + T const SrcB23 = m2[2][3]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02 + SrcA32 * SrcB03; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12 + SrcA32 * SrcB13; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22 + SrcA30 * SrcB23; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22 + SrcA31 * SrcB23; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22 + SrcA32 * SrcB23; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2] + m1[3][2] * m2[3][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] / s, + m[1] / s, + m[2] / s, + m[3] / s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + s / m[0], + s / m[1], + s / m[2], + s / m[3]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +} //namespace glm diff --git a/src/GLMath/glm/detail/type_mat4x4.hpp b/src/GLMath/glm/detail/type_mat4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3517f9f527de3eef38076c3f991284699359017c --- /dev/null +++ b/src/GLMath/glm/detail/type_mat4x4.hpp @@ -0,0 +1,189 @@ +/// @ref core +/// @file glm/detail/type_mat4x4.hpp + +#pragma once + +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 4, T, Q> type; + typedef mat<4, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x0, T const& y0, T const& z0, T const& w0, + T const& x1, T const& y1, T const& z1, T const& w1, + T const& x2, T const& y2, T const& z2, T const& w2, + T const& x3, T const& y3, T const& z3, T const& w3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3, + typename X4, typename Y4, typename Z4, typename W4> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, + X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, + X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, + X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, V1, Q> const& v1, + vec<4, V2, Q> const& v2, + vec<4, V3, Q> const& v3, + vec<4, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(mat<4, 4, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 4, T, Q> & operator++(); + GLM_FUNC_DECL mat<4, 4, T, Q> & operator--(); + GLM_FUNC_DECL mat<4, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator*(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator*(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x4.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/src/GLMath/glm/detail/type_mat4x4.inl b/src/GLMath/glm/detail/type_mat4x4.inl new file mode 100644 index 0000000000000000000000000000000000000000..e38b87f77e73a3cd731a18baa9ce4a3dfcfa99a2 --- /dev/null +++ b/src/GLMath/glm/detail/type_mat4x4.inl @@ -0,0 +1,706 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(T const& s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0), col_type(0, 0, 0, s)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); + this->value[2] = col_type(0, 0, s, 0); + this->value[3] = col_type(0, 0, 0, s); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat + ( + T const& x0, T const& y0, T const& z0, T const& w0, + T const& x1, T const& y1, T const& z1, T const& w1, + T const& x2, T const& y2, T const& z2, T const& w2, + T const& x3, T const& y3, T const& z3, T const& w3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2), + col_type(x3, y3, z3, w3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); + this->value[3] = col_type(x3, y3, z3, w3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + // -- Conversions -- + + template + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3, + typename X4, typename Y4, typename Z4, typename W4> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat + ( + X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, + X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, + X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, + X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2), col_type(x3, y3, z3, w3), col_type(x4, y4, z4, w4)} +# endif + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 5th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 6th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 7th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 8th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 9th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 10th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 11th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 12th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 13th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 14th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 15th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 16th parameter type invalid."); + +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1, w1); + this->value[1] = col_type(x2, y2, z2, w2); + this->value[2] = col_type(x3, y3, z3, w3); + this->value[3] = col_type(x4, y4, z4, w4); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2, vec<4, V3, Q> const& v3, vec<4, V4, Q> const& v4) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} +# endif + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); + +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); + this->value[3] = col_type(v4); +# endif + } + + // -- Matrix conversions -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(m[3], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); + this->value[3] = col_type(m[3], 1); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type & mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 4, T, Q>::col_type const& mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary arithmetic operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator=(mat<4, 4, U, Q> const& m) + { + //memcpy could be faster + //memcpy(&this->value, &m.value, 16 * sizeof(valType)); + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(mat<4, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(mat<4, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(mat<4, 4, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(mat<4, 4, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator++(int) + { + mat<4, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator--(int) + { + mat<4, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] - s, + m[1] - s, + m[2] - s, + m[3] - s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + s - m[0], + s - m[1], + s - m[2], + s - m[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const & s) + { + return mat<4, 4, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator* + ( + mat<4, 4, T, Q> const& m, + typename mat<4, 4, T, Q>::row_type const& v + ) + { +/* + __m128 v0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 v1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 v2 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v3 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(m[0].data, v0); + __m128 m1 = _mm_mul_ps(m[1].data, v1); + __m128 a0 = _mm_add_ps(m0, m1); + + __m128 m2 = _mm_mul_ps(m[2].data, v2); + __m128 m3 = _mm_mul_ps(m[3].data, v3); + __m128 a1 = _mm_add_ps(m2, m3); + + __m128 a2 = _mm_add_ps(a0, a1); + + return typename mat<4, 4, T, Q>::col_type(a2); +*/ + + typename mat<4, 4, T, Q>::col_type const Mov0(v[0]); + typename mat<4, 4, T, Q>::col_type const Mov1(v[1]); + typename mat<4, 4, T, Q>::col_type const Mul0 = m[0] * Mov0; + typename mat<4, 4, T, Q>::col_type const Mul1 = m[1] * Mov1; + typename mat<4, 4, T, Q>::col_type const Add0 = Mul0 + Mul1; + typename mat<4, 4, T, Q>::col_type const Mov2(v[2]); + typename mat<4, 4, T, Q>::col_type const Mov3(v[3]); + typename mat<4, 4, T, Q>::col_type const Mul2 = m[2] * Mov2; + typename mat<4, 4, T, Q>::col_type const Mul3 = m[3] * Mov3; + typename mat<4, 4, T, Q>::col_type const Add1 = Mul2 + Mul3; + typename mat<4, 4, T, Q>::col_type const Add2 = Add0 + Add1; + return Add2; + +/* + return typename mat<4, 4, T, Q>::col_type( + m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3], + m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3], + m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3], + m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]); +*/ + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator* + ( + typename mat<4, 4, T, Q>::col_type const& v, + mat<4, 4, T, Q> const& m + ) + { + return typename mat<4, 4, T, Q>::row_type( + m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], + m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], + m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], + m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2] + m1[3][3] * m2[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + typename mat<4, 4, T, Q>::col_type const SrcA0 = m1[0]; + typename mat<4, 4, T, Q>::col_type const SrcA1 = m1[1]; + typename mat<4, 4, T, Q>::col_type const SrcA2 = m1[2]; + typename mat<4, 4, T, Q>::col_type const SrcA3 = m1[3]; + + typename mat<4, 4, T, Q>::col_type const SrcB0 = m2[0]; + typename mat<4, 4, T, Q>::col_type const SrcB1 = m2[1]; + typename mat<4, 4, T, Q>::col_type const SrcB2 = m2[2]; + typename mat<4, 4, T, Q>::col_type const SrcB3 = m2[3]; + + mat<4, 4, T, Q> Result; + Result[0] = SrcA0 * SrcB0[0] + SrcA1 * SrcB0[1] + SrcA2 * SrcB0[2] + SrcA3 * SrcB0[3]; + Result[1] = SrcA0 * SrcB1[0] + SrcA1 * SrcB1[1] + SrcA2 * SrcB1[2] + SrcA3 * SrcB1[3]; + Result[2] = SrcA0 * SrcB2[0] + SrcA1 * SrcB2[1] + SrcA2 * SrcB2[2] + SrcA3 * SrcB2[3]; + Result[3] = SrcA0 * SrcB3[0] + SrcA1 * SrcB3[1] + SrcA2 * SrcB3[2] + SrcA3 * SrcB3[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] / s, + m[1] / s, + m[2] / s, + m[3] / s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + s / m[0], + s / m[1], + s / m[2], + s / m[3]); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + mat<4, 4, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_mat4x4_simd.inl" +#endif diff --git a/src/GLMath/glm/detail/type_mat4x4_simd.inl b/src/GLMath/glm/detail/type_mat4x4_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fb3a16f062901d31b8ed8c493efd17e1cf87468f --- /dev/null +++ b/src/GLMath/glm/detail/type_mat4x4_simd.inl @@ -0,0 +1,6 @@ +/// @ref core + +namespace glm +{ + +}//namespace glm diff --git a/src/GLMath/glm/detail/type_quat.hpp b/src/GLMath/glm/detail/type_quat.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b49c2534834e93a99ace4c24fed4df1724620b98 --- /dev/null +++ b/src/GLMath/glm/detail/type_quat.hpp @@ -0,0 +1,190 @@ +/// @ref gtc_quaternion +/// @file glm/gtc/quaternion.hpp +/// +/// @see core (dependence) +/// @see gtc_constants (dependence) +/// +/// @defgroup gtc_quaternion GLM_GTC_quaternion +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines a templated quaternion type and several quaternion operations. + +#pragma once + +// Dependency: +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat4x4.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" +#include "../ext/vector_relational.hpp" +#include "../ext/quaternion_relational.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/matrix_transform.hpp" + +namespace glm +{ + /// @addtogroup gtc_quaternion + /// @{ + + template + struct qua + { + // -- Implementation detail -- + + typedef qua type; + typedef T value_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_LANG & GLM_LANG_CXXMS_FLAG + union + { + struct { T x, y, z, w;}; + + typename detail::storage<4, T, detail::is_aligned::value>::type data; + }; +# else + T x, y, z, w; +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + typedef length_t length_type; + /// Return the count of components of a quaternion + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua(T s, vec<3, T, Q> const& v); + GLM_FUNC_DECL GLM_CONSTEXPR qua(T w, T x, T y, T z); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(qua const& q); + + /// Explicit conversion operators +# if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + GLM_FUNC_DECL explicit operator mat<3, 3, T, Q>(); + GLM_FUNC_DECL explicit operator mat<4, 4, T, Q>(); +# endif + + /// Create a quaternion from two normalized axis + /// + /// @param u A first normalized axis + /// @param v A second normalized axis + /// @see gtc_quaternion + /// @see http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors + GLM_FUNC_DECL qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v); + + /// Build a quaternion from euler angles (pitch, yaw, roll), in radians. + GLM_FUNC_DECL GLM_EXPLICIT qua(vec<3, T, Q> const& eulerAngles); + GLM_FUNC_DECL GLM_EXPLICIT qua(mat<3, 3, T, Q> const& q); + GLM_FUNC_DECL GLM_EXPLICIT qua(mat<4, 4, T, Q> const& q); + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL qua& operator=(qua const& q) GLM_DEFAULT; + + template + GLM_FUNC_DECL qua& operator=(qua const& q); + template + GLM_FUNC_DECL qua& operator+=(qua const& q); + template + GLM_FUNC_DECL qua& operator-=(qua const& q); + template + GLM_FUNC_DECL qua& operator*=(qua const& q); + template + GLM_FUNC_DECL qua& operator*=(U s); + template + GLM_FUNC_DECL qua& operator/=(U s); + }; + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL qua operator+(qua const& q); + + template + GLM_FUNC_DECL qua operator-(qua const& q); + + // -- Binary operators -- + + template + GLM_FUNC_DECL qua operator+(qua const& q, qua const& p); + + template + GLM_FUNC_DECL qua operator-(qua const& q, qua const& p); + + template + GLM_FUNC_DECL qua operator*(qua const& q, qua const& p); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q); + + template + GLM_FUNC_DECL qua operator*(qua const& q, T const& s); + + template + GLM_FUNC_DECL qua operator*(T const& s, qua const& q); + + template + GLM_FUNC_DECL qua operator/(qua const& q, T const& s); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2); + + /// @} +} //namespace glm + +#include "type_quat.inl" diff --git a/src/GLMath/glm/detail/type_quat.inl b/src/GLMath/glm/detail/type_quat.inl new file mode 100644 index 0000000000000000000000000000000000000000..d9f63c6744ac865b02cffb41583820247875eadc --- /dev/null +++ b/src/GLMath/glm/detail/type_quat.inl @@ -0,0 +1,379 @@ +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include "../ext/quaternion_geometric.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = GENTYPE_QUAT; + }; + + template + struct compute_dot, T, Aligned> + { + static GLM_FUNC_QUALIFIER T call(qua const& a, qua const& b) + { + vec<4, T, Q> tmp(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + return (tmp.x + tmp.y) + (tmp.z + tmp.w); + } + }; + + template + struct compute_quat_add + { + static qua call(qua const& q, qua const& p) + { + return qua(q.w + p.w, q.x + p.x, q.y + p.y, q.z + p.z); + } + }; + + template + struct compute_quat_sub + { + static qua call(qua const& q, qua const& p) + { + return qua(q.w - p.w, q.x - p.x, q.y - p.y, q.z - p.z); + } + }; + + template + struct compute_quat_mul_scalar + { + static qua call(qua const& q, T s) + { + return qua(q.w * s, q.x * s, q.y * s, q.z * s); + } + }; + + template + struct compute_quat_div_scalar + { + static qua call(qua const& q, T s) + { + return qua(q.w / s, q.x / s, q.y / s, q.z / s); + } + }; + + template + struct compute_quat_mul_vec4 + { + static vec<4, T, Q> call(qua const& q, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); + } + }; +}//namespace detail + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & qua::operator[](typename qua::length_type i) + { + assert(i >= 0 && i < this->length()); + return (&x)[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& qua::operator[](typename qua::length_type i) const + { + assert(i >= 0 && i < this->length()); + return (&x)[i]; + } + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0), z(0), w(1) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) + : x(q.x), y(q.y), z(q.z), w(q.w) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) + : x(q.x), y(q.y), z(q.z), w(q.w) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T s, vec<3, T, Q> const& v) + : x(v.x), y(v.y), z(v.z), w(s) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T _w, T _x, T _y, T _z) + : x(_x), y(_y), z(_z), w(_w) + {} + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) + : x(static_cast(q.x)) + , y(static_cast(q.y)) + , z(static_cast(q.z)) + , w(static_cast(q.w)) + {} + + //template + //GLM_FUNC_QUALIFIER qua::qua + //( + // valType const& pitch, + // valType const& yaw, + // valType const& roll + //) + //{ + // vec<3, valType> eulerAngle(pitch * valType(0.5), yaw * valType(0.5), roll * valType(0.5)); + // vec<3, valType> c = glm::cos(eulerAngle * valType(0.5)); + // vec<3, valType> s = glm::sin(eulerAngle * valType(0.5)); + // + // this->w = c.x * c.y * c.z + s.x * s.y * s.z; + // this->x = s.x * c.y * c.z - c.x * s.y * s.z; + // this->y = c.x * s.y * c.z + s.x * c.y * s.z; + // this->z = c.x * c.y * s.z - s.x * s.y * c.z; + //} + + template + GLM_FUNC_QUALIFIER qua::qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v) + { + T norm_u_norm_v = sqrt(dot(u, u) * dot(v, v)); + T real_part = norm_u_norm_v + dot(u, v); + vec<3, T, Q> t; + + if(real_part < static_cast(1.e-6f) * norm_u_norm_v) + { + // If u and v are exactly opposite, rotate 180 degrees + // around an arbitrary orthogonal axis. Axis normalisation + // can happen later, when we normalise the quaternion. + real_part = static_cast(0); + t = abs(u.x) > abs(u.z) ? vec<3, T, Q>(-u.y, u.x, static_cast(0)) : vec<3, T, Q>(static_cast(0), -u.z, u.y); + } + else + { + // Otherwise, build quaternion the standard way. + t = cross(u, v); + } + + *this = normalize(qua(real_part, t.x, t.y, t.z)); + } + + template + GLM_FUNC_QUALIFIER qua::qua(vec<3, T, Q> const& eulerAngle) + { + vec<3, T, Q> c = glm::cos(eulerAngle * T(0.5)); + vec<3, T, Q> s = glm::sin(eulerAngle * T(0.5)); + + this->w = c.x * c.y * c.z + s.x * s.y * s.z; + this->x = s.x * c.y * c.z - c.x * s.y * s.z; + this->y = c.x * s.y * c.z + s.x * c.y * s.z; + this->z = c.x * c.y * s.z - s.x * s.y * c.z; + } + + template + GLM_FUNC_QUALIFIER qua::qua(mat<3, 3, T, Q> const& m) + { + *this = quat_cast(m); + } + + template + GLM_FUNC_QUALIFIER qua::qua(mat<4, 4, T, Q> const& m) + { + *this = quat_cast(m); + } + +# if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + template + GLM_FUNC_QUALIFIER qua::operator mat<3, 3, T, Q>() + { + return mat3_cast(*this); + } + + template + GLM_FUNC_QUALIFIER qua::operator mat<4, 4, T, Q>() + { + return mat4_cast(*this); + } +# endif//GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER qua & qua::operator=(qua const& q) + { + this->w = q.w; + this->x = q.x; + this->y = q.y; + this->z = q.z; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER qua & qua::operator=(qua const& q) + { + this->w = static_cast(q.w); + this->x = static_cast(q.x); + this->y = static_cast(q.y); + this->z = static_cast(q.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER qua & qua::operator+=(qua const& q) + { + return (*this = detail::compute_quat_add::value>::call(*this, qua(q))); + } + + template + template + GLM_FUNC_QUALIFIER qua & qua::operator-=(qua const& q) + { + return (*this = detail::compute_quat_sub::value>::call(*this, qua(q))); + } + + template + template + GLM_FUNC_QUALIFIER qua & qua::operator*=(qua const& r) + { + qua const p(*this); + qua const q(r); + + this->w = p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z; + this->x = p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y; + this->y = p.w * q.y + p.y * q.w + p.z * q.x - p.x * q.z; + this->z = p.w * q.z + p.z * q.w + p.x * q.y - p.y * q.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER qua & qua::operator*=(U s) + { + return (*this = detail::compute_quat_mul_scalar::value>::call(*this, static_cast(s))); + } + + template + template + GLM_FUNC_QUALIFIER qua & qua::operator/=(U s) + { + return (*this = detail::compute_quat_div_scalar::value>::call(*this, static_cast(s))); + } + + // -- Unary bit operators -- + + template + GLM_FUNC_QUALIFIER qua operator+(qua const& q) + { + return q; + } + + template + GLM_FUNC_QUALIFIER qua operator-(qua const& q) + { + return qua(-q.w, -q.x, -q.y, -q.z); + } + + // -- Binary operators -- + + template + GLM_FUNC_QUALIFIER qua operator+(qua const& q, qua const& p) + { + return qua(q) += p; + } + + template + GLM_FUNC_QUALIFIER qua operator-(qua const& q, qua const& p) + { + return qua(q) -= p; + } + + template + GLM_FUNC_QUALIFIER qua operator*(qua const& q, qua const& p) + { + return qua(q) *= p; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v) + { + vec<3, T, Q> const QuatVector(q.x, q.y, q.z); + vec<3, T, Q> const uv(glm::cross(QuatVector, v)); + vec<3, T, Q> const uuv(glm::cross(QuatVector, uv)); + + return v + ((uv * q.w) + uuv) * static_cast(2); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v) + { + return detail::compute_quat_mul_vec4::value>::call(q, v); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER qua operator*(qua const& q, T const& s) + { + return qua( + q.w * s, q.x * s, q.y * s, q.z * s); + } + + template + GLM_FUNC_QUALIFIER qua operator*(T const& s, qua const& q) + { + return q * s; + } + + template + GLM_FUNC_QUALIFIER qua operator/(qua const& q, T const& s) + { + return qua( + q.w / s, q.x / s, q.y / s, q.z / s); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2) + { + return q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2) + { + return q1.x != q2.x || q1.y != q2.y || q1.z != q2.z || q1.w != q2.w; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_quat_simd.inl" +#endif + diff --git a/src/GLMath/glm/detail/type_quat_simd.inl b/src/GLMath/glm/detail/type_quat_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..3333e59f1c7e2626b292d3100909027e400a0f16 --- /dev/null +++ b/src/GLMath/glm/detail/type_quat_simd.inl @@ -0,0 +1,188 @@ +/// @ref core + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ +/* + template + struct compute_quat_mul + { + static qua call(qua const& q1, qua const& q2) + { + // SSE2 STATS: 11 shuffle, 8 mul, 8 add + // SSE4 STATS: 3 shuffle, 4 mul, 4 dpps + + __m128 const mul0 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(0, 1, 2, 3))); + __m128 const mul1 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(1, 0, 3, 2))); + __m128 const mul2 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(2, 3, 0, 1))); + __m128 const mul3 = _mm_mul_ps(q1.Data, q2.Data); + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + __m128 const add0 = _mm_dp_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f), 0xff); + __m128 const add1 = _mm_dp_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f), 0xff); + __m128 const add2 = _mm_dp_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f), 0xff); + __m128 const add3 = _mm_dp_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f), 0xff); +# else + __m128 const mul4 = _mm_mul_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f)); + __m128 const add0 = _mm_add_ps(mul0, _mm_movehl_ps(mul4, mul4)); + __m128 const add4 = _mm_add_ss(add0, _mm_shuffle_ps(add0, add0, 1)); + + __m128 const mul5 = _mm_mul_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f)); + __m128 const add1 = _mm_add_ps(mul1, _mm_movehl_ps(mul5, mul5)); + __m128 const add5 = _mm_add_ss(add1, _mm_shuffle_ps(add1, add1, 1)); + + __m128 const mul6 = _mm_mul_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f)); + __m128 const add2 = _mm_add_ps(mul6, _mm_movehl_ps(mul6, mul6)); + __m128 const add6 = _mm_add_ss(add2, _mm_shuffle_ps(add2, add2, 1)); + + __m128 const mul7 = _mm_mul_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f)); + __m128 const add3 = _mm_add_ps(mul3, _mm_movehl_ps(mul7, mul7)); + __m128 const add7 = _mm_add_ss(add3, _mm_shuffle_ps(add3, add3, 1)); + #endif + + // This SIMD code is a politically correct way of doing this, but in every test I've tried it has been slower than + // the final code below. I'll keep this here for reference - maybe somebody else can do something better... + // + //__m128 xxyy = _mm_shuffle_ps(add4, add5, _MM_SHUFFLE(0, 0, 0, 0)); + //__m128 zzww = _mm_shuffle_ps(add6, add7, _MM_SHUFFLE(0, 0, 0, 0)); + // + //return _mm_shuffle_ps(xxyy, zzww, _MM_SHUFFLE(2, 0, 2, 0)); + + qua Result; + _mm_store_ss(&Result.x, add4); + _mm_store_ss(&Result.y, add5); + _mm_store_ss(&Result.z, add6); + _mm_store_ss(&Result.w, add7); + return Result; + } + }; +*/ + + template + struct compute_quat_add + { + static qua call(qua const& q, qua const& p) + { + qua Result; + Result.data = _mm_add_ps(q.data, p.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_add + { + static qua call(qua const& a, qua const& b) + { + qua Result; + Result.data = _mm256_add_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_quat_sub + { + static qua call(qua const& q, qua const& p) + { + vec<4, float, Q> Result; + Result.data = _mm_sub_ps(q.data, p.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_sub + { + static qua call(qua const& a, qua const& b) + { + qua Result; + Result.data = _mm256_sub_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_quat_mul_scalar + { + static qua call(qua const& q, float s) + { + vec<4, float, Q> Result; + Result.data = _mm_mul_ps(q.data, _mm_set_ps1(s)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_mul_scalar + { + static qua call(qua const& q, double s) + { + qua Result; + Result.data = _mm256_mul_pd(q.data, _mm_set_ps1(s)); + return Result; + } + }; +# endif + + template + struct compute_quat_div_scalar + { + static qua call(qua const& q, float s) + { + vec<4, float, Q> Result; + Result.data = _mm_div_ps(q.data, _mm_set_ps1(s)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_div_scalar + { + static qua call(qua const& q, double s) + { + qua Result; + Result.data = _mm256_div_pd(q.data, _mm_set_ps1(s)); + return Result; + } + }; +# endif + + template + struct compute_quat_mul_vec4 + { + static vec<4, float, Q> call(qua const& q, vec<4, float, Q> const& v) + { + __m128 const q_wwww = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 3, 3, 3)); + __m128 const q_swp0 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 const q_swp1 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 1, 0, 2)); + __m128 const v_swp0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 const v_swp1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 1, 0, 2)); + + __m128 uv = _mm_sub_ps(_mm_mul_ps(q_swp0, v_swp1), _mm_mul_ps(q_swp1, v_swp0)); + __m128 uv_swp0 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 uv_swp1 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 1, 0, 2)); + __m128 uuv = _mm_sub_ps(_mm_mul_ps(q_swp0, uv_swp1), _mm_mul_ps(q_swp1, uv_swp0)); + + __m128 const two = _mm_set1_ps(2.0f); + uv = _mm_mul_ps(uv, _mm_mul_ps(q_wwww, two)); + uuv = _mm_mul_ps(uuv, two); + + vec<4, float, Q> Result; + Result.data = _mm_add_ps(v.Data, _mm_add_ps(uv, uuv)); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/src/GLMath/glm/detail/type_vec1.hpp b/src/GLMath/glm/detail/type_vec1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51163f14bc88aeb1c3ad4ba3449de0dc38e5266e --- /dev/null +++ b/src/GLMath/glm/detail/type_vec1.hpp @@ -0,0 +1,308 @@ +/// @ref core +/// @file glm/detail/type_vec1.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<1, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<1, T, Q> type; + typedef vec<1, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + T x; + T r; + T s; + + typename detail::storage<1, T, detail::is_aligned::value>::type data; +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + _GLM_SWIZZLE1_2_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_2_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_2_MEMBERS(T, Q, s) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, s) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, s) +# endif +*/ + }; +# else + union {T x, r, s;}; +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC1(T, Q) +# endif +*/ +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 1;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<1, U, P> const& v); + + // -- Swizzle constructors -- +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<1, T, Q, E0, -1,-2,-3> const& that) + { + *this = that(); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +*/ + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(vec<1, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(vec<1, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec1.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/src/GLMath/glm/detail/type_vec1.inl b/src/GLMath/glm/detail/type_vec1.inl new file mode 100644 index 0000000000000000000000000000000000000000..d0f49fd354e605ea10ba96769aaad769c9604eb7 --- /dev/null +++ b/src/GLMath/glm/detail/type_vec1.inl @@ -0,0 +1,551 @@ +/// @ref core + +#include "./compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, Q> const& v) + : x(v.x) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, P> const& v) + : x(v.x) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(T scalar) + : x(scalar) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<2, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) + { + return x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) const + { + return x; + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, T, Q> const& v) + { + this->x = v.x; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, U, Q> const& v) + { + this->x = static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(U scalar) + { + this->x /= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator++() + { + ++this->x; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator--() + { + --this->x; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator++(int) + { + vec<1, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator--(int) + { + vec<1, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(U scalar) + { + this->x %= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(U scalar) + { + this->x &= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(U scalar) + { + this->x |= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= U(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(U scalar) + { + this->x ^= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(U scalar) + { + this->x <<= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + return *this; + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + -v.x); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar + v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x + v2.x); + } + + //operator- + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar - v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x - v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar * v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x * v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar / v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x / v2.x); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar % v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x % v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar & v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x & v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar | v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x | v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar ^ v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x ^ v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + static_cast(v.x << scalar)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar << v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x << v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x >> scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar >> v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x >> v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + ~v.x); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return detail::compute_equal::is_iec559>::call(v1.x, v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) + { + return vec<1, bool, Q>(v1.x && v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) + { + return vec<1, bool, Q>(v1.x || v2.x); + } +}//namespace glm diff --git a/src/GLMath/glm/detail/type_vec2.hpp b/src/GLMath/glm/detail/type_vec2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..52ef408e5d2165623e764cfa664fcb8372361bf6 --- /dev/null +++ b/src/GLMath/glm/detail/type_vec2.hpp @@ -0,0 +1,399 @@ +/// @ref core +/// @file glm/detail/type_vec2.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<2, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<2, T, Q> type; + typedef vec<2, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x, y; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct{ T x, y; }; + struct{ T r, g; }; + struct{ T s, t; }; + + typename detail::storage<2, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE2_2_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_2_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_2_MEMBERS(T, Q, s, t) + GLM_SWIZZLE2_3_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_3_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_3_MEMBERS(T, Q, s, t) + GLM_SWIZZLE2_4_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_4_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_4_MEMBERS(T, Q, s, t) +# endif + }; +# else + union {T x, r, s;}; + union {T y, g, t;}; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, Q) +# endif//GLM_CONFIG_SWIZZLE +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} + + GLM_FUNC_DECL GLM_CONSTEXPR T& operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, B y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, B y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, vec<1, B, Q> const& y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, vec<1, B, Q> const& y); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1,-1,-2> const& that) + { + *this = that(); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<2, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<2, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec2.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/src/GLMath/glm/detail/type_vec2.inl b/src/GLMath/glm/detail/type_vec2.inl new file mode 100644 index 0000000000000000000000000000000000000000..8e65d6bb9e2e358c6284404b84dda0373b2f90fe --- /dev/null +++ b/src/GLMath/glm/detail/type_vec2.inl @@ -0,0 +1,913 @@ +/// @ref core + +#include "./compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, Q> const& v) + : x(v.x), y(v.y) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, P> const& v) + : x(v.x), y(v.y) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T scalar) + : x(scalar), y(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T _x, T _y) + : x(_x), y(_y) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, B _y) + : x(static_cast(_x)) + , y(static_cast(_y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, B _y) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, vec<1, B, Q> const& _y) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, vec<1, B, Q> const& _y) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) const + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + this->y += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<2, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + this->y -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<2, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + this->y *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<2, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(U scalar) + { + this->x /= static_cast(scalar); + this->y /= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<2, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.y); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator++() + { + ++this->x; + ++this->y; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator--() + { + --this->x; + --this->y; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator++(int) + { + vec<2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator--(int) + { + vec<2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(U scalar) + { + this->x %= static_cast(scalar); + this->y %= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= static_cast(v.x); + this->y %= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<2, U, Q> const& v) + { + this->x %= static_cast(v.x); + this->y %= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(U scalar) + { + this->x &= static_cast(scalar); + this->y &= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= static_cast(v.x); + this->y &= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<2, U, Q> const& v) + { + this->x &= static_cast(v.x); + this->y &= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(U scalar) + { + this->x |= static_cast(scalar); + this->y |= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= static_cast(v.x); + this->y |= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<2, U, Q> const& v) + { + this->x |= static_cast(v.x); + this->y |= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(U scalar) + { + this->x ^= static_cast(scalar); + this->y ^= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= static_cast(v.x); + this->y ^= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<2, U, Q> const& v) + { + this->x ^= static_cast(v.x); + this->y ^= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(U scalar) + { + this->x <<= static_cast(scalar); + this->y <<= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<2, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + this->y >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<2, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.y); + return *this; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + -v.x, + -v.y); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x + scalar, + v.y + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.y + v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar + v.x, + scalar + v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.x + v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.y + v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x - scalar, + v.y - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.y - v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar - v.x, + scalar - v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.x - v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.y - v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x * scalar, + v.y * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.y * v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar * v.x, + scalar * v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.x * v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.y * v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x / scalar, + v.y / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.y / v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar / v.x, + scalar / v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.x / v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.y / v2.y); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x % scalar, + v.y % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.y % v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar % v.x, + scalar % v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.x % v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.y % v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x & scalar, + v.y & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.y & v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar & v.x, + scalar & v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.x & v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.y & v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x | scalar, + v.y | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.y | v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar | v.x, + scalar | v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.x | v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.y | v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x ^ scalar, + v.y ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar ^ v.x, + scalar ^ v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.x ^ v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x << scalar, + v.y << scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.y << v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar << v.x, + scalar << v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.x << v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.y << v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x >> scalar, + v.y >> scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.y >> v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar >> v.x, + scalar >> v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.x >> v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.y >> v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + ~v.x, + ~v.y); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) + { + return vec<2, bool, Q>(v1.x && v2.x, v1.y && v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) + { + return vec<2, bool, Q>(v1.x || v2.x, v1.y || v2.y); + } +}//namespace glm diff --git a/src/GLMath/glm/detail/type_vec3.hpp b/src/GLMath/glm/detail/type_vec3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d83cde678f8b695532e94cdf2a78c589f72eb1b4 --- /dev/null +++ b/src/GLMath/glm/detail/type_vec3.hpp @@ -0,0 +1,432 @@ +/// @ref core +/// @file glm/detail/type_vec3.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<3, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<3, T, Q> type; + typedef vec<3, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# pragma warning(disable: 4324) // structure was padded due to alignment specifier +# endif +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x, y, z; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct{ T x, y, z; }; + struct{ T r, g, b; }; + struct{ T s, t, p; }; + + typename detail::storage<3, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE3_2_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_2_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_2_MEMBERS(T, Q, s, t, p) + GLM_SWIZZLE3_3_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_3_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_3_MEMBERS(T, Q, s, t, p) + GLM_SWIZZLE3_4_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_4_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_4_MEMBERS(T, Q, s, t, p) +# endif + }; +# else + union { T x, r, s; }; + union { T y, g, t; }; + union { T z, b, p; }; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, Q) +# endif//GLM_CONFIG_SWIZZLE +# endif//GLM_LANG + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 3;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T a, T b, T c); + + // -- Conversion scalar constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X x, Y y, Z z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& that) + { + *this = that(); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& scalar) + { + *this = vec(v(), scalar); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& scalar, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) + { + *this = vec(scalar, v()); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q>& operator=(vec<3, T, Q> const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<3, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<3, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec3.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/src/GLMath/glm/detail/type_vec3.inl b/src/GLMath/glm/detail/type_vec3.inl new file mode 100644 index 0000000000000000000000000000000000000000..6532c9e6e06ba8fac8edc1fcefeff7547118641e --- /dev/null +++ b/src/GLMath/glm/detail/type_vec3.inl @@ -0,0 +1,1068 @@ +/// @ref core + +#include "compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0), z(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, Q> const& v) + : x(v.x), y(v.y), z(v.z) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, P> const& v) + : x(v.x), y(v.y), z(v.z) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T scalar) + : x(scalar), y(scalar), z(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T _x, T _y, T _z) + : x(_x), y(_y), z(_z) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + , z(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, Z _z) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, B _z) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(A _x, vec<2, B, P> const& _yz) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) const + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + this->z = v.z; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + this->z = static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + this->y += static_cast(scalar); + this->z += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.x); + this->z += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<3, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.y); + this->z += static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + this->y -= static_cast(scalar); + this->z -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.x); + this->z -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<3, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.y); + this->z -= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + this->y *= static_cast(scalar); + this->z *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.x); + this->z *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<3, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.y); + this->z *= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(U v) + { + this->x /= static_cast(v); + this->y /= static_cast(v); + this->z /= static_cast(v); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.x); + this->z /= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<3, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.y); + this->z /= static_cast(v.z); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator++() + { + ++this->x; + ++this->y; + ++this->z; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator--() + { + --this->x; + --this->y; + --this->z; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator++(int) + { + vec<3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator--(int) + { + vec<3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(U scalar) + { + this->x %= scalar; + this->y %= scalar; + this->z %= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= v.x; + this->y %= v.x; + this->z %= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<3, U, Q> const& v) + { + this->x %= v.x; + this->y %= v.y; + this->z %= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(U scalar) + { + this->x &= scalar; + this->y &= scalar; + this->z &= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= v.x; + this->y &= v.x; + this->z &= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<3, U, Q> const& v) + { + this->x &= v.x; + this->y &= v.y; + this->z &= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(U scalar) + { + this->x |= scalar; + this->y |= scalar; + this->z |= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= v.x; + this->y |= v.x; + this->z |= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<3, U, Q> const& v) + { + this->x |= v.x; + this->y |= v.y; + this->z |= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(U scalar) + { + this->x ^= scalar; + this->y ^= scalar; + this->z ^= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= v.x; + this->y ^= v.x; + this->z ^= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<3, U, Q> const& v) + { + this->x ^= v.x; + this->y ^= v.y; + this->z ^= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(U scalar) + { + this->x <<= scalar; + this->y <<= scalar; + this->z <<= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.x); + this->z <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<3, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.y); + this->z <<= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + this->y >>= static_cast(scalar); + this->z >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.x); + this->z >>= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<3, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.y); + this->z >>= static_cast(v.z); + return *this; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + -v.x, + -v.y, + -v.z); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x + scalar, + v.y + scalar, + v.z + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x + scalar.x, + v.y + scalar.x, + v.z + scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar + v.x, + scalar + v.y, + scalar + v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x + v.x, + scalar.x + v.y, + scalar.x + v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x + v2.x, + v1.y + v2.y, + v1.z + v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x - scalar, + v.y - scalar, + v.z - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x - scalar.x, + v.y - scalar.x, + v.z - scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar - v.x, + scalar - v.y, + scalar - v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x - v.x, + scalar.x - v.y, + scalar.x - v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x - v2.x, + v1.y - v2.y, + v1.z - v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x * scalar, + v.y * scalar, + v.z * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x * scalar.x, + v.y * scalar.x, + v.z * scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar * v.x, + scalar * v.y, + scalar * v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x * v.x, + scalar.x * v.y, + scalar.x * v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x * v2.x, + v1.y * v2.y, + v1.z * v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x / scalar, + v.y / scalar, + v.z / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x / scalar.x, + v.y / scalar.x, + v.z / scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar / v.x, + scalar / v.y, + scalar / v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x / v.x, + scalar.x / v.y, + scalar.x / v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x / v2.x, + v1.y / v2.y, + v1.z / v2.z); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x % scalar, + v.y % scalar, + v.z % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x % scalar.x, + v.y % scalar.x, + v.z % scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar % v.x, + scalar % v.y, + scalar % v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x % v.x, + scalar.x % v.y, + scalar.x % v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x % v2.x, + v1.y % v2.y, + v1.z % v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x & scalar, + v.y & scalar, + v.z & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x & scalar.x, + v.y & scalar.x, + v.z & scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar & v.x, + scalar & v.y, + scalar & v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x & v.x, + scalar.x & v.y, + scalar.x & v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x & v2.x, + v1.y & v2.y, + v1.z & v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x | scalar, + v.y | scalar, + v.z | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x | scalar.x, + v.y | scalar.x, + v.z | scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar | v.x, + scalar | v.y, + scalar | v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x | v.x, + scalar.x | v.y, + scalar.x | v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x | v2.x, + v1.y | v2.y, + v1.z | v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x ^ scalar, + v.y ^ scalar, + v.z ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x ^ scalar.x, + v.y ^ scalar.x, + v.z ^ scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar ^ v.x, + scalar ^ v.y, + scalar ^ v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x ^ v.x, + scalar.x ^ v.y, + scalar.x ^ v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.y, + v1.z ^ v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x << scalar, + v.y << scalar, + v.z << scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x << scalar.x, + v.y << scalar.x, + v.z << scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar << v.x, + scalar << v.y, + scalar << v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x << v.x, + scalar.x << v.y, + scalar.x << v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x << v2.x, + v1.y << v2.y, + v1.z << v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x >> scalar, + v.y >> scalar, + v.z >> scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x >> scalar.x, + v.y >> scalar.x, + v.z >> scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar >> v.x, + scalar >> v.y, + scalar >> v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x >> v.x, + scalar.x >> v.y, + scalar.x >> v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x >> v2.x, + v1.y >> v2.y, + v1.z >> v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + ~v.x, + ~v.y, + ~v.z); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y) && + detail::compute_equal::is_iec559>::call(v1.z, v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) + { + return vec<3, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) + { + return vec<3, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z); + } +}//namespace glm diff --git a/src/GLMath/glm/detail/type_vec4.hpp b/src/GLMath/glm/detail/type_vec4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..15fabe12a689944db0bc341f9deb8bc1a24a6e24 --- /dev/null +++ b/src/GLMath/glm/detail/type_vec4.hpp @@ -0,0 +1,504 @@ +/// @ref core +/// @file glm/detail/type_vec4.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<4, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<4, T, Q> type; + typedef vec<4, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x, y, z, w; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct { T x, y, z, w; }; + struct { T r, g, b, a; }; + struct { T s, t, p, q; }; + + typename detail::storage<4, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE4_2_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_2_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_2_MEMBERS(T, Q, s, t, p, q) + GLM_SWIZZLE4_3_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_3_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_3_MEMBERS(T, Q, s, t, p, q) + GLM_SWIZZLE4_4_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_4_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_4_MEMBERS(T, Q, s, t, p, q) +# endif + }; +# else + union { T x, r, s; }; + union { T y, g, t; }; + union { T z, b, p; }; + union { T w, a, q; }; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, Q) +# endif +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, Q> const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y, T z, T w); + + // -- Conversion scalar constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _Y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, B _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, B _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<3, B, P> const& _yzw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<4, T, Q, E0, E1, E2, E3> const& that) + { + *this = that(); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, detail::_swizzle<2, T, Q, F0, F1, -1, -2> const& u) + { + *this = vec<4, T, Q>(v(), u()); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, T const& y, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) + { + *this = vec<4, T, Q>(x, y, v()); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& w) + { + *this = vec<4, T, Q>(x, v(), w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& z, T const& w) + { + *this = vec<4, T, Q>(v(), z, w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v, T const& w) + { + *this = vec<4, T, Q>(v(), w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v) + { + *this = vec<4, T, Q>(x, v()); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, T, Q> const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<4, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<4, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec4.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/src/GLMath/glm/detail/type_vec4.inl b/src/GLMath/glm/detail/type_vec4.inl new file mode 100644 index 0000000000000000000000000000000000000000..3c212d98bbeb05aa98a416fb6dd4f096087b07ab --- /dev/null +++ b/src/GLMath/glm/detail/type_vec4.inl @@ -0,0 +1,1140 @@ +/// @ref core + +#include "compute_vector_relational.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_vec4_add + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + } + }; + + template + struct compute_vec4_sub + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + } + }; + + template + struct compute_vec4_mul + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + } + }; + + template + struct compute_vec4_div + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + } + }; + + template + struct compute_vec4_mod + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x % b.x, a.y % b.y, a.z % b.z, a.w % b.w); + } + }; + + template + struct compute_vec4_and + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); + } + }; + + template + struct compute_vec4_or + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); + } + }; + + template + struct compute_vec4_xor + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); + } + }; + + template + struct compute_vec4_shift_left + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x << b.x, a.y << b.y, a.z << b.z, a.w << b.w); + } + }; + + template + struct compute_vec4_shift_right + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x >> b.x, a.y >> b.y, a.z >> b.z, a.w >> b.w); + } + }; + + template + struct compute_vec4_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y) && + detail::compute_equal::is_iec559>::call(v1.z, v2.z) && + detail::compute_equal::is_iec559>::call(v1.w, v2.w); + } + }; + + template + struct compute_vec4_nequal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return !compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + }; + + template + struct compute_vec4_bitwise_not + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + return vec<4, T, Q>(~v.x, ~v.y, ~v.z, ~v.w); + } + }; +}//namespace detail + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0), z(0), w(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, Q> const& v) + : x(v.x), y(v.y), z(v.z), w(v.w) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, P> const& v) + : x(v.x), y(v.y), z(v.z), w(v.w) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T scalar) + : x(scalar), y(scalar), z(scalar), w(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T _x, T _y, T _z, T _w) + : x(_x), y(_y), z(_z), w(_w) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + , z(static_cast(v.x)) + , w(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, Z _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, C _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, C _w) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, B _y, vec<2, C, P> const& _zw) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, B _w) + : x(static_cast(_xyz.x)) + , y(static_cast(_xyz.y)) + , z(static_cast(_xyz.z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w) + : x(static_cast(_xyz.x)) + , y(static_cast(_xyz.y)) + , z(static_cast(_xyz.z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<3, B, P> const& _yzw) + : x(static_cast(_x)) + , y(static_cast(_yzw.x)) + , z(static_cast(_yzw.y)) + , w(static_cast(_yzw.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw) + : x(static_cast(_x.x)) + , y(static_cast(_yzw.x)) + , z(static_cast(_yzw.y)) + , w(static_cast(_yzw.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + , w(static_cast(v.w)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) const + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + this->z = v.z; + this->w = v.w; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + this->z = static_cast(v.z); + this->w = static_cast(v.w); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(U scalar) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(U scalar) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(U scalar) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(U scalar) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v))); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator++() + { + ++this->x; + ++this->y; + ++this->z; + ++this->w; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator--() + { + --this->x; + --this->y; + --this->z; + --this->w; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator++(int) + { + vec<4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator--(int) + { + vec<4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(U scalar) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(U scalar) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(U scalar) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(U scalar) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(U scalar) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(U scalar) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v) + { + return vec<4, T, Q>(0) -= v; + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) += scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) += v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(v) += scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v2) += v1; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) += v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) -= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) -= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) *= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) *= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(v) *= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v2) *= v1; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) *= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) /= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) /= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) /= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) /= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) /= v2; + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) %= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) %= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) %= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar.x) %= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) %= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) &= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<4, T, Q>(v) &= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) &= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) &= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) &= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) |= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) |= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) |= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) |= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) |= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) ^= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) ^= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) ^= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) ^= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) ^= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) <<= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) <<= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) <<= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) <<= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) <<= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) >>= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) >>= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) >>= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) >>= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) >>= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v) + { + return detail::compute_vec4_bitwise_not::value, sizeof(T) * 8, detail::is_aligned::value>::call(v); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return detail::compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return detail::compute_vec4_nequal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) + { + return vec<4, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z, v1.w && v2.w); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) + { + return vec<4, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_vec4_simd.inl" +#endif diff --git a/src/GLMath/glm/detail/type_vec4_simd.inl b/src/GLMath/glm/detail/type_vec4_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..415b73cb73094b20038d3ba5bb44f9eef4586f02 --- /dev/null +++ b/src/GLMath/glm/detail/type_vec4_simd.inl @@ -0,0 +1,463 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + struct _swizzle_base1<4, float, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, float, Q> operator ()() const + { + __m128 data = *reinterpret_cast<__m128 const*>(&this->_buffer); + + vec<4, float, Q> Result; +# if GLM_ARCH & GLM_ARCH_AVX_BIT + Result.data = _mm_permute_ps(data, _MM_SHUFFLE(E3, E2, E1, E0)); +# else + Result.data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(E3, E2, E1, E0)); +# endif + return Result; + } + }; + + template + struct _swizzle_base1<4, int, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, int, Q> operator ()() const + { + __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); + + vec<4, int, Q> Result; + Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); + return Result; + } + }; + + template + struct _swizzle_base1<4, uint, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, uint, Q> operator ()() const + { + __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); + + vec<4, uint, Q> Result; + Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); + return Result; + } + }; +# endif// GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + template + struct compute_vec4_add + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_add_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_add + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_add_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_sub + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_sub_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_sub + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_sub_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_mul + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_mul_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_mul + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_mul_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_div + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_div_ps(a.data, b.data); + return Result; + } + }; + + # if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_div + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_div_pd(a.data, b.data); + return Result; + } + }; +# endif + + template<> + struct compute_vec4_div + { + static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& a, vec<4, float, aligned_lowp> const& b) + { + vec<4, float, aligned_lowp> Result; + Result.data = _mm_mul_ps(a.data, _mm_rcp_ps(b.data)); + return Result; + } + }; + + template + struct compute_vec4_and + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_and_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_and + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_and_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_or + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_or_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_or + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_or_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_xor + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_xor_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_xor + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_xor_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_shift_left + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_sll_epi32(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_shift_left + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_sll_epi64(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_shift_right + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_srl_epi32(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_shift_right + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_srl_epi64(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_bitwise_not + { + static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + vec<4, T, Q> Result; + Result.data = _mm_xor_si128(v.data, _mm_set1_epi32(-1)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_bitwise_not + { + static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + vec<4, T, Q> Result; + Result.data = _mm256_xor_si256(v.data, _mm_set1_epi32(-1)); + return Result; + } + }; +# endif + + template + struct compute_vec4_equal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return _mm_movemask_ps(_mm_cmpeq_ps(v1.data, v2.data)) != 0; + } + }; + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + template + struct compute_vec4_equal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + //return _mm_movemask_epi8(_mm_cmpeq_epi32(v1.data, v2.data)) != 0; + __m128i neq = _mm_xor_si128(v1.data, v2.data); + return _mm_test_all_zeros(neq, neq) == 0; + } + }; +# endif + + template + struct compute_vec4_nequal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return _mm_movemask_ps(_mm_cmpneq_ps(v1.data, v2.data)) != 0; + } + }; + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + template + struct compute_vec4_nequal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + //return _mm_movemask_epi8(_mm_cmpneq_epi32(v1.data, v2.data)) != 0; + __m128i neq = _mm_xor_si128(v1.data, v2.data); + return _mm_test_all_zeros(neq, neq) != 0; + } + }; +# endif +}//namespace detail + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_lowp>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_mediump>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_highp>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} +# endif + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_lowp>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_mediump>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_highp>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} +# endif + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/exponential.hpp b/src/GLMath/glm/exponential.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f8fb886f6ed8a1b8f5ba29a86dba6719af05caff --- /dev/null +++ b/src/GLMath/glm/exponential.hpp @@ -0,0 +1,110 @@ +/// @ref core +/// @file glm/exponential.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions +/// +/// @defgroup core_func_exponential Exponential functions +/// @ingroup core +/// +/// Provides GLSL exponential functions +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/type_vec1.hpp" +#include "detail/type_vec2.hpp" +#include "detail/type_vec3.hpp" +#include "detail/type_vec4.hpp" +#include + +namespace glm +{ + /// @addtogroup core_func_exponential + /// @{ + + /// Returns 'base' raised to the power 'exponent'. + /// + /// @param base Floating point value. pow function is defined for input values of 'base' defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @param exponent Floating point value representing the 'exponent'. + /// + /// @see GLSL pow man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec pow(vec const& base, vec const& exponent); + + /// Returns the natural exponentiation of x, i.e., e^x. + /// + /// @param v exp function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL exp man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec exp(vec const& v); + + /// Returns the natural logarithm of v, i.e., + /// returns the value y which satisfies the equation x = e^y. + /// Results are undefined if v <= 0. + /// + /// @param v log function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL log man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec log(vec const& v); + + /// Returns 2 raised to the v power. + /// + /// @param v exp2 function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL exp2 man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec exp2(vec const& v); + + /// Returns the base 2 log of x, i.e., returns the value y, + /// which satisfies the equation x = 2 ^ y. + /// + /// @param v log2 function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL log2 man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec log2(vec const& v); + + /// Returns the positive square root of v. + /// + /// @param v sqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL sqrt man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec sqrt(vec const& v); + + /// Returns the reciprocal of the positive square root of v. + /// + /// @param v inversesqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL inversesqrt man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec inversesqrt(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_exponential.inl" diff --git a/src/GLMath/glm/ext.hpp b/src/GLMath/glm/ext.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3bc8db27d807b67384bc83ed530a3a72064a3027 --- /dev/null +++ b/src/GLMath/glm/ext.hpp @@ -0,0 +1,196 @@ +/// @file glm/ext.hpp +/// +/// @ref core (Dependence) + +#include "detail/setup.hpp" + +#pragma once + +#include "glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_EXT_INCLUDED_DISPLAYED) +# define GLM_MESSAGE_EXT_INCLUDED_DISPLAYED +# pragma message("GLM: All extensions included (not recommended)") +#endif//GLM_MESSAGES + +#include "./ext/matrix_double2x2.hpp" +#include "./ext/matrix_double2x2_precision.hpp" +#include "./ext/matrix_double2x3.hpp" +#include "./ext/matrix_double2x3_precision.hpp" +#include "./ext/matrix_double2x4.hpp" +#include "./ext/matrix_double2x4_precision.hpp" +#include "./ext/matrix_double3x2.hpp" +#include "./ext/matrix_double3x2_precision.hpp" +#include "./ext/matrix_double3x3.hpp" +#include "./ext/matrix_double3x3_precision.hpp" +#include "./ext/matrix_double3x4.hpp" +#include "./ext/matrix_double3x4_precision.hpp" +#include "./ext/matrix_double4x2.hpp" +#include "./ext/matrix_double4x2_precision.hpp" +#include "./ext/matrix_double4x3.hpp" +#include "./ext/matrix_double4x3_precision.hpp" +#include "./ext/matrix_double4x4.hpp" +#include "./ext/matrix_double4x4_precision.hpp" + +#include "./ext/matrix_float2x2.hpp" +#include "./ext/matrix_float2x2_precision.hpp" +#include "./ext/matrix_float2x3.hpp" +#include "./ext/matrix_float2x3_precision.hpp" +#include "./ext/matrix_float2x4.hpp" +#include "./ext/matrix_float2x4_precision.hpp" +#include "./ext/matrix_float3x2.hpp" +#include "./ext/matrix_float3x2_precision.hpp" +#include "./ext/matrix_float3x3.hpp" +#include "./ext/matrix_float3x3_precision.hpp" +#include "./ext/matrix_float3x4.hpp" +#include "./ext/matrix_float3x4_precision.hpp" +#include "./ext/matrix_float4x2.hpp" +#include "./ext/matrix_float4x2_precision.hpp" +#include "./ext/matrix_float4x3.hpp" +#include "./ext/matrix_float4x3_precision.hpp" +#include "./ext/matrix_float4x4.hpp" +#include "./ext/matrix_float4x4_precision.hpp" + +#include "./ext/matrix_relational.hpp" + +#include "./ext/quaternion_double.hpp" +#include "./ext/quaternion_double_precision.hpp" +#include "./ext/quaternion_float.hpp" +#include "./ext/quaternion_float_precision.hpp" +#include "./ext/quaternion_geometric.hpp" +#include "./ext/quaternion_relational.hpp" + +#include "./ext/scalar_constants.hpp" +#include "./ext/scalar_int_sized.hpp" +#include "./ext/scalar_relational.hpp" + +#include "./ext/vector_bool1.hpp" +#include "./ext/vector_bool1_precision.hpp" +#include "./ext/vector_bool2.hpp" +#include "./ext/vector_bool2_precision.hpp" +#include "./ext/vector_bool3.hpp" +#include "./ext/vector_bool3_precision.hpp" +#include "./ext/vector_bool4.hpp" +#include "./ext/vector_bool4_precision.hpp" + +#include "./ext/vector_double1.hpp" +#include "./ext/vector_double1_precision.hpp" +#include "./ext/vector_double2.hpp" +#include "./ext/vector_double2_precision.hpp" +#include "./ext/vector_double3.hpp" +#include "./ext/vector_double3_precision.hpp" +#include "./ext/vector_double4.hpp" +#include "./ext/vector_double4_precision.hpp" + +#include "./ext/vector_float1.hpp" +#include "./ext/vector_float1_precision.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float2_precision.hpp" +#include "./ext/vector_float3.hpp" +#include "./ext/vector_float3_precision.hpp" +#include "./ext/vector_float4.hpp" +#include "./ext/vector_float4_precision.hpp" + +#include "./ext/vector_int1.hpp" +#include "./ext/vector_int1_precision.hpp" +#include "./ext/vector_int2.hpp" +#include "./ext/vector_int2_precision.hpp" +#include "./ext/vector_int3.hpp" +#include "./ext/vector_int3_precision.hpp" +#include "./ext/vector_int4.hpp" +#include "./ext/vector_int4_precision.hpp" + +#include "./ext/vector_relational.hpp" + +#include "./ext/vector_uint1.hpp" +#include "./ext/vector_uint1_precision.hpp" +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_uint2_precision.hpp" +#include "./ext/vector_uint3.hpp" +#include "./ext/vector_uint3_precision.hpp" +#include "./ext/vector_uint4.hpp" +#include "./ext/vector_uint4_precision.hpp" + +#include "./gtc/bitfield.hpp" +#include "./gtc/color_space.hpp" +#include "./gtc/constants.hpp" +#include "./gtc/epsilon.hpp" +#include "./gtc/integer.hpp" +#include "./gtc/matrix_access.hpp" +#include "./gtc/matrix_integer.hpp" +#include "./gtc/matrix_inverse.hpp" +#include "./gtc/matrix_transform.hpp" +#include "./gtc/noise.hpp" +#include "./gtc/packing.hpp" +#include "./gtc/quaternion.hpp" +#include "./gtc/random.hpp" +#include "./gtc/reciprocal.hpp" +#include "./gtc/round.hpp" +#include "./gtc/type_precision.hpp" +#include "./gtc/type_ptr.hpp" +#include "./gtc/ulp.hpp" +#include "./gtc/vec1.hpp" +#if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# include "./gtc/type_aligned.hpp" +#endif + +#ifdef GLM_ENABLE_EXPERIMENTAL +#include "./gtx/associated_min_max.hpp" +#include "./gtx/bit.hpp" +#include "./gtx/closest_point.hpp" +#include "./gtx/color_encoding.hpp" +#include "./gtx/color_space.hpp" +#include "./gtx/color_space_YCoCg.hpp" +#include "./gtx/compatibility.hpp" +#include "./gtx/component_wise.hpp" +#include "./gtx/dual_quaternion.hpp" +#include "./gtx/euler_angles.hpp" +#include "./gtx/extend.hpp" +#include "./gtx/extended_min_max.hpp" +#include "./gtx/fast_exponential.hpp" +#include "./gtx/fast_square_root.hpp" +#include "./gtx/fast_trigonometry.hpp" +#include "./gtx/functions.hpp" +#include "./gtx/gradient_paint.hpp" +#include "./gtx/handed_coordinate_space.hpp" +#include "./gtx/integer.hpp" +#include "./gtx/intersect.hpp" +#include "./gtx/log_base.hpp" +#include "./gtx/matrix_cross_product.hpp" +#include "./gtx/matrix_interpolation.hpp" +#include "./gtx/matrix_major_storage.hpp" +#include "./gtx/matrix_operation.hpp" +#include "./gtx/matrix_query.hpp" +#include "./gtx/mixed_product.hpp" +#include "./gtx/norm.hpp" +#include "./gtx/normal.hpp" +#include "./gtx/normalize_dot.hpp" +#include "./gtx/number_precision.hpp" +#include "./gtx/optimum_pow.hpp" +#include "./gtx/orthonormalize.hpp" +#include "./gtx/perpendicular.hpp" +#include "./gtx/polar_coordinates.hpp" +#include "./gtx/projection.hpp" +#include "./gtx/quaternion.hpp" +#include "./gtx/raw_data.hpp" +#include "./gtx/rotate_vector.hpp" +#include "./gtx/spline.hpp" +#include "./gtx/std_based_type.hpp" +#if !(GLM_COMPILER & GLM_COMPILER_CUDA) +# include "./gtx/string_cast.hpp" +#endif +#include "./gtx/transform.hpp" +#include "./gtx/transform2.hpp" +#include "./gtx/vec_swizzle.hpp" +#include "./gtx/vector_angle.hpp" +#include "./gtx/vector_query.hpp" +#include "./gtx/wrap.hpp" + +#if GLM_HAS_TEMPLATE_ALIASES +# include "./gtx/scalar_multiplication.hpp" +#endif + +#if GLM_HAS_RANGE_FOR +# include "./gtx/range.hpp" +#endif +#endif//GLM_ENABLE_EXPERIMENTAL diff --git a/src/GLMath/glm/ext/matrix_clip_space.hpp b/src/GLMath/glm/ext/matrix_clip_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c3874f2f8d753268e6f20618b9d448a6eb62c0d4 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_clip_space.hpp @@ -0,0 +1,522 @@ +/// @ref ext_matrix_clip_space +/// @file glm/ext/matrix_clip_space.hpp +/// +/// @defgroup ext_matrix_clip_space GLM_EXT_matrix_clip_space +/// @ingroup ext +/// +/// Defines functions that generate clip space transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_transform +/// @see ext_matrix_projection + +#pragma once + +// Dependencies +#include "../ext/scalar_constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_clip_space extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_clip_space + /// @{ + + /// Creates a matrix for projecting two-dimensional coordinates onto the screen. + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top, T const& zNear, T const& zFar) + /// @see gluOrtho2D man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( + T left, T right, T bottom, T top); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_ZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_NO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_ZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_NO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoNO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + /// @see glOrtho man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a left handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_ZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a left handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_NO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_ZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_NO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumNO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a left handed frustum matrix. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right handed frustum matrix. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix with default handedness, using the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @tparam T A floating-point scalar type + /// @see glFrustum man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustum( + T left, T right, T bottom, T top, T near, T far); + + + /// Creates a matrix for a right handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_ZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a right handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_NO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_ZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_NO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveNO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a right handed, symetric perspective-view frustum. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left handed, symetric perspective-view frustum. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symetric perspective-view frustum based on the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param fovy Specifies the field of view angle in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + /// @see gluPerspective man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspective( + T fovy, T aspect, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_ZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_NO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_ZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_NO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovNO( + T fov, T width, T height, T near, T far); + + /// Builds a right handed perspective projection matrix based on a field of view. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH( + T fov, T width, T height, T near, T far); + + /// Builds a left handed perspective projection matrix based on a field of view. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view and the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFov( + T fov, T width, T height, T near, T far); + + /// Creates a matrix for a left handed, symmetric perspective-view frustum with far plane at infinite. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveLH( + T fovy, T aspect, T near); + + /// Creates a matrix for a right handed, symmetric perspective-view frustum with far plane at infinite. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveRH( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite with default handedness. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspective( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param ep Epsilon + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( + T fovy, T aspect, T near, T ep); + + /// @} +}//namespace glm + +#include "matrix_clip_space.inl" diff --git a/src/GLMath/glm/ext/matrix_clip_space.inl b/src/GLMath/glm/ext/matrix_clip_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..baf68ccab14585752342910bacc85d19d53d8a87 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_clip_space.inl @@ -0,0 +1,534 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top) + { + mat<4, 4, T, defaultp> Result(static_cast(1)); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(1); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = static_cast(1) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - zNear / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_NO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = static_cast(2) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - (zFar + zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(1) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - zNear / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(2) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - (zFar + zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoZO(T left, T right, T bottom, T top, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); + else + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoNO(T left, T right, T bottom, T top, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return orthoLH_NO(left, right, bottom, top, zNear, zFar); + else + return orthoRH_NO(left, right, bottom, top, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH(T left, T right, T bottom, T top, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); + else + return orthoLH_NO(left, right, bottom, top, zNear, zFar); + + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH(T left, T right, T bottom, T top, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); + else + return orthoRH_NO(left, right, bottom, top, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) + return orthoLH_NO(left, right, bottom, top, zNear, zFar); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) + return orthoRH_NO(left, right, bottom, top, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = farVal / (farVal - nearVal); + Result[2][3] = static_cast(1); + Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = (farVal + nearVal) / (farVal - nearVal); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = farVal / (nearVal - farVal); + Result[2][3] = static_cast(-1); + Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = - (farVal + nearVal) / (farVal - nearVal); + Result[2][3] = static_cast(-1); + Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); + else + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumNO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); + else + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH(T left, T right, T bottom, T top, T nearVal, T farVal) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); + else + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH(T left, T right, T bottom, T top, T nearVal, T farVal) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); + else + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustum(T left, T right, T bottom, T top, T nearVal, T farVal) + { + if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_ZO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = zFar / (zNear - zFar); + Result[2][3] = - static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = - (zFar + zNear) / (zFar - zNear); + Result[2][3] = - static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = zFar / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_NO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = (zFar + zNear) / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveZO(T fovy, T aspect, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); + else + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveNO(T fovy, T aspect, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return perspectiveLH_NO(fovy, aspect, zNear, zFar); + else + return perspectiveRH_NO(fovy, aspect, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); + else + return perspectiveLH_NO(fovy, aspect, zNear, zFar); + + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); + else + return perspectiveRH_NO(fovy, aspect, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar) + { + GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); + else GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) + return perspectiveLH_NO(fovy, aspect, zNear, zFar); + else GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); + else GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) + return perspectiveRH_NO(fovy, aspect, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_ZO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = zFar / (zNear - zFar); + Result[2][3] = - static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_NO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = - (zFar + zNear) / (zFar - zNear); + Result[2][3] = - static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_ZO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = zFar / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_NO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = (zFar + zNear) / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovZO(T fov, T width, T height, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); + else + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovNO(T fov, T width, T height, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); + else + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); + else + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); + else + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar) + { + if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); + else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = - static_cast(1); + Result[2][3] = - static_cast(1); + Result[3][2] = - static_cast(2) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(T(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = static_cast(1); + Result[2][3] = static_cast(1); + Result[3][2] = - static_cast(2) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return infinitePerspectiveLH(fovy, aspect, zNear); + else + return infinitePerspectiveRH(fovy, aspect, zNear); + } + + // Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = ep - static_cast(1); + Result[2][3] = static_cast(-1); + Result[3][2] = (ep - static_cast(2)) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear) + { + return tweakedInfinitePerspective(fovy, aspect, zNear, epsilon()); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_common.hpp b/src/GLMath/glm/ext/matrix_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..05c37991c5d6e4d1e3c90f469ceffd9cce57e1a6 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_common.hpp @@ -0,0 +1,36 @@ +/// @ref ext_matrix_common +/// @file glm/ext/matrix_common.hpp +/// +/// @defgroup ext_matrix_common GLM_EXT_matrix_common +/// @ingroup ext +/// +/// Defines functions for common matrix operations. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_common + +#pragma once + +#include "../detail/qualifier.hpp" +#include "../detail/_fixes.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_common + /// @{ + + template + GLM_FUNC_DECL mat mix(mat const& x, mat const& y, mat const& a); + + template + GLM_FUNC_DECL mat mix(mat const& x, mat const& y, U a); + + /// @} +}//namespace glm + +#include "matrix_common.inl" diff --git a/src/GLMath/glm/ext/matrix_common.inl b/src/GLMath/glm/ext/matrix_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..9d508485b866c1a64b7d9db67792f50b61357b1f --- /dev/null +++ b/src/GLMath/glm/ext/matrix_common.inl @@ -0,0 +1,16 @@ +#include "../matrix.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, U a) + { + return mat(x) * (static_cast(1) - a) + mat(y) * a; + } + + template + GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, mat const& a) + { + return matrixCompMult(mat(x), static_cast(1) - a) + matrixCompMult(mat(y), a); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double2x2.hpp b/src/GLMath/glm/ext/matrix_double2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..94dca54b59bd00e36e28a37816525f59c8eb2a56 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double2x2.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double2x2.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, double, defaultp> dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, double, defaultp> dmat2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double2x2_precision.hpp b/src/GLMath/glm/ext/matrix_double2x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9e2c174e43be2dea558bbe45b75c19a4351c12bc --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double2x2_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, lowp> lowp_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, mediump> mediump_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, highp> highp_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, lowp> lowp_dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, mediump> mediump_dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, highp> highp_dmat2x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double2x3.hpp b/src/GLMath/glm/ext/matrix_double2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bfef87a666c1346ef7053f44b8e0d862b86e3af0 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double2x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double2x3.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 3, double, defaultp> dmat2x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double2x3_precision.hpp b/src/GLMath/glm/ext/matrix_double2x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..098fb6046e889cf7e2b19039c08ffd9a51bf2fda --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double2x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double2x3_precision.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, lowp> lowp_dmat2x3; + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, mediump> mediump_dmat2x3; + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, highp> highp_dmat2x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double2x4.hpp b/src/GLMath/glm/ext/matrix_double2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..499284bce161de74be5cb0ab7798d45c69d682e2 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double2x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double2x4.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 4, double, defaultp> dmat2x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double2x4_precision.hpp b/src/GLMath/glm/ext/matrix_double2x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9b61ebcee1efbb63b0d95b2fe9e88c804ecb631a --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double2x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double2x4_precision.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, lowp> lowp_dmat2x4; + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, mediump> mediump_dmat2x4; + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, highp> highp_dmat2x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double3x2.hpp b/src/GLMath/glm/ext/matrix_double3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dd23f36cdbb2530d9305f4e6e037eb2f88ecb544 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double3x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double3x2.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 2, double, defaultp> dmat3x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double3x2_precision.hpp b/src/GLMath/glm/ext/matrix_double3x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..068d9e911721623bfb7c5d5ac3ac5591581907e2 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double3x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double3x2_precision.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, lowp> lowp_dmat3x2; + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, mediump> mediump_dmat3x2; + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, highp> highp_dmat3x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double3x3.hpp b/src/GLMath/glm/ext/matrix_double3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..53572b735626e224c52eb386a794353308574b6a --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double3x3.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double3x3.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, double, defaultp> dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, double, defaultp> dmat3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double3x3_precision.hpp b/src/GLMath/glm/ext/matrix_double3x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8691e7808dc95b7f4466ec9b6c829f54f9416edf --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double3x3_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double3x3_precision.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, lowp> lowp_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, mediump> mediump_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, highp> highp_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, lowp> lowp_dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, mediump> mediump_dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, highp> highp_dmat3x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double3x4.hpp b/src/GLMath/glm/ext/matrix_double3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c572d637cd2dce86aa0d8d45c4457498880a95ca --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double3x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double3x4.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 4, double, defaultp> dmat3x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double3x4_precision.hpp b/src/GLMath/glm/ext/matrix_double3x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f040217e748ab7b56a8a292b4825c5926716b176 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double3x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double3x4_precision.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, lowp> lowp_dmat3x4; + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, mediump> mediump_dmat3x4; + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, highp> highp_dmat3x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double4x2.hpp b/src/GLMath/glm/ext/matrix_double4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9b229f471e8d4904c7135e7a27719820dfe5225b --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double4x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double4x2.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 2, double, defaultp> dmat4x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double4x2_precision.hpp b/src/GLMath/glm/ext/matrix_double4x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6ad18ba9e65e108090e8354e5a55a5ac1c5f3b8f --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double4x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double4x2_precision.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, lowp> lowp_dmat4x2; + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, mediump> mediump_dmat4x2; + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, highp> highp_dmat4x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double4x3.hpp b/src/GLMath/glm/ext/matrix_double4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dca4cf956f9189b7b74cece7fc3f2af9501ae49f --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double4x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double4x3.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 3, double, defaultp> dmat4x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double4x3_precision.hpp b/src/GLMath/glm/ext/matrix_double4x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f7371de84942ac21b33e7eb81e97352c6a4ec449 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double4x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double4x3_precision.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, lowp> lowp_dmat4x3; + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, mediump> mediump_dmat4x3; + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, highp> highp_dmat4x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double4x4.hpp b/src/GLMath/glm/ext/matrix_double4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..81e1bf65cb5c4b071a394b6dc1d9d53e04b21500 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double4x4.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double4x4.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, double, defaultp> dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, double, defaultp> dmat4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_double4x4_precision.hpp b/src/GLMath/glm/ext/matrix_double4x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4c36a8486c72988f4d0d1f8a822a69c4e477fa95 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_double4x4_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double4x4_precision.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, lowp> lowp_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, mediump> mediump_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, highp> highp_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, lowp> lowp_dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, mediump> mediump_dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, highp> highp_dmat4x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float2x2.hpp b/src/GLMath/glm/ext/matrix_float2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..53df921fe216b575c92239c478301db803416a14 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float2x2.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, float, defaultp> mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, float, defaultp> mat2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float2x2_precision.hpp b/src/GLMath/glm/ext/matrix_float2x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..898b6db7140807bc0d30b676724827d623c64da3 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float2x2_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, lowp> lowp_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, mediump> mediump_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, highp> highp_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, lowp> lowp_mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, mediump> mediump_mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, highp> highp_mat2x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float2x3.hpp b/src/GLMath/glm/ext/matrix_float2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6f68822dbf1e742431163115f4bafc35b6896606 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float2x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float2x3.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 3, float, defaultp> mat2x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float2x3_precision.hpp b/src/GLMath/glm/ext/matrix_float2x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..50c103245c3a177b958de4df333245d09f4d1e28 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float2x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x3_precision.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, lowp> lowp_mat2x3; + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, mediump> mediump_mat2x3; + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, highp> highp_mat2x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float2x4.hpp b/src/GLMath/glm/ext/matrix_float2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..30f30de3cbd4c12cc642a6ac211e40876bdca525 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float2x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float2x4.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 4, float, defaultp> mat2x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float2x4_precision.hpp b/src/GLMath/glm/ext/matrix_float2x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..079d6382863172411ae6a82837bb34ea6e2096c9 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float2x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x4_precision.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, lowp> lowp_mat2x4; + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, mediump> mediump_mat2x4; + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, highp> highp_mat2x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float3x2.hpp b/src/GLMath/glm/ext/matrix_float3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d39dd2fedd670f353f4ad9b5f9246475e2e69686 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float3x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float3x2.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core + /// @{ + + /// 3 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 2, float, defaultp> mat3x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float3x2_precision.hpp b/src/GLMath/glm/ext/matrix_float3x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8572c2a1b20e5a1e47bedd72ec6d0009fd15d9bf --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float3x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float3x2_precision.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, lowp> lowp_mat3x2; + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, mediump> mediump_mat3x2; + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, highp> highp_mat3x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float3x3.hpp b/src/GLMath/glm/ext/matrix_float3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..177d809ff9f4c157beda61885ad3994fe3e3d141 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float3x3.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float3x3.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, float, defaultp> mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, float, defaultp> mat3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float3x3_precision.hpp b/src/GLMath/glm/ext/matrix_float3x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8a900c16420006f110c9bfeaf186156d9fc135c3 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float3x3_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float3x3_precision.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, lowp> lowp_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, mediump> mediump_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, highp> highp_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, lowp> lowp_mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, mediump> mediump_mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, highp> highp_mat3x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float3x4.hpp b/src/GLMath/glm/ext/matrix_float3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..64b8459dcdd2d489a7a8fc93c1282f7cf1ec2673 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float3x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float3x4.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 4, float, defaultp> mat3x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float3x4_precision.hpp b/src/GLMath/glm/ext/matrix_float3x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bc36bf13a1e957ab625e3162312f311a9d5a287e --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float3x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float3x4_precision.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, lowp> lowp_mat3x4; + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, mediump> mediump_mat3x4; + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, highp> highp_mat3x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float4x2.hpp b/src/GLMath/glm/ext/matrix_float4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1ed5227bf58000e7c2d822014b29b49d685f6972 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float4x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float4x2.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 2, float, defaultp> mat4x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float4x2_precision.hpp b/src/GLMath/glm/ext/matrix_float4x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..88fd069630a802ab8c7d80791ae91f98969098a4 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float4x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, lowp> lowp_mat4x2; + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, mediump> mediump_mat4x2; + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, highp> highp_mat4x2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float4x3.hpp b/src/GLMath/glm/ext/matrix_float4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5dbe7657043f704017228a0ebc03ed5a7a0c9e40 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float4x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float4x3.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 3, float, defaultp> mat4x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float4x3_precision.hpp b/src/GLMath/glm/ext/matrix_float4x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..846ed4fc8d9ccb0de18374fa039cffb823d3586a --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float4x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float4x3_precision.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, lowp> lowp_mat4x3; + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, mediump> mediump_mat4x3; + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, highp> highp_mat4x3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float4x4.hpp b/src/GLMath/glm/ext/matrix_float4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5ba111de048171ae0f9849a2c5e375f9351a8bbc --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float4x4.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float4x4.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @ingroup core_matrix + /// @{ + + /// 4 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, float, defaultp> mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, float, defaultp> mat4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_float4x4_precision.hpp b/src/GLMath/glm/ext/matrix_float4x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..597149bcf90fcd34e1b22e970fbd01cc45742fa5 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_float4x4_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float4x4_precision.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, lowp> lowp_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, mediump> mediump_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, highp> highp_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, lowp> lowp_mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, mediump> mediump_mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, highp> highp_mat4x4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_projection.hpp b/src/GLMath/glm/ext/matrix_projection.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51fd01bd8ee7fb28c992579c31c6200bfff98cf0 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_projection.hpp @@ -0,0 +1,149 @@ +/// @ref ext_matrix_projection +/// @file glm/ext/matrix_projection.hpp +/// +/// @defgroup ext_matrix_projection GLM_EXT_matrix_projection +/// @ingroup ext +/// +/// Functions that generate common projection transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_transform +/// @see ext_matrix_clip_space + +#pragma once + +// Dependencies +#include "../gtc/constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_projection extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_projection + /// @{ + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> projectZO( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> projectNO( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates using default near and far clip planes definition. + /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> project( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProjectZO( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProjectNO( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using default near and far clip planes definition. + /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProject( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Define a picking region + /// + /// @param center Specify the center of a picking region in window coordinates. + /// @param delta Specify the width and height, respectively, of the picking region in window coordinates. + /// @param viewport Rendering viewport + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluPickMatrix man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> pickMatrix( + vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport); + + /// @} +}//namespace glm + +#include "matrix_projection.inl" diff --git a/src/GLMath/glm/ext/matrix_projection.inl b/src/GLMath/glm/ext/matrix_projection.inl new file mode 100644 index 0000000000000000000000000000000000000000..8b4eea98602afb60cc11c5b36b5d1b16d4d49e71 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_projection.inl @@ -0,0 +1,104 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> projectZO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); + tmp = model * tmp; + tmp = proj * tmp; + + tmp /= tmp.w; + tmp.x = tmp.x * static_cast(0.5) + static_cast(0.5); + tmp.y = tmp.y * static_cast(0.5) + static_cast(0.5); + + tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); + tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); + + return vec<3, T, Q>(tmp); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> projectNO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); + tmp = model * tmp; + tmp = proj * tmp; + + tmp /= tmp.w; + tmp = tmp * static_cast(0.5) + static_cast(0.5); + tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); + tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); + + return vec<3, T, Q>(tmp); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> project(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return projectZO(obj, model, proj, viewport); + else + return projectNO(obj, model, proj, viewport); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectZO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + mat<4, 4, T, Q> Inverse = inverse(proj * model); + + vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); + tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); + tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); + tmp.x = tmp.x * static_cast(2) - static_cast(1); + tmp.y = tmp.y * static_cast(2) - static_cast(1); + + vec<4, T, Q> obj = Inverse * tmp; + obj /= obj.w; + + return vec<3, T, Q>(obj); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectNO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + mat<4, 4, T, Q> Inverse = inverse(proj * model); + + vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); + tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); + tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); + tmp = tmp * static_cast(2) - static_cast(1); + + vec<4, T, Q> obj = Inverse * tmp; + obj /= obj.w; + + return vec<3, T, Q>(obj); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProject(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) + return unProjectZO(win, model, proj, viewport); + else + return unProjectNO(win, model, proj, viewport); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> pickMatrix(vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport) + { + assert(delta.x > static_cast(0) && delta.y > static_cast(0)); + mat<4, 4, T, Q> Result(static_cast(1)); + + if(!(delta.x > static_cast(0) && delta.y > static_cast(0))) + return Result; // Error + + vec<3, T, Q> Temp( + (static_cast(viewport[2]) - static_cast(2) * (center.x - static_cast(viewport[0]))) / delta.x, + (static_cast(viewport[3]) - static_cast(2) * (center.y - static_cast(viewport[1]))) / delta.y, + static_cast(0)); + + // Translate and scale the picked region to the entire window + Result = translate(Result, Temp); + return scale(Result, vec<3, T, Q>(static_cast(viewport[2]) / delta.x, static_cast(viewport[3]) / delta.y, static_cast(1))); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_relational.hpp b/src/GLMath/glm/ext/matrix_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..20023ad89a0ce6fa19b1294212ab78d0dff479b3 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_relational.hpp @@ -0,0 +1,132 @@ +/// @ref ext_matrix_relational +/// @file glm/ext/matrix_relational.hpp +/// +/// @defgroup ext_matrix_relational GLM_EXT_matrix_relational +/// @ingroup ext +/// +/// Exposes comparison functions for matrix types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_relational +/// @see ext_scalar_relational +/// @see ext_quaternion_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_relational + /// @{ + + /// Perform a component-wise equal-to comparison of two matrices. + /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y); + + /// Perform a component-wise not-equal-to comparison of two matrices. + /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& epsilon); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& ULPs); + + /// @} +}//namespace glm + +#include "matrix_relational.inl" diff --git a/src/GLMath/glm/ext/matrix_relational.inl b/src/GLMath/glm/ext/matrix_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..b2b875309decbe275ca68432f4b4992ca55a6409 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_relational.inl @@ -0,0 +1,82 @@ +/// @ref ext_vector_relational +/// @file glm/ext/vector_relational.inl + +// Dependency: +#include "../ext/vector_relational.hpp" +#include "../common.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b) + { + return equal(a, b, static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, T Epsilon) + { + return equal(a, b, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& Epsilon) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = all(equal(a[i], b[i], Epsilon[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y) + { + return notEqual(x, y, static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, T Epsilon) + { + return notEqual(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& Epsilon) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = any(notEqual(a[i], b[i], Epsilon[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, int MaxULPs) + { + return equal(a, b, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& MaxULPs) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = all(equal(a[i], b[i], MaxULPs[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, int MaxULPs) + { + return notEqual(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& MaxULPs) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = any(notEqual(a[i], b[i], MaxULPs[i])); + return Result; + } + +}//namespace glm diff --git a/src/GLMath/glm/ext/matrix_transform.hpp b/src/GLMath/glm/ext/matrix_transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cbd187efd85015605dc7d33e4f919b99070ade44 --- /dev/null +++ b/src/GLMath/glm/ext/matrix_transform.hpp @@ -0,0 +1,144 @@ +/// @ref ext_matrix_transform +/// @file glm/ext/matrix_transform.hpp +/// +/// @defgroup ext_matrix_transform GLM_EXT_matrix_transform +/// @ingroup ext +/// +/// Defines functions that generate common transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_projection +/// @see ext_matrix_clip_space + +#pragma once + +// Dependencies +#include "../gtc/constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_transform + /// @{ + + /// Builds an identity matrix. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType identity(); + + /// Builds a translation 4 * 4 matrix created from a vector of 3 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a translation vector. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @code + /// #include + /// #include + /// ... + /// glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f)); + /// // m[0][0] == 1.0f, m[0][1] == 0.0f, m[0][2] == 0.0f, m[0][3] == 0.0f + /// // m[1][0] == 0.0f, m[1][1] == 1.0f, m[1][2] == 0.0f, m[1][3] == 0.0f + /// // m[2][0] == 0.0f, m[2][1] == 0.0f, m[2][2] == 1.0f, m[2][3] == 0.0f + /// // m[3][0] == 1.0f, m[3][1] == 1.0f, m[3][2] == 1.0f, m[3][3] == 1.0f + /// @endcode + /// + /// @see - translate(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - translate(vec<3, T, Q> const& v) + /// @see glTranslate man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> translate( + mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); + + /// Builds a rotation 4 * 4 matrix created from an axis vector and an angle. + /// + /// @param m Input matrix multiplied by this rotation matrix. + /// @param angle Rotation angle expressed in radians. + /// @param axis Rotation axis, recommended to be normalized. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) + /// @see - rotate(T angle, vec<3, T, Q> const& v) + /// @see glRotate man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotate( + mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& axis); + + /// Builds a scale 4 * 4 matrix created from 3 scalars. + /// + /// @param m Input matrix multiplied by this scale matrix. + /// @param v Ratio of scaling for each axis. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - scale(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - scale(vec<3, T, Q> const& v) + /// @see glScale man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> scale( + mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); + + /// Build a right handed look at view matrix. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAtRH( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// Build a left handed look at view matrix. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAtLH( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// Build a look at view matrix based on the default handedness. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + /// @see gluLookAt man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAt( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// @} +}//namespace glm + +#include "matrix_transform.inl" diff --git a/src/GLMath/glm/ext/matrix_transform.inl b/src/GLMath/glm/ext/matrix_transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..a415157e0d9ef2f1d709cbbe6a3d10c1778b8a5c --- /dev/null +++ b/src/GLMath/glm/ext/matrix_transform.inl @@ -0,0 +1,152 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType identity() + { + return detail::init_gentype::GENTYPE>::identity(); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result(m); + Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + vec<3, T, Q> axis(normalize(v)); + vec<3, T, Q> temp((T(1) - c) * axis); + + mat<4, 4, T, Q> Rotate; + Rotate[0][0] = c + temp[0] * axis[0]; + Rotate[0][1] = temp[0] * axis[1] + s * axis[2]; + Rotate[0][2] = temp[0] * axis[2] - s * axis[1]; + + Rotate[1][0] = temp[1] * axis[0] - s * axis[2]; + Rotate[1][1] = c + temp[1] * axis[1]; + Rotate[1][2] = temp[1] * axis[2] + s * axis[0]; + + Rotate[2][0] = temp[2] * axis[0] + s * axis[1]; + Rotate[2][1] = temp[2] * axis[1] - s * axis[0]; + Rotate[2][2] = c + temp[2] * axis[2]; + + mat<4, 4, T, Q> Result; + Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate_slow(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + mat<4, 4, T, Q> Result; + + vec<3, T, Q> axis = normalize(v); + + Result[0][0] = c + (static_cast(1) - c) * axis.x * axis.x; + Result[0][1] = (static_cast(1) - c) * axis.x * axis.y + s * axis.z; + Result[0][2] = (static_cast(1) - c) * axis.x * axis.z - s * axis.y; + Result[0][3] = static_cast(0); + + Result[1][0] = (static_cast(1) - c) * axis.y * axis.x - s * axis.z; + Result[1][1] = c + (static_cast(1) - c) * axis.y * axis.y; + Result[1][2] = (static_cast(1) - c) * axis.y * axis.z + s * axis.x; + Result[1][3] = static_cast(0); + + Result[2][0] = (static_cast(1) - c) * axis.z * axis.x + s * axis.y; + Result[2][1] = (static_cast(1) - c) * axis.z * axis.y - s * axis.x; + Result[2][2] = c + (static_cast(1) - c) * axis.z * axis.z; + Result[2][3] = static_cast(0); + + Result[3] = vec<4, T, Q>(0, 0, 0, 1); + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result; + Result[0] = m[0] * v[0]; + Result[1] = m[1] * v[1]; + Result[2] = m[2] * v[2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale_slow(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result(T(1)); + Result[0][0] = v.x; + Result[1][1] = v.y; + Result[2][2] = v.z; + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + vec<3, T, Q> const f(normalize(center - eye)); + vec<3, T, Q> const s(normalize(cross(f, up))); + vec<3, T, Q> const u(cross(s, f)); + + mat<4, 4, T, Q> Result(1); + Result[0][0] = s.x; + Result[1][0] = s.y; + Result[2][0] = s.z; + Result[0][1] = u.x; + Result[1][1] = u.y; + Result[2][1] = u.z; + Result[0][2] =-f.x; + Result[1][2] =-f.y; + Result[2][2] =-f.z; + Result[3][0] =-dot(s, eye); + Result[3][1] =-dot(u, eye); + Result[3][2] = dot(f, eye); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + vec<3, T, Q> const f(normalize(center - eye)); + vec<3, T, Q> const s(normalize(cross(up, f))); + vec<3, T, Q> const u(cross(f, s)); + + mat<4, 4, T, Q> Result(1); + Result[0][0] = s.x; + Result[1][0] = s.y; + Result[2][0] = s.z; + Result[0][1] = u.x; + Result[1][1] = u.y; + Result[2][1] = u.z; + Result[0][2] = f.x; + Result[1][2] = f.y; + Result[2][2] = f.z; + Result[3][0] = -dot(s, eye); + Result[3][1] = -dot(u, eye); + Result[3][2] = -dot(f, eye); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return lookAtLH(eye, center, up); + else + return lookAtRH(eye, center, up); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/quaternion_common.hpp b/src/GLMath/glm/ext/quaternion_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2980ed4d43ae216a2f35622b69035b606ec192f2 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_common.hpp @@ -0,0 +1,120 @@ +/// @ref ext_quaternion_common +/// @file glm/ext/quaternion_common.hpp +/// +/// @defgroup ext_quaternion_common GLM_EXT_quaternion_common +/// @ingroup ext +/// +/// Provides common functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_common +/// @see ext_vector_common +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_trigonometric +/// @see ext_quaternion_transform + +#pragma once + +// Dependency: +#include "../ext/scalar_constants.hpp" +#include "../ext/quaternion_geometric.hpp" +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_common + /// @{ + + /// Spherical linear interpolation of two quaternions. + /// The interpolation is oriented and the rotation is performed at constant speed. + /// For short path spherical linear interpolation, use the slerp function. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - slerp(qua const& x, qua const& y, T const& a) + template + GLM_FUNC_DECL qua mix(qua const& x, qua const& y, T a); + + /// Linear interpolation of two quaternions. + /// The interpolation is oriented. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined in the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua lerp(qua const& x, qua const& y, T a); + + /// Spherical linear interpolation of two quaternions. + /// The interpolation always take the short path and the rotation is performed at constant speed. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua slerp(qua const& x, qua const& y, T a); + + /// Returns the q conjugate. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua conjugate(qua const& q); + + /// Returns the q inverse. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua inverse(qua const& q); + + /// Returns true if x holds a NaN (not a number) + /// representation in the underlying implementation's set of + /// floating point representations. Returns false otherwise, + /// including for implementations with no NaN + /// representations. + /// + /// /!\ When using compiler fast math, this function may fail. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> isnan(qua const& x); + + /// Returns true if x holds a positive infinity or negative + /// infinity representation in the underlying implementation's + /// set of floating point representations. Returns false + /// otherwise, including for implementations with no infinity + /// representations. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> isinf(qua const& x); + + /// @} +} //namespace glm + +#include "quaternion_common.inl" diff --git a/src/GLMath/glm/ext/quaternion_common.inl b/src/GLMath/glm/ext/quaternion_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..3b2846f36ee532552b2478212be1fb15be96991d --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_common.inl @@ -0,0 +1,107 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua mix(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mix' only accept floating-point inputs"); + + T const cosTheta = dot(x, y); + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if(cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, y.w, a), + mix(x.x, y.x, a), + mix(x.y, y.y, a), + mix(x.z, y.z, a)); + } + else + { + // Essential Mathematics, page 467 + T angle = acos(cosTheta); + return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * y) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua lerp(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'lerp' only accept floating-point inputs"); + + // Lerp is only defined in [0, 1] + assert(a >= static_cast(0)); + assert(a <= static_cast(1)); + + return x * (static_cast(1) - a) + (y * a); + } + + template + GLM_FUNC_QUALIFIER qua slerp(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'slerp' only accept floating-point inputs"); + + qua z = y; + + T cosTheta = dot(x, y); + + // If cosTheta < 0, the interpolation will take the long way around the sphere. + // To fix this, one quat must be negated. + if(cosTheta < static_cast(0)) + { + z = -y; + cosTheta = -cosTheta; + } + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if(cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, z.w, a), + mix(x.x, z.x, a), + mix(x.y, z.y, a), + mix(x.z, z.z, a)); + } + else + { + // Essential Mathematics, page 467 + T angle = acos(cosTheta); + return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua conjugate(qua const& q) + { + return qua(q.w, -q.x, -q.y, -q.z); + } + + template + GLM_FUNC_QUALIFIER qua inverse(qua const& q) + { + return conjugate(q) / dot(q, q); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isnan(qua const& q) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + + return vec<4, bool, Q>(isnan(q.x), isnan(q.y), isnan(q.z), isnan(q.w)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isinf(qua const& q) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + + return vec<4, bool, Q>(isinf(q.x), isinf(q.y), isinf(q.z), isinf(q.w)); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "quaternion_common_simd.inl" +#endif + diff --git a/src/GLMath/glm/ext/quaternion_common_simd.inl b/src/GLMath/glm/ext/quaternion_common_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..ddfc8a44f6a32774ff092201bc9ee2fd2a11b80b --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_common_simd.inl @@ -0,0 +1,18 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_dot, float, true> + { + static GLM_FUNC_QUALIFIER float call(qua const& x, qua const& y) + { + return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/src/GLMath/glm/ext/quaternion_double.hpp b/src/GLMath/glm/ext/quaternion_double.hpp new file mode 100644 index 0000000000000000000000000000000000000000..63b24de4d52afb415cdaf8a8077cbb95e5a01d90 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_double.hpp @@ -0,0 +1,39 @@ +/// @ref ext_quaternion_double +/// @file glm/ext/quaternion_double.hpp +/// +/// @defgroup ext_quaternion_double GLM_EXT_quaternion_double +/// @ingroup ext +/// +/// Exposes double-precision floating point quaternion type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double_precision +/// @see ext_quaternion_common +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_double extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_double + /// @{ + + /// Quaternion of double-precision floating-point numbers. + typedef qua dquat; + + /// @} +} //namespace glm + diff --git a/src/GLMath/glm/ext/quaternion_double_precision.hpp b/src/GLMath/glm/ext/quaternion_double_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8aa24a17752dfd04aa05bc80ff179c0b02d58fbb --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_double_precision.hpp @@ -0,0 +1,42 @@ +/// @ref ext_quaternion_double_precision +/// @file glm/ext/quaternion_double_precision.hpp +/// +/// @defgroup ext_quaternion_double_precision GLM_EXT_quaternion_double_precision +/// @ingroup ext +/// +/// Exposes double-precision floating point quaternion type with various precision in term of ULPs. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_double_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_double_precision + /// @{ + + /// Quaternion of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua lowp_dquat; + + /// Quaternion of medium double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua mediump_dquat; + + /// Quaternion of high double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua highp_dquat; + + /// @} +} //namespace glm + diff --git a/src/GLMath/glm/ext/quaternion_exponential.hpp b/src/GLMath/glm/ext/quaternion_exponential.hpp new file mode 100644 index 0000000000000000000000000000000000000000..affe2979aad5bcc7a475d8293bab6421ae0c7bba --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_exponential.hpp @@ -0,0 +1,63 @@ +/// @ref ext_quaternion_exponential +/// @file glm/ext/quaternion_exponential.hpp +/// +/// @defgroup ext_quaternion_exponential GLM_EXT_quaternion_exponential +/// @ingroup ext +/// +/// Provides exponential functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see core_exponential +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../geometric.hpp" +#include "../ext/scalar_constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_exponential extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_transform + /// @{ + + /// Returns a exponential of a quaternion. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua exp(qua const& q); + + /// Returns a logarithm of a quaternion + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua log(qua const& q); + + /// Returns a quaternion raised to a power. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua pow(qua const& q, T y); + + /// Returns the square root of a quaternion + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua sqrt(qua const& q); + + /// @} +} //namespace glm + +#include "quaternion_exponential.inl" diff --git a/src/GLMath/glm/ext/quaternion_exponential.inl b/src/GLMath/glm/ext/quaternion_exponential.inl new file mode 100644 index 0000000000000000000000000000000000000000..1365d0a96471824d6facea3167e225166ce595d7 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_exponential.inl @@ -0,0 +1,69 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua exp(qua const& q) + { + vec<3, T, Q> u(q.x, q.y, q.z); + T const Angle = glm::length(u); + if (Angle < epsilon()) + return qua(); + + vec<3, T, Q> const v(u / Angle); + return qua(cos(Angle), sin(Angle) * v); + } + + template + GLM_FUNC_QUALIFIER qua log(qua const& q) + { + vec<3, T, Q> u(q.x, q.y, q.z); + T Vec3Len = length(u); + + if (Vec3Len < epsilon()) + { + if(q.w > static_cast(0)) + return qua(log(q.w), static_cast(0), static_cast(0), static_cast(0)); + else if(q.w < static_cast(0)) + return qua(log(-q.w), pi(), static_cast(0), static_cast(0)); + else + return qua(std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); + } + else + { + T t = atan(Vec3Len, T(q.w)) / Vec3Len; + T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w; + return qua(static_cast(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z); + } + } + + template + GLM_FUNC_QUALIFIER qua pow(qua const& x, T y) + { + //Raising to the power of 0 should yield 1 + //Needed to prevent a division by 0 error later on + if(y > -epsilon() && y < epsilon()) + return qua(1,0,0,0); + + //To deal with non-unit quaternions + T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w); + + //Equivalent to raising a real number to a power + //Needed to prevent a division by 0 error later on + if(abs(x.w / magnitude) > static_cast(1) - epsilon() && abs(x.w / magnitude) < static_cast(1) + epsilon()) + return qua(pow(x.w, y), 0, 0, 0); + + T Angle = acos(x.w / magnitude); + T NewAngle = Angle * y; + T Div = sin(NewAngle) / sin(Angle); + T Mag = pow(magnitude, y - static_cast(1)); + + return qua(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag); + } + + template + GLM_FUNC_QUALIFIER qua sqrt(qua const& x) + { + return pow(x, static_cast(0.5)); + } +}//namespace glm + + diff --git a/src/GLMath/glm/ext/quaternion_float.hpp b/src/GLMath/glm/ext/quaternion_float.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ca42a60597f43d241f7e6a82bf6d0b98c2161621 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_float.hpp @@ -0,0 +1,39 @@ +/// @ref ext_quaternion_float +/// @file glm/ext/quaternion_float.hpp +/// +/// @defgroup ext_quaternion_float GLM_EXT_quaternion_float +/// @ingroup ext +/// +/// Exposes single-precision floating point quaternion type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_double +/// @see ext_quaternion_float_precision +/// @see ext_quaternion_common +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_float extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_float + /// @{ + + /// Quaternion of single-precision floating-point numbers. + typedef qua quat; + + /// @} +} //namespace glm + diff --git a/src/GLMath/glm/ext/quaternion_float_precision.hpp b/src/GLMath/glm/ext/quaternion_float_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9e4f5c21d9075fbd6cf3d684774a62a39c0d15b --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_float_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_quaternion_float_precision +/// @file glm/ext/quaternion_float_precision.hpp +/// +/// @defgroup ext_quaternion_float_precision GLM_EXT_quaternion_float_precision +/// @ingroup ext +/// +/// Exposes single-precision floating point quaternion type with various precision in term of ULPs. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_float_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_float_precision + /// @{ + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua lowp_quat; + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua mediump_quat; + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua highp_quat; + + /// @} +} //namespace glm + diff --git a/src/GLMath/glm/ext/quaternion_geometric.hpp b/src/GLMath/glm/ext/quaternion_geometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6d98bbe93fc6b0ea0f2e082a51793379682b7eb2 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_geometric.hpp @@ -0,0 +1,70 @@ +/// @ref ext_quaternion_geometric +/// @file glm/ext/quaternion_geometric.hpp +/// +/// @defgroup ext_quaternion_geometric GLM_EXT_quaternion_geometric +/// @ingroup ext +/// +/// Provides geometric functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see core_geometric +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "../ext/vector_relational.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_geometric extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_geometric + /// @{ + + /// Returns the norm of a quaternions + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL T length(qua const& q); + + /// Returns the normalized quaternion. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL qua normalize(qua const& q); + + /// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ... + /// + /// @tparam T Floating-point scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL T dot(qua const& x, qua const& y); + + /// Compute a cross product. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2); + + /// @} +} //namespace glm + +#include "quaternion_geometric.inl" diff --git a/src/GLMath/glm/ext/quaternion_geometric.inl b/src/GLMath/glm/ext/quaternion_geometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..e155ac5218075dfc37aa0720ace9b0bce901c071 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_geometric.inl @@ -0,0 +1,36 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER T dot(qua const& x, qua const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER T length(qua const& q) + { + return glm::sqrt(dot(q, q)); + } + + template + GLM_FUNC_QUALIFIER qua normalize(qua const& q) + { + T len = length(q); + if(len <= static_cast(0)) // Problem + return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + T oneOverLen = static_cast(1) / len; + return qua(q.w * oneOverLen, q.x * oneOverLen, q.y * oneOverLen, q.z * oneOverLen); + } + + template + GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2) + { + return qua( + q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, + q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, + q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, + q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x); + } +}//namespace glm + diff --git a/src/GLMath/glm/ext/quaternion_relational.hpp b/src/GLMath/glm/ext/quaternion_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7aa121da0a1570460ecf379cf3d4b3ae7c9941c3 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_relational.hpp @@ -0,0 +1,62 @@ +/// @ref ext_quaternion_relational +/// @file glm/ext/quaternion_relational.hpp +/// +/// @defgroup ext_quaternion_relational GLM_EXT_quaternion_relational +/// @ingroup ext +/// +/// Exposes comparison functions for quaternion types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_vector_relational +/// @see ext_matrix_relational +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../vector_relational.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_relational + /// @{ + + /// Returns the component-wise comparison of result x == y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon); + + /// Returns the component-wise comparison of result x != y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon); + + /// @} +} //namespace glm + +#include "quaternion_relational.inl" diff --git a/src/GLMath/glm/ext/quaternion_relational.inl b/src/GLMath/glm/ext/quaternion_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..b1713e95c6c5b9dffb8f49aeeb659d7e82a7dbc6 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_relational.inl @@ -0,0 +1,35 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] == y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return lessThan(abs(v), vec<4, T, Q>(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] != y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); + } +}//namespace glm + diff --git a/src/GLMath/glm/ext/quaternion_transform.hpp b/src/GLMath/glm/ext/quaternion_transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a9cc5c2b59ff883d1de1b2bc2a0b57ca57144089 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_transform.hpp @@ -0,0 +1,47 @@ +/// @ref ext_quaternion_transform +/// @file glm/ext/quaternion_transform.hpp +/// +/// @defgroup ext_quaternion_transform GLM_EXT_quaternion_transform +/// @ingroup ext +/// +/// Provides transformation functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_transform + /// @{ + + /// Rotates a quaternion from a vector of 3 components axis and an angle. + /// + /// @param q Source orientation + /// @param angle Angle expressed in radians. + /// @param axis Axis of the rotation + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& axis); + /// @} +} //namespace glm + +#include "quaternion_transform.inl" diff --git a/src/GLMath/glm/ext/quaternion_transform.inl b/src/GLMath/glm/ext/quaternion_transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..b87ecb65d9f7ce739f5f3eeb1e57d5b4f4edf9e6 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_transform.inl @@ -0,0 +1,24 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& v) + { + vec<3, T, Q> Tmp = v; + + // Axis of rotation must be normalised + T len = glm::length(Tmp); + if(abs(len - static_cast(1)) > static_cast(0.001)) + { + T oneOverLen = static_cast(1) / len; + Tmp.x *= oneOverLen; + Tmp.y *= oneOverLen; + Tmp.z *= oneOverLen; + } + + T const AngleRad(angle); + T const Sin = sin(AngleRad * static_cast(0.5)); + + return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); + } +}//namespace glm + diff --git a/src/GLMath/glm/ext/quaternion_trigonometric.hpp b/src/GLMath/glm/ext/quaternion_trigonometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..76cea27add64c4d32ec8dd0e164132090e1a43c7 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_trigonometric.hpp @@ -0,0 +1,63 @@ +/// @ref ext_quaternion_trigonometric +/// @file glm/ext/quaternion_trigonometric.hpp +/// +/// @defgroup ext_quaternion_trigonometric GLM_EXT_quaternion_trigonometric +/// @ingroup ext +/// +/// Provides trigonometric functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform + +#pragma once + +// Dependency: +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include "scalar_constants.hpp" +#include "vector_relational.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_trigonometric extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_trigonometric + /// @{ + + /// Returns the quaternion rotation angle. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL T angle(qua const& x); + + /// Returns the q rotation axis. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<3, T, Q> axis(qua const& x); + + /// Build a quaternion from an angle and a normalized axis. + /// + /// @param angle Angle expressed in radians. + /// @param axis Axis of the quaternion, must be normalized. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua angleAxis(T const& angle, vec<3, T, Q> const& axis); + + /// @} +} //namespace glm + +#include "quaternion_trigonometric.inl" diff --git a/src/GLMath/glm/ext/quaternion_trigonometric.inl b/src/GLMath/glm/ext/quaternion_trigonometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..0c0bf63f536e9b6fbdb858d686c97a15e5711111 --- /dev/null +++ b/src/GLMath/glm/ext/quaternion_trigonometric.inl @@ -0,0 +1,27 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER T angle(qua const& x) + { + return acos(x.w) * static_cast(2); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> axis(qua const& x) + { + T const tmp1 = static_cast(1) - x.w * x.w; + if(tmp1 <= static_cast(0)) + return vec<3, T, Q>(0, 0, 1); + T const tmp2 = static_cast(1) / sqrt(tmp1); + return vec<3, T, Q>(x.x * tmp2, x.y * tmp2, x.z * tmp2); + } + + template + GLM_FUNC_QUALIFIER qua angleAxis(T const& angle, vec<3, T, Q> const& v) + { + T const a(angle); + T const s = glm::sin(a * static_cast(0.5)); + + return qua(glm::cos(a * static_cast(0.5)), v * s); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/scalar_common.hpp b/src/GLMath/glm/ext/scalar_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4ab0f88bec700b1bc63db5bad730f349a8756d60 --- /dev/null +++ b/src/GLMath/glm/ext/scalar_common.hpp @@ -0,0 +1,103 @@ +/// @ref ext_scalar_common +/// @file glm/ext/scalar_common.hpp +/// +/// @defgroup ext_scalar_common GLM_EXT_scalar_common +/// @ingroup ext +/// +/// Exposes min and max functions for 3 to 4 scalar parameters. +/// +/// Include to use the features of this extension. +/// +/// @see core_func_common +/// @see ext_vector_common + +#pragma once + +// Dependency: +#include "../common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_common + /// @{ + + /// Returns the minimum component-wise values of 3 inputs + /// + /// @tparam T A floating-point scalar type. + template + GLM_FUNC_DECL T min(T a, T b, T c); + + /// Returns the minimum component-wise values of 4 inputs + /// + /// @tparam T A floating-point scalar type. + template + GLM_FUNC_DECL T min(T a, T b, T c, T d); + + /// Returns the maximum component-wise values of 3 inputs + /// + /// @tparam T A floating-point scalar type. + template + GLM_FUNC_DECL T max(T a, T b, T c); + + /// Returns the maximum component-wise values of 4 inputs + /// + /// @tparam T A floating-point scalar type. + template + GLM_FUNC_DECL T max(T a, T b, T c, T d); + + /// Returns the minimum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL T fmin(T a, T b); + + /// Returns the minimum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL T fmin(T a, T b, T c); + + /// Returns the minimum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL T fmin(T a, T b, T c, T d); + + /// Returns the maximum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL T fmax(T a, T b); + + /// Returns the maximum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL T fmax(T a, T b, T C); + + /// Returns the maximum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL T fmax(T a, T b, T C, T D); + + /// @} +}//namespace glm + +#include "scalar_common.inl" diff --git a/src/GLMath/glm/ext/scalar_common.inl b/src/GLMath/glm/ext/scalar_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..118a670ea7599e80652fb8b6e8e765cf9bcebe3f --- /dev/null +++ b/src/GLMath/glm/ext/scalar_common.inl @@ -0,0 +1,115 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER T min(T a, T b, T c) + { + return glm::min(glm::min(a, b), c); + } + + template + GLM_FUNC_QUALIFIER T min(T a, T b, T c, T d) + { + return glm::min(glm::min(a, b), glm::min(c, d)); + } + + template + GLM_FUNC_QUALIFIER T max(T a, T b, T c) + { + return glm::max(glm::max(a, b), c); + } + + template + GLM_FUNC_QUALIFIER T max(T a, T b, T c, T d) + { + return glm::max(glm::max(a, b), glm::max(c, d)); + } + +# if GLM_HAS_CXX11_STL + using std::fmin; +# else + template + GLM_FUNC_QUALIFIER T fmin(T a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return b; + return min(a, b); + } +# endif + + template + GLM_FUNC_QUALIFIER T fmin(T a, T b, T c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return fmin(b, c); + if (isnan(b)) + return fmin(a, c); + if (isnan(c)) + return min(a, b); + return min(a, b, c); + } + + template + GLM_FUNC_QUALIFIER T fmin(T a, T b, T c, T d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return fmin(b, c, d); + if (isnan(b)) + return min(a, fmin(c, d)); + if (isnan(c)) + return fmin(min(a, b), d); + if (isnan(d)) + return min(a, b, c); + return min(a, b, c, d); + } + + +# if GLM_HAS_CXX11_STL + using std::fmax; +# else + template + GLM_FUNC_QUALIFIER T fmax(T a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return b; + return max(a, b); + } +# endif + + template + GLM_FUNC_QUALIFIER T fmax(T a, T b, T c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return fmax(b, c); + if (isnan(b)) + return fmax(a, c); + if (isnan(c)) + return max(a, b); + return max(a, b, c); + } + + template + GLM_FUNC_QUALIFIER T fmax(T a, T b, T c, T d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return fmax(b, c, d); + if (isnan(b)) + return max(a, fmax(c, d)); + if (isnan(c)) + return fmax(max(a, b), d); + if (isnan(d)) + return max(a, b, c); + return max(a, b, c, d); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/scalar_constants.hpp b/src/GLMath/glm/ext/scalar_constants.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4a61faa5fbfa7b6ff019a4643f4b8e32351b576a --- /dev/null +++ b/src/GLMath/glm/ext/scalar_constants.hpp @@ -0,0 +1,36 @@ +/// @ref ext_scalar_constants +/// @file glm/ext/scalar_constants.hpp +/// +/// @defgroup ext_scalar_constants GLM_EXT_scalar_constants +/// @ingroup ext +/// +/// Provides a list of constants and precomputed useful values. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_constants extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_constants + /// @{ + + /// Return the epsilon constant for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType epsilon(); + + /// Return the pi constant for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType pi(); + + /// @} +} //namespace glm + +#include "scalar_constants.inl" diff --git a/src/GLMath/glm/ext/scalar_constants.inl b/src/GLMath/glm/ext/scalar_constants.inl new file mode 100644 index 0000000000000000000000000000000000000000..c075fbc7d651b81f22d954184c390f2df1bc239a --- /dev/null +++ b/src/GLMath/glm/ext/scalar_constants.inl @@ -0,0 +1,18 @@ +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType epsilon() + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'epsilon' only accepts floating-point inputs"); + return std::numeric_limits::epsilon(); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType pi() + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'epsilon' only accepts floating-point inputs"); + return static_cast(3.14159265358979323846264338327950288); + } +} //namespace glm diff --git a/src/GLMath/glm/ext/scalar_int_sized.hpp b/src/GLMath/glm/ext/scalar_int_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8e9c511c9cb51010b4063882e14477d71eb3c7eb --- /dev/null +++ b/src/GLMath/glm/ext/scalar_int_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_scalar_int_sized +/// @file glm/ext/scalar_int_sized.hpp +/// +/// @defgroup ext_scalar_int_sized GLM_EXT_scalar_int_sized +/// @ingroup ext +/// +/// Exposes sized signed integer scalar types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_int_sized extension included") +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::int8_t int8; + typedef std::int16_t int16; + typedef std::int32_t int32; +# else + typedef signed char int8; + typedef signed short int16; + typedef signed int int32; +#endif// + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + + /// @addtogroup ext_scalar_int_sized + /// @{ + + /// 8 bit signed integer type. + typedef detail::int8 int8; + + /// 16 bit signed integer type. + typedef detail::int16 int16; + + /// 32 bit signed integer type. + typedef detail::int32 int32; + + /// 64 bit signed integer type. + typedef detail::int64 int64; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/scalar_relational.hpp b/src/GLMath/glm/ext/scalar_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3076a5e63f93112b9a60974b8b33388272df96e8 --- /dev/null +++ b/src/GLMath/glm/ext/scalar_relational.hpp @@ -0,0 +1,65 @@ +/// @ref ext_scalar_relational +/// @file glm/ext/scalar_relational.hpp +/// +/// @defgroup ext_scalar_relational GLM_EXT_scalar_relational +/// @ingroup ext +/// +/// Exposes comparison functions for scalar types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_vector_relational +/// @see ext_matrix_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_relational extension included") +#endif + +namespace glm +{ + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison between two scalars in term of ULPs. + /// True if this expression is satisfied. + /// + /// @param x First operand. + /// @param y Second operand. + /// @param ULPs Maximum difference in ULPs between the two operators to consider them equal. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int ULPs); + + /// Returns the component-wise comparison between two scalars in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @param x First operand. + /// @param y Second operand. + /// @param ULPs Maximum difference in ULPs between the two operators to consider them not equal. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs); + + /// @} +}//namespace glm + +#include "scalar_relational.inl" diff --git a/src/GLMath/glm/ext/scalar_relational.inl b/src/GLMath/glm/ext/scalar_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..27370e1445f3353574a9afa103fa0f4762c2f07e --- /dev/null +++ b/src/GLMath/glm/ext/scalar_relational.inl @@ -0,0 +1,43 @@ +#include "../common.hpp" +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/type_float.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon) + { + return abs(x - y) <= epsilon; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon) + { + return abs(x - y) > epsilon; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int MaxULPs) + { + detail::float_t const a(x); + detail::float_t const b(y); + + // Different signs means they do not match. + if(a.negative() != b.negative()) + { + // Check for equality to make sure +0==-0 + return a.mantissa() == b.mantissa() && a.exponent() == b.exponent(); + } + + // Find the difference in ULPs. + typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); + return DiffULPs <= MaxULPs; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs) + { + return !equal(x, y, ULPs); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/scalar_uint_sized.hpp b/src/GLMath/glm/ext/scalar_uint_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fd5267fad7c16dc5670f1622b3328ea5089d5a66 --- /dev/null +++ b/src/GLMath/glm/ext/scalar_uint_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_scalar_uint_sized +/// @file glm/ext/scalar_uint_sized.hpp +/// +/// @defgroup ext_scalar_uint_sized GLM_EXT_scalar_uint_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer scalar types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_uint_sized extension included") +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::uint8_t uint8; + typedef std::uint16_t uint16; + typedef std::uint32_t uint32; +# else + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; +#endif + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + + /// @addtogroup ext_scalar_uint_sized + /// @{ + + /// 8 bit unsigned integer type. + typedef detail::uint8 uint8; + + /// 16 bit unsigned integer type. + typedef detail::uint16 uint16; + + /// 32 bit unsigned integer type. + typedef detail::uint32 uint32; + + /// 64 bit unsigned integer type. + typedef detail::uint64 uint64; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/scalar_ulp.hpp b/src/GLMath/glm/ext/scalar_ulp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..90e177da1e12b9acb852f659238d1f5eadd21013 --- /dev/null +++ b/src/GLMath/glm/ext/scalar_ulp.hpp @@ -0,0 +1,74 @@ +/// @ref ext_scalar_ulp +/// @file glm/ext/scalar_ulp.hpp +/// +/// @defgroup ext_scalar_ulp GLM_EXT_scalar_ulp +/// @ingroup ext +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_ulp +/// @see ext_scalar_relational + +#pragma once + +// Dependencies +#include "../ext/scalar_int_sized.hpp" +#include "../common.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_ulp extension included") +#endif + +namespace glm +{ + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType next_float(genType x); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType prev_float(genType x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType next_float(genType x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType prev_float(genType x, int ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @see ext_scalar_ulp + GLM_FUNC_DECL int float_distance(float x, float y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @see ext_scalar_ulp + GLM_FUNC_DECL int64 float_distance(double x, double y); + + /// @} +}//namespace glm + +#include "scalar_ulp.inl" diff --git a/src/GLMath/glm/ext/scalar_ulp.inl b/src/GLMath/glm/ext/scalar_ulp.inl new file mode 100644 index 0000000000000000000000000000000000000000..8fc3759b9878b3a5eca9c3e6c72d55d03350c114 --- /dev/null +++ b/src/GLMath/glm/ext/scalar_ulp.inl @@ -0,0 +1,284 @@ +/// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +/// +/// Developed at SunPro, a Sun Microsystems, Inc. business. +/// Permission to use, copy, modify, and distribute this +/// software is freely granted, provided that this notice +/// is preserved. + +#include "../detail/type_float.hpp" +#include "../ext/scalar_constants.hpp" +#include +#include + +#if(GLM_COMPILER & GLM_COMPILER_VC) +# pragma warning(push) +# pragma warning(disable : 4127) +#endif + +typedef union +{ + float value; + /* FIXME: Assumes 32 bit int. */ + unsigned int word; +} ieee_float_shape_type; + +typedef union +{ + double value; + struct + { + int lsw; + int msw; + } parts; +} ieee_double_shape_type; + +#define GLM_EXTRACT_WORDS(ix0,ix1,d) \ + do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ + } while (0) + +#define GLM_GET_FLOAT_WORD(i,d) \ + do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ + } while (0) + +#define GLM_SET_FLOAT_WORD(d,i) \ + do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ + } while (0) + +#define GLM_INSERT_WORDS(d,ix0,ix1) \ + do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ + } while (0) + +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER float nextafterf(float x, float y) + { + volatile float t; + int hx, hy, ix, iy; + + GLM_GET_FLOAT_WORD(hx, x); + GLM_GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; // |x| + iy = hy & 0x7fffffff; // |y| + + if((ix > 0x7f800000) || // x is nan + (iy > 0x7f800000)) // y is nan + return x + y; + if(abs(y - x) <= epsilon()) + return y; // x=y, return y + if(ix == 0) + { // x == 0 + GLM_SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);// return +-minsubnormal + t = x * x; + if(abs(t - x) <= epsilon()) + return t; + else + return x; // raise underflow flag + } + if(hx >= 0) + { // x > 0 + if(hx > hy) // x > y, x -= ulp + hx -= 1; + else // x < y, x += ulp + hx += 1; + } + else + { // x < 0 + if(hy >= 0 || hx > hy) // x < y, x -= ulp + hx -= 1; + else // x > y, x += ulp + hx += 1; + } + hy = hx & 0x7f800000; + if(hy >= 0x7f800000) + return x + x; // overflow + if(hy < 0x00800000) // underflow + { + t = x * x; + if(abs(t - x) > epsilon()) + { // raise underflow flag + GLM_SET_FLOAT_WORD(y, hx); + return y; + } + } + GLM_SET_FLOAT_WORD(x, hx); + return x; + } + + GLM_FUNC_QUALIFIER double nextafter(double x, double y) + { + volatile double t; + int hx, hy, ix, iy; + unsigned int lx, ly; + + GLM_EXTRACT_WORDS(hx, lx, x); + GLM_EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; // |x| + iy = hy & 0x7fffffff; // |y| + + if(((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0) || // x is nan + ((iy >= 0x7ff00000) && ((iy - 0x7ff00000) | ly) != 0)) // y is nan + return x + y; + if(abs(y - x) <= epsilon()) + return y; // x=y, return y + if((ix | lx) == 0) + { // x == 0 + GLM_INSERT_WORDS(x, hy & 0x80000000, 1); // return +-minsubnormal + t = x * x; + if(abs(t - x) <= epsilon()) + return t; + else + return x; // raise underflow flag + } + if(hx >= 0) { // x > 0 + if(hx > hy || ((hx == hy) && (lx > ly))) { // x > y, x -= ulp + if(lx == 0) hx -= 1; + lx -= 1; + } + else { // x < y, x += ulp + lx += 1; + if(lx == 0) hx += 1; + } + } + else { // x < 0 + if(hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))){// x < y, x -= ulp + if(lx == 0) hx -= 1; + lx -= 1; + } + else { // x > y, x += ulp + lx += 1; + if(lx == 0) hx += 1; + } + } + hy = hx & 0x7ff00000; + if(hy >= 0x7ff00000) + return x + x; // overflow + if(hy < 0x00100000) + { // underflow + t = x * x; + if(abs(t - x) > epsilon()) + { // raise underflow flag + GLM_INSERT_WORDS(y, hx, lx); + return y; + } + } + GLM_INSERT_WORDS(x, hx, lx); + return x; + } +}//namespace detail +}//namespace glm + +#if(GLM_COMPILER & GLM_COMPILER_VC) +# pragma warning(pop) +#endif + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER float next_float(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MAX); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MAX); +# else + return nextafterf(x, FLT_MAX); +# endif + } + + template<> + GLM_FUNC_QUALIFIER double next_float(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafter(x, std::numeric_limits::max()); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MAX); +# else + return nextafter(x, DBL_MAX); +# endif + } + + template + GLM_FUNC_QUALIFIER T next_float(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'next_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for(int i = 0; i < ULPs; ++i) + temp = next_float(temp); + return temp; + } + + GLM_FUNC_QUALIFIER float prev_float(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MIN); +# else + return nextafterf(x, FLT_MIN); +# endif + } + + GLM_FUNC_QUALIFIER double prev_float(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return _nextafter(x, DBL_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MIN); +# else + return nextafter(x, DBL_MIN); +# endif + } + + template + GLM_FUNC_QUALIFIER T prev_float(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'prev_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for(int i = 0; i < ULPs; ++i) + temp = prev_float(temp); + return temp; + } + + GLM_FUNC_QUALIFIER int float_distance(float x, float y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } + + GLM_FUNC_QUALIFIER int64 float_distance(double x, double y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool1.hpp b/src/GLMath/glm/ext/vector_bool1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..002c3202adf0dfbb2db1eedf23f2f677d343c6f3 --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool1.hpp @@ -0,0 +1,30 @@ +/// @ref ext_vector_bool1 +/// @file glm/ext/vector_bool1.hpp +/// +/// @defgroup ext_vector_bool1 GLM_EXT_vector_bool1 +/// @ingroup ext +/// +/// Exposes bvec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_bool1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_bool1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_bool1 + /// @{ + + /// 1 components vector of boolean. + typedef vec<1, bool, defaultp> bvec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool1_precision.hpp b/src/GLMath/glm/ext/vector_bool1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e62d3cfb5fd4c6f31e9bb22cc4129c7bf7f28e01 --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool1_precision.hpp @@ -0,0 +1,34 @@ +/// @ref ext_vector_bool1_precision +/// @file glm/ext/vector_bool1_precision.hpp +/// +/// @defgroup ext_vector_bool1_precision GLM_EXT_vector_bool1_precision +/// @ingroup ext +/// +/// Exposes highp_bvec1, mediump_bvec1 and lowp_bvec1 types. +/// +/// Include to use the features of this extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_bool1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_bool1_precision + /// @{ + + /// 1 component vector of bool values. + typedef vec<1, bool, highp> highp_bvec1; + + /// 1 component vector of bool values. + typedef vec<1, bool, mediump> mediump_bvec1; + + /// 1 component vector of bool values. + typedef vec<1, bool, lowp> lowp_bvec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool2.hpp b/src/GLMath/glm/ext/vector_bool2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..52288b75c6973f49aabb5b8a15ddd1036b172f84 --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, bool, defaultp> bvec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool2_precision.hpp b/src/GLMath/glm/ext/vector_bool2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..43709332c6298ff345ab3b061917272aa954f655 --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, highp> highp_bvec2; + + /// 2 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, mediump> mediump_bvec2; + + /// 2 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, lowp> lowp_bvec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool3.hpp b/src/GLMath/glm/ext/vector_bool3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..90a0b7ea5ac048f264dff79fe8d270993e55d414 --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, bool, defaultp> bvec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool3_precision.hpp b/src/GLMath/glm/ext/vector_bool3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..89cd2d3207a168545f98a3d0af69b9c772a7c965 --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, highp> highp_bvec3; + + /// 3 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, mediump> mediump_bvec3; + + /// 3 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, lowp> lowp_bvec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool4.hpp b/src/GLMath/glm/ext/vector_bool4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..18aa71bd0f49851cac489520c4df893370ddeb6e --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, bool, defaultp> bvec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_bool4_precision.hpp b/src/GLMath/glm/ext/vector_bool4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..79786e54206b9cb3e92c6ba3d9d69f35200e552b --- /dev/null +++ b/src/GLMath/glm/ext/vector_bool4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, highp> highp_bvec4; + + /// 4 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, mediump> mediump_bvec4; + + /// 4 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, lowp> lowp_bvec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_common.hpp b/src/GLMath/glm/ext/vector_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..324fe1c70fea7d7a636549bd2509b9a57b21ffc9 --- /dev/null +++ b/src/GLMath/glm/ext/vector_common.hpp @@ -0,0 +1,144 @@ +/// @ref ext_vector_common +/// @file glm/ext/vector_common.hpp +/// +/// @defgroup ext_vector_common GLM_EXT_vector_common +/// @ingroup ext +/// +/// Exposes min and max functions for 3 to 4 vector parameters. +/// +/// Include to use the features of this extension. +/// +/// @see core_common +/// @see ext_scalar_common + +#pragma once + +// Dependency: +#include "../ext/scalar_common.hpp" +#include "../common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_common + /// @{ + + /// Return the minimum component-wise values of 3 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c); + + /// Return the minimum component-wise values of 4 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Return the maximum component-wise values of 3 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z); + + /// Return the maximum component-wise values of 4 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max( vec const& x, vec const& y, vec const& z, vec const& w); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& x, T y); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& x, vec const& y); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, T b); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c, vec const& d); + + /// @} +}//namespace glm + +#include "vector_common.inl" diff --git a/src/GLMath/glm/ext/vector_common.inl b/src/GLMath/glm/ext/vector_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..71f38093ad07a36cb7d733636b84b5f38334c72c --- /dev/null +++ b/src/GLMath/glm/ext/vector_common.inl @@ -0,0 +1,88 @@ +#include "../detail/_vectorize.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'min' only accept floating-point or integer inputs"); + return glm::min(glm::min(x, y), z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z, vec const& w) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'min' only accept floating-point or integer inputs"); + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'max' only accept floating-point or integer inputs"); + return glm::max(glm::max(x, y), z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z, vec const& w) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'max' only accept floating-point or integer inputs"); + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return detail::functor2::call(fmin, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return detail::functor2::call(fmin, a, b); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return fmin(fmin(a, b), c); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c, vec const& d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return fmin(fmin(a, b), fmin(c, d)); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return detail::functor2::call(fmax, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return detail::functor2::call(fmax, a, b); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return fmax(fmax(a, b), c); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c, vec const& d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return fmax(fmax(a, b), fmax(c, d)); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double1.hpp b/src/GLMath/glm/ext/vector_double1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ef12def4217c2e90c973f8d1b8622124ea73cf00 --- /dev/null +++ b/src/GLMath/glm/ext/vector_double1.hpp @@ -0,0 +1,31 @@ +/// @ref ext_vector_double1 +/// @file glm/ext/vector_double1.hpp +/// +/// @defgroup ext_vector_double1 GLM_EXT_vector_double1 +/// @ingroup ext +/// +/// Exposes double-precision floating point vector type with one component. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_double1_precision extension. +/// @see ext_vector_float1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_dvec1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_double1 + /// @{ + + /// 1 components vector of double-precision floating-point numbers. + typedef vec<1, double, defaultp> dvec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double1_precision.hpp b/src/GLMath/glm/ext/vector_double1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1d4719595481adf57c071e0fbf6df4716447a55a --- /dev/null +++ b/src/GLMath/glm/ext/vector_double1_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_vector_double1_precision +/// @file glm/ext/vector_double1_precision.hpp +/// +/// @defgroup ext_vector_double1_precision GLM_EXT_vector_double1_precision +/// @ingroup ext +/// +/// Exposes highp_dvec1, mediump_dvec1 and lowp_dvec1 types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_double1 + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_double1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_double1_precision + /// @{ + + /// 1 component vector of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, highp> highp_dvec1; + + /// 1 component vector of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, mediump> mediump_dvec1; + + /// 1 component vector of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, lowp> lowp_dvec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double2.hpp b/src/GLMath/glm/ext/vector_double2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..60e357750b675415da9d8911b92ba702b7aa8390 --- /dev/null +++ b/src/GLMath/glm/ext/vector_double2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, double, defaultp> dvec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double2_precision.hpp b/src/GLMath/glm/ext/vector_double2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fa53940f6bbed061a7f3fc4162877b68b96c9388 --- /dev/null +++ b/src/GLMath/glm/ext/vector_double2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_double2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, highp> highp_dvec2; + + /// 2 components vector of medium double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, mediump> mediump_dvec2; + + /// 2 components vector of low double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, lowp> lowp_dvec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double3.hpp b/src/GLMath/glm/ext/vector_double3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6dfe4c675b5d7af1f3538f5c32203065453b4025 --- /dev/null +++ b/src/GLMath/glm/ext/vector_double3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, double, defaultp> dvec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double3_precision.hpp b/src/GLMath/glm/ext/vector_double3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a8cfa37a8c78009bd18ddfbfff7e4a658300e712 --- /dev/null +++ b/src/GLMath/glm/ext/vector_double3_precision.hpp @@ -0,0 +1,34 @@ +/// @ref core +/// @file glm/ext/vector_double3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, highp> highp_dvec3; + + /// 3 components vector of medium double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, mediump> mediump_dvec3; + + /// 3 components vector of low double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, lowp> lowp_dvec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double4.hpp b/src/GLMath/glm/ext/vector_double4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..87f225f64d4ab38b0d7212174308e606e2c9ad18 --- /dev/null +++ b/src/GLMath/glm/ext/vector_double4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, double, defaultp> dvec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_double4_precision.hpp b/src/GLMath/glm/ext/vector_double4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..09cafa1ebafdd72b85c4f01746bf315ddee1c02a --- /dev/null +++ b/src/GLMath/glm/ext/vector_double4_precision.hpp @@ -0,0 +1,35 @@ +/// @ref core +/// @file glm/ext/vector_double4_precision.hpp + +#pragma once +#include "../detail/setup.hpp" +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, highp> highp_dvec4; + + /// 4 components vector of medium double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, mediump> mediump_dvec4; + + /// 4 components vector of low double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, lowp> lowp_dvec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float1.hpp b/src/GLMath/glm/ext/vector_float1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..28acc2c9ca59619ba1401032141ed223d347650f --- /dev/null +++ b/src/GLMath/glm/ext/vector_float1.hpp @@ -0,0 +1,31 @@ +/// @ref ext_vector_float1 +/// @file glm/ext/vector_float1.hpp +/// +/// @defgroup ext_vector_float1 GLM_EXT_vector_float1 +/// @ingroup ext +/// +/// Exposes single-precision floating point vector type with one component. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_float1_precision extension. +/// @see ext_vector_double1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_float1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_float1 + /// @{ + + /// 1 components vector of single-precision floating-point numbers. + typedef vec<1, float, defaultp> vec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float1_precision.hpp b/src/GLMath/glm/ext/vector_float1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6e8dad8d17c8e0e2765aa53323a1c093c685279e --- /dev/null +++ b/src/GLMath/glm/ext/vector_float1_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_vector_float1_precision +/// @file glm/ext/vector_float1_precision.hpp +/// +/// @defgroup ext_vector_float1_precision GLM_EXT_vector_float1_precision +/// @ingroup ext +/// +/// Exposes highp_vec1, mediump_vec1 and lowp_vec1 types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_float1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_float1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_float1_precision + /// @{ + + /// 1 component vector of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, highp> highp_vec1; + + /// 1 component vector of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, mediump> mediump_vec1; + + /// 1 component vector of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, lowp> lowp_vec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float2.hpp b/src/GLMath/glm/ext/vector_float2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d31545dcc966b37c0c942a9d248bb337c4b178a5 --- /dev/null +++ b/src/GLMath/glm/ext/vector_float2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, float, defaultp> vec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float2_precision.hpp b/src/GLMath/glm/ext/vector_float2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..23c0820d0ae8445f4539bf0b7f7c18886eb8ae41 --- /dev/null +++ b/src/GLMath/glm/ext/vector_float2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, highp> highp_vec2; + + /// 2 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, mediump> mediump_vec2; + + /// 2 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, lowp> lowp_vec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float3.hpp b/src/GLMath/glm/ext/vector_float3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cd79a62004e41ebb2798363235b7573496eacf05 --- /dev/null +++ b/src/GLMath/glm/ext/vector_float3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, float, defaultp> vec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float3_precision.hpp b/src/GLMath/glm/ext/vector_float3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..be640b53168387c07c3c2f8640794699a8e5953c --- /dev/null +++ b/src/GLMath/glm/ext/vector_float3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, highp> highp_vec3; + + /// 3 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, mediump> mediump_vec3; + + /// 3 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, lowp> lowp_vec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float4.hpp b/src/GLMath/glm/ext/vector_float4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d84adcc22fd2b2e914ab6f56af92d534a00ddbd7 --- /dev/null +++ b/src/GLMath/glm/ext/vector_float4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, float, defaultp> vec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_float4_precision.hpp b/src/GLMath/glm/ext/vector_float4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aede83882e55140fa53adde2ea0b72be29c77490 --- /dev/null +++ b/src/GLMath/glm/ext/vector_float4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, highp> highp_vec4; + + /// 4 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, mediump> mediump_vec4; + + /// 4 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, lowp> lowp_vec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_int1.hpp b/src/GLMath/glm/ext/vector_int1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dc8603891a9967bace26b4c23f4c5485b22f6ba4 --- /dev/null +++ b/src/GLMath/glm/ext/vector_int1.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_int1 +/// @file glm/ext/vector_int1.hpp +/// +/// @defgroup ext_vector_int1 GLM_EXT_vector_int1 +/// @ingroup ext +/// +/// Exposes ivec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_uint1 extension. +/// @see ext_vector_int1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int1 + /// @{ + + /// 1 component vector of signed integer numbers. + typedef vec<1, int, defaultp> ivec1; + + /// @} +}//namespace glm + diff --git a/src/GLMath/glm/ext/vector_int1_precision.hpp b/src/GLMath/glm/ext/vector_int1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3323954b557078fbc8df6b80c04b44dd0ed2e167 --- /dev/null +++ b/src/GLMath/glm/ext/vector_int1_precision.hpp @@ -0,0 +1,34 @@ +/// @ref ext_vector_int1_precision +/// @file glm/ext/vector_int1_precision.hpp +/// +/// @defgroup ext_vector_int1_precision GLM_EXT_vector_int1_precision +/// @ingroup ext +/// +/// Exposes highp_ivec1, mediump_ivec1 and lowp_ivec1 types. +/// +/// Include to use the features of this extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int1_precision + /// @{ + + /// 1 component vector of signed integer values. + typedef vec<1, int, highp> highp_ivec1; + + /// 1 component vector of signed integer values. + typedef vec<1, int, mediump> mediump_ivec1; + + /// 1 component vector of signed integer values. + typedef vec<1, int, lowp> lowp_ivec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_int2.hpp b/src/GLMath/glm/ext/vector_int2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aef803e91b736a1f2a3a32deefecdebbbc70fe5d --- /dev/null +++ b/src/GLMath/glm/ext/vector_int2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, int, defaultp> ivec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_int2_precision.hpp b/src/GLMath/glm/ext/vector_int2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..97315fc311738c8afb2b4dc1632b27680b5bc3ee --- /dev/null +++ b/src/GLMath/glm/ext/vector_int2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_int2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, int, highp> highp_ivec2; + + /// 2 components vector of medium qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, int, mediump> mediump_ivec2; + + /// 2 components vector of low qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, int, lowp> lowp_ivec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_int3.hpp b/src/GLMath/glm/ext/vector_int3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4767e61e88c08a38696700ab9d2517bcde346085 --- /dev/null +++ b/src/GLMath/glm/ext/vector_int3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, int, defaultp> ivec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_int3_precision.hpp b/src/GLMath/glm/ext/vector_int3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2cd3f5ff8a62ffe438f08479748812264aaba77a --- /dev/null +++ b/src/GLMath/glm/ext/vector_int3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_int3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, int, highp> highp_ivec3; + + /// 3 components vector of medium qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, int, mediump> mediump_ivec3; + + /// 3 components vector of low qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, int, lowp> lowp_ivec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_int4.hpp b/src/GLMath/glm/ext/vector_int4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bb23adf706c226d13cb3291f7ab9ded06c30e945 --- /dev/null +++ b/src/GLMath/glm/ext/vector_int4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, int, defaultp> ivec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_int4_precision.hpp b/src/GLMath/glm/ext/vector_int4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4fcd791691e2175783d7e60c64351f977c329b4d --- /dev/null +++ b/src/GLMath/glm/ext/vector_int4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_int4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, int, highp> highp_ivec4; + + /// 4 components vector of medium qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, int, mediump> mediump_ivec4; + + /// 4 components vector of low qualifier signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, int, lowp> lowp_ivec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_relational.hpp b/src/GLMath/glm/ext/vector_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a556bdfa9ae5def5db13c3249f79afce94ba627e --- /dev/null +++ b/src/GLMath/glm/ext/vector_relational.hpp @@ -0,0 +1,104 @@ +/// @ref ext_vector_relational +/// @file glm/ext/vector_relational.hpp +/// +/// @defgroup ext_vector_relational GLM_EXT_vector_relational +/// @ingroup ext +/// +/// Exposes comparison functions for vector types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_scalar_relational +/// @see ext_matrix_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_relational + /// @{ + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& epsilon); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& ULPs); + + /// @} +}//namespace glm + +#include "vector_relational.inl" diff --git a/src/GLMath/glm/ext/vector_relational.inl b/src/GLMath/glm/ext/vector_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..7a39ab50897e35588cf226c741df6e7beb00e884 --- /dev/null +++ b/src/GLMath/glm/ext/vector_relational.inl @@ -0,0 +1,75 @@ +#include "../vector_relational.hpp" +#include "../common.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/type_float.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T Epsilon) + { + return equal(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& Epsilon) + { + return lessThanEqual(abs(x - y), Epsilon); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T Epsilon) + { + return notEqual(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& Epsilon) + { + return greaterThan(abs(x - y), Epsilon); + } + + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int MaxULPs) + { + return equal(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& MaxULPs) + { + vec Result(false); + for(length_t i = 0; i < L; ++i) + { + detail::float_t const a(x[i]); + detail::float_t const b(y[i]); + + // Different signs means they do not match. + if(a.negative() != b.negative()) + { + // Check for equality to make sure +0==-0 + Result[i] = a.mantissa() == b.mantissa() && a.exponent() == b.exponent(); + } + else + { + // Find the difference in ULPs. + typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); + Result[i] = DiffULPs <= MaxULPs[i]; + } + } + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int MaxULPs) + { + return notEqual(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& MaxULPs) + { + return not_(equal(x, y, MaxULPs)); + } +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_uint1.hpp b/src/GLMath/glm/ext/vector_uint1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..eb8a7049761f0bb7c735ba689faac84ea5eb65d8 --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint1.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_uint1 +/// @file glm/ext/vector_uint1.hpp +/// +/// @defgroup ext_vector_uint1 GLM_EXT_vector_uint1 +/// @ingroup ext +/// +/// Exposes uvec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_int1 extension. +/// @see ext_vector_uint1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint1 + /// @{ + + /// 1 component vector of unsigned integer numbers. + typedef vec<1, unsigned int, defaultp> uvec1; + + /// @} +}//namespace glm + diff --git a/src/GLMath/glm/ext/vector_uint1_precision.hpp b/src/GLMath/glm/ext/vector_uint1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..30daa5b6619ba78b3aa7068f2bde32f3287d1324 --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint1_precision.hpp @@ -0,0 +1,40 @@ +/// @ref ext_vector_uint1_precision +/// @file glm/ext/vector_uint1_precision.hpp +/// +/// @defgroup ext_vector_uint1_precision GLM_EXT_vector_uint1_precision +/// @ingroup ext +/// +/// Exposes highp_uvec1, mediump_uvec1 and lowp_uvec1 types. +/// +/// Include to use the features of this extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint1_precision + /// @{ + + /// 1 component vector of unsigned integer values. + /// + /// @see ext_vector_uint1_precision + typedef vec<1, unsigned int, highp> highp_uvec1; + + /// 1 component vector of unsigned integer values. + /// + /// @see ext_vector_uint1_precision + typedef vec<1, unsigned int, mediump> mediump_uvec1; + + /// 1 component vector of unsigned integer values. + /// + /// @see ext_vector_uint1_precision + typedef vec<1, unsigned int, lowp> lowp_uvec1; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_uint2.hpp b/src/GLMath/glm/ext/vector_uint2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..03c00f5ff584d48baf6aab0ed8c5a794138f3219 --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, unsigned int, defaultp> uvec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_uint2_precision.hpp b/src/GLMath/glm/ext/vector_uint2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2ba7b0d437e1fdbeff72a9768947028edc1e5feb --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_uint2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, unsigned int, highp> highp_uvec2; + + /// 2 components vector of medium qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, unsigned int, mediump> mediump_uvec2; + + /// 2 components vector of low qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, unsigned int, lowp> lowp_uvec2; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_uint3.hpp b/src/GLMath/glm/ext/vector_uint3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f5b41c40882ac5fda0c1440956c8bcd8f7c098d4 --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, unsigned int, defaultp> uvec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_uint3_precision.hpp b/src/GLMath/glm/ext/vector_uint3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..125191c775d014d0aa78612d7d10ce19a190c573 --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_uint3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, unsigned int, highp> highp_uvec3; + + /// 3 components vector of medium qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, unsigned int, mediump> mediump_uvec3; + + /// 3 components vector of low qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, unsigned int, lowp> lowp_uvec3; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_uint4.hpp b/src/GLMath/glm/ext/vector_uint4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..32ced58a8f03f902acae6e0fd0e79a0efdb0653a --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, unsigned int, defaultp> uvec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_uint4_precision.hpp b/src/GLMath/glm/ext/vector_uint4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cf4097ce9d7a99bb302a0afe2b1c38e1773f49da --- /dev/null +++ b/src/GLMath/glm/ext/vector_uint4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_uint4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, unsigned int, highp> highp_uvec4; + + /// 4 components vector of medium qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, unsigned int, mediump> mediump_uvec4; + + /// 4 components vector of low qualifier unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, unsigned int, lowp> lowp_uvec4; + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/ext/vector_ulp.hpp b/src/GLMath/glm/ext/vector_ulp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3883758f06fa3f5336912807cad47b34a925ac5e --- /dev/null +++ b/src/GLMath/glm/ext/vector_ulp.hpp @@ -0,0 +1,109 @@ +/// @ref ext_vector_ulp +/// @file glm/ext/vector_ulp.hpp +/// +/// @defgroup ext_vector_ulp GLM_EXT_vector_ulp +/// @ingroup ext +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_ulp +/// @see ext_scalar_relational +/// @see ext_vector_relational + +#pragma once + +// Dependencies +#include "../ext/scalar_ulp.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_ulp extension included") +#endif + +namespace glm +{ + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x, int ULPs); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x, vec const& ULPs); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x, vec const& ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "vector_ulp.inl" diff --git a/src/GLMath/glm/ext/vector_ulp.inl b/src/GLMath/glm/ext/vector_ulp.inl new file mode 100644 index 0000000000000000000000000000000000000000..864653431fb2fff5084441263f2e3ae7cba4e289 --- /dev/null +++ b/src/GLMath/glm/ext/vector_ulp.inl @@ -0,0 +1,74 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x, int ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x, vec const& ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x, int ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x, vec const& ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = float_distance(x[i], y[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = float_distance(x[i], y[i]); + return Result; + } +}//namespace glm diff --git a/src/GLMath/glm/fwd.hpp b/src/GLMath/glm/fwd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..474d44f76c2160da5abcf9188d9b4a246b27f632 --- /dev/null +++ b/src/GLMath/glm/fwd.hpp @@ -0,0 +1,818 @@ +#pragma once + +#include "detail/qualifier.hpp" + +namespace glm +{ +#if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::int8_t int8; + typedef std::int16_t int16; + typedef std::int32_t int32; + typedef std::int64_t int64; + + typedef std::uint8_t uint8; + typedef std::uint16_t uint16; + typedef std::uint32_t uint32; + typedef std::uint64_t uint64; +#else + typedef signed char int8; + typedef signed short int16; + typedef signed int int32; + typedef detail::int64 int64; + + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef detail::uint64 uint64; +#endif + + // Scalar int + + typedef int8 lowp_i8; + typedef int8 mediump_i8; + typedef int8 highp_i8; + typedef int8 i8; + + typedef int8 lowp_int8; + typedef int8 mediump_int8; + typedef int8 highp_int8; + + typedef int8 lowp_int8_t; + typedef int8 mediump_int8_t; + typedef int8 highp_int8_t; + typedef int8 int8_t; + + typedef int16 lowp_i16; + typedef int16 mediump_i16; + typedef int16 highp_i16; + typedef int16 i16; + + typedef int16 lowp_int16; + typedef int16 mediump_int16; + typedef int16 highp_int16; + + typedef int16 lowp_int16_t; + typedef int16 mediump_int16_t; + typedef int16 highp_int16_t; + typedef int16 int16_t; + + typedef int32 lowp_i32; + typedef int32 mediump_i32; + typedef int32 highp_i32; + typedef int32 i32; + + typedef int32 lowp_int32; + typedef int32 mediump_int32; + typedef int32 highp_int32; + + typedef int32 lowp_int32_t; + typedef int32 mediump_int32_t; + typedef int32 highp_int32_t; + typedef int32 int32_t; + + typedef int64 lowp_i64; + typedef int64 mediump_i64; + typedef int64 highp_i64; + typedef int64 i64; + + typedef int64 lowp_int64; + typedef int64 mediump_int64; + typedef int64 highp_int64; + + typedef int64 lowp_int64_t; + typedef int64 mediump_int64_t; + typedef int64 highp_int64_t; + typedef int64 int64_t; + + // Scalar uint + + typedef uint8 lowp_u8; + typedef uint8 mediump_u8; + typedef uint8 highp_u8; + typedef uint8 u8; + + typedef uint8 lowp_uint8; + typedef uint8 mediump_uint8; + typedef uint8 highp_uint8; + + typedef uint8 lowp_uint8_t; + typedef uint8 mediump_uint8_t; + typedef uint8 highp_uint8_t; + typedef uint8 uint8_t; + + typedef uint16 lowp_u16; + typedef uint16 mediump_u16; + typedef uint16 highp_u16; + typedef uint16 u16; + + typedef uint16 lowp_uint16; + typedef uint16 mediump_uint16; + typedef uint16 highp_uint16; + + typedef uint16 lowp_uint16_t; + typedef uint16 mediump_uint16_t; + typedef uint16 highp_uint16_t; + typedef uint16 uint16_t; + + typedef uint32 lowp_u32; + typedef uint32 mediump_u32; + typedef uint32 highp_u32; + typedef uint32 u32; + + typedef uint32 lowp_uint32; + typedef uint32 mediump_uint32; + typedef uint32 highp_uint32; + + typedef uint32 lowp_uint32_t; + typedef uint32 mediump_uint32_t; + typedef uint32 highp_uint32_t; + typedef uint32 uint32_t; + + typedef uint64 lowp_u64; + typedef uint64 mediump_u64; + typedef uint64 highp_u64; + typedef uint64 u64; + + typedef uint64 lowp_uint64; + typedef uint64 mediump_uint64; + typedef uint64 highp_uint64; + + typedef uint64 lowp_uint64_t; + typedef uint64 mediump_uint64_t; + typedef uint64 highp_uint64_t; + typedef uint64 uint64_t; + + // Scalar float + + typedef float lowp_f32; + typedef float mediump_f32; + typedef float highp_f32; + typedef float f32; + + typedef float lowp_float32; + typedef float mediump_float32; + typedef float highp_float32; + typedef float float32; + + typedef float lowp_float32_t; + typedef float mediump_float32_t; + typedef float highp_float32_t; + typedef float float32_t; + + + typedef double lowp_f64; + typedef double mediump_f64; + typedef double highp_f64; + typedef double f64; + + typedef double lowp_float64; + typedef double mediump_float64; + typedef double highp_float64; + typedef double float64; + + typedef double lowp_float64_t; + typedef double mediump_float64_t; + typedef double highp_float64_t; + typedef double float64_t; + + // Vector bool + + typedef vec<1, bool, lowp> lowp_bvec1; + typedef vec<2, bool, lowp> lowp_bvec2; + typedef vec<3, bool, lowp> lowp_bvec3; + typedef vec<4, bool, lowp> lowp_bvec4; + + typedef vec<1, bool, mediump> mediump_bvec1; + typedef vec<2, bool, mediump> mediump_bvec2; + typedef vec<3, bool, mediump> mediump_bvec3; + typedef vec<4, bool, mediump> mediump_bvec4; + + typedef vec<1, bool, highp> highp_bvec1; + typedef vec<2, bool, highp> highp_bvec2; + typedef vec<3, bool, highp> highp_bvec3; + typedef vec<4, bool, highp> highp_bvec4; + + typedef vec<1, bool, defaultp> bvec1; + typedef vec<2, bool, defaultp> bvec2; + typedef vec<3, bool, defaultp> bvec3; + typedef vec<4, bool, defaultp> bvec4; + + // Vector int + + typedef vec<1, i32, lowp> lowp_ivec1; + typedef vec<2, i32, lowp> lowp_ivec2; + typedef vec<3, i32, lowp> lowp_ivec3; + typedef vec<4, i32, lowp> lowp_ivec4; + + typedef vec<1, i32, mediump> mediump_ivec1; + typedef vec<2, i32, mediump> mediump_ivec2; + typedef vec<3, i32, mediump> mediump_ivec3; + typedef vec<4, i32, mediump> mediump_ivec4; + + typedef vec<1, i32, highp> highp_ivec1; + typedef vec<2, i32, highp> highp_ivec2; + typedef vec<3, i32, highp> highp_ivec3; + typedef vec<4, i32, highp> highp_ivec4; + + typedef vec<1, i32, defaultp> ivec1; + typedef vec<2, i32, defaultp> ivec2; + typedef vec<3, i32, defaultp> ivec3; + typedef vec<4, i32, defaultp> ivec4; + + typedef vec<1, i8, lowp> lowp_i8vec1; + typedef vec<2, i8, lowp> lowp_i8vec2; + typedef vec<3, i8, lowp> lowp_i8vec3; + typedef vec<4, i8, lowp> lowp_i8vec4; + + typedef vec<1, i8, mediump> mediump_i8vec1; + typedef vec<2, i8, mediump> mediump_i8vec2; + typedef vec<3, i8, mediump> mediump_i8vec3; + typedef vec<4, i8, mediump> mediump_i8vec4; + + typedef vec<1, i8, highp> highp_i8vec1; + typedef vec<2, i8, highp> highp_i8vec2; + typedef vec<3, i8, highp> highp_i8vec3; + typedef vec<4, i8, highp> highp_i8vec4; + + typedef vec<1, i8, defaultp> i8vec1; + typedef vec<2, i8, defaultp> i8vec2; + typedef vec<3, i8, defaultp> i8vec3; + typedef vec<4, i8, defaultp> i8vec4; + + typedef vec<1, i16, lowp> lowp_i16vec1; + typedef vec<2, i16, lowp> lowp_i16vec2; + typedef vec<3, i16, lowp> lowp_i16vec3; + typedef vec<4, i16, lowp> lowp_i16vec4; + + typedef vec<1, i16, mediump> mediump_i16vec1; + typedef vec<2, i16, mediump> mediump_i16vec2; + typedef vec<3, i16, mediump> mediump_i16vec3; + typedef vec<4, i16, mediump> mediump_i16vec4; + + typedef vec<1, i16, highp> highp_i16vec1; + typedef vec<2, i16, highp> highp_i16vec2; + typedef vec<3, i16, highp> highp_i16vec3; + typedef vec<4, i16, highp> highp_i16vec4; + + typedef vec<1, i16, defaultp> i16vec1; + typedef vec<2, i16, defaultp> i16vec2; + typedef vec<3, i16, defaultp> i16vec3; + typedef vec<4, i16, defaultp> i16vec4; + + typedef vec<1, i32, lowp> lowp_i32vec1; + typedef vec<2, i32, lowp> lowp_i32vec2; + typedef vec<3, i32, lowp> lowp_i32vec3; + typedef vec<4, i32, lowp> lowp_i32vec4; + + typedef vec<1, i32, mediump> mediump_i32vec1; + typedef vec<2, i32, mediump> mediump_i32vec2; + typedef vec<3, i32, mediump> mediump_i32vec3; + typedef vec<4, i32, mediump> mediump_i32vec4; + + typedef vec<1, i32, highp> highp_i32vec1; + typedef vec<2, i32, highp> highp_i32vec2; + typedef vec<3, i32, highp> highp_i32vec3; + typedef vec<4, i32, highp> highp_i32vec4; + + typedef vec<1, i32, defaultp> i32vec1; + typedef vec<2, i32, defaultp> i32vec2; + typedef vec<3, i32, defaultp> i32vec3; + typedef vec<4, i32, defaultp> i32vec4; + + typedef vec<1, i64, lowp> lowp_i64vec1; + typedef vec<2, i64, lowp> lowp_i64vec2; + typedef vec<3, i64, lowp> lowp_i64vec3; + typedef vec<4, i64, lowp> lowp_i64vec4; + + typedef vec<1, i64, mediump> mediump_i64vec1; + typedef vec<2, i64, mediump> mediump_i64vec2; + typedef vec<3, i64, mediump> mediump_i64vec3; + typedef vec<4, i64, mediump> mediump_i64vec4; + + typedef vec<1, i64, highp> highp_i64vec1; + typedef vec<2, i64, highp> highp_i64vec2; + typedef vec<3, i64, highp> highp_i64vec3; + typedef vec<4, i64, highp> highp_i64vec4; + + typedef vec<1, i64, defaultp> i64vec1; + typedef vec<2, i64, defaultp> i64vec2; + typedef vec<3, i64, defaultp> i64vec3; + typedef vec<4, i64, defaultp> i64vec4; + + // Vector uint + + typedef vec<1, u32, lowp> lowp_uvec1; + typedef vec<2, u32, lowp> lowp_uvec2; + typedef vec<3, u32, lowp> lowp_uvec3; + typedef vec<4, u32, lowp> lowp_uvec4; + + typedef vec<1, u32, mediump> mediump_uvec1; + typedef vec<2, u32, mediump> mediump_uvec2; + typedef vec<3, u32, mediump> mediump_uvec3; + typedef vec<4, u32, mediump> mediump_uvec4; + + typedef vec<1, u32, highp> highp_uvec1; + typedef vec<2, u32, highp> highp_uvec2; + typedef vec<3, u32, highp> highp_uvec3; + typedef vec<4, u32, highp> highp_uvec4; + + typedef vec<1, u32, defaultp> uvec1; + typedef vec<2, u32, defaultp> uvec2; + typedef vec<3, u32, defaultp> uvec3; + typedef vec<4, u32, defaultp> uvec4; + + typedef vec<1, u8, lowp> lowp_u8vec1; + typedef vec<2, u8, lowp> lowp_u8vec2; + typedef vec<3, u8, lowp> lowp_u8vec3; + typedef vec<4, u8, lowp> lowp_u8vec4; + + typedef vec<1, u8, mediump> mediump_u8vec1; + typedef vec<2, u8, mediump> mediump_u8vec2; + typedef vec<3, u8, mediump> mediump_u8vec3; + typedef vec<4, u8, mediump> mediump_u8vec4; + + typedef vec<1, u8, highp> highp_u8vec1; + typedef vec<2, u8, highp> highp_u8vec2; + typedef vec<3, u8, highp> highp_u8vec3; + typedef vec<4, u8, highp> highp_u8vec4; + + typedef vec<1, u8, defaultp> u8vec1; + typedef vec<2, u8, defaultp> u8vec2; + typedef vec<3, u8, defaultp> u8vec3; + typedef vec<4, u8, defaultp> u8vec4; + + typedef vec<1, u16, lowp> lowp_u16vec1; + typedef vec<2, u16, lowp> lowp_u16vec2; + typedef vec<3, u16, lowp> lowp_u16vec3; + typedef vec<4, u16, lowp> lowp_u16vec4; + + typedef vec<1, u16, mediump> mediump_u16vec1; + typedef vec<2, u16, mediump> mediump_u16vec2; + typedef vec<3, u16, mediump> mediump_u16vec3; + typedef vec<4, u16, mediump> mediump_u16vec4; + + typedef vec<1, u16, highp> highp_u16vec1; + typedef vec<2, u16, highp> highp_u16vec2; + typedef vec<3, u16, highp> highp_u16vec3; + typedef vec<4, u16, highp> highp_u16vec4; + + typedef vec<1, u16, defaultp> u16vec1; + typedef vec<2, u16, defaultp> u16vec2; + typedef vec<3, u16, defaultp> u16vec3; + typedef vec<4, u16, defaultp> u16vec4; + + typedef vec<1, u32, lowp> lowp_u32vec1; + typedef vec<2, u32, lowp> lowp_u32vec2; + typedef vec<3, u32, lowp> lowp_u32vec3; + typedef vec<4, u32, lowp> lowp_u32vec4; + + typedef vec<1, u32, mediump> mediump_u32vec1; + typedef vec<2, u32, mediump> mediump_u32vec2; + typedef vec<3, u32, mediump> mediump_u32vec3; + typedef vec<4, u32, mediump> mediump_u32vec4; + + typedef vec<1, u32, highp> highp_u32vec1; + typedef vec<2, u32, highp> highp_u32vec2; + typedef vec<3, u32, highp> highp_u32vec3; + typedef vec<4, u32, highp> highp_u32vec4; + + typedef vec<1, u32, defaultp> u32vec1; + typedef vec<2, u32, defaultp> u32vec2; + typedef vec<3, u32, defaultp> u32vec3; + typedef vec<4, u32, defaultp> u32vec4; + + typedef vec<1, u64, lowp> lowp_u64vec1; + typedef vec<2, u64, lowp> lowp_u64vec2; + typedef vec<3, u64, lowp> lowp_u64vec3; + typedef vec<4, u64, lowp> lowp_u64vec4; + + typedef vec<1, u64, mediump> mediump_u64vec1; + typedef vec<2, u64, mediump> mediump_u64vec2; + typedef vec<3, u64, mediump> mediump_u64vec3; + typedef vec<4, u64, mediump> mediump_u64vec4; + + typedef vec<1, u64, highp> highp_u64vec1; + typedef vec<2, u64, highp> highp_u64vec2; + typedef vec<3, u64, highp> highp_u64vec3; + typedef vec<4, u64, highp> highp_u64vec4; + + typedef vec<1, u64, defaultp> u64vec1; + typedef vec<2, u64, defaultp> u64vec2; + typedef vec<3, u64, defaultp> u64vec3; + typedef vec<4, u64, defaultp> u64vec4; + + // Vector float + + typedef vec<1, float, lowp> lowp_vec1; + typedef vec<2, float, lowp> lowp_vec2; + typedef vec<3, float, lowp> lowp_vec3; + typedef vec<4, float, lowp> lowp_vec4; + + typedef vec<1, float, mediump> mediump_vec1; + typedef vec<2, float, mediump> mediump_vec2; + typedef vec<3, float, mediump> mediump_vec3; + typedef vec<4, float, mediump> mediump_vec4; + + typedef vec<1, float, highp> highp_vec1; + typedef vec<2, float, highp> highp_vec2; + typedef vec<3, float, highp> highp_vec3; + typedef vec<4, float, highp> highp_vec4; + + typedef vec<1, float, defaultp> vec1; + typedef vec<2, float, defaultp> vec2; + typedef vec<3, float, defaultp> vec3; + typedef vec<4, float, defaultp> vec4; + + typedef vec<1, float, lowp> lowp_fvec1; + typedef vec<2, float, lowp> lowp_fvec2; + typedef vec<3, float, lowp> lowp_fvec3; + typedef vec<4, float, lowp> lowp_fvec4; + + typedef vec<1, float, mediump> mediump_fvec1; + typedef vec<2, float, mediump> mediump_fvec2; + typedef vec<3, float, mediump> mediump_fvec3; + typedef vec<4, float, mediump> mediump_fvec4; + + typedef vec<1, float, highp> highp_fvec1; + typedef vec<2, float, highp> highp_fvec2; + typedef vec<3, float, highp> highp_fvec3; + typedef vec<4, float, highp> highp_fvec4; + + typedef vec<1, f32, defaultp> fvec1; + typedef vec<2, f32, defaultp> fvec2; + typedef vec<3, f32, defaultp> fvec3; + typedef vec<4, f32, defaultp> fvec4; + + typedef vec<1, f32, lowp> lowp_f32vec1; + typedef vec<2, f32, lowp> lowp_f32vec2; + typedef vec<3, f32, lowp> lowp_f32vec3; + typedef vec<4, f32, lowp> lowp_f32vec4; + + typedef vec<1, f32, mediump> mediump_f32vec1; + typedef vec<2, f32, mediump> mediump_f32vec2; + typedef vec<3, f32, mediump> mediump_f32vec3; + typedef vec<4, f32, mediump> mediump_f32vec4; + + typedef vec<1, f32, highp> highp_f32vec1; + typedef vec<2, f32, highp> highp_f32vec2; + typedef vec<3, f32, highp> highp_f32vec3; + typedef vec<4, f32, highp> highp_f32vec4; + + typedef vec<1, f32, defaultp> f32vec1; + typedef vec<2, f32, defaultp> f32vec2; + typedef vec<3, f32, defaultp> f32vec3; + typedef vec<4, f32, defaultp> f32vec4; + + typedef vec<1, f64, lowp> lowp_dvec1; + typedef vec<2, f64, lowp> lowp_dvec2; + typedef vec<3, f64, lowp> lowp_dvec3; + typedef vec<4, f64, lowp> lowp_dvec4; + + typedef vec<1, f64, mediump> mediump_dvec1; + typedef vec<2, f64, mediump> mediump_dvec2; + typedef vec<3, f64, mediump> mediump_dvec3; + typedef vec<4, f64, mediump> mediump_dvec4; + + typedef vec<1, f64, highp> highp_dvec1; + typedef vec<2, f64, highp> highp_dvec2; + typedef vec<3, f64, highp> highp_dvec3; + typedef vec<4, f64, highp> highp_dvec4; + + typedef vec<1, f64, defaultp> dvec1; + typedef vec<2, f64, defaultp> dvec2; + typedef vec<3, f64, defaultp> dvec3; + typedef vec<4, f64, defaultp> dvec4; + + typedef vec<1, f64, lowp> lowp_f64vec1; + typedef vec<2, f64, lowp> lowp_f64vec2; + typedef vec<3, f64, lowp> lowp_f64vec3; + typedef vec<4, f64, lowp> lowp_f64vec4; + + typedef vec<1, f64, mediump> mediump_f64vec1; + typedef vec<2, f64, mediump> mediump_f64vec2; + typedef vec<3, f64, mediump> mediump_f64vec3; + typedef vec<4, f64, mediump> mediump_f64vec4; + + typedef vec<1, f64, highp> highp_f64vec1; + typedef vec<2, f64, highp> highp_f64vec2; + typedef vec<3, f64, highp> highp_f64vec3; + typedef vec<4, f64, highp> highp_f64vec4; + + typedef vec<1, f64, defaultp> f64vec1; + typedef vec<2, f64, defaultp> f64vec2; + typedef vec<3, f64, defaultp> f64vec3; + typedef vec<4, f64, defaultp> f64vec4; + + // Matrix NxN + + typedef mat<2, 2, f32, lowp> lowp_mat2; + typedef mat<3, 3, f32, lowp> lowp_mat3; + typedef mat<4, 4, f32, lowp> lowp_mat4; + + typedef mat<2, 2, f32, mediump> mediump_mat2; + typedef mat<3, 3, f32, mediump> mediump_mat3; + typedef mat<4, 4, f32, mediump> mediump_mat4; + + typedef mat<2, 2, f32, highp> highp_mat2; + typedef mat<3, 3, f32, highp> highp_mat3; + typedef mat<4, 4, f32, highp> highp_mat4; + + typedef mat<2, 2, f32, defaultp> mat2; + typedef mat<3, 3, f32, defaultp> mat3; + typedef mat<4, 4, f32, defaultp> mat4; + + typedef mat<2, 2, f32, lowp> lowp_fmat2; + typedef mat<3, 3, f32, lowp> lowp_fmat3; + typedef mat<4, 4, f32, lowp> lowp_fmat4; + + typedef mat<2, 2, f32, mediump> mediump_fmat2; + typedef mat<3, 3, f32, mediump> mediump_fmat3; + typedef mat<4, 4, f32, mediump> mediump_fmat4; + + typedef mat<2, 2, f32, highp> highp_fmat2; + typedef mat<3, 3, f32, highp> highp_fmat3; + typedef mat<4, 4, f32, highp> highp_fmat4; + + typedef mat<2, 2, f32, defaultp> fmat2; + typedef mat<3, 3, f32, defaultp> fmat3; + typedef mat<4, 4, f32, defaultp> fmat4; + + typedef mat<2, 2, f32, lowp> lowp_f32mat2; + typedef mat<3, 3, f32, lowp> lowp_f32mat3; + typedef mat<4, 4, f32, lowp> lowp_f32mat4; + + typedef mat<2, 2, f32, mediump> mediump_f32mat2; + typedef mat<3, 3, f32, mediump> mediump_f32mat3; + typedef mat<4, 4, f32, mediump> mediump_f32mat4; + + typedef mat<2, 2, f32, highp> highp_f32mat2; + typedef mat<3, 3, f32, highp> highp_f32mat3; + typedef mat<4, 4, f32, highp> highp_f32mat4; + + typedef mat<2, 2, f32, defaultp> f32mat2; + typedef mat<3, 3, f32, defaultp> f32mat3; + typedef mat<4, 4, f32, defaultp> f32mat4; + + typedef mat<2, 2, f64, lowp> lowp_dmat2; + typedef mat<3, 3, f64, lowp> lowp_dmat3; + typedef mat<4, 4, f64, lowp> lowp_dmat4; + + typedef mat<2, 2, f64, mediump> mediump_dmat2; + typedef mat<3, 3, f64, mediump> mediump_dmat3; + typedef mat<4, 4, f64, mediump> mediump_dmat4; + + typedef mat<2, 2, f64, highp> highp_dmat2; + typedef mat<3, 3, f64, highp> highp_dmat3; + typedef mat<4, 4, f64, highp> highp_dmat4; + + typedef mat<2, 2, f64, defaultp> dmat2; + typedef mat<3, 3, f64, defaultp> dmat3; + typedef mat<4, 4, f64, defaultp> dmat4; + + typedef mat<2, 2, f64, lowp> lowp_f64mat2; + typedef mat<3, 3, f64, lowp> lowp_f64mat3; + typedef mat<4, 4, f64, lowp> lowp_f64mat4; + + typedef mat<2, 2, f64, mediump> mediump_f64mat2; + typedef mat<3, 3, f64, mediump> mediump_f64mat3; + typedef mat<4, 4, f64, mediump> mediump_f64mat4; + + typedef mat<2, 2, f64, highp> highp_f64mat2; + typedef mat<3, 3, f64, highp> highp_f64mat3; + typedef mat<4, 4, f64, highp> highp_f64mat4; + + typedef mat<2, 2, f64, defaultp> f64mat2; + typedef mat<3, 3, f64, defaultp> f64mat3; + typedef mat<4, 4, f64, defaultp> f64mat4; + + // Matrix MxN + + typedef mat<2, 2, f32, lowp> lowp_mat2x2; + typedef mat<2, 3, f32, lowp> lowp_mat2x3; + typedef mat<2, 4, f32, lowp> lowp_mat2x4; + typedef mat<3, 2, f32, lowp> lowp_mat3x2; + typedef mat<3, 3, f32, lowp> lowp_mat3x3; + typedef mat<3, 4, f32, lowp> lowp_mat3x4; + typedef mat<4, 2, f32, lowp> lowp_mat4x2; + typedef mat<4, 3, f32, lowp> lowp_mat4x3; + typedef mat<4, 4, f32, lowp> lowp_mat4x4; + + typedef mat<2, 2, f32, mediump> mediump_mat2x2; + typedef mat<2, 3, f32, mediump> mediump_mat2x3; + typedef mat<2, 4, f32, mediump> mediump_mat2x4; + typedef mat<3, 2, f32, mediump> mediump_mat3x2; + typedef mat<3, 3, f32, mediump> mediump_mat3x3; + typedef mat<3, 4, f32, mediump> mediump_mat3x4; + typedef mat<4, 2, f32, mediump> mediump_mat4x2; + typedef mat<4, 3, f32, mediump> mediump_mat4x3; + typedef mat<4, 4, f32, mediump> mediump_mat4x4; + + typedef mat<2, 2, f32, highp> highp_mat2x2; + typedef mat<2, 3, f32, highp> highp_mat2x3; + typedef mat<2, 4, f32, highp> highp_mat2x4; + typedef mat<3, 2, f32, highp> highp_mat3x2; + typedef mat<3, 3, f32, highp> highp_mat3x3; + typedef mat<3, 4, f32, highp> highp_mat3x4; + typedef mat<4, 2, f32, highp> highp_mat4x2; + typedef mat<4, 3, f32, highp> highp_mat4x3; + typedef mat<4, 4, f32, highp> highp_mat4x4; + + typedef mat<2, 2, f32, defaultp> mat2x2; + typedef mat<3, 2, f32, defaultp> mat3x2; + typedef mat<4, 2, f32, defaultp> mat4x2; + typedef mat<2, 3, f32, defaultp> mat2x3; + typedef mat<3, 3, f32, defaultp> mat3x3; + typedef mat<4, 3, f32, defaultp> mat4x3; + typedef mat<2, 4, f32, defaultp> mat2x4; + typedef mat<3, 4, f32, defaultp> mat3x4; + typedef mat<4, 4, f32, defaultp> mat4x4; + + typedef mat<2, 2, f32, lowp> lowp_fmat2x2; + typedef mat<2, 3, f32, lowp> lowp_fmat2x3; + typedef mat<2, 4, f32, lowp> lowp_fmat2x4; + typedef mat<3, 2, f32, lowp> lowp_fmat3x2; + typedef mat<3, 3, f32, lowp> lowp_fmat3x3; + typedef mat<3, 4, f32, lowp> lowp_fmat3x4; + typedef mat<4, 2, f32, lowp> lowp_fmat4x2; + typedef mat<4, 3, f32, lowp> lowp_fmat4x3; + typedef mat<4, 4, f32, lowp> lowp_fmat4x4; + + typedef mat<2, 2, f32, mediump> mediump_fmat2x2; + typedef mat<2, 3, f32, mediump> mediump_fmat2x3; + typedef mat<2, 4, f32, mediump> mediump_fmat2x4; + typedef mat<3, 2, f32, mediump> mediump_fmat3x2; + typedef mat<3, 3, f32, mediump> mediump_fmat3x3; + typedef mat<3, 4, f32, mediump> mediump_fmat3x4; + typedef mat<4, 2, f32, mediump> mediump_fmat4x2; + typedef mat<4, 3, f32, mediump> mediump_fmat4x3; + typedef mat<4, 4, f32, mediump> mediump_fmat4x4; + + typedef mat<2, 2, f32, highp> highp_fmat2x2; + typedef mat<2, 3, f32, highp> highp_fmat2x3; + typedef mat<2, 4, f32, highp> highp_fmat2x4; + typedef mat<3, 2, f32, highp> highp_fmat3x2; + typedef mat<3, 3, f32, highp> highp_fmat3x3; + typedef mat<3, 4, f32, highp> highp_fmat3x4; + typedef mat<4, 2, f32, highp> highp_fmat4x2; + typedef mat<4, 3, f32, highp> highp_fmat4x3; + typedef mat<4, 4, f32, highp> highp_fmat4x4; + + typedef mat<2, 2, f32, defaultp> fmat2x2; + typedef mat<3, 2, f32, defaultp> fmat3x2; + typedef mat<4, 2, f32, defaultp> fmat4x2; + typedef mat<2, 3, f32, defaultp> fmat2x3; + typedef mat<3, 3, f32, defaultp> fmat3x3; + typedef mat<4, 3, f32, defaultp> fmat4x3; + typedef mat<2, 4, f32, defaultp> fmat2x4; + typedef mat<3, 4, f32, defaultp> fmat3x4; + typedef mat<4, 4, f32, defaultp> fmat4x4; + + typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; + typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; + typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; + typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; + typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; + typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; + typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; + typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; + typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; + + typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; + typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; + typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; + typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; + typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; + typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; + typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; + typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; + typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; + + typedef mat<2, 2, f32, highp> highp_f32mat2x2; + typedef mat<2, 3, f32, highp> highp_f32mat2x3; + typedef mat<2, 4, f32, highp> highp_f32mat2x4; + typedef mat<3, 2, f32, highp> highp_f32mat3x2; + typedef mat<3, 3, f32, highp> highp_f32mat3x3; + typedef mat<3, 4, f32, highp> highp_f32mat3x4; + typedef mat<4, 2, f32, highp> highp_f32mat4x2; + typedef mat<4, 3, f32, highp> highp_f32mat4x3; + typedef mat<4, 4, f32, highp> highp_f32mat4x4; + + typedef mat<2, 2, f32, defaultp> f32mat2x2; + typedef mat<3, 2, f32, defaultp> f32mat3x2; + typedef mat<4, 2, f32, defaultp> f32mat4x2; + typedef mat<2, 3, f32, defaultp> f32mat2x3; + typedef mat<3, 3, f32, defaultp> f32mat3x3; + typedef mat<4, 3, f32, defaultp> f32mat4x3; + typedef mat<2, 4, f32, defaultp> f32mat2x4; + typedef mat<3, 4, f32, defaultp> f32mat3x4; + typedef mat<4, 4, f32, defaultp> f32mat4x4; + + typedef mat<2, 2, double, lowp> lowp_dmat2x2; + typedef mat<2, 3, double, lowp> lowp_dmat2x3; + typedef mat<2, 4, double, lowp> lowp_dmat2x4; + typedef mat<3, 2, double, lowp> lowp_dmat3x2; + typedef mat<3, 3, double, lowp> lowp_dmat3x3; + typedef mat<3, 4, double, lowp> lowp_dmat3x4; + typedef mat<4, 2, double, lowp> lowp_dmat4x2; + typedef mat<4, 3, double, lowp> lowp_dmat4x3; + typedef mat<4, 4, double, lowp> lowp_dmat4x4; + + typedef mat<2, 2, double, mediump> mediump_dmat2x2; + typedef mat<2, 3, double, mediump> mediump_dmat2x3; + typedef mat<2, 4, double, mediump> mediump_dmat2x4; + typedef mat<3, 2, double, mediump> mediump_dmat3x2; + typedef mat<3, 3, double, mediump> mediump_dmat3x3; + typedef mat<3, 4, double, mediump> mediump_dmat3x4; + typedef mat<4, 2, double, mediump> mediump_dmat4x2; + typedef mat<4, 3, double, mediump> mediump_dmat4x3; + typedef mat<4, 4, double, mediump> mediump_dmat4x4; + + typedef mat<2, 2, double, highp> highp_dmat2x2; + typedef mat<2, 3, double, highp> highp_dmat2x3; + typedef mat<2, 4, double, highp> highp_dmat2x4; + typedef mat<3, 2, double, highp> highp_dmat3x2; + typedef mat<3, 3, double, highp> highp_dmat3x3; + typedef mat<3, 4, double, highp> highp_dmat3x4; + typedef mat<4, 2, double, highp> highp_dmat4x2; + typedef mat<4, 3, double, highp> highp_dmat4x3; + typedef mat<4, 4, double, highp> highp_dmat4x4; + + typedef mat<2, 2, double, defaultp> dmat2x2; + typedef mat<3, 2, double, defaultp> dmat3x2; + typedef mat<4, 2, double, defaultp> dmat4x2; + typedef mat<2, 3, double, defaultp> dmat2x3; + typedef mat<3, 3, double, defaultp> dmat3x3; + typedef mat<4, 3, double, defaultp> dmat4x3; + typedef mat<2, 4, double, defaultp> dmat2x4; + typedef mat<3, 4, double, defaultp> dmat3x4; + typedef mat<4, 4, double, defaultp> dmat4x4; + + typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; + typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; + typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; + typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; + typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; + typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; + typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; + typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; + typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; + + typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; + typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; + typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; + typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; + typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; + typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; + typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; + typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; + typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; + + typedef mat<2, 2, f64, highp> highp_f64mat2x2; + typedef mat<2, 3, f64, highp> highp_f64mat2x3; + typedef mat<2, 4, f64, highp> highp_f64mat2x4; + typedef mat<3, 2, f64, highp> highp_f64mat3x2; + typedef mat<3, 3, f64, highp> highp_f64mat3x3; + typedef mat<3, 4, f64, highp> highp_f64mat3x4; + typedef mat<4, 2, f64, highp> highp_f64mat4x2; + typedef mat<4, 3, f64, highp> highp_f64mat4x3; + typedef mat<4, 4, f64, highp> highp_f64mat4x4; + + typedef mat<2, 2, f64, defaultp> f64mat2x2; + typedef mat<3, 2, f64, defaultp> f64mat3x2; + typedef mat<4, 2, f64, defaultp> f64mat4x2; + typedef mat<2, 3, f64, defaultp> f64mat2x3; + typedef mat<3, 3, f64, defaultp> f64mat3x3; + typedef mat<4, 3, f64, defaultp> f64mat4x3; + typedef mat<2, 4, f64, defaultp> f64mat2x4; + typedef mat<3, 4, f64, defaultp> f64mat3x4; + typedef mat<4, 4, f64, defaultp> f64mat4x4; + + // Quaternion + + typedef qua lowp_quat; + typedef qua mediump_quat; + typedef qua highp_quat; + typedef qua quat; + + typedef qua lowp_fquat; + typedef qua mediump_fquat; + typedef qua highp_fquat; + typedef qua fquat; + + typedef qua lowp_f32quat; + typedef qua mediump_f32quat; + typedef qua highp_f32quat; + typedef qua f32quat; + + typedef qua lowp_dquat; + typedef qua mediump_dquat; + typedef qua highp_dquat; + typedef qua dquat; + + typedef qua lowp_f64quat; + typedef qua mediump_f64quat; + typedef qua highp_f64quat; + typedef qua f64quat; +}//namespace glm + + diff --git a/src/GLMath/glm/geometric.hpp b/src/GLMath/glm/geometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c068a3cbdb58b2b3826f4924de6420936527cbae --- /dev/null +++ b/src/GLMath/glm/geometric.hpp @@ -0,0 +1,116 @@ +/// @ref core +/// @file glm/geometric.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions +/// +/// @defgroup core_func_geometric Geometric functions +/// @ingroup core +/// +/// These operate on vectors as vectors, not component-wise. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_func_geometric + /// @{ + + /// Returns the length of x, i.e., sqrt(x * x). + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL length man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T length(vec const& x); + + /// Returns the distance betwwen p0 and p1, i.e., length(p0 - p1). + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL distance man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T distance(vec const& p0, vec const& p1); + + /// Returns the dot product of x and y, i.e., result = x * y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL dot man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T dot(vec const& x, vec const& y); + + /// Returns the cross product of x and y. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL cross man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + /// Returns a vector in the same direction as x but with length of 1. + /// According to issue 10 GLSL 1.10 specification, if length(x) == 0 then result is undefined and generate an error. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL normalize man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec normalize(vec const& x); + + /// If dot(Nref, I) < 0.0, return N, otherwise, return -N. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL faceforward man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec faceforward( + vec const& N, + vec const& I, + vec const& Nref); + + /// For the incident vector I and surface orientation N, + /// returns the reflection direction : result = I - 2.0 * dot(N, I) * N. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL reflect man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec reflect( + vec const& I, + vec const& N); + + /// For the incident vector I and surface normal N, + /// and the ratio of indices of refraction eta, + /// return the refraction vector. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL refract man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec refract( + vec const& I, + vec const& N, + T eta); + + /// @} +}//namespace glm + +#include "detail/func_geometric.inl" diff --git a/src/GLMath/glm/glm.hpp b/src/GLMath/glm/glm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8b61064968032e6ef56a0f7e572b4b1abc5976c7 --- /dev/null +++ b/src/GLMath/glm/glm.hpp @@ -0,0 +1,136 @@ +/// @ref core +/// @file glm/glm.hpp +/// +/// @defgroup core Core features +/// +/// @brief Features that implement in C++ the GLSL specification as closely as possible. +/// +/// The GLM core consists of C++ types that mirror GLSL types and +/// C++ functions that mirror the GLSL functions. +/// +/// The best documentation for GLM Core is the current GLSL specification, +/// version 4.2 +/// (pdf file). +/// +/// GLM core functionalities require to be included to be used. +/// +/// +/// @defgroup core_vector Vector types +/// +/// Vector types of two to four components with an exhaustive set of operators. +/// +/// @ingroup core +/// +/// +/// @defgroup core_vector_precision Vector types with precision qualifiers +/// +/// @brief Vector types with precision qualifiers which may result in various precision in term of ULPs +/// +/// GLSL allows defining qualifiers for particular variables. +/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, +/// with OpenGL ES's GLSL, these qualifiers do have an effect. +/// +/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: +/// a number of typedefs that use a particular qualifier. +/// +/// None of these types make any guarantees about the actual qualifier used. +/// +/// @ingroup core +/// +/// +/// @defgroup core_matrix Matrix types +/// +/// Matrix types of with C columns and R rows where C and R are values between 2 to 4 included. +/// These types have exhaustive sets of operators. +/// +/// @ingroup core +/// +/// +/// @defgroup core_matrix_precision Matrix types with precision qualifiers +/// +/// @brief Matrix types with precision qualifiers which may result in various precision in term of ULPs +/// +/// GLSL allows defining qualifiers for particular variables. +/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, +/// with OpenGL ES's GLSL, these qualifiers do have an effect. +/// +/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: +/// a number of typedefs that use a particular qualifier. +/// +/// None of these types make any guarantees about the actual qualifier used. +/// +/// @ingroup core +/// +/// +/// @defgroup ext Stable extensions +/// +/// @brief Additional features not specified by GLSL specification. +/// +/// EXT extensions are fully tested and documented. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions at once by +/// including . Otherwise, each extension needs to be included a specific file. +/// +/// +/// @defgroup gtc Recommended extensions +/// +/// @brief Additional features not specified by GLSL specification. +/// +/// GTC extensions aim to be stable with tests and documentation. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions at once by +/// including . Otherwise, each extension needs to be included a specific file. +/// +/// +/// @defgroup gtx Experimental extensions +/// +/// @brief Experimental features not specified by GLSL specification. +/// +/// Experimental extensions are useful functions and types, but the development of +/// their API and functionality is not necessarily stable. They can change +/// substantially between versions. Backwards compatibility is not much of an issue +/// for them. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions +/// at once by including . Otherwise, each extension needs to be +/// included a specific file. +/// +/// @mainpage OpenGL Mathematics (GLM) +/// - Website: glm.g-truc.net +/// - GLM API documentation +/// - GLM Manual + +#include "detail/_fixes.hpp" + +#include "detail/setup.hpp" + +#pragma once + +#include +#include +#include +#include +#include +#include "fwd.hpp" + +#include "vec2.hpp" +#include "vec3.hpp" +#include "vec4.hpp" +#include "mat2x2.hpp" +#include "mat2x3.hpp" +#include "mat2x4.hpp" +#include "mat3x2.hpp" +#include "mat3x3.hpp" +#include "mat3x4.hpp" +#include "mat4x2.hpp" +#include "mat4x3.hpp" +#include "mat4x4.hpp" + +#include "trigonometric.hpp" +#include "exponential.hpp" +#include "common.hpp" +#include "packing.hpp" +#include "geometric.hpp" +#include "matrix.hpp" +#include "vector_relational.hpp" +#include "integer.hpp" diff --git a/src/GLMath/glm/gtc/bitfield.hpp b/src/GLMath/glm/gtc/bitfield.hpp new file mode 100644 index 0000000000000000000000000000000000000000..084fbe75ff144c36e700d9f800fdfba6a0106c30 --- /dev/null +++ b/src/GLMath/glm/gtc/bitfield.hpp @@ -0,0 +1,266 @@ +/// @ref gtc_bitfield +/// @file glm/gtc/bitfield.hpp +/// +/// @see core (dependence) +/// @see gtc_bitfield (dependence) +/// +/// @defgroup gtc_bitfield GLM_GTC_bitfield +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#include "../detail/setup.hpp" + +#pragma once + +// Dependencies +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "type_precision.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_bitfield extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_bitfield + /// @{ + + /// Build a mask of 'count' bits + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType mask(genIUType Bits); + + /// Build a mask of 'count' bits + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec mask(vec const& v); + + /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldRotateRight(genIUType In, int Shift); + + /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldRotateRight(vec const& In, int Shift); + + /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldRotateLeft(genIUType In, int Shift); + + /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldRotateLeft(vec const& In, int Shift); + + /// Set to 1 a range of bits. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount); + + /// Set to 1 a range of bits. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount); + + /// Set to 0 a range of bits. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount); + + /// Set to 0 a range of bits. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int16 bitfieldInterleave(int8 x, int8 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint16 bitfieldInterleave(uint8 x, uint8 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint16 bitfieldInterleave(u8vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u8vec2 bitfieldDeinterleave(glm::uint16 x); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int16 x, int16 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint16 x, uint16 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(u16vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u16vec2 bitfieldDeinterleave(glm::uint32 x); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(u32vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u32vec2 bitfieldDeinterleave(glm::uint64 x); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y, int32 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w); + + /// @} +} //namespace glm + +#include "bitfield.inl" diff --git a/src/GLMath/glm/gtc/bitfield.inl b/src/GLMath/glm/gtc/bitfield.inl new file mode 100644 index 0000000000000000000000000000000000000000..06cf1889cd40b366882a1f408c8c7ca40da5b680 --- /dev/null +++ b/src/GLMath/glm/gtc/bitfield.inl @@ -0,0 +1,626 @@ +/// @ref gtc_bitfield + +#include "../simd/integer.h" + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y); + + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z); + + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z, PARAM w); + + template<> + GLM_FUNC_QUALIFIER glm::uint16 bitfieldInterleave(glm::uint8 x, glm::uint8 y) + { + glm::uint16 REG1(x); + glm::uint16 REG2(y); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555); + + return REG1 | static_cast(REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint16 x, glm::uint16 y) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x33333333); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x33333333); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x55555555); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x55555555); + + return REG1 | (REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x0000FFFF0000FFFFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x0000FFFF0000FFFFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF00FF00FFull); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF00FF00FFull); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333333333333333ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333333333333333ull); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555555555555555ull); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555555555555555ull); + + return REG1 | (REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + glm::uint32 REG3(z); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0xFF0000FFu); + REG2 = ((REG2 << 16) | REG2) & static_cast(0xFF0000FFu); + REG3 = ((REG3 << 16) | REG3) & static_cast(0xFF0000FFu); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x0F00F00Fu); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x0F00F00Fu); + REG3 = ((REG3 << 8) | REG3) & static_cast(0x0F00F00Fu); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0xC30C30C3u); + REG2 = ((REG2 << 4) | REG2) & static_cast(0xC30C30C3u); + REG3 = ((REG3 << 4) | REG3) & static_cast(0xC30C30C3u); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x49249249u); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x49249249u); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x49249249u); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + + REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); + REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); + REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); + REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); + REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); + REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); + REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y, glm::uint32 z) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + + REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); + REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); + REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); + REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); + REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); + REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); + REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z, glm::uint8 w) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + glm::uint32 REG3(z); + glm::uint32 REG4(w); + + REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000Fu); + REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000Fu); + REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000Fu); + REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000Fu); + + REG1 = ((REG1 << 6) | REG1) & static_cast(0x03030303u); + REG2 = ((REG2 << 6) | REG2) & static_cast(0x03030303u); + REG3 = ((REG3 << 6) | REG3) & static_cast(0x03030303u); + REG4 = ((REG4 << 6) | REG4) & static_cast(0x03030303u); + + REG1 = ((REG1 << 3) | REG1) & static_cast(0x11111111u); + REG2 = ((REG2 << 3) | REG2) & static_cast(0x11111111u); + REG3 = ((REG3 << 3) | REG3) & static_cast(0x11111111u); + REG4 = ((REG4 << 3) | REG4) & static_cast(0x11111111u); + + return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z, glm::uint16 w) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + glm::uint64 REG4(w); + + REG1 = ((REG1 << 24) | REG1) & static_cast(0x000000FF000000FFull); + REG2 = ((REG2 << 24) | REG2) & static_cast(0x000000FF000000FFull); + REG3 = ((REG3 << 24) | REG3) & static_cast(0x000000FF000000FFull); + REG4 = ((REG4 << 24) | REG4) & static_cast(0x000000FF000000FFull); + + REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000F000F000Full); + REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000F000F000Full); + REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000F000F000Full); + REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000F000F000Full); + + REG1 = ((REG1 << 6) | REG1) & static_cast(0x0303030303030303ull); + REG2 = ((REG2 << 6) | REG2) & static_cast(0x0303030303030303ull); + REG3 = ((REG3 << 6) | REG3) & static_cast(0x0303030303030303ull); + REG4 = ((REG4 << 6) | REG4) & static_cast(0x0303030303030303ull); + + REG1 = ((REG1 << 3) | REG1) & static_cast(0x1111111111111111ull); + REG2 = ((REG2 << 3) | REG2) & static_cast(0x1111111111111111ull); + REG3 = ((REG3 << 3) | REG3) & static_cast(0x1111111111111111ull); + REG4 = ((REG4 << 3) | REG4) & static_cast(0x1111111111111111ull); + + return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER genIUType mask(genIUType Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); + + return Bits >= sizeof(genIUType) * 8 ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); + } + + template + GLM_FUNC_QUALIFIER vec mask(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); + + return detail::functor1::call(mask, v); + } + + template + GLM_FUNC_QUALIFIER genIType bitfieldRotateRight(genIType In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); + + int const BitSize = static_cast(sizeof(genIType) * 8); + return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldRotateRight(vec const& In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); + + int const BitSize = static_cast(sizeof(T) * 8); + return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER genIType bitfieldRotateLeft(genIType In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); + + int const BitSize = static_cast(sizeof(genIType) * 8); + return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldRotateLeft(vec const& In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); + + int const BitSize = static_cast(sizeof(T) * 8); + return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount) + { + return Value | static_cast(mask(BitCount) << FirstBit); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount) + { + return Value | static_cast(mask(BitCount) << FirstBit); + } + + template + GLM_FUNC_QUALIFIER genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount) + { + return Value & static_cast(~(mask(BitCount) << FirstBit)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount) + { + return Value & static_cast(~(mask(BitCount) << FirstBit)); + } + + GLM_FUNC_QUALIFIER int16 bitfieldInterleave(int8 x, int8 y) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y; + + union sign16 + { + int16 i; + uint16 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(uint8 x, uint8 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(u8vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER u8vec2 bitfieldDeinterleave(glm::uint16 x) + { + uint16 REG1(x); + uint16 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x5555); + REG2 = REG2 & static_cast(0x5555); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0xFFFF); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0xFFFF); + + return glm::u8vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int16 x, int16 y) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint16 x, uint16 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(u16vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER glm::u16vec2 bitfieldDeinterleave(glm::uint32 x) + { + glm::uint32 REG1(x); + glm::uint32 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x55555555); + REG2 = REG2 & static_cast(0x55555555); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x33333333); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x33333333); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF); + + return glm::u16vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y) + { + union sign32 + { + int32 i; + uint32 u; + } sign_x, sign_y; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(u32vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER glm::u32vec2 bitfieldDeinterleave(glm::uint64 x) + { + glm::uint64 REG1(x); + glm::uint64 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x5555555555555555ull); + REG2 = REG2 & static_cast(0x5555555555555555ull); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333333333333333ull); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333333333333333ull); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF00FF00FFull); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF00FF00FFull); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF0000FFFFull); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF0000FFFFull); + + REG1 = ((REG1 >> 16) | REG1) & static_cast(0x00000000FFFFFFFFull); + REG2 = ((REG2 >> 16) | REG2) & static_cast(0x00000000FFFFFFFFull); + + return glm::u32vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y, sign_z; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y, sign_z; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y, int32 z) + { + union sign16 + { + int32 i; + uint32 u; + } sign_x, sign_y, sign_z; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u32vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y, sign_z, sign_w; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + sign_w.i = w; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w) + { + return detail::bitfieldInterleave(x, y, z, w); + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec4 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y, sign_z, sign_w; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + sign_w.i = w; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w) + { + return detail::bitfieldInterleave(x, y, z, w); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec4 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/color_space.hpp b/src/GLMath/glm/gtc/color_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cffd9f093fb953ed2f52ef5a427c8b889072d899 --- /dev/null +++ b/src/GLMath/glm/gtc/color_space.hpp @@ -0,0 +1,56 @@ +/// @ref gtc_color_space +/// @file glm/gtc/color_space.hpp +/// +/// @see core (dependence) +/// @see gtc_color_space (dependence) +/// +/// @defgroup gtc_color_space GLM_GTC_color_space +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../exponential.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_color_space extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_color_space + /// @{ + + /// Convert a linear color to sRGB color using a standard gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear); + + /// Convert a linear color to sRGB color using a custom gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear, T Gamma); + + /// Convert a sRGB color to linear color using a standard gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB); + + /// Convert a sRGB color to linear color using a custom gamma correction. + // IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma); + + /// @} +} //namespace glm + +#include "color_space.inl" diff --git a/src/GLMath/glm/gtc/color_space.inl b/src/GLMath/glm/gtc/color_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..2a900044e99b7507e9921782684461acfbd6ab1f --- /dev/null +++ b/src/GLMath/glm/gtc/color_space.inl @@ -0,0 +1,84 @@ +/// @ref gtc_color_space + +namespace glm{ +namespace detail +{ + template + struct compute_rgbToSrgb + { + GLM_FUNC_QUALIFIER static vec call(vec const& ColorRGB, T GammaCorrection) + { + vec const ClampedColor(clamp(ColorRGB, static_cast(0), static_cast(1))); + + return mix( + pow(ClampedColor, vec(GammaCorrection)) * static_cast(1.055) - static_cast(0.055), + ClampedColor * static_cast(12.92), + lessThan(ClampedColor, vec(static_cast(0.0031308)))); + } + }; + + template + struct compute_rgbToSrgb<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorRGB, T GammaCorrection) + { + return vec<4, T, Q>(compute_rgbToSrgb<3, T, Q>::call(vec<3, T, Q>(ColorRGB), GammaCorrection), ColorRGB.w); + } + }; + + template + struct compute_srgbToRgb + { + GLM_FUNC_QUALIFIER static vec call(vec const& ColorSRGB, T Gamma) + { + return mix( + pow((ColorSRGB + static_cast(0.055)) * static_cast(0.94786729857819905213270142180095), vec(Gamma)), + ColorSRGB * static_cast(0.07739938080495356037151702786378), + lessThanEqual(ColorSRGB, vec(static_cast(0.04045)))); + } + }; + + template + struct compute_srgbToRgb<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorSRGB, T Gamma) + { + return vec<4, T, Q>(compute_srgbToRgb<3, T, Q>::call(vec<3, T, Q>(ColorSRGB), Gamma), ColorSRGB.w); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear) + { + return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(0.41666)); + } + + // Based on Ian Taylor http://chilliant.blogspot.fr/2012/08/srgb-approximations-for-hlsl.html + template<> + GLM_FUNC_QUALIFIER vec<3, float, lowp> convertLinearToSRGB(vec<3, float, lowp> const& ColorLinear) + { + vec<3, float, lowp> S1 = sqrt(ColorLinear); + vec<3, float, lowp> S2 = sqrt(S1); + vec<3, float, lowp> S3 = sqrt(S2); + return 0.662002687f * S1 + 0.684122060f * S2 - 0.323583601f * S3 - 0.0225411470f * ColorLinear; + } + + template + GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear, T Gamma) + { + return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(1) / Gamma); + } + + template + GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB) + { + return detail::compute_srgbToRgb::call(ColorSRGB, static_cast(2.4)); + } + + template + GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma) + { + return detail::compute_srgbToRgb::call(ColorSRGB, Gamma); + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/constants.hpp b/src/GLMath/glm/gtc/constants.hpp new file mode 100644 index 0000000000000000000000000000000000000000..99f212869e0d753d10e0ccaebd51f681de1cce05 --- /dev/null +++ b/src/GLMath/glm/gtc/constants.hpp @@ -0,0 +1,165 @@ +/// @ref gtc_constants +/// @file glm/gtc/constants.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_constants GLM_GTC_constants +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Provide a list of constants and precomputed useful values. + +#pragma once + +// Dependencies +#include "../ext/scalar_constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_constants extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_constants + /// @{ + + /// Return 0. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType zero(); + + /// Return 1. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one(); + + /// Return pi * 2. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_pi(); + + /// Return square root of pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_pi(); + + /// Return pi / 2. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType half_pi(); + + /// Return pi / 2 * 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType three_over_two_pi(); + + /// Return pi / 4. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType quarter_pi(); + + /// Return 1 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_pi(); + + /// Return 1 / (pi * 2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_two_pi(); + + /// Return 2 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_pi(); + + /// Return 4 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType four_over_pi(); + + /// Return 2 / sqrt(pi). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_root_pi(); + + /// Return 1 / sqrt(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_root_two(); + + /// Return sqrt(pi / 2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_half_pi(); + + /// Return sqrt(2 * pi). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_two_pi(); + + /// Return sqrt(ln(4)). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_ln_four(); + + /// Return e constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType e(); + + /// Return Euler's constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType euler(); + + /// Return sqrt(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_two(); + + /// Return sqrt(3). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_three(); + + /// Return sqrt(5). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_five(); + + /// Return ln(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_two(); + + /// Return ln(10). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ten(); + + /// Return ln(ln(2)). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ln_two(); + + /// Return 1 / 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType third(); + + /// Return 2 / 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_thirds(); + + /// Return the golden ratio constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType golden_ratio(); + + /// @} +} //namespace glm + +#include "constants.inl" diff --git a/src/GLMath/glm/gtc/constants.inl b/src/GLMath/glm/gtc/constants.inl new file mode 100644 index 0000000000000000000000000000000000000000..87f5c860f4705ee1d6cb7f6ebddaa64246318fde --- /dev/null +++ b/src/GLMath/glm/gtc/constants.inl @@ -0,0 +1,166 @@ +/// @ref gtc_constants + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType zero() + { + return genType(0); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one() + { + return genType(1); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_pi() + { + return genType(6.28318530717958647692528676655900576); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_pi() + { + return genType(1.772453850905516027); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType half_pi() + { + return genType(1.57079632679489661923132169163975144); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType three_over_two_pi() + { + return genType(4.71238898038468985769396507491925432); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType quarter_pi() + { + return genType(0.785398163397448309615660845819875721); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_pi() + { + return genType(0.318309886183790671537767526745028724); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_two_pi() + { + return genType(0.159154943091895335768883763372514362); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_pi() + { + return genType(0.636619772367581343075535053490057448); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType four_over_pi() + { + return genType(1.273239544735162686151070106980114898); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_root_pi() + { + return genType(1.12837916709551257389615890312154517); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_root_two() + { + return genType(0.707106781186547524400844362104849039); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_half_pi() + { + return genType(1.253314137315500251); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two_pi() + { + return genType(2.506628274631000502); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_ln_four() + { + return genType(1.17741002251547469); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType e() + { + return genType(2.71828182845904523536); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType euler() + { + return genType(0.577215664901532860606); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two() + { + return genType(1.41421356237309504880168872420969808); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_three() + { + return genType(1.73205080756887729352744634150587236); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_five() + { + return genType(2.23606797749978969640917366873127623); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_two() + { + return genType(0.693147180559945309417232121458176568); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ten() + { + return genType(2.30258509299404568401799145468436421); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ln_two() + { + return genType(-0.3665129205816643); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType third() + { + return genType(0.3333333333333333333333333333333333333333); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_thirds() + { + return genType(0.666666666666666666666666666666666666667); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType golden_ratio() + { + return genType(1.61803398874989484820458683436563811); + } +} //namespace glm diff --git a/src/GLMath/glm/gtc/epsilon.hpp b/src/GLMath/glm/gtc/epsilon.hpp new file mode 100644 index 0000000000000000000000000000000000000000..640439b11c36cd5df5261bc0e7a62c280700a252 --- /dev/null +++ b/src/GLMath/glm/gtc/epsilon.hpp @@ -0,0 +1,60 @@ +/// @ref gtc_epsilon +/// @file glm/gtc/epsilon.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_epsilon GLM_GTC_epsilon +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Comparison functions for a user defined epsilon values. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_epsilon extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_epsilon + /// @{ + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL vec epsilonEqual(vec const& x, vec const& y, T const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL bool epsilonEqual(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is not satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL bool epsilonNotEqual(genType const& x, genType const& y, genType const& epsilon); + + /// @} +}//namespace glm + +#include "epsilon.inl" diff --git a/src/GLMath/glm/gtc/epsilon.inl b/src/GLMath/glm/gtc/epsilon.inl new file mode 100644 index 0000000000000000000000000000000000000000..508b9f8966feff92b269182a24e03b67358a4a91 --- /dev/null +++ b/src/GLMath/glm/gtc/epsilon.inl @@ -0,0 +1,80 @@ +/// @ref gtc_epsilon + +// Dependency: +#include "../vector_relational.hpp" +#include "../common.hpp" + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER bool epsilonEqual + ( + float const& x, + float const& y, + float const& epsilon + ) + { + return abs(x - y) < epsilon; + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonEqual + ( + double const& x, + double const& y, + double const& epsilon + ) + { + return abs(x - y) < epsilon; + } + + template + GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, T const& epsilon) + { + return lessThan(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, vec const& epsilon) + { + return lessThan(abs(x - y), vec(epsilon)); + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonNotEqual(float const& x, float const& y, float const& epsilon) + { + return abs(x - y) >= epsilon; + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonNotEqual(double const& x, double const& y, double const& epsilon) + { + return abs(x - y) >= epsilon; + } + + template + GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon) + { + return greaterThanEqual(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, vec const& epsilon) + { + return greaterThanEqual(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonEqual(qua const& x, qua const& y, T const& epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return lessThan(abs(v), vec<4, T, Q>(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonNotEqual(qua const& x, qua const& y, T const& epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/integer.hpp b/src/GLMath/glm/gtc/integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4c3f28f651d8e49423d91ccf0eb45c8b9f72aed0 --- /dev/null +++ b/src/GLMath/glm/gtc/integer.hpp @@ -0,0 +1,65 @@ +/// @ref gtc_integer +/// @file glm/gtc/integer.hpp +/// +/// @see core (dependence) +/// @see gtc_integer (dependence) +/// +/// @defgroup gtc_integer GLM_GTC_integer +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../common.hpp" +#include "../integer.hpp" +#include "../exponential.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_integer + /// @{ + + /// Returns the log2 of x for integer values. Can be reliably using to compute mipmap count from the texture size. + /// @see gtc_integer + template + GLM_FUNC_DECL genIUType log2(genIUType x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam T floating point scalar types. + /// + /// @see GLSL round man page + /// @see gtc_integer + template + GLM_FUNC_DECL vec iround(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam T floating point scalar types. + /// + /// @see GLSL round man page + /// @see gtc_integer + template + GLM_FUNC_DECL vec uround(vec const& x); + + /// @} +} //namespace glm + +#include "integer.inl" diff --git a/src/GLMath/glm/gtc/integer.inl b/src/GLMath/glm/gtc/integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..f0a8b4f2578e2935008defa43f6864c8d9dfb72d --- /dev/null +++ b/src/GLMath/glm/gtc/integer.inl @@ -0,0 +1,68 @@ +/// @ref gtc_integer + +namespace glm{ +namespace detail +{ + template + struct compute_log2 + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + //Equivalent to return findMSB(vec); but save one function call in ASM with VC + //return findMSB(vec); + return vec(detail::compute_findMSB_vec::call(v)); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + struct compute_log2<4, int, Q, false, Aligned> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) + { + vec<4, int, Q> Result; + _BitScanReverse(reinterpret_cast(&Result.x), v.x); + _BitScanReverse(reinterpret_cast(&Result.y), v.y); + _BitScanReverse(reinterpret_cast(&Result.z), v.z); + _BitScanReverse(reinterpret_cast(&Result.w), v.w); + return Result; + } + }; +# endif//GLM_HAS_BITSCAN_WINDOWS +}//namespace detail + template + GLM_FUNC_QUALIFIER int iround(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); + assert(static_cast(0.0) <= x); + + return static_cast(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER vec iround(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); + assert(all(lessThanEqual(vec(0), x))); + + return vec(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER uint uround(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); + assert(static_cast(0.0) <= x); + + return static_cast(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER vec uround(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); + assert(all(lessThanEqual(vec(0), x))); + + return vec(x + static_cast(0.5)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/matrix_access.hpp b/src/GLMath/glm/gtc/matrix_access.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4935ba755dd502af46a80bfc30a49b39e188a8bc --- /dev/null +++ b/src/GLMath/glm/gtc/matrix_access.hpp @@ -0,0 +1,60 @@ +/// @ref gtc_matrix_access +/// @file glm/gtc/matrix_access.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_access GLM_GTC_matrix_access +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines functions to access rows or columns of a matrix easily. + +#pragma once + +// Dependency: +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_access extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_access + /// @{ + + /// Get a specific row of a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL typename genType::row_type row( + genType const& m, + length_t index); + + /// Set a specific row to a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL genType row( + genType const& m, + length_t index, + typename genType::row_type const& x); + + /// Get a specific column of a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL typename genType::col_type column( + genType const& m, + length_t index); + + /// Set a specific column to a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL genType column( + genType const& m, + length_t index, + typename genType::col_type const& x); + + /// @} +}//namespace glm + +#include "matrix_access.inl" diff --git a/src/GLMath/glm/gtc/matrix_access.inl b/src/GLMath/glm/gtc/matrix_access.inl new file mode 100644 index 0000000000000000000000000000000000000000..09fcc10d3d7e4c2c1d70de38b4d02628e09477fc --- /dev/null +++ b/src/GLMath/glm/gtc/matrix_access.inl @@ -0,0 +1,62 @@ +/// @ref gtc_matrix_access + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType row + ( + genType const& m, + length_t index, + typename genType::row_type const& x + ) + { + assert(index >= 0 && index < m[0].length()); + + genType Result = m; + for(length_t i = 0; i < m.length(); ++i) + Result[i][index] = x[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER typename genType::row_type row + ( + genType const& m, + length_t index + ) + { + assert(index >= 0 && index < m[0].length()); + + typename genType::row_type Result(0); + for(length_t i = 0; i < m.length(); ++i) + Result[i] = m[i][index]; + return Result; + } + + template + GLM_FUNC_QUALIFIER genType column + ( + genType const& m, + length_t index, + typename genType::col_type const& x + ) + { + assert(index >= 0 && index < m.length()); + + genType Result = m; + Result[index] = x; + return Result; + } + + template + GLM_FUNC_QUALIFIER typename genType::col_type column + ( + genType const& m, + length_t index + ) + { + assert(index >= 0 && index < m.length()); + + return m[index]; + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/matrix_integer.hpp b/src/GLMath/glm/gtc/matrix_integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..557a9775baa5f8f45e8148b18994f74907b13621 --- /dev/null +++ b/src/GLMath/glm/gtc/matrix_integer.hpp @@ -0,0 +1,487 @@ +/// @ref gtc_matrix_integer +/// @file glm/gtc/matrix_integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_integer GLM_GTC_matrix_integer +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_integer + /// @{ + + /// High-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, highp> highp_imat2; + + /// High-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, highp> highp_imat3; + + /// High-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, highp> highp_imat4; + + /// High-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, highp> highp_imat2x2; + + /// High-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, highp> highp_imat2x3; + + /// High-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, highp> highp_imat2x4; + + /// High-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, highp> highp_imat3x2; + + /// High-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, highp> highp_imat3x3; + + /// High-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, highp> highp_imat3x4; + + /// High-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, highp> highp_imat4x2; + + /// High-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, highp> highp_imat4x3; + + /// High-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, highp> highp_imat4x4; + + + /// Medium-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, mediump> mediump_imat2; + + /// Medium-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, mediump> mediump_imat3; + + /// Medium-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, mediump> mediump_imat4; + + + /// Medium-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, mediump> mediump_imat2x2; + + /// Medium-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, mediump> mediump_imat2x3; + + /// Medium-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, mediump> mediump_imat2x4; + + /// Medium-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, mediump> mediump_imat3x2; + + /// Medium-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, mediump> mediump_imat3x3; + + /// Medium-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, mediump> mediump_imat3x4; + + /// Medium-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, mediump> mediump_imat4x2; + + /// Medium-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, mediump> mediump_imat4x3; + + /// Medium-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, mediump> mediump_imat4x4; + + + /// Low-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, lowp> lowp_imat2; + + /// Low-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, lowp> lowp_imat3; + + /// Low-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, lowp> lowp_imat4; + + + /// Low-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, lowp> lowp_imat2x2; + + /// Low-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, lowp> lowp_imat2x3; + + /// Low-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, lowp> lowp_imat2x4; + + /// Low-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, lowp> lowp_imat3x2; + + /// Low-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, lowp> lowp_imat3x3; + + /// Low-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, lowp> lowp_imat3x4; + + /// Low-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, lowp> lowp_imat4x2; + + /// Low-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, lowp> lowp_imat4x3; + + /// Low-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, lowp> lowp_imat4x4; + + + /// High-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, highp> highp_umat2; + + /// High-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, highp> highp_umat3; + + /// High-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, highp> highp_umat4; + + /// High-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, highp> highp_umat2x2; + + /// High-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, highp> highp_umat2x3; + + /// High-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, highp> highp_umat2x4; + + /// High-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, highp> highp_umat3x2; + + /// High-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, highp> highp_umat3x3; + + /// High-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, highp> highp_umat3x4; + + /// High-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, highp> highp_umat4x2; + + /// High-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, highp> highp_umat4x3; + + /// High-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, highp> highp_umat4x4; + + + /// Medium-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, mediump> mediump_umat2; + + /// Medium-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, mediump> mediump_umat3; + + /// Medium-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, mediump> mediump_umat4; + + + /// Medium-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, mediump> mediump_umat2x2; + + /// Medium-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, mediump> mediump_umat2x3; + + /// Medium-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, mediump> mediump_umat2x4; + + /// Medium-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, mediump> mediump_umat3x2; + + /// Medium-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, mediump> mediump_umat3x3; + + /// Medium-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, mediump> mediump_umat3x4; + + /// Medium-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, mediump> mediump_umat4x2; + + /// Medium-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, mediump> mediump_umat4x3; + + /// Medium-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, mediump> mediump_umat4x4; + + + /// Low-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, lowp> lowp_umat2; + + /// Low-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, lowp> lowp_umat3; + + /// Low-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, lowp> lowp_umat4; + + + /// Low-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, lowp> lowp_umat2x2; + + /// Low-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, lowp> lowp_umat2x3; + + /// Low-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, lowp> lowp_umat2x4; + + /// Low-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, lowp> lowp_umat3x2; + + /// Low-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, lowp> lowp_umat3x3; + + /// Low-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, lowp> lowp_umat3x4; + + /// Low-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, lowp> lowp_umat4x2; + + /// Low-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, lowp> lowp_umat4x3; + + /// Low-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, lowp> lowp_umat4x4; + +#if(defined(GLM_PRECISION_HIGHP_INT)) + typedef highp_imat2 imat2; + typedef highp_imat3 imat3; + typedef highp_imat4 imat4; + typedef highp_imat2x2 imat2x2; + typedef highp_imat2x3 imat2x3; + typedef highp_imat2x4 imat2x4; + typedef highp_imat3x2 imat3x2; + typedef highp_imat3x3 imat3x3; + typedef highp_imat3x4 imat3x4; + typedef highp_imat4x2 imat4x2; + typedef highp_imat4x3 imat4x3; + typedef highp_imat4x4 imat4x4; +#elif(defined(GLM_PRECISION_LOWP_INT)) + typedef lowp_imat2 imat2; + typedef lowp_imat3 imat3; + typedef lowp_imat4 imat4; + typedef lowp_imat2x2 imat2x2; + typedef lowp_imat2x3 imat2x3; + typedef lowp_imat2x4 imat2x4; + typedef lowp_imat3x2 imat3x2; + typedef lowp_imat3x3 imat3x3; + typedef lowp_imat3x4 imat3x4; + typedef lowp_imat4x2 imat4x2; + typedef lowp_imat4x3 imat4x3; + typedef lowp_imat4x4 imat4x4; +#else //if(defined(GLM_PRECISION_MEDIUMP_INT)) + + /// Signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat2 imat2; + + /// Signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat3 imat3; + + /// Signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat4 imat4; + + /// Signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat2x2 imat2x2; + + /// Signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat2x3 imat2x3; + + /// Signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat2x4 imat2x4; + + /// Signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat3x2 imat3x2; + + /// Signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat3x3 imat3x3; + + /// Signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat3x4 imat3x4; + + /// Signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat4x2 imat4x2; + + /// Signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat4x3 imat4x3; + + /// Signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_imat4x4 imat4x4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_HIGHP_UINT)) + typedef highp_umat2 umat2; + typedef highp_umat3 umat3; + typedef highp_umat4 umat4; + typedef highp_umat2x2 umat2x2; + typedef highp_umat2x3 umat2x3; + typedef highp_umat2x4 umat2x4; + typedef highp_umat3x2 umat3x2; + typedef highp_umat3x3 umat3x3; + typedef highp_umat3x4 umat3x4; + typedef highp_umat4x2 umat4x2; + typedef highp_umat4x3 umat4x3; + typedef highp_umat4x4 umat4x4; +#elif(defined(GLM_PRECISION_LOWP_UINT)) + typedef lowp_umat2 umat2; + typedef lowp_umat3 umat3; + typedef lowp_umat4 umat4; + typedef lowp_umat2x2 umat2x2; + typedef lowp_umat2x3 umat2x3; + typedef lowp_umat2x4 umat2x4; + typedef lowp_umat3x2 umat3x2; + typedef lowp_umat3x3 umat3x3; + typedef lowp_umat3x4 umat3x4; + typedef lowp_umat4x2 umat4x2; + typedef lowp_umat4x3 umat4x3; + typedef lowp_umat4x4 umat4x4; +#else //if(defined(GLM_PRECISION_MEDIUMP_UINT)) + + /// Unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat2 umat2; + + /// Unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat3 umat3; + + /// Unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat4 umat4; + + /// Unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat2x2 umat2x2; + + /// Unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat2x3 umat2x3; + + /// Unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat2x4 umat2x4; + + /// Unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat3x2 umat3x2; + + /// Unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat3x3 umat3x3; + + /// Unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat3x4 umat3x4; + + /// Unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat4x2 umat4x2; + + /// Unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat4x3 umat4x3; + + /// Unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mediump_umat4x4 umat4x4; +#endif//GLM_PRECISION + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/gtc/matrix_inverse.hpp b/src/GLMath/glm/gtc/matrix_inverse.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a1900adcbb06703235b1528b33cb239bd0a16c29 --- /dev/null +++ b/src/GLMath/glm/gtc/matrix_inverse.hpp @@ -0,0 +1,50 @@ +/// @ref gtc_matrix_inverse +/// @file glm/gtc/matrix_inverse.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_inverse GLM_GTC_matrix_inverse +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines additional matrix inverting functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../matrix.hpp" +#include "../mat2x2.hpp" +#include "../mat3x3.hpp" +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_inverse extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_inverse + /// @{ + + /// Fast matrix inverse for affine matrix. + /// + /// @param m Input matrix to invert. + /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate. + /// @see gtc_matrix_inverse + template + GLM_FUNC_DECL genType affineInverse(genType const& m); + + /// Compute the inverse transpose of a matrix. + /// + /// @param m Input matrix to invert transpose. + /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate. + /// @see gtc_matrix_inverse + template + GLM_FUNC_DECL genType inverseTranspose(genType const& m); + + /// @} +}//namespace glm + +#include "matrix_inverse.inl" diff --git a/src/GLMath/glm/gtc/matrix_inverse.inl b/src/GLMath/glm/gtc/matrix_inverse.inl new file mode 100644 index 0000000000000000000000000000000000000000..c004b9e146706b64fb9e73ba95e7bc3401b8c42a --- /dev/null +++ b/src/GLMath/glm/gtc/matrix_inverse.inl @@ -0,0 +1,118 @@ +/// @ref gtc_matrix_inverse + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> affineInverse(mat<3, 3, T, Q> const& m) + { + mat<2, 2, T, Q> const Inv(inverse(mat<2, 2, T, Q>(m))); + + return mat<3, 3, T, Q>( + vec<3, T, Q>(Inv[0], static_cast(0)), + vec<3, T, Q>(Inv[1], static_cast(0)), + vec<3, T, Q>(-Inv * vec<2, T, Q>(m[2]), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> affineInverse(mat<4, 4, T, Q> const& m) + { + mat<3, 3, T, Q> const Inv(inverse(mat<3, 3, T, Q>(m))); + + return mat<4, 4, T, Q>( + vec<4, T, Q>(Inv[0], static_cast(0)), + vec<4, T, Q>(Inv[1], static_cast(0)), + vec<4, T, Q>(Inv[2], static_cast(0)), + vec<4, T, Q>(-Inv * vec<3, T, Q>(m[3]), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> inverseTranspose(mat<2, 2, T, Q> const& m) + { + T Determinant = m[0][0] * m[1][1] - m[1][0] * m[0][1]; + + mat<2, 2, T, Q> Inverse( + + m[1][1] / Determinant, + - m[0][1] / Determinant, + - m[1][0] / Determinant, + + m[0][0] / Determinant); + + return Inverse; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> inverseTranspose(mat<3, 3, T, Q> const& m) + { + T Determinant = + + m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) + - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + + mat<3, 3, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]); + Inverse[0][1] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]); + Inverse[0][2] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]); + Inverse[1][0] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]); + Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]); + Inverse[1][2] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]); + Inverse[2][0] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]); + Inverse[2][1] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]); + Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]); + Inverse /= Determinant; + + return Inverse; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> inverseTranspose(mat<4, 4, T, Q> const& m) + { + T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + T SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + T SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + T SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + T SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + T SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + T SubFactor11 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + T SubFactor12 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + T SubFactor13 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + T SubFactor14 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + T SubFactor15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + T SubFactor16 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + T SubFactor17 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + mat<4, 4, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02); + Inverse[0][1] = - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04); + Inverse[0][2] = + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05); + Inverse[0][3] = - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05); + + Inverse[1][0] = - (m[0][1] * SubFactor00 - m[0][2] * SubFactor01 + m[0][3] * SubFactor02); + Inverse[1][1] = + (m[0][0] * SubFactor00 - m[0][2] * SubFactor03 + m[0][3] * SubFactor04); + Inverse[1][2] = - (m[0][0] * SubFactor01 - m[0][1] * SubFactor03 + m[0][3] * SubFactor05); + Inverse[1][3] = + (m[0][0] * SubFactor02 - m[0][1] * SubFactor04 + m[0][2] * SubFactor05); + + Inverse[2][0] = + (m[0][1] * SubFactor06 - m[0][2] * SubFactor07 + m[0][3] * SubFactor08); + Inverse[2][1] = - (m[0][0] * SubFactor06 - m[0][2] * SubFactor09 + m[0][3] * SubFactor10); + Inverse[2][2] = + (m[0][0] * SubFactor07 - m[0][1] * SubFactor09 + m[0][3] * SubFactor11); + Inverse[2][3] = - (m[0][0] * SubFactor08 - m[0][1] * SubFactor10 + m[0][2] * SubFactor11); + + Inverse[3][0] = - (m[0][1] * SubFactor12 - m[0][2] * SubFactor13 + m[0][3] * SubFactor14); + Inverse[3][1] = + (m[0][0] * SubFactor12 - m[0][2] * SubFactor15 + m[0][3] * SubFactor16); + Inverse[3][2] = - (m[0][0] * SubFactor13 - m[0][1] * SubFactor15 + m[0][3] * SubFactor17); + Inverse[3][3] = + (m[0][0] * SubFactor14 - m[0][1] * SubFactor16 + m[0][2] * SubFactor17); + + T Determinant = + + m[0][0] * Inverse[0][0] + + m[0][1] * Inverse[0][1] + + m[0][2] * Inverse[0][2] + + m[0][3] * Inverse[0][3]; + + Inverse /= Determinant; + + return Inverse; + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/matrix_transform.hpp b/src/GLMath/glm/gtc/matrix_transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..612418fa51c49d91c4e4e4a315083044a3db0b4c --- /dev/null +++ b/src/GLMath/glm/gtc/matrix_transform.hpp @@ -0,0 +1,36 @@ +/// @ref gtc_matrix_transform +/// @file glm/gtc/matrix_transform.hpp +/// +/// @see core (dependence) +/// @see gtx_transform +/// @see gtx_transform2 +/// +/// @defgroup gtc_matrix_transform GLM_GTC_matrix_transform +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines functions that generate common transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. + +#pragma once + +// Dependencies +#include "../mat4x4.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../ext/matrix_projection.hpp" +#include "../ext/matrix_clip_space.hpp" +#include "../ext/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_transform extension included") +#endif + +#include "matrix_transform.inl" diff --git a/src/GLMath/glm/gtc/matrix_transform.inl b/src/GLMath/glm/gtc/matrix_transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..15b46bc9db617b238d8a60d382f584372e9d0855 --- /dev/null +++ b/src/GLMath/glm/gtc/matrix_transform.inl @@ -0,0 +1,3 @@ +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" diff --git a/src/GLMath/glm/gtc/noise.hpp b/src/GLMath/glm/gtc/noise.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ab1772e78125da6c280f4b1a676d7ff2c8fae082 --- /dev/null +++ b/src/GLMath/glm/gtc/noise.hpp @@ -0,0 +1,61 @@ +/// @ref gtc_noise +/// @file glm/gtc/noise.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_noise GLM_GTC_noise +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines 2D, 3D and 4D procedural noise functions +/// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": +/// https://github.com/ashima/webgl-noise +/// Following Stefan Gustavson's paper "Simplex noise demystified": +/// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_noise.hpp" +#include "../geometric.hpp" +#include "../common.hpp" +#include "../vector_relational.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_noise extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_noise + /// @{ + + /// Classic perlin noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T perlin( + vec const& p); + + /// Periodic perlin noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T perlin( + vec const& p, + vec const& rep); + + /// Simplex noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T simplex( + vec const& p); + + /// @} +}//namespace glm + +#include "noise.inl" diff --git a/src/GLMath/glm/gtc/noise.inl b/src/GLMath/glm/gtc/noise.inl new file mode 100644 index 0000000000000000000000000000000000000000..30d0b274d337a8e990fe0e264130e0e42c0321cb --- /dev/null +++ b/src/GLMath/glm/gtc/noise.inl @@ -0,0 +1,807 @@ +/// @ref gtc_noise +/// +// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": +// https://github.com/ashima/webgl-noise +// Following Stefan Gustavson's paper "Simplex noise demystified": +// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + +namespace glm{ +namespace gtc +{ + template + GLM_FUNC_QUALIFIER vec<4, T, Q> grad4(T const& j, vec<4, T, Q> const& ip) + { + vec<3, T, Q> pXYZ = floor(fract(vec<3, T, Q>(j) * vec<3, T, Q>(ip)) * T(7)) * ip[2] - T(1); + T pW = static_cast(1.5) - dot(abs(pXYZ), vec<3, T, Q>(1)); + vec<4, T, Q> s = vec<4, T, Q>(lessThan(vec<4, T, Q>(pXYZ, pW), vec<4, T, Q>(0.0))); + pXYZ = pXYZ + (vec<3, T, Q>(s) * T(2) - T(1)) * s.w; + return vec<4, T, Q>(pXYZ, pW); + } +}//namespace gtc + + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position) + { + vec<4, T, Q> Pi = glm::floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + vec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation + vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); + vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); + vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); + vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); + + vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); + + vec<4, T, Q> gx = static_cast(2) * glm::fract(i / T(41)) - T(1); + vec<4, T, Q> gy = glm::abs(gx) - T(0.5); + vec<4, T, Q> tx = glm::floor(gx + T(0.5)); + gx = gx - tx; + + vec<2, T, Q> g00(gx.x, gy.x); + vec<2, T, Q> g10(gx.y, gy.y); + vec<2, T, Q> g01(gx.z, gy.z); + vec<2, T, Q> g11(gx.w, gy.w); + + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); + T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); + T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); + T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); + + vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); + vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); + T n_xy = mix(n_x.x, n_x.y, fade_xy.y); + return T(2.3) * n_xy; + } + + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position) + { + vec<3, T, Q> Pi0 = floor(Position); // Integer part for indexing + vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = detail::mod289(Pi0); + Pi1 = detail::mod289(Pi1); + vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(vec<2, T, Q>(Pi0.y), vec<2, T, Q>(Pi1.y)); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0); + vec<4, T, Q> gy0 = fract(floor(gx0) * T(1.0 / 7.0)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); + gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); + gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 * T(1.0 / 7.0); + vec<4, T, Q> gy1 = fract(floor(gx1) * T(1.0 / 7.0)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = detail::fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + /* + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& P) + { + vec<3, T, Q> Pi0 = floor(P); // Integer part for indexing + vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = mod(Pi0, T(289)); + Pi1 = mod(Pi1, T(289)); + vec<3, T, Q> Pf0 = fract(P); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = permute(permute(ix) + iy); + vec<4, T, Q> ixy0 = permute(ixy + iz0); + vec<4, T, Q> ixy1 = permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 / T(7); + vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); + gx0 -= sz0 * (step(0.0, gx0) - T(0.5)); + gy0 -= sz0 * (step(0.0, gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 / T(7); + vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix( + vec<2, T, Q>(n_z.x, n_z.y), + vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + */ + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position) + { + vec<4, T, Q> Pi0 = floor(Position); // Integer part for indexing + vec<4, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = mod(Pi0, vec<4, T, Q>(289)); + Pi1 = mod(Pi1, vec<4, T, Q>(289)); + vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + vec<4, T, Q> iw0(Pi0.w); + vec<4, T, Q> iw1(Pi1.w); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); + vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); + vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); + vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); + + vec<4, T, Q> gx00 = ixy00 / T(7); + vec<4, T, Q> gy00 = floor(gx00) / T(7); + vec<4, T, Q> gz00 = floor(gy00) / T(6); + gx00 = fract(gx00) - T(0.5); + gy00 = fract(gy00) - T(0.5); + gz00 = fract(gz00) - T(0.5); + vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); + vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0.0)); + gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); + gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); + + vec<4, T, Q> gx01 = ixy01 / T(7); + vec<4, T, Q> gy01 = floor(gx01) / T(7); + vec<4, T, Q> gz01 = floor(gy01) / T(6); + gx01 = fract(gx01) - T(0.5); + gy01 = fract(gy01) - T(0.5); + gz01 = fract(gz01) - T(0.5); + vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); + vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); + gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); + gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); + + vec<4, T, Q> gx10 = ixy10 / T(7); + vec<4, T, Q> gy10 = floor(gx10) / T(7); + vec<4, T, Q> gz10 = floor(gy10) / T(6); + gx10 = fract(gx10) - T(0.5); + gy10 = fract(gy10) - T(0.5); + gz10 = fract(gz10) - T(0.5); + vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); + vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0)); + gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); + gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); + + vec<4, T, Q> gx11 = ixy11 / T(7); + vec<4, T, Q> gy11 = floor(gx11) / T(7); + vec<4, T, Q> gz11 = floor(gy11) / T(6); + gx11 = fract(gx11) - T(0.5); + gy11 = fract(gy11) - T(0.5); + gz11 = fract(gz11) - T(0.5); + vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); + vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(0.0)); + gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); + gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); + + vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); + vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); + vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); + vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); + vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); + vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); + vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); + vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); + vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); + vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); + vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); + vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); + vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); + vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); + vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); + vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); + + vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); + g0000 *= norm00.x; + g0100 *= norm00.y; + g1000 *= norm00.z; + g1100 *= norm00.w; + + vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); + g0001 *= norm01.x; + g0101 *= norm01.y; + g1001 *= norm01.z; + g1101 *= norm01.w; + + vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); + g0010 *= norm10.x; + g0110 *= norm10.y; + g1010 *= norm10.z; + g1110 *= norm10.w; + + vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); + g0011 *= norm11.x; + g0111 *= norm11.y; + g1011 *= norm11.z; + g1111 *= norm11.w; + + T n0000 = dot(g0000, Pf0); + T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); + T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); + T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); + T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); + T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); + T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); + T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); + T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); + T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); + T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); + T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); + T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); + T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); + T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); + T n1111 = dot(g1111, Pf1); + + vec<4, T, Q> fade_xyzw = detail::fade(Pf0); + vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); + vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); + vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); + vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); + T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); + return T(2.2) * n_xyzw; + } + + // Classic Perlin noise, periodic variant + template + GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position, vec<2, T, Q> const& rep) + { + vec<4, T, Q> Pi = floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + vec<4, T, Q> Pf = fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, vec<4, T, Q>(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period + Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation + vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); + vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); + vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); + vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); + + vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); + + vec<4, T, Q> gx = static_cast(2) * fract(i / T(41)) - T(1); + vec<4, T, Q> gy = abs(gx) - T(0.5); + vec<4, T, Q> tx = floor(gx + T(0.5)); + gx = gx - tx; + + vec<2, T, Q> g00(gx.x, gy.x); + vec<2, T, Q> g10(gx.y, gy.y); + vec<2, T, Q> g01(gx.z, gy.z); + vec<2, T, Q> g11(gx.w, gy.w); + + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); + T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); + T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); + T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); + + vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); + vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); + T n_xy = mix(n_x.x, n_x.y, fade_xy.y); + return T(2.3) * n_xy; + } + + // Classic Perlin noise, periodic variant + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position, vec<3, T, Q> const& rep) + { + vec<3, T, Q> Pi0 = mod(floor(Position), rep); // Integer part, modulo period + vec<3, T, Q> Pi1 = mod(Pi0 + vec<3, T, Q>(T(1)), rep); // Integer part + 1, mod period + Pi0 = mod(Pi0, vec<3, T, Q>(289)); + Pi1 = mod(Pi1, vec<3, T, Q>(289)); + vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - vec<3, T, Q>(T(1)); // Fractional part - 1.0 + vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 / T(7); + vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0)); + gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); + gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 / T(7); + vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(T(0))); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000 = vec<3, T, Q>(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100 = vec<3, T, Q>(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010 = vec<3, T, Q>(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110 = vec<3, T, Q>(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001 = vec<3, T, Q>(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101 = vec<3, T, Q>(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011 = vec<3, T, Q>(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111 = vec<3, T, Q>(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = detail::fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + + // Classic Perlin noise, periodic version + template + GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position, vec<4, T, Q> const& rep) + { + vec<4, T, Q> Pi0 = mod(floor(Position), rep); // Integer part modulo rep + vec<4, T, Q> Pi1 = mod(Pi0 + T(1), rep); // Integer part + 1 mod rep + vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + vec<4, T, Q> iw0(Pi0.w); + vec<4, T, Q> iw1(Pi1.w); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); + vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); + vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); + vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); + + vec<4, T, Q> gx00 = ixy00 / T(7); + vec<4, T, Q> gy00 = floor(gx00) / T(7); + vec<4, T, Q> gz00 = floor(gy00) / T(6); + gx00 = fract(gx00) - T(0.5); + gy00 = fract(gy00) - T(0.5); + gz00 = fract(gz00) - T(0.5); + vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); + vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0)); + gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); + gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); + + vec<4, T, Q> gx01 = ixy01 / T(7); + vec<4, T, Q> gy01 = floor(gx01) / T(7); + vec<4, T, Q> gz01 = floor(gy01) / T(6); + gx01 = fract(gx01) - T(0.5); + gy01 = fract(gy01) - T(0.5); + gz01 = fract(gz01) - T(0.5); + vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); + vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); + gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); + gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); + + vec<4, T, Q> gx10 = ixy10 / T(7); + vec<4, T, Q> gy10 = floor(gx10) / T(7); + vec<4, T, Q> gz10 = floor(gy10) / T(6); + gx10 = fract(gx10) - T(0.5); + gy10 = fract(gy10) - T(0.5); + gz10 = fract(gz10) - T(0.5); + vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); + vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0.0)); + gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); + gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); + + vec<4, T, Q> gx11 = ixy11 / T(7); + vec<4, T, Q> gy11 = floor(gx11) / T(7); + vec<4, T, Q> gz11 = floor(gy11) / T(6); + gx11 = fract(gx11) - T(0.5); + gy11 = fract(gy11) - T(0.5); + gz11 = fract(gz11) - T(0.5); + vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); + vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(T(0))); + gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); + gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); + + vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); + vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); + vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); + vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); + vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); + vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); + vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); + vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); + vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); + vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); + vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); + vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); + vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); + vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); + vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); + vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); + + vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); + g0000 *= norm00.x; + g0100 *= norm00.y; + g1000 *= norm00.z; + g1100 *= norm00.w; + + vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); + g0001 *= norm01.x; + g0101 *= norm01.y; + g1001 *= norm01.z; + g1101 *= norm01.w; + + vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); + g0010 *= norm10.x; + g0110 *= norm10.y; + g1010 *= norm10.z; + g1110 *= norm10.w; + + vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); + g0011 *= norm11.x; + g0111 *= norm11.y; + g1011 *= norm11.z; + g1111 *= norm11.w; + + T n0000 = dot(g0000, Pf0); + T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); + T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); + T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); + T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); + T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); + T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); + T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); + T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); + T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); + T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); + T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); + T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); + T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); + T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); + T n1111 = dot(g1111, Pf1); + + vec<4, T, Q> fade_xyzw = detail::fade(Pf0); + vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); + vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); + vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); + vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); + T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); + return T(2.2) * n_xyzw; + } + + template + GLM_FUNC_QUALIFIER T simplex(glm::vec<2, T, Q> const& v) + { + vec<4, T, Q> const C = vec<4, T, Q>( + T( 0.211324865405187), // (3.0 - sqrt(3.0)) / 6.0 + T( 0.366025403784439), // 0.5 * (sqrt(3.0) - 1.0) + T(-0.577350269189626), // -1.0 + 2.0 * C.x + T( 0.024390243902439)); // 1.0 / 41.0 + + // First corner + vec<2, T, Q> i = floor(v + dot(v, vec<2, T, Q>(C[1]))); + vec<2, T, Q> x0 = v - i + dot(i, vec<2, T, Q>(C[0])); + + // Other corners + //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 + //i1.y = 1.0 - i1.x; + vec<2, T, Q> i1 = (x0.x > x0.y) ? vec<2, T, Q>(1, 0) : vec<2, T, Q>(0, 1); + // x0 = x0 - 0.0 + 0.0 * C.xx ; + // x1 = x0 - i1 + 1.0 * C.xx ; + // x2 = x0 - 1.0 + 2.0 * C.xx ; + vec<4, T, Q> x12 = vec<4, T, Q>(x0.x, x0.y, x0.x, x0.y) + vec<4, T, Q>(C.x, C.x, C.z, C.z); + x12 = vec<4, T, Q>(vec<2, T, Q>(x12) - i1, x12.z, x12.w); + + // Permutations + i = mod(i, vec<2, T, Q>(289)); // Avoid truncation effects in permutation + vec<3, T, Q> p = detail::permute( + detail::permute(i.y + vec<3, T, Q>(T(0), i1.y, T(1))) + + i.x + vec<3, T, Q>(T(0), i1.x, T(1))); + + vec<3, T, Q> m = max(vec<3, T, Q>(0.5) - vec<3, T, Q>( + dot(x0, x0), + dot(vec<2, T, Q>(x12.x, x12.y), vec<2, T, Q>(x12.x, x12.y)), + dot(vec<2, T, Q>(x12.z, x12.w), vec<2, T, Q>(x12.z, x12.w))), vec<3, T, Q>(0)); + m = m * m ; + m = m * m ; + + // Gradients: 41 points uniformly over a line, mapped onto a diamond. + // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) + + vec<3, T, Q> x = static_cast(2) * fract(p * C.w) - T(1); + vec<3, T, Q> h = abs(x) - T(0.5); + vec<3, T, Q> ox = floor(x + T(0.5)); + vec<3, T, Q> a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Inlined for speed: m *= taylorInvSqrt( a0*a0 + h*h ); + m *= static_cast(1.79284291400159) - T(0.85373472095314) * (a0 * a0 + h * h); + + // Compute final noise value at P + vec<3, T, Q> g; + g.x = a0.x * x0.x + h.x * x0.y; + //g.yz = a0.yz * x12.xz + h.yz * x12.yw; + g.y = a0.y * x12.x + h.y * x12.y; + g.z = a0.z * x12.z + h.z * x12.w; + return T(130) * dot(m, g); + } + + template + GLM_FUNC_QUALIFIER T simplex(vec<3, T, Q> const& v) + { + vec<2, T, Q> const C(1.0 / 6.0, 1.0 / 3.0); + vec<4, T, Q> const D(0.0, 0.5, 1.0, 2.0); + + // First corner + vec<3, T, Q> i(floor(v + dot(v, vec<3, T, Q>(C.y)))); + vec<3, T, Q> x0(v - i + dot(i, vec<3, T, Q>(C.x))); + + // Other corners + vec<3, T, Q> g(step(vec<3, T, Q>(x0.y, x0.z, x0.x), x0)); + vec<3, T, Q> l(T(1) - g); + vec<3, T, Q> i1(min(g, vec<3, T, Q>(l.z, l.x, l.y))); + vec<3, T, Q> i2(max(g, vec<3, T, Q>(l.z, l.x, l.y))); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec<3, T, Q> x1(x0 - i1 + C.x); + vec<3, T, Q> x2(x0 - i2 + C.y); // 2.0*C.x = 1/3 = C.y + vec<3, T, Q> x3(x0 - D.y); // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = detail::mod289(i); + vec<4, T, Q> p(detail::permute(detail::permute(detail::permute( + i.z + vec<4, T, Q>(T(0), i1.z, i2.z, T(1))) + + i.y + vec<4, T, Q>(T(0), i1.y, i2.y, T(1))) + + i.x + vec<4, T, Q>(T(0), i1.x, i2.x, T(1)))); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + T n_ = static_cast(0.142857142857); // 1.0/7.0 + vec<3, T, Q> ns(n_ * vec<3, T, Q>(D.w, D.y, D.z) - vec<3, T, Q>(D.x, D.z, D.x)); + + vec<4, T, Q> j(p - T(49) * floor(p * ns.z * ns.z)); // mod(p,7*7) + + vec<4, T, Q> x_(floor(j * ns.z)); + vec<4, T, Q> y_(floor(j - T(7) * x_)); // mod(j,N) + + vec<4, T, Q> x(x_ * ns.x + ns.y); + vec<4, T, Q> y(y_ * ns.x + ns.y); + vec<4, T, Q> h(T(1) - abs(x) - abs(y)); + + vec<4, T, Q> b0(x.x, x.y, y.x, y.y); + vec<4, T, Q> b1(x.z, x.w, y.z, y.w); + + // vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + // vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec<4, T, Q> s0(floor(b0) * T(2) + T(1)); + vec<4, T, Q> s1(floor(b1) * T(2) + T(1)); + vec<4, T, Q> sh(-step(h, vec<4, T, Q>(0.0))); + + vec<4, T, Q> a0 = vec<4, T, Q>(b0.x, b0.z, b0.y, b0.w) + vec<4, T, Q>(s0.x, s0.z, s0.y, s0.w) * vec<4, T, Q>(sh.x, sh.x, sh.y, sh.y); + vec<4, T, Q> a1 = vec<4, T, Q>(b1.x, b1.z, b1.y, b1.w) + vec<4, T, Q>(s1.x, s1.z, s1.y, s1.w) * vec<4, T, Q>(sh.z, sh.z, sh.w, sh.w); + + vec<3, T, Q> p0(a0.x, a0.y, h.x); + vec<3, T, Q> p1(a0.z, a0.w, h.y); + vec<3, T, Q> p2(a1.x, a1.y, h.z); + vec<3, T, Q> p3(a1.z, a1.w, h.w); + + // Normalise gradients + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec<4, T, Q> m = max(T(0.6) - vec<4, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec<4, T, Q>(0)); + m = m * m; + return T(42) * dot(m * m, vec<4, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); + } + + template + GLM_FUNC_QUALIFIER T simplex(vec<4, T, Q> const& v) + { + vec<4, T, Q> const C( + 0.138196601125011, // (5 - sqrt(5))/20 G4 + 0.276393202250021, // 2 * G4 + 0.414589803375032, // 3 * G4 + -0.447213595499958); // -1 + 4 * G4 + + // (sqrt(5) - 1)/4 = F4, used once below + T const F4 = static_cast(0.309016994374947451); + + // First corner + vec<4, T, Q> i = floor(v + dot(v, vec<4, T, Q>(F4))); + vec<4, T, Q> x0 = v - i + dot(i, vec<4, T, Q>(C.x)); + + // Other corners + + // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) + vec<4, T, Q> i0; + vec<3, T, Q> isX = step(vec<3, T, Q>(x0.y, x0.z, x0.w), vec<3, T, Q>(x0.x)); + vec<3, T, Q> isYZ = step(vec<3, T, Q>(x0.z, x0.w, x0.w), vec<3, T, Q>(x0.y, x0.y, x0.z)); + // i0.x = dot(isX, vec3(1.0)); + //i0.x = isX.x + isX.y + isX.z; + //i0.yzw = static_cast(1) - isX; + i0 = vec<4, T, Q>(isX.x + isX.y + isX.z, T(1) - isX); + // i0.y += dot(isYZ.xy, vec2(1.0)); + i0.y += isYZ.x + isYZ.y; + //i0.zw += 1.0 - vec<2, T, Q>(isYZ.x, isYZ.y); + i0.z += static_cast(1) - isYZ.x; + i0.w += static_cast(1) - isYZ.y; + i0.z += isYZ.z; + i0.w += static_cast(1) - isYZ.z; + + // i0 now contains the unique values 0,1,2,3 in each channel + vec<4, T, Q> i3 = clamp(i0, T(0), T(1)); + vec<4, T, Q> i2 = clamp(i0 - T(1), T(0), T(1)); + vec<4, T, Q> i1 = clamp(i0 - T(2), T(0), T(1)); + + // x0 = x0 - 0.0 + 0.0 * C.xxxx + // x1 = x0 - i1 + 0.0 * C.xxxx + // x2 = x0 - i2 + 0.0 * C.xxxx + // x3 = x0 - i3 + 0.0 * C.xxxx + // x4 = x0 - 1.0 + 4.0 * C.xxxx + vec<4, T, Q> x1 = x0 - i1 + C.x; + vec<4, T, Q> x2 = x0 - i2 + C.y; + vec<4, T, Q> x3 = x0 - i3 + C.z; + vec<4, T, Q> x4 = x0 + C.w; + + // Permutations + i = mod(i, vec<4, T, Q>(289)); + T j0 = detail::permute(detail::permute(detail::permute(detail::permute(i.w) + i.z) + i.y) + i.x); + vec<4, T, Q> j1 = detail::permute(detail::permute(detail::permute(detail::permute( + i.w + vec<4, T, Q>(i1.w, i2.w, i3.w, T(1))) + + i.z + vec<4, T, Q>(i1.z, i2.z, i3.z, T(1))) + + i.y + vec<4, T, Q>(i1.y, i2.y, i3.y, T(1))) + + i.x + vec<4, T, Q>(i1.x, i2.x, i3.x, T(1))); + + // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope + // 7*7*6 = 294, which is close to the ring size 17*17 = 289. + vec<4, T, Q> ip = vec<4, T, Q>(T(1) / T(294), T(1) / T(49), T(1) / T(7), T(0)); + + vec<4, T, Q> p0 = gtc::grad4(j0, ip); + vec<4, T, Q> p1 = gtc::grad4(j1.x, ip); + vec<4, T, Q> p2 = gtc::grad4(j1.y, ip); + vec<4, T, Q> p3 = gtc::grad4(j1.z, ip); + vec<4, T, Q> p4 = gtc::grad4(j1.w, ip); + + // Normalise gradients + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + p4 *= detail::taylorInvSqrt(dot(p4, p4)); + + // Mix contributions from the five corners + vec<3, T, Q> m0 = max(T(0.6) - vec<3, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2)), vec<3, T, Q>(0)); + vec<2, T, Q> m1 = max(T(0.6) - vec<2, T, Q>(dot(x3, x3), dot(x4, x4) ), vec<2, T, Q>(0)); + m0 = m0 * m0; + m1 = m1 * m1; + return T(49) * + (dot(m0 * m0, vec<3, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2))) + + dot(m1 * m1, vec<2, T, Q>(dot(p3, x3), dot(p4, x4)))); + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/packing.hpp b/src/GLMath/glm/gtc/packing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2852395221683ab3937beb709eac8f12055fac2b --- /dev/null +++ b/src/GLMath/glm/gtc/packing.hpp @@ -0,0 +1,728 @@ +/// @ref gtc_packing +/// @file glm/gtc/packing.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_packing GLM_GTC_packing +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// This extension provides a set of function to convert vertors to packed +/// formats. + +#pragma once + +// Dependency: +#include "type_precision.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_packing extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_packing + /// @{ + + /// First, converts the normalized floating-point value v into a 8-bit integer value. + /// Then, the results are packed into the returned 8-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm1x8: round(clamp(c, 0, +1) * 255.0) + /// + /// @see gtc_packing + /// @see uint16 packUnorm2x8(vec2 const& v) + /// @see uint32 packUnorm4x8(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint8 packUnorm1x8(float v); + + /// Convert a single 8-bit integer to a normalized floating-point value. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x8(uint16 p) + /// @see vec4 unpackUnorm4x8(uint32 p) + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackUnorm1x8(uint8 p); + + /// First, converts each component of the normalized floating-point value v into 8-bit integer values. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm2x8: round(clamp(c, 0, +1) * 255.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint8 packUnorm1x8(float const& v) + /// @see uint32 packUnorm4x8(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packUnorm2x8(vec2 const& v); + + /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit unsigned integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackUnorm1x8(uint8 v) + /// @see vec4 unpackUnorm4x8(uint32 p) + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackUnorm2x8(uint16 p); + + /// First, converts the normalized floating-point value v into 8-bit integer value. + /// Then, the results are packed into the returned 8-bit unsigned integer. + /// + /// The conversion to fixed point is done as follows: + /// packSnorm1x8: round(clamp(s, -1, +1) * 127.0) + /// + /// @see gtc_packing + /// @see uint16 packSnorm2x8(vec2 const& v) + /// @see uint32 packSnorm4x8(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint8 packSnorm1x8(float s); + + /// First, unpacks a single 8-bit unsigned integer p into a single 8-bit signed integers. + /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm1x8: clamp(f / 127.0, -1, +1) + /// + /// @see gtc_packing + /// @see vec2 unpackSnorm2x8(uint16 p) + /// @see vec4 unpackSnorm4x8(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackSnorm1x8(uint8 p); + + /// First, converts each component of the normalized floating-point value v into 8-bit integer values. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x8: round(clamp(c, -1, +1) * 127.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint8 packSnorm1x8(float const& v) + /// @see uint32 packSnorm4x8(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packSnorm2x8(vec2 const& v); + + /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm2x8: clamp(f / 127.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackSnorm1x8(uint8 p) + /// @see vec4 unpackSnorm4x8(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackSnorm2x8(uint16 p); + + /// First, converts the normalized floating-point value v into a 16-bit integer value. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm1x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// @see gtc_packing + /// @see uint16 packSnorm1x16(float const& v) + /// @see uint64 packSnorm4x16(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packUnorm1x16(float v); + + /// First, unpacks a single 16-bit unsigned integer p into a of 16-bit unsigned integers. + /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm1x16: f / 65535.0 + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x16(uint32 p) + /// @see vec4 unpackUnorm4x16(uint64 p) + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackUnorm1x16(uint16 p); + + /// First, converts each component of the normalized floating-point value v into 16-bit integer values. + /// Then, the results are packed into the returned 64-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm4x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint16 packUnorm1x16(float const& v) + /// @see uint32 packUnorm2x16(vec2 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packUnorm4x16(vec4 const& v); + + /// First, unpacks a single 64-bit unsigned integer p into four 16-bit unsigned integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnormx4x16: f / 65535.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackUnorm1x16(uint16 p) + /// @see vec2 unpackUnorm2x16(uint32 p) + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackUnorm4x16(uint64 p); + + /// First, converts the normalized floating-point value v into 16-bit integer value. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion to fixed point is done as follows: + /// packSnorm1x8: round(clamp(s, -1, +1) * 32767.0) + /// + /// @see gtc_packing + /// @see uint32 packSnorm2x16(vec2 const& v) + /// @see uint64 packSnorm4x16(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packSnorm1x16(float v); + + /// First, unpacks a single 16-bit unsigned integer p into a single 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm1x16: clamp(f / 32767.0, -1, +1) + /// + /// @see gtc_packing + /// @see vec2 unpackSnorm2x16(uint32 p) + /// @see vec4 unpackSnorm4x16(uint64 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackSnorm1x16(uint16 p); + + /// First, converts each component of the normalized floating-point value v into 16-bit integer values. + /// Then, the results are packed into the returned 64-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x8: round(clamp(c, -1, +1) * 32767.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint16 packSnorm1x16(float const& v) + /// @see uint32 packSnorm2x16(vec2 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packSnorm4x16(vec4 const& v); + + /// First, unpacks a single 64-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm4x16: clamp(f / 32767.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackSnorm1x16(uint16 p) + /// @see vec2 unpackSnorm2x16(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackSnorm4x16(uint64 p); + + /// Returns an unsigned integer obtained by converting the components of a floating-point scalar + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing this 16-bit value into a 16-bit unsigned integer. + /// + /// @see gtc_packing + /// @see uint32 packHalf2x16(vec2 const& v) + /// @see uint64 packHalf4x16(vec4 const& v) + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packHalf1x16(float v); + + /// Returns a floating-point scalar with components obtained by unpacking a 16-bit unsigned integer into a 16-bit value, + /// interpreted as a 16-bit floating-point number according to the OpenGL Specification, + /// and converting it to 32-bit floating-point values. + /// + /// @see gtc_packing + /// @see vec2 unpackHalf2x16(uint32 const& v) + /// @see vec4 unpackHalf4x16(uint64 const& v) + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackHalf1x16(uint16 v); + + /// Returns an unsigned integer obtained by converting the components of a four-component floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing these four 16-bit values into a 64-bit unsigned integer. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see uint16 packHalf1x16(float const& v) + /// @see uint32 packHalf2x16(vec2 const& v) + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packHalf4x16(vec4 const& v); + + /// Returns a four-component floating-point vector with components obtained by unpacking a 64-bit unsigned integer into four 16-bit values, + /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, + /// and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see float unpackHalf1x16(uint16 const& v) + /// @see vec2 unpackHalf2x16(uint32 const& v) + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackHalf4x16(uint64 p); + + /// Returns an unsigned integer obtained by converting the components of a four-component signed integer vector + /// to the 10-10-10-2-bit signed integer representation found in the OpenGL Specification, + /// and then packing these four values into a 32-bit unsigned integer. + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see uint32 packI3x10_1x2(uvec4 const& v) + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see ivec4 unpackI3x10_1x2(uint32 const& p) + GLM_FUNC_DECL uint32 packI3x10_1x2(ivec4 const& v); + + /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit signed integers. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); + /// @see uvec4 unpackI3x10_1x2(uint32 const& p); + GLM_FUNC_DECL ivec4 unpackI3x10_1x2(uint32 p); + + /// Returns an unsigned integer obtained by converting the components of a four-component unsigned integer vector + /// to the 10-10-10-2-bit unsigned integer representation found in the OpenGL Specification, + /// and then packing these four values into a 32-bit unsigned integer. + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see uint32 packI3x10_1x2(ivec4 const& v) + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see ivec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL uint32 packU3x10_1x2(uvec4 const& v); + + /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit unsigned integers. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); + /// @see uvec4 unpackI3x10_1x2(uint32 const& p); + GLM_FUNC_DECL uvec4 unpackU3x10_1x2(uint32 p); + + /// First, converts the first three components of the normalized floating-point value v into 10-bit signed integer values. + /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm3x10_1x2(xyz): round(clamp(c, -1, +1) * 511.0) + /// packSnorm3x10_1x2(w): round(clamp(c, -1, +1) * 1.0) + /// + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see uint32 packI3x10_1x2(ivec4 const& v) + GLM_FUNC_DECL uint32 packSnorm3x10_1x2(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm3x10_1x2(xyz): clamp(f / 511.0, -1, +1) + /// unpackSnorm3x10_1x2(w): clamp(f / 511.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p)) + /// @see uvec4 unpackI3x10_1x2(uint32 const& p) + /// @see uvec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL vec4 unpackSnorm3x10_1x2(uint32 p); + + /// First, converts the first three components of the normalized floating-point value v into 10-bit unsigned integer values. + /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed uninteger values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm3x10_1x2(xyz): round(clamp(c, 0, +1) * 1023.0) + /// packUnorm3x10_1x2(w): round(clamp(c, 0, +1) * 3.0) + /// + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see uint32 packI3x10_1x2(ivec4 const& v) + GLM_FUNC_DECL uint32 packUnorm3x10_1x2(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm3x10_1x2(xyz): clamp(f / 1023.0, 0, +1) + /// unpackSnorm3x10_1x2(w): clamp(f / 3.0, 0, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see vec4 unpackInorm3x10_1x2(uint32 const& p)) + /// @see uvec4 unpackI3x10_1x2(uint32 const& p) + /// @see uvec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL vec4 unpackUnorm3x10_1x2(uint32 p); + + /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. + /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The first vector component specifies the 11 least-significant bits of the result; + /// the last component specifies the 10 most-significant bits. + /// + /// @see gtc_packing + /// @see vec3 unpackF2x11_1x10(uint32 const& p) + GLM_FUNC_DECL uint32 packF2x11_1x10(vec3 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . + /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packF2x11_1x10(vec3 const& v) + GLM_FUNC_DECL vec3 unpackF2x11_1x10(uint32 p); + + + /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. + /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The first vector component specifies the 11 least-significant bits of the result; + /// the last component specifies the 10 most-significant bits. + /// + /// packF3x9_E1x5 allows encoding into RGBE / RGB9E5 format + /// + /// @see gtc_packing + /// @see vec3 unpackF3x9_E1x5(uint32 const& p) + GLM_FUNC_DECL uint32 packF3x9_E1x5(vec3 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . + /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// unpackF3x9_E1x5 allows decoding RGBE / RGB9E5 data + /// + /// @see gtc_packing + /// @see uint32 packF3x9_E1x5(vec3 const& v) + GLM_FUNC_DECL vec3 unpackF3x9_E1x5(uint32 p); + + /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& p) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb); + + /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see vec<4, T, Q> packRGBM(vec<3, float, Q> const& v) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm); + + /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see vec unpackHalf(vec const& p) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec packHalf(vec const& v); + + /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see vec packHalf(vec const& v) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec unpackHalf(vec const& p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec unpackUnorm(vec const& p); + template + GLM_FUNC_DECL vec packUnorm(vec const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see vec packUnorm(vec const& v) + template + GLM_FUNC_DECL vec unpackUnorm(vec const& v); + + /// Convert each component of the normalized floating-point vector into signed integer values. + /// + /// @see gtc_packing + /// @see vec unpackSnorm(vec const& p); + template + GLM_FUNC_DECL vec packSnorm(vec const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see vec packSnorm(vec const& v) + template + GLM_FUNC_DECL vec unpackSnorm(vec const& v); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x4(uint8 p) + GLM_FUNC_DECL uint8 packUnorm2x4(vec2 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint8 packUnorm2x4(vec2 const& v) + GLM_FUNC_DECL vec2 unpackUnorm2x4(uint8 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm4x4(uint16 p) + GLM_FUNC_DECL uint16 packUnorm4x4(vec4 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm4x4(vec4 const& v) + GLM_FUNC_DECL vec4 unpackUnorm4x4(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec3 unpackUnorm1x5_1x6_1x5(uint16 p) + GLM_FUNC_DECL uint16 packUnorm1x5_1x6_1x5(vec3 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm1x5_1x6_1x5(vec3 const& v) + GLM_FUNC_DECL vec3 unpackUnorm1x5_1x6_1x5(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm3x5_1x1(uint16 p) + GLM_FUNC_DECL uint16 packUnorm3x5_1x1(vec4 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm3x5_1x1(vec4 const& v) + GLM_FUNC_DECL vec4 unpackUnorm3x5_1x1(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec3 unpackUnorm2x3_1x2(uint8 p) + GLM_FUNC_DECL uint8 packUnorm2x3_1x2(vec3 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint8 packUnorm2x3_1x2(vec3 const& v) + GLM_FUNC_DECL vec3 unpackUnorm2x3_1x2(uint8 p); + + + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see i8vec2 unpackInt2x8(int16 p) + GLM_FUNC_DECL int16 packInt2x8(i8vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int16 packInt2x8(i8vec2 const& v) + GLM_FUNC_DECL i8vec2 unpackInt2x8(int16 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u8vec2 unpackInt2x8(uint16 p) + GLM_FUNC_DECL uint16 packUint2x8(u8vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint16 packInt2x8(u8vec2 const& v) + GLM_FUNC_DECL u8vec2 unpackUint2x8(uint16 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see i8vec4 unpackInt4x8(int32 p) + GLM_FUNC_DECL int32 packInt4x8(i8vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int32 packInt2x8(i8vec4 const& v) + GLM_FUNC_DECL i8vec4 unpackInt4x8(int32 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u8vec4 unpackUint4x8(uint32 p) + GLM_FUNC_DECL uint32 packUint4x8(u8vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint32 packUint4x8(u8vec2 const& v) + GLM_FUNC_DECL u8vec4 unpackUint4x8(uint32 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see i16vec2 unpackInt2x16(int p) + GLM_FUNC_DECL int packInt2x16(i16vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packInt2x16(i16vec2 const& v) + GLM_FUNC_DECL i16vec2 unpackInt2x16(int p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see i16vec4 unpackInt4x16(int64 p) + GLM_FUNC_DECL int64 packInt4x16(i16vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int64 packInt4x16(i16vec4 const& v) + GLM_FUNC_DECL i16vec4 unpackInt4x16(int64 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u16vec2 unpackUint2x16(uint p) + GLM_FUNC_DECL uint packUint2x16(u16vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint packUint2x16(u16vec2 const& v) + GLM_FUNC_DECL u16vec2 unpackUint2x16(uint p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u16vec4 unpackUint4x16(uint64 p) + GLM_FUNC_DECL uint64 packUint4x16(u16vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint64 packUint4x16(u16vec4 const& v) + GLM_FUNC_DECL u16vec4 unpackUint4x16(uint64 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see i32vec2 unpackInt2x32(int p) + GLM_FUNC_DECL int64 packInt2x32(i32vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packInt2x16(i32vec2 const& v) + GLM_FUNC_DECL i32vec2 unpackInt2x32(int64 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u32vec2 unpackUint2x32(int p) + GLM_FUNC_DECL uint64 packUint2x32(u32vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packUint2x16(u32vec2 const& v) + GLM_FUNC_DECL u32vec2 unpackUint2x32(uint64 p); + + + /// @} +}// namespace glm + +#include "packing.inl" diff --git a/src/GLMath/glm/gtc/packing.inl b/src/GLMath/glm/gtc/packing.inl new file mode 100644 index 0000000000000000000000000000000000000000..8c906e16c11aac784720d8a5ec29b49729e840eb --- /dev/null +++ b/src/GLMath/glm/gtc/packing.inl @@ -0,0 +1,938 @@ +/// @ref gtc_packing + +#include "../ext/scalar_relational.hpp" +#include "../ext/vector_relational.hpp" +#include "../common.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../detail/type_half.hpp" +#include +#include + +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER glm::uint16 float2half(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((f >> 16) & 0x8000) | // sign + ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | // exponential + ((f >> 13) & 0x03ff); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 float2packed11(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x000007c0 => 00000000 00000000 00000111 11000000 + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((f & 0x7f800000) - 0x38000000) >> 17) & 0x07c0) | // exponential + ((f >> 17) & 0x003f); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 packed11ToFloat(glm::uint32 p) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x000007c0 => 00000000 00000000 00000111 11000000 + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((p & 0x07c0) << 17) + 0x38000000) & 0x7f800000) | // exponential + ((p & 0x003f) << 17); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 float2packed10(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x0000001F => 00000000 00000000 00000000 00011111 + // 0x0000003F => 00000000 00000000 00000000 00111111 + // 0x000003E0 => 00000000 00000000 00000011 11100000 + // 0x000007C0 => 00000000 00000000 00000111 11000000 + // 0x00007C00 => 00000000 00000000 01111100 00000000 + // 0x000003FF => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((f & 0x7f800000) - 0x38000000) >> 18) & 0x03E0) | // exponential + ((f >> 18) & 0x001f); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 packed10ToFloat(glm::uint32 p) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x0000001F => 00000000 00000000 00000000 00011111 + // 0x0000003F => 00000000 00000000 00000000 00111111 + // 0x000003E0 => 00000000 00000000 00000011 11100000 + // 0x000007C0 => 00000000 00000000 00000111 11000000 + // 0x00007C00 => 00000000 00000000 01111100 00000000 + // 0x000003FF => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((p & 0x03E0) << 18) + 0x38000000) & 0x7f800000) | // exponential + ((p & 0x001f) << 18); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint half2float(glm::uint h) + { + return ((h & 0x8000) << 16) | ((( h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); + } + + GLM_FUNC_QUALIFIER glm::uint floatTo11bit(float x) + { + if(x == 0.0f) + return 0u; + else if(glm::isnan(x)) + return ~0u; + else if(glm::isinf(x)) + return 0x1Fu << 6u; + + uint Pack = 0u; + memcpy(&Pack, &x, sizeof(Pack)); + return float2packed11(Pack); + } + + GLM_FUNC_QUALIFIER float packed11bitToFloat(glm::uint x) + { + if(x == 0) + return 0.0f; + else if(x == ((1 << 11) - 1)) + return ~0;//NaN + else if(x == (0x1f << 6)) + return ~0;//Inf + + uint Result = packed11ToFloat(x); + + float Temp = 0; + memcpy(&Temp, &Result, sizeof(Temp)); + return Temp; + } + + GLM_FUNC_QUALIFIER glm::uint floatTo10bit(float x) + { + if(x == 0.0f) + return 0u; + else if(glm::isnan(x)) + return ~0u; + else if(glm::isinf(x)) + return 0x1Fu << 5u; + + uint Pack = 0; + memcpy(&Pack, &x, sizeof(Pack)); + return float2packed10(Pack); + } + + GLM_FUNC_QUALIFIER float packed10bitToFloat(glm::uint x) + { + if(x == 0) + return 0.0f; + else if(x == ((1 << 10) - 1)) + return ~0;//NaN + else if(x == (0x1f << 5)) + return ~0;//Inf + + uint Result = packed10ToFloat(x); + + float Temp = 0; + memcpy(&Temp, &Result, sizeof(Temp)); + return Temp; + } + +// GLM_FUNC_QUALIFIER glm::uint f11_f11_f10(float x, float y, float z) +// { +// return ((floatTo11bit(x) & ((1 << 11) - 1)) << 0) | ((floatTo11bit(y) & ((1 << 11) - 1)) << 11) | ((floatTo10bit(z) & ((1 << 10) - 1)) << 22); +// } + + union u3u3u2 + { + struct + { + uint x : 3; + uint y : 3; + uint z : 2; + } data; + uint8 pack; + }; + + union u4u4 + { + struct + { + uint x : 4; + uint y : 4; + } data; + uint8 pack; + }; + + union u4u4u4u4 + { + struct + { + uint x : 4; + uint y : 4; + uint z : 4; + uint w : 4; + } data; + uint16 pack; + }; + + union u5u6u5 + { + struct + { + uint x : 5; + uint y : 6; + uint z : 5; + } data; + uint16 pack; + }; + + union u5u5u5u1 + { + struct + { + uint x : 5; + uint y : 5; + uint z : 5; + uint w : 1; + } data; + uint16 pack; + }; + + union u10u10u10u2 + { + struct + { + uint x : 10; + uint y : 10; + uint z : 10; + uint w : 2; + } data; + uint32 pack; + }; + + union i10i10i10i2 + { + struct + { + int x : 10; + int y : 10; + int z : 10; + int w : 2; + } data; + uint32 pack; + }; + + union u9u9u9e5 + { + struct + { + uint x : 9; + uint y : 9; + uint z : 9; + uint w : 5; + } data; + uint32 pack; + }; + + template + struct compute_half + {}; + + template + struct compute_half<1, Q> + { + GLM_FUNC_QUALIFIER static vec<1, uint16, Q> pack(vec<1, float, Q> const& v) + { + int16 const Unpack(detail::toFloat16(v.x)); + u16vec1 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<1, float, Q> unpack(vec<1, uint16, Q> const& v) + { + i16vec1 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<1, float, Q>(detail::toFloat32(v.x)); + } + }; + + template + struct compute_half<2, Q> + { + GLM_FUNC_QUALIFIER static vec<2, uint16, Q> pack(vec<2, float, Q> const& v) + { + vec<2, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y)); + u16vec2 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<2, float, Q> unpack(vec<2, uint16, Q> const& v) + { + i16vec2 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<2, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y)); + } + }; + + template + struct compute_half<3, Q> + { + GLM_FUNC_QUALIFIER static vec<3, uint16, Q> pack(vec<3, float, Q> const& v) + { + vec<3, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z)); + u16vec3 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<3, float, Q> unpack(vec<3, uint16, Q> const& v) + { + i16vec3 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<3, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z)); + } + }; + + template + struct compute_half<4, Q> + { + GLM_FUNC_QUALIFIER static vec<4, uint16, Q> pack(vec<4, float, Q> const& v) + { + vec<4, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z), detail::toFloat16(v.w)); + u16vec4 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<4, float, Q> unpack(vec<4, uint16, Q> const& v) + { + i16vec4 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<4, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z), detail::toFloat32(v.w)); + } + }; +}//namespace detail + + GLM_FUNC_QUALIFIER uint8 packUnorm1x8(float v) + { + return static_cast(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + } + + GLM_FUNC_QUALIFIER float unpackUnorm1x8(uint8 p) + { + float const Unpack(p); + return Unpack * static_cast(0.0039215686274509803921568627451); // 1 / 255 + } + + GLM_FUNC_QUALIFIER uint16 packUnorm2x8(vec2 const& v) + { + u8vec2 const Topack(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + + uint16 Unpack = 0; + memcpy(&Unpack, &Topack, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x8(uint16 p) + { + u8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return vec2(Unpack) * float(0.0039215686274509803921568627451); // 1 / 255 + } + + GLM_FUNC_QUALIFIER uint8 packSnorm1x8(float v) + { + int8 const Topack(static_cast(round(clamp(v ,-1.0f, 1.0f) * 127.0f))); + uint8 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackSnorm1x8(uint8 p) + { + int8 Unpack = 0; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + static_cast(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packSnorm2x8(vec2 const& v) + { + i8vec2 const Topack(round(clamp(v, -1.0f, 1.0f) * 127.0f)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec2 unpackSnorm2x8(uint16 p) + { + i8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + vec2(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packUnorm1x16(float s) + { + return static_cast(round(clamp(s, 0.0f, 1.0f) * 65535.0f)); + } + + GLM_FUNC_QUALIFIER float unpackUnorm1x16(uint16 p) + { + float const Unpack(p); + return Unpack * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 + } + + GLM_FUNC_QUALIFIER uint64 packUnorm4x16(vec4 const& v) + { + u16vec4 const Topack(round(clamp(v , 0.0f, 1.0f) * 65535.0f)); + uint64 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x16(uint64 p) + { + u16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return vec4(Unpack) * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 + } + + GLM_FUNC_QUALIFIER uint16 packSnorm1x16(float v) + { + int16 const Topack = static_cast(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackSnorm1x16(uint16 p) + { + int16 Unpack = 0; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + static_cast(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint64 packSnorm4x16(vec4 const& v) + { + i16vec4 const Topack(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); + uint64 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec4 unpackSnorm4x16(uint64 p) + { + i16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + vec4(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packHalf1x16(float v) + { + int16 const Topack(detail::toFloat16(v)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackHalf1x16(uint16 v) + { + int16 Unpack = 0; + memcpy(&Unpack, &v, sizeof(Unpack)); + return detail::toFloat32(Unpack); + } + + GLM_FUNC_QUALIFIER uint64 packHalf4x16(glm::vec4 const& v) + { + i16vec4 const Unpack( + detail::toFloat16(v.x), + detail::toFloat16(v.y), + detail::toFloat16(v.z), + detail::toFloat16(v.w)); + uint64 Packed = 0; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER glm::vec4 unpackHalf4x16(uint64 v) + { + i16vec4 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec4( + detail::toFloat32(Unpack.x), + detail::toFloat32(Unpack.y), + detail::toFloat32(Unpack.z), + detail::toFloat32(Unpack.w)); + } + + GLM_FUNC_QUALIFIER uint32 packI3x10_1x2(ivec4 const& v) + { + detail::i10i10i10i2 Result; + Result.data.x = v.x; + Result.data.y = v.y; + Result.data.z = v.z; + Result.data.w = v.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER ivec4 unpackI3x10_1x2(uint32 v) + { + detail::i10i10i10i2 Unpack; + Unpack.pack = v; + return ivec4( + Unpack.data.x, + Unpack.data.y, + Unpack.data.z, + Unpack.data.w); + } + + GLM_FUNC_QUALIFIER uint32 packU3x10_1x2(uvec4 const& v) + { + detail::u10u10u10u2 Result; + Result.data.x = v.x; + Result.data.y = v.y; + Result.data.z = v.z; + Result.data.w = v.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER uvec4 unpackU3x10_1x2(uint32 v) + { + detail::u10u10u10u2 Unpack; + Unpack.pack = v; + return uvec4( + Unpack.data.x, + Unpack.data.y, + Unpack.data.z, + Unpack.data.w); + } + + GLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const& v) + { + ivec4 const Pack(round(clamp(v,-1.0f, 1.0f) * vec4(511.f, 511.f, 511.f, 1.f))); + + detail::i10i10i10i2 Result; + Result.data.x = Pack.x; + Result.data.y = Pack.y; + Result.data.z = Pack.z; + Result.data.w = Pack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackSnorm3x10_1x2(uint32 v) + { + detail::i10i10i10i2 Unpack; + Unpack.pack = v; + + vec4 const Result(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w); + + return clamp(Result * vec4(1.f / 511.f, 1.f / 511.f, 1.f / 511.f, 1.f), -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint32 packUnorm3x10_1x2(vec4 const& v) + { + uvec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(1023.f, 1023.f, 1023.f, 3.f))); + + detail::u10u10u10u2 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm3x10_1x2(uint32 v) + { + vec4 const ScaleFactors(1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 3.f); + + detail::u10u10u10u2 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactors; + } + + GLM_FUNC_QUALIFIER uint32 packF2x11_1x10(vec3 const& v) + { + return + ((detail::floatTo11bit(v.x) & ((1 << 11) - 1)) << 0) | + ((detail::floatTo11bit(v.y) & ((1 << 11) - 1)) << 11) | + ((detail::floatTo10bit(v.z) & ((1 << 10) - 1)) << 22); + } + + GLM_FUNC_QUALIFIER vec3 unpackF2x11_1x10(uint32 v) + { + return vec3( + detail::packed11bitToFloat(v >> 0), + detail::packed11bitToFloat(v >> 11), + detail::packed10bitToFloat(v >> 22)); + } + + GLM_FUNC_QUALIFIER uint32 packF3x9_E1x5(vec3 const& v) + { + float const SharedExpMax = (pow(2.0f, 9.0f - 1.0f) / pow(2.0f, 9.0f)) * pow(2.0f, 31.f - 15.f); + vec3 const Color = clamp(v, 0.0f, SharedExpMax); + float const MaxColor = max(Color.x, max(Color.y, Color.z)); + + float const ExpSharedP = max(-15.f - 1.f, floor(log2(MaxColor))) + 1.0f + 15.f; + float const MaxShared = floor(MaxColor / pow(2.0f, (ExpSharedP - 15.f - 9.f)) + 0.5f); + float const ExpShared = equal(MaxShared, pow(2.0f, 9.0f), epsilon()) ? ExpSharedP + 1.0f : ExpSharedP; + + uvec3 const ColorComp(floor(Color / pow(2.f, (ExpShared - 15.f - 9.f)) + 0.5f)); + + detail::u9u9u9e5 Unpack; + Unpack.data.x = ColorComp.x; + Unpack.data.y = ColorComp.y; + Unpack.data.z = ColorComp.z; + Unpack.data.w = uint(ExpShared); + return Unpack.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackF3x9_E1x5(uint32 v) + { + detail::u9u9u9e5 Unpack; + Unpack.pack = v; + + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * pow(2.0f, Unpack.data.w - 15.f - 9.f); + } + + // Based on Brian Karis http://graphicrants.blogspot.fr/2009/04/rgbm-color-encoding.html + template + GLM_FUNC_QUALIFIER vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb) + { + vec<3, T, Q> const Color(rgb * static_cast(1.0 / 6.0)); + T Alpha = clamp(max(max(Color.x, Color.y), max(Color.z, static_cast(1e-6))), static_cast(0), static_cast(1)); + Alpha = ceil(Alpha * static_cast(255.0)) / static_cast(255.0); + return vec<4, T, Q>(Color / Alpha, Alpha); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm) + { + return vec<3, T, Q>(rgbm.x, rgbm.y, rgbm.z) * rgbm.w * static_cast(6); + } + + template + GLM_FUNC_QUALIFIER vec packHalf(vec const& v) + { + return detail::compute_half::pack(v); + } + + template + GLM_FUNC_QUALIFIER vec unpackHalf(vec const& v) + { + return detail::compute_half::unpack(v); + } + + template + GLM_FUNC_QUALIFIER vec packUnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(round(clamp(v, static_cast(0), static_cast(1)) * static_cast(std::numeric_limits::max()))); + } + + template + GLM_FUNC_QUALIFIER vec unpackUnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())); + } + + template + GLM_FUNC_QUALIFIER vec packSnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(round(clamp(v , static_cast(-1), static_cast(1)) * static_cast(std::numeric_limits::max()))); + } + + template + GLM_FUNC_QUALIFIER vec unpackSnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return clamp(vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())), static_cast(-1), static_cast(1)); + } + + GLM_FUNC_QUALIFIER uint8 packUnorm2x4(vec2 const& v) + { + u32vec2 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); + detail::u4u4 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x4(uint8 v) + { + float const ScaleFactor(1.f / 15.f); + detail::u4u4 Unpack; + Unpack.pack = v; + return vec2(Unpack.data.x, Unpack.data.y) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm4x4(vec4 const& v) + { + u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); + detail::u4u4u4u4 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x4(uint16 v) + { + float const ScaleFactor(1.f / 15.f); + detail::u4u4u4u4 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm1x5_1x6_1x5(vec3 const& v) + { + u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(31.f, 63.f, 31.f))); + detail::u5u6u5 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackUnorm1x5_1x6_1x5(uint16 v) + { + vec3 const ScaleFactor(1.f / 31.f, 1.f / 63.f, 1.f / 31.f); + detail::u5u6u5 Unpack; + Unpack.pack = v; + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm3x5_1x1(vec4 const& v) + { + u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(31.f, 31.f, 31.f, 1.f))); + detail::u5u5u5u1 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm3x5_1x1(uint16 v) + { + vec4 const ScaleFactor(1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f); + detail::u5u5u5u1 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint8 packUnorm2x3_1x2(vec3 const& v) + { + u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(7.f, 7.f, 3.f))); + detail::u3u3u2 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackUnorm2x3_1x2(uint8 v) + { + vec3 const ScaleFactor(1.f / 7.f, 1.f / 7.f, 1.f / 3.f); + detail::u3u3u2 Unpack; + Unpack.pack = v; + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER int16 packInt2x8(i8vec2 const& v) + { + int16 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i8vec2 unpackInt2x8(int16 p) + { + i8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint16 packUint2x8(u8vec2 const& v) + { + uint16 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u8vec2 unpackUint2x8(uint16 p) + { + u8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int32 packInt4x8(i8vec4 const& v) + { + int32 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i8vec4 unpackInt4x8(int32 p) + { + i8vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint32 packUint4x8(u8vec4 const& v) + { + uint32 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u8vec4 unpackUint4x8(uint32 p) + { + u8vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int packInt2x16(i16vec2 const& v) + { + int Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i16vec2 unpackInt2x16(int p) + { + i16vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int64 packInt4x16(i16vec4 const& v) + { + int64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i16vec4 unpackInt4x16(int64 p) + { + i16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint packUint2x16(u16vec2 const& v) + { + uint Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u16vec2 unpackUint2x16(uint p) + { + u16vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint64 packUint4x16(u16vec4 const& v) + { + uint64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u16vec4 unpackUint4x16(uint64 p) + { + u16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int64 packInt2x32(i32vec2 const& v) + { + int64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i32vec2 unpackInt2x32(int64 p) + { + i32vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint64 packUint2x32(u32vec2 const& v) + { + uint64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u32vec2 unpackUint2x32(uint64 p) + { + u32vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } +}//namespace glm + diff --git a/src/GLMath/glm/gtc/quaternion.hpp b/src/GLMath/glm/gtc/quaternion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..359e072b9fa8d7667d54f3afc8ba63ec23563ddf --- /dev/null +++ b/src/GLMath/glm/gtc/quaternion.hpp @@ -0,0 +1,173 @@ +/// @ref gtc_quaternion +/// @file glm/gtc/quaternion.hpp +/// +/// @see core (dependence) +/// @see gtc_constants (dependence) +/// +/// @defgroup gtc_quaternion GLM_GTC_quaternion +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines a templated quaternion type and several quaternion operations. + +#pragma once + +// Dependency: +#include "../gtc/constants.hpp" +#include "../gtc/matrix_transform.hpp" +#include "../ext/vector_relational.hpp" +#include "../ext/quaternion_common.hpp" +#include "../ext/quaternion_float.hpp" +#include "../ext/quaternion_float_precision.hpp" +#include "../ext/quaternion_double.hpp" +#include "../ext/quaternion_double_precision.hpp" +#include "../ext/quaternion_relational.hpp" +#include "../ext/quaternion_geometric.hpp" +#include "../ext/quaternion_trigonometric.hpp" +#include "../ext/quaternion_transform.hpp" +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat4x4.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_quaternion extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_quaternion + /// @{ + + /// Returns euler angles, pitch as x, yaw as y, roll as z. + /// The result is expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> eulerAngles(qua const& x); + + /// Returns roll value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T roll(qua const& x); + + /// Returns pitch value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T pitch(qua const& x); + + /// Returns yaw value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T yaw(qua const& x); + + /// Converts a quaternion to a 3 * 3 matrix. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL mat<3, 3, T, Q> mat3_cast(qua const& x); + + /// Converts a quaternion to a 4 * 4 matrix. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL mat<4, 4, T, Q> mat4_cast(qua const& x); + + /// Converts a pure rotation 3 * 3 matrix to a quaternion. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL qua quat_cast(mat<3, 3, T, Q> const& x); + + /// Converts a pure rotation 4 * 4 matrix to a quaternion. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL qua quat_cast(mat<4, 4, T, Q> const& x); + + /// Returns the component-wise comparison result of x < y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> lessThan(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x <= y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x > y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> greaterThan(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x >= y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y); + + /// Build a look at quaternion based on the default handedness. + /// + /// @param direction Desired forward direction. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAt( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + + /// Build a right-handed look at quaternion. + /// + /// @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAtRH( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + + /// Build a left-handed look at quaternion. + /// + /// @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAtLH( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + /// @} +} //namespace glm + +#include "quaternion.inl" diff --git a/src/GLMath/glm/gtc/quaternion.inl b/src/GLMath/glm/gtc/quaternion.inl new file mode 100644 index 0000000000000000000000000000000000000000..9dd037ee84d9e4db6b18e69c209cba5f5d242e8a --- /dev/null +++ b/src/GLMath/glm/gtc/quaternion.inl @@ -0,0 +1,200 @@ +#include "../trigonometric.hpp" +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "epsilon.hpp" +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> eulerAngles(qua const& x) + { + return vec<3, T, Q>(pitch(x), yaw(x), roll(x)); + } + + template + GLM_FUNC_QUALIFIER T roll(qua const& q) + { + return static_cast(atan(static_cast(2) * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z)); + } + + template + GLM_FUNC_QUALIFIER T pitch(qua const& q) + { + //return T(atan(T(2) * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z)); + T const y = static_cast(2) * (q.y * q.z + q.w * q.x); + T const x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z; + + if(all(equal(vec<2, T, Q>(x, y), vec<2, T, Q>(0), epsilon()))) //avoid atan2(0,0) - handle singularity - Matiis + return static_cast(static_cast(2) * atan(q.x, q.w)); + + return static_cast(atan(y, x)); + } + + template + GLM_FUNC_QUALIFIER T yaw(qua const& q) + { + return asin(clamp(static_cast(-2) * (q.x * q.z - q.w * q.y), static_cast(-1), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat3_cast(qua const& q) + { + mat<3, 3, T, Q> Result(T(1)); + T qxx(q.x * q.x); + T qyy(q.y * q.y); + T qzz(q.z * q.z); + T qxz(q.x * q.z); + T qxy(q.x * q.y); + T qyz(q.y * q.z); + T qwx(q.w * q.x); + T qwy(q.w * q.y); + T qwz(q.w * q.z); + + Result[0][0] = T(1) - T(2) * (qyy + qzz); + Result[0][1] = T(2) * (qxy + qwz); + Result[0][2] = T(2) * (qxz - qwy); + + Result[1][0] = T(2) * (qxy - qwz); + Result[1][1] = T(1) - T(2) * (qxx + qzz); + Result[1][2] = T(2) * (qyz + qwx); + + Result[2][0] = T(2) * (qxz + qwy); + Result[2][1] = T(2) * (qyz - qwx); + Result[2][2] = T(1) - T(2) * (qxx + qyy); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat4_cast(qua const& q) + { + return mat<4, 4, T, Q>(mat3_cast(q)); + } + + template + GLM_FUNC_QUALIFIER qua quat_cast(mat<3, 3, T, Q> const& m) + { + T fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2]; + T fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2]; + T fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1]; + T fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2]; + + int biggestIndex = 0; + T fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if(fourXSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + if(fourYSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + if(fourZSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + + T biggestVal = sqrt(fourBiggestSquaredMinus1 + static_cast(1)) * static_cast(0.5); + T mult = static_cast(0.25) / biggestVal; + + switch(biggestIndex) + { + case 0: + return qua(biggestVal, (m[1][2] - m[2][1]) * mult, (m[2][0] - m[0][2]) * mult, (m[0][1] - m[1][0]) * mult); + case 1: + return qua((m[1][2] - m[2][1]) * mult, biggestVal, (m[0][1] + m[1][0]) * mult, (m[2][0] + m[0][2]) * mult); + case 2: + return qua((m[2][0] - m[0][2]) * mult, (m[0][1] + m[1][0]) * mult, biggestVal, (m[1][2] + m[2][1]) * mult); + case 3: + return qua((m[0][1] - m[1][0]) * mult, (m[2][0] + m[0][2]) * mult, (m[1][2] + m[2][1]) * mult, biggestVal); + default: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity. + assert(false); + return qua(1, 0, 0, 0); + } + } + + template + GLM_FUNC_QUALIFIER qua quat_cast(mat<4, 4, T, Q> const& m4) + { + return quat_cast(mat<3, 3, T, Q>(m4)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThan(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] < y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] <= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThan(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] > y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] >= y[i]; + return Result; + } + + + template + GLM_FUNC_QUALIFIER qua quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return quatLookAtLH(direction, up); +# else + return quatLookAtRH(direction, up); +# endif + } + + template + GLM_FUNC_QUALIFIER qua quatLookAtRH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { + mat<3, 3, T, Q> Result; + + Result[2] = -direction; + Result[0] = normalize(cross(up, Result[2])); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } + + template + GLM_FUNC_QUALIFIER qua quatLookAtLH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { + mat<3, 3, T, Q> Result; + + Result[2] = direction; + Result[0] = normalize(cross(up, Result[2])); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "quaternion_simd.inl" +#endif + diff --git a/src/GLMath/glm/gtc/quaternion_simd.inl b/src/GLMath/glm/gtc/quaternion_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/GLMath/glm/gtc/random.hpp b/src/GLMath/glm/gtc/random.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9a859580e409c1d3ef1d11f89c91f1b8aa7b56d1 --- /dev/null +++ b/src/GLMath/glm/gtc/random.hpp @@ -0,0 +1,82 @@ +/// @ref gtc_random +/// @file glm/gtc/random.hpp +/// +/// @see core (dependence) +/// @see gtx_random (extended) +/// +/// @defgroup gtc_random GLM_GTC_random +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Generate random number from various distribution methods. + +#pragma once + +// Dependency: +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_random extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_random + /// @{ + + /// Generate random numbers in the interval [Min, Max], according a linear distribution + /// + /// @param Min Minimum value included in the sampling + /// @param Max Maximum value included in the sampling + /// @tparam genType Value type. Currently supported: float or double scalars. + /// @see gtc_random + template + GLM_FUNC_DECL genType linearRand(genType Min, genType Max); + + /// Generate random numbers in the interval [Min, Max], according a linear distribution + /// + /// @param Min Minimum value included in the sampling + /// @param Max Maximum value included in the sampling + /// @tparam T Value type. Currently supported: float or double. + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec linearRand(vec const& Min, vec const& Max); + + /// Generate random numbers in the interval [Min, Max], according a gaussian distribution + /// + /// @see gtc_random + template + GLM_FUNC_DECL genType gaussRand(genType Mean, genType Deviation); + + /// Generate a random 2D vector which coordinates are regulary distributed on a circle of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<2, T, defaultp> circularRand(T Radius); + + /// Generate a random 3D vector which coordinates are regulary distributed on a sphere of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<3, T, defaultp> sphericalRand(T Radius); + + /// Generate a random 2D vector which coordinates are regulary distributed within the area of a disk of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<2, T, defaultp> diskRand(T Radius); + + /// Generate a random 3D vector which coordinates are regulary distributed within the volume of a ball of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<3, T, defaultp> ballRand(T Radius); + + /// @} +}//namespace glm + +#include "random.inl" diff --git a/src/GLMath/glm/gtc/random.inl b/src/GLMath/glm/gtc/random.inl new file mode 100644 index 0000000000000000000000000000000000000000..de10a409dd9327b6674bea5d05455cca784ea3a0 --- /dev/null +++ b/src/GLMath/glm/gtc/random.inl @@ -0,0 +1,303 @@ +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "../trigonometric.hpp" +#include "../detail/type_vec1.hpp" +#include +#include +#include +#include + +namespace glm{ +namespace detail +{ + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call(); + }; + + template + struct compute_rand<1, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<1, uint8, P> call() + { + return vec<1, uint8, P>( + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<2, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<2, uint8, P> call() + { + return vec<2, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<3, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<3, uint8, P> call() + { + return vec<3, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<4, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<4, uint8, P> call() + { + return vec<4, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(8)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(16)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(32)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max); + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER genType linearRand(genType Min, genType Max) + { + return detail::compute_linearRand<1, genType, highp>::call( + vec<1, genType, highp>(Min), + vec<1, genType, highp>(Max)).x; + } + + template + GLM_FUNC_QUALIFIER vec linearRand(vec const& Min, vec const& Max) + { + return detail::compute_linearRand::call(Min, Max); + } + + template + GLM_FUNC_QUALIFIER genType gaussRand(genType Mean, genType Deviation) + { + genType w, x1, x2; + + do + { + x1 = linearRand(genType(-1), genType(1)); + x2 = linearRand(genType(-1), genType(1)); + + w = x1 * x1 + x2 * x2; + } while(w > genType(1)); + + return x2 * Deviation * Deviation * sqrt((genType(-2) * log(w)) / w) + Mean; + } + + template + GLM_FUNC_QUALIFIER vec gaussRand(vec const& Mean, vec const& Deviation) + { + return detail::functor2::call(gaussRand, Mean, Deviation); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> diskRand(T Radius) + { + assert(Radius > static_cast(0)); + + vec<2, T, defaultp> Result(T(0)); + T LenRadius(T(0)); + + do + { + Result = linearRand( + vec<2, T, defaultp>(-Radius), + vec<2, T, defaultp>(Radius)); + LenRadius = length(Result); + } + while(LenRadius > Radius); + + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> ballRand(T Radius) + { + assert(Radius > static_cast(0)); + + vec<3, T, defaultp> Result(T(0)); + T LenRadius(T(0)); + + do + { + Result = linearRand( + vec<3, T, defaultp>(-Radius), + vec<3, T, defaultp>(Radius)); + LenRadius = length(Result); + } + while(LenRadius > Radius); + + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> circularRand(T Radius) + { + assert(Radius > static_cast(0)); + + T a = linearRand(T(0), static_cast(6.283185307179586476925286766559)); + return vec<2, T, defaultp>(glm::cos(a), glm::sin(a)) * Radius; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> sphericalRand(T Radius) + { + assert(Radius > static_cast(0)); + + T theta = linearRand(T(0), T(6.283185307179586476925286766559f)); + T phi = std::acos(linearRand(T(-1.0f), T(1.0f))); + + T x = std::sin(phi) * std::cos(theta); + T y = std::sin(phi) * std::sin(theta); + T z = std::cos(phi); + + return vec<3, T, defaultp>(x, y, z) * Radius; + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/reciprocal.hpp b/src/GLMath/glm/gtc/reciprocal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c7d1330383827ef0e7b6be0441c09fdf7b5d60b6 --- /dev/null +++ b/src/GLMath/glm/gtc/reciprocal.hpp @@ -0,0 +1,135 @@ +/// @ref gtc_reciprocal +/// @file glm/gtc/reciprocal.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_reciprocal GLM_GTC_reciprocal +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Define secant, cosecant and cotangent functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_reciprocal extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_reciprocal + /// @{ + + /// Secant function. + /// hypotenuse / adjacent or 1 / cos(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType sec(genType angle); + + /// Cosecant function. + /// hypotenuse / opposite or 1 / sin(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType csc(genType angle); + + /// Cotangent function. + /// adjacent / opposite or 1 / tan(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType cot(genType angle); + + /// Inverse secant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType asec(genType x); + + /// Inverse cosecant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acsc(genType x); + + /// Inverse cotangent function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acot(genType x); + + /// Secant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType sech(genType angle); + + /// Cosecant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType csch(genType angle); + + /// Cotangent hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType coth(genType angle); + + /// Inverse secant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType asech(genType x); + + /// Inverse cosecant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acsch(genType x); + + /// Inverse cotangent hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acoth(genType x); + + /// @} +}//namespace glm + +#include "reciprocal.inl" diff --git a/src/GLMath/glm/gtc/reciprocal.inl b/src/GLMath/glm/gtc/reciprocal.inl new file mode 100644 index 0000000000000000000000000000000000000000..d88729e88f4098ca26ce757f54b88318d29bc45d --- /dev/null +++ b/src/GLMath/glm/gtc/reciprocal.inl @@ -0,0 +1,191 @@ +/// @ref gtc_reciprocal + +#include "../trigonometric.hpp" +#include + +namespace glm +{ + // sec + template + GLM_FUNC_QUALIFIER genType sec(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point values"); + return genType(1) / glm::cos(angle); + } + + template + GLM_FUNC_QUALIFIER vec sec(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point inputs"); + return detail::functor1::call(sec, x); + } + + // csc + template + GLM_FUNC_QUALIFIER genType csc(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point values"); + return genType(1) / glm::sin(angle); + } + + template + GLM_FUNC_QUALIFIER vec csc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point inputs"); + return detail::functor1::call(csc, x); + } + + // cot + template + GLM_FUNC_QUALIFIER genType cot(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point values"); + + genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); + return glm::tan(pi_over_2 - angle); + } + + template + GLM_FUNC_QUALIFIER vec cot(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point inputs"); + return detail::functor1::call(cot, x); + } + + // asec + template + GLM_FUNC_QUALIFIER genType asec(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point values"); + return acos(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec asec(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point inputs"); + return detail::functor1::call(asec, x); + } + + // acsc + template + GLM_FUNC_QUALIFIER genType acsc(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point values"); + return asin(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec acsc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point inputs"); + return detail::functor1::call(acsc, x); + } + + // acot + template + GLM_FUNC_QUALIFIER genType acot(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point values"); + + genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); + return pi_over_2 - atan(x); + } + + template + GLM_FUNC_QUALIFIER vec acot(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point inputs"); + return detail::functor1::call(acot, x); + } + + // sech + template + GLM_FUNC_QUALIFIER genType sech(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point values"); + return genType(1) / glm::cosh(angle); + } + + template + GLM_FUNC_QUALIFIER vec sech(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point inputs"); + return detail::functor1::call(sech, x); + } + + // csch + template + GLM_FUNC_QUALIFIER genType csch(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point values"); + return genType(1) / glm::sinh(angle); + } + + template + GLM_FUNC_QUALIFIER vec csch(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point inputs"); + return detail::functor1::call(csch, x); + } + + // coth + template + GLM_FUNC_QUALIFIER genType coth(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point values"); + return glm::cosh(angle) / glm::sinh(angle); + } + + template + GLM_FUNC_QUALIFIER vec coth(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point inputs"); + return detail::functor1::call(coth, x); + } + + // asech + template + GLM_FUNC_QUALIFIER genType asech(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point values"); + return acosh(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec asech(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point inputs"); + return detail::functor1::call(asech, x); + } + + // acsch + template + GLM_FUNC_QUALIFIER genType acsch(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point values"); + return asinh(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec acsch(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point inputs"); + return detail::functor1::call(acsch, x); + } + + // acoth + template + GLM_FUNC_QUALIFIER genType acoth(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point values"); + return atanh(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec acoth(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point inputs"); + return detail::functor1::call(acoth, x); + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/round.hpp b/src/GLMath/glm/gtc/round.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fbbcdeb55092dbe8fb8304f5e4888a23f05cc7eb --- /dev/null +++ b/src/GLMath/glm/gtc/round.hpp @@ -0,0 +1,202 @@ +/// @ref gtc_round +/// @file glm/gtc/round.hpp +/// +/// @see core (dependence) +/// @see gtc_round (dependence) +/// +/// @defgroup gtc_round GLM_GTC_round +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Rounding value to specific boundings + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../vector_relational.hpp" +#include "../common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_round + /// @{ + + /// Return true if the value is a power of two number. + /// + /// @see gtc_round + template + GLM_FUNC_DECL bool isPowerOfTwo(genIUType v); + + /// Return true if the value is a power of two number. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec isPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType ceilPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec ceilPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType floorPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec floorPowerOfTwo(vec const& v); + + /// Return the power of two number which value is the closet to the input value. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType roundPowerOfTwo(genIUType v); + + /// Return the power of two number which value is the closet to the input value. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec roundPowerOfTwo(vec const& v); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @see gtc_round + template + GLM_FUNC_DECL bool isMultiple(genIUType v, genIUType Multiple); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec isMultiple(vec const& v, T Multiple); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec isMultiple(vec const& v, vec const& Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType ceilMultiple(genType v, genType Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec ceilMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType floorMultiple(genType v, genType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec floorMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType roundMultiple(genType v, genType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec roundMultiple(vec const& v, vec const& Multiple); + + /// @} +} //namespace glm + +#include "round.inl" diff --git a/src/GLMath/glm/gtc/round.inl b/src/GLMath/glm/gtc/round.inl new file mode 100644 index 0000000000000000000000000000000000000000..0d4d7d67de913573021083c51b6a55415bb6fe54 --- /dev/null +++ b/src/GLMath/glm/gtc/round.inl @@ -0,0 +1,343 @@ +/// @ref gtc_round + +#include "../integer.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_ceilShift + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T) + { + return v; + } + }; + + template + struct compute_ceilShift + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Shift) + { + return v | (v >> Shift); + } + }; + + template + struct compute_ceilPowerOfTwo + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); + + vec const Sign(sign(x)); + + vec v(abs(x)); + + v = v - static_cast(1); + v = v | (v >> static_cast(1)); + v = v | (v >> static_cast(2)); + v = v | (v >> static_cast(4)); + v = compute_ceilShift= 2>::call(v, 8); + v = compute_ceilShift= 4>::call(v, 16); + v = compute_ceilShift= 8>::call(v, 32); + return (v + static_cast(1)) * Sign; + } + }; + + template + struct compute_ceilPowerOfTwo + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); + + vec v(x); + + v = v - static_cast(1); + v = v | (v >> static_cast(1)); + v = v | (v >> static_cast(2)); + v = v | (v >> static_cast(4)); + v = compute_ceilShift= 2>::call(v, 8); + v = compute_ceilShift= 4>::call(v, 16); + v = compute_ceilShift= 8>::call(v, 32); + return v + static_cast(1); + } + }; + + template + struct compute_ceilMultiple{}; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source > genType(0)) + return Source + (Multiple - std::fmod(Source, Multiple)); + else + return Source + std::fmod(-Source, Multiple); + } + }; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + genType Tmp = Source - genType(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + }; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source > genType(0)) + { + genType Tmp = Source - genType(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + else + return Source + (-Source % Multiple); + } + }; + + template + struct compute_floorMultiple{}; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - std::fmod(Source, Multiple); + else + return Source - std::fmod(Source, Multiple) - Multiple; + } + }; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; + + template + struct compute_roundMultiple{}; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - std::fmod(Source, Multiple); + else + { + genType Tmp = Source + genType(1); + return Tmp - std::fmod(Tmp, Multiple) - Multiple; + } + } + }; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; +}//namespace detail + + //////////////// + // isPowerOfTwo + + template + GLM_FUNC_QUALIFIER bool isPowerOfTwo(genType Value) + { + genType const Result = glm::abs(Value); + return !(Result & (Result - 1)); + } + + template + GLM_FUNC_QUALIFIER vec isPowerOfTwo(vec const& Value) + { + vec const Result(abs(Value)); + return equal(Result & (Result - 1), vec(0)); + } + + ////////////////// + // ceilPowerOfTwo + + template + GLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value) + { + return detail::compute_ceilPowerOfTwo<1, genType, defaultp, std::numeric_limits::is_signed>::call(vec<1, genType, defaultp>(value)).x; + } + + template + GLM_FUNC_QUALIFIER vec ceilPowerOfTwo(vec const& v) + { + return detail::compute_ceilPowerOfTwo::is_signed>::call(v); + } + + /////////////////// + // floorPowerOfTwo + + template + GLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value) + { + return isPowerOfTwo(value) ? value : static_cast(1) << findMSB(value); + } + + template + GLM_FUNC_QUALIFIER vec floorPowerOfTwo(vec const& v) + { + return detail::functor1::call(floorPowerOfTwo, v); + } + + /////////////////// + // roundPowerOfTwo + + template + GLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value) + { + if(isPowerOfTwo(value)) + return value; + + genIUType const prev = static_cast(1) << findMSB(value); + genIUType const next = prev << static_cast(1); + return (next - value) < (value - prev) ? next : prev; + } + + template + GLM_FUNC_QUALIFIER vec roundPowerOfTwo(vec const& v) + { + return detail::functor1::call(roundPowerOfTwo, v); + } + + //////////////// + // isMultiple + + template + GLM_FUNC_QUALIFIER bool isMultiple(genType Value, genType Multiple) + { + return isMultiple(vec<1, genType>(Value), vec<1, genType>(Multiple)).x; + } + + template + GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, T Multiple) + { + return (Value % Multiple) == vec(0); + } + + template + GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, vec const& Multiple) + { + return (Value % Multiple) == vec(0); + } + + ////////////////////// + // ceilMultiple + + template + GLM_FUNC_QUALIFIER genType ceilMultiple(genType Source, genType Multiple) + { + return detail::compute_ceilMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec ceilMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(ceilMultiple, Source, Multiple); + } + + ////////////////////// + // floorMultiple + + template + GLM_FUNC_QUALIFIER genType floorMultiple(genType Source, genType Multiple) + { + return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec floorMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(floorMultiple, Source, Multiple); + } + + ////////////////////// + // roundMultiple + + template + GLM_FUNC_QUALIFIER genType roundMultiple(genType Source, genType Multiple) + { + return detail::compute_roundMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec roundMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(roundMultiple, Source, Multiple); + } +}//namespace glm diff --git a/src/GLMath/glm/gtc/type_aligned.hpp b/src/GLMath/glm/gtc/type_aligned.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5403abf675256b1dcb53bcd7eb553336daed29f6 --- /dev/null +++ b/src/GLMath/glm/gtc/type_aligned.hpp @@ -0,0 +1,1315 @@ +/// @ref gtc_type_aligned +/// @file glm/gtc/type_aligned.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_type_aligned GLM_GTC_type_aligned +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Aligned types allowing SIMD optimizations of vectors and matrices types + +#pragma once + +#if (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) +# error "GLM: Aligned gentypes require to enable C++ language extensions. Define GLM_FORCE_ALIGNED_GENTYPES before including GLM headers to use aligned types." +#endif + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_aligned extension included") +#endif + +#include "../mat4x4.hpp" +#include "../mat4x3.hpp" +#include "../mat4x2.hpp" +#include "../mat3x4.hpp" +#include "../mat3x3.hpp" +#include "../mat3x2.hpp" +#include "../mat2x4.hpp" +#include "../mat2x3.hpp" +#include "../mat2x2.hpp" +#include "../gtc/vec1.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" + +namespace glm +{ + /// @addtogroup gtc_type_aligned + /// @{ + + // -- *vec1 -- + + /// 1 component vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_highp> aligned_highp_vec1; + + /// 1 component vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_mediump> aligned_mediump_vec1; + + /// 1 component vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_lowp> aligned_lowp_vec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_highp> aligned_highp_dvec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_mediump> aligned_mediump_dvec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_lowp> aligned_lowp_dvec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_highp> aligned_highp_ivec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_mediump> aligned_mediump_ivec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_lowp> aligned_lowp_ivec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_highp> aligned_highp_uvec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_mediump> aligned_mediump_uvec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_lowp> aligned_lowp_uvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_highp> aligned_highp_bvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_mediump> aligned_mediump_bvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_lowp> aligned_lowp_bvec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, packed_highp> packed_highp_vec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, packed_mediump> packed_mediump_vec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, packed_lowp> packed_lowp_vec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, packed_highp> packed_highp_dvec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, packed_mediump> packed_mediump_dvec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, packed_lowp> packed_lowp_dvec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_highp> packed_highp_ivec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_mediump> packed_mediump_ivec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_lowp> packed_lowp_ivec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_highp> packed_highp_uvec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_mediump> packed_mediump_uvec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_lowp> packed_lowp_uvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_highp> packed_highp_bvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_mediump> packed_mediump_bvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_lowp> packed_lowp_bvec1; + + // -- *vec2 -- + + /// 2 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_highp> aligned_highp_vec2; + + /// 2 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_mediump> aligned_mediump_vec2; + + /// 2 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_lowp> aligned_lowp_vec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_highp> aligned_highp_dvec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_mediump> aligned_mediump_dvec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_lowp> aligned_lowp_dvec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_highp> aligned_highp_ivec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_mediump> aligned_mediump_ivec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_lowp> aligned_lowp_ivec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_highp> aligned_highp_uvec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_mediump> aligned_mediump_uvec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_lowp> aligned_lowp_uvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_highp> aligned_highp_bvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_mediump> aligned_mediump_bvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_lowp> aligned_lowp_bvec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, float, packed_highp> packed_highp_vec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, float, packed_mediump> packed_mediump_vec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, float, packed_lowp> packed_lowp_vec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, double, packed_highp> packed_highp_dvec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, double, packed_mediump> packed_mediump_dvec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, double, packed_lowp> packed_lowp_dvec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_highp> packed_highp_ivec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_mediump> packed_mediump_ivec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_lowp> packed_lowp_ivec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_highp> packed_highp_uvec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_mediump> packed_mediump_uvec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_lowp> packed_lowp_uvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_highp> packed_highp_bvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_mediump> packed_mediump_bvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_lowp> packed_lowp_bvec2; + + // -- *vec3 -- + + /// 3 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_highp> aligned_highp_vec3; + + /// 3 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_mediump> aligned_mediump_vec3; + + /// 3 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_lowp> aligned_lowp_vec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_highp> aligned_highp_dvec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_mediump> aligned_mediump_dvec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_lowp> aligned_lowp_dvec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_highp> aligned_highp_ivec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_mediump> aligned_mediump_ivec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_lowp> aligned_lowp_ivec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_highp> aligned_highp_uvec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_mediump> aligned_mediump_uvec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_lowp> aligned_lowp_uvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_highp> aligned_highp_bvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_mediump> aligned_mediump_bvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_lowp> aligned_lowp_bvec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, float, packed_highp> packed_highp_vec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, float, packed_mediump> packed_mediump_vec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, float, packed_lowp> packed_lowp_vec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, double, packed_highp> packed_highp_dvec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, double, packed_mediump> packed_mediump_dvec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, double, packed_lowp> packed_lowp_dvec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_highp> packed_highp_ivec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_mediump> packed_mediump_ivec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_lowp> packed_lowp_ivec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_highp> packed_highp_uvec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_mediump> packed_mediump_uvec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_lowp> packed_lowp_uvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_highp> packed_highp_bvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_mediump> packed_mediump_bvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_lowp> packed_lowp_bvec3; + + // -- *vec4 -- + + /// 4 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_highp> aligned_highp_vec4; + + /// 4 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_mediump> aligned_mediump_vec4; + + /// 4 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_lowp> aligned_lowp_vec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_highp> aligned_highp_dvec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_mediump> aligned_mediump_dvec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_lowp> aligned_lowp_dvec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_highp> aligned_highp_ivec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_mediump> aligned_mediump_ivec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_lowp> aligned_lowp_ivec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_highp> aligned_highp_uvec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_mediump> aligned_mediump_uvec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_lowp> aligned_lowp_uvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_highp> aligned_highp_bvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_mediump> aligned_mediump_bvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_lowp> aligned_lowp_bvec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, float, packed_highp> packed_highp_vec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, float, packed_mediump> packed_mediump_vec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, float, packed_lowp> packed_lowp_vec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, double, packed_highp> packed_highp_dvec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, double, packed_mediump> packed_mediump_dvec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, double, packed_lowp> packed_lowp_dvec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_highp> packed_highp_ivec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_mediump> packed_mediump_ivec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_lowp> packed_lowp_ivec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_highp> packed_highp_uvec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_mediump> packed_mediump_uvec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_lowp> packed_lowp_uvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_highp> packed_highp_bvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_mediump> packed_mediump_bvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_lowp> packed_lowp_bvec4; + + // -- *mat2 -- + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_highp> packed_highp_mat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_highp> packed_highp_dmat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2; + + // -- *mat3 -- + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_highp> packed_highp_mat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_highp> packed_highp_dmat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3; + + // -- *mat4 -- + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_highp> packed_highp_mat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_highp> packed_highp_dmat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4; + + // -- *mat2x2 -- + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2x2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2x2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_highp> packed_highp_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_highp> packed_highp_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2x2; + + // -- *mat2x3 -- + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_highp> aligned_highp_mat2x3; + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_mediump> aligned_mediump_mat2x3; + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_lowp> aligned_lowp_mat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_highp> aligned_highp_dmat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_mediump> aligned_mediump_dmat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_lowp> aligned_lowp_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_highp> packed_highp_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_mediump> packed_mediump_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_lowp> packed_lowp_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_highp> packed_highp_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_mediump> packed_mediump_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_lowp> packed_lowp_dmat2x3; + + // -- *mat2x4 -- + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_highp> aligned_highp_mat2x4; + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_mediump> aligned_mediump_mat2x4; + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_lowp> aligned_lowp_mat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_highp> aligned_highp_dmat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_mediump> aligned_mediump_dmat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_lowp> aligned_lowp_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_highp> packed_highp_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_mediump> packed_mediump_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_lowp> packed_lowp_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_highp> packed_highp_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_mediump> packed_mediump_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_lowp> packed_lowp_dmat2x4; + + // -- *mat3x2 -- + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_highp> aligned_highp_mat3x2; + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_mediump> aligned_mediump_mat3x2; + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_lowp> aligned_lowp_mat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_highp> aligned_highp_dmat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_mediump> aligned_mediump_dmat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_lowp> aligned_lowp_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_highp> packed_highp_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_mediump> packed_mediump_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_lowp> packed_lowp_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_highp> packed_highp_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_mediump> packed_mediump_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_lowp> packed_lowp_dmat3x2; + + // -- *mat3x3 -- + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3x3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3x3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_highp> packed_highp_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_highp> packed_highp_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3x3; + + // -- *mat3x4 -- + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_highp> aligned_highp_mat3x4; + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_mediump> aligned_mediump_mat3x4; + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_lowp> aligned_lowp_mat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_highp> aligned_highp_dmat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_mediump> aligned_mediump_dmat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_lowp> aligned_lowp_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_highp> packed_highp_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_mediump> packed_mediump_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_lowp> packed_lowp_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_highp> packed_highp_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_mediump> packed_mediump_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_lowp> packed_lowp_dmat3x4; + + // -- *mat4x2 -- + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_highp> aligned_highp_mat4x2; + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_mediump> aligned_mediump_mat4x2; + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_lowp> aligned_lowp_mat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_highp> aligned_highp_dmat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_mediump> aligned_mediump_dmat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_lowp> aligned_lowp_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_highp> packed_highp_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_mediump> packed_mediump_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_lowp> packed_lowp_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_highp> packed_highp_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_mediump> packed_mediump_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_lowp> packed_lowp_dmat4x2; + + // -- *mat4x3 -- + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_highp> aligned_highp_mat4x3; + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_mediump> aligned_mediump_mat4x3; + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_lowp> aligned_lowp_mat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_highp> aligned_highp_dmat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_mediump> aligned_mediump_dmat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_lowp> aligned_lowp_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_highp> packed_highp_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_mediump> packed_mediump_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_lowp> packed_lowp_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_highp> packed_highp_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_mediump> packed_mediump_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_lowp> packed_lowp_dmat4x3; + + // -- *mat4x4 -- + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4x4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4x4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_highp> packed_highp_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_highp> packed_highp_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4x4; + + // -- default -- + +#if(defined(GLM_PRECISION_LOWP_FLOAT)) + typedef aligned_lowp_vec1 aligned_vec1; + typedef aligned_lowp_vec2 aligned_vec2; + typedef aligned_lowp_vec3 aligned_vec3; + typedef aligned_lowp_vec4 aligned_vec4; + typedef packed_lowp_vec1 packed_vec1; + typedef packed_lowp_vec2 packed_vec2; + typedef packed_lowp_vec3 packed_vec3; + typedef packed_lowp_vec4 packed_vec4; + + typedef aligned_lowp_mat2 aligned_mat2; + typedef aligned_lowp_mat3 aligned_mat3; + typedef aligned_lowp_mat4 aligned_mat4; + typedef packed_lowp_mat2 packed_mat2; + typedef packed_lowp_mat3 packed_mat3; + typedef packed_lowp_mat4 packed_mat4; + + typedef aligned_lowp_mat2x2 aligned_mat2x2; + typedef aligned_lowp_mat2x3 aligned_mat2x3; + typedef aligned_lowp_mat2x4 aligned_mat2x4; + typedef aligned_lowp_mat3x2 aligned_mat3x2; + typedef aligned_lowp_mat3x3 aligned_mat3x3; + typedef aligned_lowp_mat3x4 aligned_mat3x4; + typedef aligned_lowp_mat4x2 aligned_mat4x2; + typedef aligned_lowp_mat4x3 aligned_mat4x3; + typedef aligned_lowp_mat4x4 aligned_mat4x4; + typedef packed_lowp_mat2x2 packed_mat2x2; + typedef packed_lowp_mat2x3 packed_mat2x3; + typedef packed_lowp_mat2x4 packed_mat2x4; + typedef packed_lowp_mat3x2 packed_mat3x2; + typedef packed_lowp_mat3x3 packed_mat3x3; + typedef packed_lowp_mat3x4 packed_mat3x4; + typedef packed_lowp_mat4x2 packed_mat4x2; + typedef packed_lowp_mat4x3 packed_mat4x3; + typedef packed_lowp_mat4x4 packed_mat4x4; +#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) + typedef aligned_mediump_vec1 aligned_vec1; + typedef aligned_mediump_vec2 aligned_vec2; + typedef aligned_mediump_vec3 aligned_vec3; + typedef aligned_mediump_vec4 aligned_vec4; + typedef packed_mediump_vec1 packed_vec1; + typedef packed_mediump_vec2 packed_vec2; + typedef packed_mediump_vec3 packed_vec3; + typedef packed_mediump_vec4 packed_vec4; + + typedef aligned_mediump_mat2 aligned_mat2; + typedef aligned_mediump_mat3 aligned_mat3; + typedef aligned_mediump_mat4 aligned_mat4; + typedef packed_mediump_mat2 packed_mat2; + typedef packed_mediump_mat3 packed_mat3; + typedef packed_mediump_mat4 packed_mat4; + + typedef aligned_mediump_mat2x2 aligned_mat2x2; + typedef aligned_mediump_mat2x3 aligned_mat2x3; + typedef aligned_mediump_mat2x4 aligned_mat2x4; + typedef aligned_mediump_mat3x2 aligned_mat3x2; + typedef aligned_mediump_mat3x3 aligned_mat3x3; + typedef aligned_mediump_mat3x4 aligned_mat3x4; + typedef aligned_mediump_mat4x2 aligned_mat4x2; + typedef aligned_mediump_mat4x3 aligned_mat4x3; + typedef aligned_mediump_mat4x4 aligned_mat4x4; + typedef packed_mediump_mat2x2 packed_mat2x2; + typedef packed_mediump_mat2x3 packed_mat2x3; + typedef packed_mediump_mat2x4 packed_mat2x4; + typedef packed_mediump_mat3x2 packed_mat3x2; + typedef packed_mediump_mat3x3 packed_mat3x3; + typedef packed_mediump_mat3x4 packed_mat3x4; + typedef packed_mediump_mat4x2 packed_mat4x2; + typedef packed_mediump_mat4x3 packed_mat4x3; + typedef packed_mediump_mat4x4 packed_mat4x4; +#else //defined(GLM_PRECISION_HIGHP_FLOAT) + /// 1 component vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec1 aligned_vec1; + + /// 2 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec2 aligned_vec2; + + /// 3 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec3 aligned_vec3; + + /// 4 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec4 aligned_vec4; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec1 packed_vec1; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec2 packed_vec2; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec3 packed_vec3; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec4 packed_vec4; + + /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2 aligned_mat2; + + /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3 aligned_mat3; + + /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4 aligned_mat4; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2 packed_mat2; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3 packed_mat3; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4 packed_mat4; + + /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x2 aligned_mat2x2; + + /// 2 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x3 aligned_mat2x3; + + /// 2 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x4 aligned_mat2x4; + + /// 3 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x2 aligned_mat3x2; + + /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x3 aligned_mat3x3; + + /// 3 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x4 aligned_mat3x4; + + /// 4 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x2 aligned_mat4x2; + + /// 4 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x3 aligned_mat4x3; + + /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x4 aligned_mat4x4; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x2 packed_mat2x2; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x3 packed_mat2x3; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x4 packed_mat2x4; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x2 packed_mat3x2; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x3 packed_mat3x3; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x4 packed_mat3x4; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x2 packed_mat4x2; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x3 packed_mat4x3; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x4 packed_mat4x4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef aligned_lowp_dvec1 aligned_dvec1; + typedef aligned_lowp_dvec2 aligned_dvec2; + typedef aligned_lowp_dvec3 aligned_dvec3; + typedef aligned_lowp_dvec4 aligned_dvec4; + typedef packed_lowp_dvec1 packed_dvec1; + typedef packed_lowp_dvec2 packed_dvec2; + typedef packed_lowp_dvec3 packed_dvec3; + typedef packed_lowp_dvec4 packed_dvec4; + + typedef aligned_lowp_dmat2 aligned_dmat2; + typedef aligned_lowp_dmat3 aligned_dmat3; + typedef aligned_lowp_dmat4 aligned_dmat4; + typedef packed_lowp_dmat2 packed_dmat2; + typedef packed_lowp_dmat3 packed_dmat3; + typedef packed_lowp_dmat4 packed_dmat4; + + typedef aligned_lowp_dmat2x2 aligned_dmat2x2; + typedef aligned_lowp_dmat2x3 aligned_dmat2x3; + typedef aligned_lowp_dmat2x4 aligned_dmat2x4; + typedef aligned_lowp_dmat3x2 aligned_dmat3x2; + typedef aligned_lowp_dmat3x3 aligned_dmat3x3; + typedef aligned_lowp_dmat3x4 aligned_dmat3x4; + typedef aligned_lowp_dmat4x2 aligned_dmat4x2; + typedef aligned_lowp_dmat4x3 aligned_dmat4x3; + typedef aligned_lowp_dmat4x4 aligned_dmat4x4; + typedef packed_lowp_dmat2x2 packed_dmat2x2; + typedef packed_lowp_dmat2x3 packed_dmat2x3; + typedef packed_lowp_dmat2x4 packed_dmat2x4; + typedef packed_lowp_dmat3x2 packed_dmat3x2; + typedef packed_lowp_dmat3x3 packed_dmat3x3; + typedef packed_lowp_dmat3x4 packed_dmat3x4; + typedef packed_lowp_dmat4x2 packed_dmat4x2; + typedef packed_lowp_dmat4x3 packed_dmat4x3; + typedef packed_lowp_dmat4x4 packed_dmat4x4; +#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE)) + typedef aligned_mediump_dvec1 aligned_dvec1; + typedef aligned_mediump_dvec2 aligned_dvec2; + typedef aligned_mediump_dvec3 aligned_dvec3; + typedef aligned_mediump_dvec4 aligned_dvec4; + typedef packed_mediump_dvec1 packed_dvec1; + typedef packed_mediump_dvec2 packed_dvec2; + typedef packed_mediump_dvec3 packed_dvec3; + typedef packed_mediump_dvec4 packed_dvec4; + + typedef aligned_mediump_dmat2 aligned_dmat2; + typedef aligned_mediump_dmat3 aligned_dmat3; + typedef aligned_mediump_dmat4 aligned_dmat4; + typedef packed_mediump_dmat2 packed_dmat2; + typedef packed_mediump_dmat3 packed_dmat3; + typedef packed_mediump_dmat4 packed_dmat4; + + typedef aligned_mediump_dmat2x2 aligned_dmat2x2; + typedef aligned_mediump_dmat2x3 aligned_dmat2x3; + typedef aligned_mediump_dmat2x4 aligned_dmat2x4; + typedef aligned_mediump_dmat3x2 aligned_dmat3x2; + typedef aligned_mediump_dmat3x3 aligned_dmat3x3; + typedef aligned_mediump_dmat3x4 aligned_dmat3x4; + typedef aligned_mediump_dmat4x2 aligned_dmat4x2; + typedef aligned_mediump_dmat4x3 aligned_dmat4x3; + typedef aligned_mediump_dmat4x4 aligned_dmat4x4; + typedef packed_mediump_dmat2x2 packed_dmat2x2; + typedef packed_mediump_dmat2x3 packed_dmat2x3; + typedef packed_mediump_dmat2x4 packed_dmat2x4; + typedef packed_mediump_dmat3x2 packed_dmat3x2; + typedef packed_mediump_dmat3x3 packed_dmat3x3; + typedef packed_mediump_dmat3x4 packed_dmat3x4; + typedef packed_mediump_dmat4x2 packed_dmat4x2; + typedef packed_mediump_dmat4x3 packed_dmat4x3; + typedef packed_mediump_dmat4x4 packed_dmat4x4; +#else //defined(GLM_PRECISION_HIGHP_DOUBLE) + /// 1 component vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec1 aligned_dvec1; + + /// 2 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec2 aligned_dvec2; + + /// 3 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec3 aligned_dvec3; + + /// 4 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec4 aligned_dvec4; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec1 packed_dvec1; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec2 packed_dvec2; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec3 packed_dvec3; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec4 packed_dvec4; + + /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2 aligned_dmat2; + + /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3 aligned_dmat3; + + /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4 aligned_dmat4; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2 packed_dmat2; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3 packed_dmat3; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4 packed_dmat4; + + /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x2 aligned_dmat2x2; + + /// 2 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x3 aligned_dmat2x3; + + /// 2 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x4 aligned_dmat2x4; + + /// 3 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x2 aligned_dmat3x2; + + /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x3 aligned_dmat3x3; + + /// 3 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x4 aligned_dmat3x4; + + /// 4 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x2 aligned_dmat4x2; + + /// 4 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x3 aligned_dmat4x3; + + /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x4 aligned_dmat4x4; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x2 packed_dmat2x2; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x3 packed_dmat2x3; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x4 packed_dmat2x4; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x2 packed_dmat3x2; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x3 packed_dmat3x3; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x4 packed_dmat3x4; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x2 packed_dmat4x2; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x3 packed_dmat4x3; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x4 packed_dmat4x4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_INT)) + typedef aligned_lowp_ivec1 aligned_ivec1; + typedef aligned_lowp_ivec2 aligned_ivec2; + typedef aligned_lowp_ivec3 aligned_ivec3; + typedef aligned_lowp_ivec4 aligned_ivec4; +#elif(defined(GLM_PRECISION_MEDIUMP_INT)) + typedef aligned_mediump_ivec1 aligned_ivec1; + typedef aligned_mediump_ivec2 aligned_ivec2; + typedef aligned_mediump_ivec3 aligned_ivec3; + typedef aligned_mediump_ivec4 aligned_ivec4; +#else //defined(GLM_PRECISION_HIGHP_INT) + /// 1 component vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec1 aligned_ivec1; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec2 aligned_ivec2; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec3 aligned_ivec3; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec4 aligned_ivec4; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec1 packed_ivec1; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec2 packed_ivec2; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec3 packed_ivec3; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec4 packed_ivec4; +#endif//GLM_PRECISION + + // -- Unsigned integer definition -- + +#if(defined(GLM_PRECISION_LOWP_UINT)) + typedef aligned_lowp_uvec1 aligned_uvec1; + typedef aligned_lowp_uvec2 aligned_uvec2; + typedef aligned_lowp_uvec3 aligned_uvec3; + typedef aligned_lowp_uvec4 aligned_uvec4; +#elif(defined(GLM_PRECISION_MEDIUMP_UINT)) + typedef aligned_mediump_uvec1 aligned_uvec1; + typedef aligned_mediump_uvec2 aligned_uvec2; + typedef aligned_mediump_uvec3 aligned_uvec3; + typedef aligned_mediump_uvec4 aligned_uvec4; +#else //defined(GLM_PRECISION_HIGHP_UINT) + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec1 aligned_uvec1; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec2 aligned_uvec2; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec3 aligned_uvec3; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec4 aligned_uvec4; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec1 packed_uvec1; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec2 packed_uvec2; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec3 packed_uvec3; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec4 packed_uvec4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_BOOL)) + typedef aligned_lowp_bvec1 aligned_bvec1; + typedef aligned_lowp_bvec2 aligned_bvec2; + typedef aligned_lowp_bvec3 aligned_bvec3; + typedef aligned_lowp_bvec4 aligned_bvec4; +#elif(defined(GLM_PRECISION_MEDIUMP_BOOL)) + typedef aligned_mediump_bvec1 aligned_bvec1; + typedef aligned_mediump_bvec2 aligned_bvec2; + typedef aligned_mediump_bvec3 aligned_bvec3; + typedef aligned_mediump_bvec4 aligned_bvec4; +#else //defined(GLM_PRECISION_HIGHP_BOOL) + /// 1 component vector aligned in memory of bool values. + typedef aligned_highp_bvec1 aligned_bvec1; + + /// 2 components vector aligned in memory of bool values. + typedef aligned_highp_bvec2 aligned_bvec2; + + /// 3 components vector aligned in memory of bool values. + typedef aligned_highp_bvec3 aligned_bvec3; + + /// 4 components vector aligned in memory of bool values. + typedef aligned_highp_bvec4 aligned_bvec4; + + /// 1 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec1 packed_bvec1; + + /// 2 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec2 packed_bvec2; + + /// 3 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec3 packed_bvec3; + + /// 4 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec4 packed_bvec4; +#endif//GLM_PRECISION + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/gtc/type_precision.hpp b/src/GLMath/glm/gtc/type_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..250bc4f96dd2167f4ced0b1cc9899ced7c96e422 --- /dev/null +++ b/src/GLMath/glm/gtc/type_precision.hpp @@ -0,0 +1,2138 @@ +/// @ref gtc_type_precision +/// @file glm/gtc/type_precision.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_type_precision GLM_GTC_type_precision +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines specific C++-based qualifier types. + +#pragma once + +// Dependency: +#include "../gtc/quaternion.hpp" +#include "../gtc/vec1.hpp" +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/type_vec2.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" +#include "../detail/type_mat2x2.hpp" +#include "../detail/type_mat2x3.hpp" +#include "../detail/type_mat2x4.hpp" +#include "../detail/type_mat3x2.hpp" +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat3x4.hpp" +#include "../detail/type_mat4x2.hpp" +#include "../detail/type_mat4x3.hpp" +#include "../detail/type_mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_precision extension included") +#endif + +namespace glm +{ + /////////////////////////// + // Signed int vector types + + /// @addtogroup gtc_type_precision + /// @{ + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_int8; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_int16; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_int32; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_int64; + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_int8_t; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_int16_t; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_int32_t; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_int64_t; + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_i8; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_i16; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_i32; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_i64; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_int8; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_int16; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_int32; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_int64; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_int8_t; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_int16_t; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_int32_t; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_int64_t; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_i8; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_i16; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_i32; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_i64; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_int8; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_int16; + + /// High qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_int32; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_int64; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_int8_t; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_int16_t; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_int32_t; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_int64_t; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_i8; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_i16; + + /// High qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_i32; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_i64; + + +#if GLM_HAS_EXTENDED_INTEGER_TYPE + using std::int8_t; + using std::int16_t; + using std::int32_t; + using std::int64_t; +#else + /// 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 int8_t; + + /// 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 int16_t; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 int32_t; + + /// 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 int64_t; +#endif + + /// 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 i8; + + /// 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 i16; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 i32; + + /// 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 i64; + + + + /// Low qualifier 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, lowp> lowp_i8vec1; + + /// Low qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, lowp> lowp_i8vec2; + + /// Low qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, lowp> lowp_i8vec3; + + /// Low qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, lowp> lowp_i8vec4; + + + /// Medium qualifier 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, mediump> mediump_i8vec1; + + /// Medium qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, mediump> mediump_i8vec2; + + /// Medium qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, mediump> mediump_i8vec3; + + /// Medium qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, mediump> mediump_i8vec4; + + + /// High qualifier 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, highp> highp_i8vec1; + + /// High qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, highp> highp_i8vec2; + + /// High qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, highp> highp_i8vec3; + + /// High qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, highp> highp_i8vec4; + + + + /// 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, defaultp> i8vec1; + + /// 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, defaultp> i8vec2; + + /// 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, defaultp> i8vec3; + + /// 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, defaultp> i8vec4; + + + + + + /// Low qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, lowp> lowp_i16vec1; + + /// Low qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, lowp> lowp_i16vec2; + + /// Low qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, lowp> lowp_i16vec3; + + /// Low qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, lowp> lowp_i16vec4; + + + /// Medium qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, mediump> mediump_i16vec1; + + /// Medium qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, mediump> mediump_i16vec2; + + /// Medium qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, mediump> mediump_i16vec3; + + /// Medium qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, mediump> mediump_i16vec4; + + + /// High qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, highp> highp_i16vec1; + + /// High qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, highp> highp_i16vec2; + + /// High qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, highp> highp_i16vec3; + + /// High qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, highp> highp_i16vec4; + + + + + /// 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, defaultp> i16vec1; + + /// 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, defaultp> i16vec2; + + /// 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, defaultp> i16vec3; + + /// 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, defaultp> i16vec4; + + + + /// Low qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, lowp> lowp_i32vec1; + + /// Low qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, lowp> lowp_i32vec2; + + /// Low qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, lowp> lowp_i32vec3; + + /// Low qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, lowp> lowp_i32vec4; + + + /// Medium qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, mediump> mediump_i32vec1; + + /// Medium qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, mediump> mediump_i32vec2; + + /// Medium qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, mediump> mediump_i32vec3; + + /// Medium qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, mediump> mediump_i32vec4; + + + /// High qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, highp> highp_i32vec1; + + /// High qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, highp> highp_i32vec2; + + /// High qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, highp> highp_i32vec3; + + /// High qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, highp> highp_i32vec4; + + + /// 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, defaultp> i32vec1; + + /// 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, defaultp> i32vec2; + + /// 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, defaultp> i32vec3; + + /// 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, defaultp> i32vec4; + + + + + /// Low qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, lowp> lowp_i64vec1; + + /// Low qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, lowp> lowp_i64vec2; + + /// Low qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, lowp> lowp_i64vec3; + + /// Low qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, lowp> lowp_i64vec4; + + + /// Medium qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, mediump> mediump_i64vec1; + + /// Medium qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, mediump> mediump_i64vec2; + + /// Medium qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, mediump> mediump_i64vec3; + + /// Medium qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, mediump> mediump_i64vec4; + + + /// High qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, highp> highp_i64vec1; + + /// High qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, highp> highp_i64vec2; + + /// High qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, highp> highp_i64vec3; + + /// High qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, highp> highp_i64vec4; + + + /// 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, defaultp> i64vec1; + + /// 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, defaultp> i64vec2; + + /// 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, defaultp> i64vec3; + + /// 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, defaultp> i64vec4; + + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_uint8; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_uint16; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_uint32; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_uint64; + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_uint8_t; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_uint16_t; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_uint32_t; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_uint64_t; + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_u8; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_u16; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_u32; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_u64; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_uint8; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_uint16; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_uint32; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_uint64; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_uint8_t; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_uint16_t; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_uint32_t; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_uint64_t; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_u8; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_u16; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_u32; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_u64; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_uint8; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_uint16; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_uint32; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_uint64; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_uint8_t; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_uint16_t; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_uint32_t; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_uint64_t; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_u8; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_u16; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_u32; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_u64; + +#if GLM_HAS_EXTENDED_INTEGER_TYPE + using std::uint8_t; + using std::uint16_t; + using std::uint32_t; + using std::uint64_t; +#else + /// Default qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 uint8_t; + + /// Default qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 uint16_t; + + /// Default qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 uint32_t; + + /// Default qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 uint64_t; +#endif + + /// Default qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 u8; + + /// Default qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 u16; + + /// Default qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 u32; + + /// Default qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 u64; + + + + + + ////////////////////// + // Float vector types + + /// Single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float float32; + + /// Double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef double float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_float32; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_float64; + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_float32_t; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_float64_t; + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_f32; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_f64; + + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_float32; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_float64; + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_float32_t; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_float64_t; + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_f32; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_f64; + + +#if(defined(GLM_PRECISION_LOWP_FLOAT)) + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_float32_t float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_float64_t float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_f32 f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_f64 f64; + +#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float32 float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float64 float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float32 f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float64 f64; + +#else//(defined(GLM_PRECISION_HIGHP_FLOAT)) + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float32_t float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float64_t float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float32_t f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float64_t f64; +#endif + + + /// Low single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, lowp> lowp_fvec1; + + /// Low single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, lowp> lowp_fvec2; + + /// Low single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, lowp> lowp_fvec3; + + /// Low single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, lowp> lowp_fvec4; + + + /// Medium single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, mediump> mediump_fvec1; + + /// Medium Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, mediump> mediump_fvec2; + + /// Medium Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, mediump> mediump_fvec3; + + /// Medium Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, mediump> mediump_fvec4; + + + /// High single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, highp> highp_fvec1; + + /// High Single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, float, highp> highp_fvec2; + + /// High Single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, float, highp> highp_fvec3; + + /// High Single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, float, highp> highp_fvec4; + + + /// Low single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, lowp> lowp_f32vec1; + + /// Low single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, f32, lowp> lowp_f32vec2; + + /// Low single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, f32, lowp> lowp_f32vec3; + + /// Low single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, f32, lowp> lowp_f32vec4; + + /// Medium single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, mediump> mediump_f32vec1; + + /// Medium single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, f32, mediump> mediump_f32vec2; + + /// Medium single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, f32, mediump> mediump_f32vec3; + + /// Medium single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, f32, mediump> mediump_f32vec4; + + /// High single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, highp> highp_f32vec1; + + /// High single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f32, highp> highp_f32vec2; + + /// High single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f32, highp> highp_f32vec3; + + /// High single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f32, highp> highp_f32vec4; + + + /// Low double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, lowp> lowp_f64vec1; + + /// Low double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, lowp> lowp_f64vec2; + + /// Low double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, lowp> lowp_f64vec3; + + /// Low double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, lowp> lowp_f64vec4; + + /// Medium double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, mediump> mediump_f64vec1; + + /// Medium double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, mediump> mediump_f64vec2; + + /// Medium double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, mediump> mediump_f64vec3; + + /// Medium double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, mediump> mediump_f64vec4; + + /// High double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, highp> highp_f64vec1; + + /// High double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, highp> highp_f64vec2; + + /// High double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, highp> highp_f64vec3; + + /// High double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, highp> highp_f64vec4; + + + + ////////////////////// + // Float matrix types + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_f32 lowp_fmat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, lowp> lowp_fmat2x2; + + /// Low single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, lowp> lowp_fmat2x3; + + /// Low single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, lowp> lowp_fmat2x4; + + /// Low single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, lowp> lowp_fmat3x2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, lowp> lowp_fmat3x3; + + /// Low single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, lowp> lowp_fmat3x4; + + /// Low single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, lowp> lowp_fmat4x2; + + /// Low single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, lowp> lowp_fmat4x3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, lowp> lowp_fmat4x4; + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_fmat1x1 lowp_fmat1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_fmat2x2 lowp_fmat2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_fmat3x3 lowp_fmat3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_fmat4x4 lowp_fmat4; + + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_f32 mediump_fmat1x1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, mediump> mediump_fmat2x2; + + /// Medium single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, mediump> mediump_fmat2x3; + + /// Medium single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, mediump> mediump_fmat2x4; + + /// Medium single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, mediump> mediump_fmat3x2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, mediump> mediump_fmat3x3; + + /// Medium single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, mediump> mediump_fmat3x4; + + /// Medium single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, mediump> mediump_fmat4x2; + + /// Medium single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, mediump> mediump_fmat4x3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, mediump> mediump_fmat4x4; + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_fmat1x1 mediump_fmat1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_fmat2x2 mediump_fmat2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_fmat3x3 mediump_fmat3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_fmat4x4 mediump_fmat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_f32 highp_fmat1x1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, highp> highp_fmat2x2; + + /// High single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, highp> highp_fmat2x3; + + /// High single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, highp> highp_fmat2x4; + + /// High single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, highp> highp_fmat3x2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, highp> highp_fmat3x3; + + /// High single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, highp> highp_fmat3x4; + + /// High single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, highp> highp_fmat4x2; + + /// High single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, highp> highp_fmat4x3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, highp> highp_fmat4x4; + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_fmat1x1 highp_fmat1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_fmat2x2 highp_fmat2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_fmat3x3 highp_fmat3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_fmat4x4 highp_fmat4; + + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 lowp_f32mat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; + + /// Low single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; + + /// Low single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; + + /// Low single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; + + /// Low single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; + + /// Low single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; + + /// Low single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 lowp_f32mat1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat2x2 lowp_f32mat2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat3x3 lowp_f32mat3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat4x4 lowp_f32mat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 mediump_f32mat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; + + /// Medium single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; + + /// Medium single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; + + /// Medium single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; + + /// Medium single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; + + /// Medium single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; + + /// Medium single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat2x2 mediump_f32mat2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat3x3 mediump_f32mat3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat4x4 mediump_f32mat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 highp_f32mat1x1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, highp> highp_f32mat2x2; + + /// High single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, highp> highp_f32mat2x3; + + /// High single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, highp> highp_f32mat2x4; + + /// High single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, highp> highp_f32mat3x2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, highp> highp_f32mat3x3; + + /// High single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, highp> highp_f32mat3x4; + + /// High single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, highp> highp_f32mat4x2; + + /// High single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, highp> highp_f32mat4x3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, highp> highp_f32mat4x4; + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_f32mat2x2 highp_f32mat2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_f32mat3x3 highp_f32mat3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_f32mat4x4 highp_f32mat4; + + + /// Low double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 lowp_f64mat1x1; + + /// Low double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; + + /// Low double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; + + /// Low double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; + + /// Low double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; + + /// Low double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; + + /// Low double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; + + /// Low double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; + + /// Low double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; + + /// Low double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; + + /// Low double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_f64mat1x1 lowp_f64mat1; + + /// Low double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat2x2 lowp_f64mat2; + + /// Low double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat3x3 lowp_f64mat3; + + /// Low double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat4x4 lowp_f64mat4; + + + /// Medium double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 Highp_f64mat1x1; + + /// Medium double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; + + /// Medium double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; + + /// Medium double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; + + /// Medium double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; + + /// Medium double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; + + /// Medium double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; + + /// Medium double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; + + /// Medium double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; + + /// Medium double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; + + /// Medium double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_f64mat1x1 mediump_f64mat1; + + /// Medium double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat2x2 mediump_f64mat2; + + /// Medium double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat3x3 mediump_f64mat3; + + /// Medium double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat4x4 mediump_f64mat4; + + /// High double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 highp_f64mat1x1; + + /// High double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, highp> highp_f64mat2x2; + + /// High double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, highp> highp_f64mat2x3; + + /// High double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, highp> highp_f64mat2x4; + + /// High double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, highp> highp_f64mat3x2; + + /// High double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, highp> highp_f64mat3x3; + + /// High double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, highp> highp_f64mat3x4; + + /// High double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, highp> highp_f64mat4x2; + + /// High double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, highp> highp_f64mat4x3; + + /// High double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, highp> highp_f64mat4x4; + + /// High double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_f64mat1x1 highp_f64mat1; + + /// High double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_f64mat2x2 highp_f64mat2; + + /// High double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_f64mat3x3 highp_f64mat3; + + /// High double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_f64mat4x4 highp_f64mat4; + + + + + /// Low qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, lowp> lowp_u8vec1; + + /// Low qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, lowp> lowp_u8vec2; + + /// Low qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, lowp> lowp_u8vec3; + + /// Low qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, lowp> lowp_u8vec4; + + + /// Medium qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, mediump> mediump_u8vec1; + + /// Medium qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, mediump> mediump_u8vec2; + + /// Medium qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, mediump> mediump_u8vec3; + + /// Medium qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, mediump> mediump_u8vec4; + + + /// High qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, highp> highp_u8vec1; + + /// High qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, highp> highp_u8vec2; + + /// High qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, highp> highp_u8vec3; + + /// High qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, highp> highp_u8vec4; + + + + /// Default qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, defaultp> u8vec1; + + /// Default qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, defaultp> u8vec2; + + /// Default qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, defaultp> u8vec3; + + /// Default qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, defaultp> u8vec4; + + + + + /// Low qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, lowp> lowp_u16vec1; + + /// Low qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, lowp> lowp_u16vec2; + + /// Low qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, lowp> lowp_u16vec3; + + /// Low qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, lowp> lowp_u16vec4; + + + /// Medium qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, mediump> mediump_u16vec1; + + /// Medium qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, mediump> mediump_u16vec2; + + /// Medium qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, mediump> mediump_u16vec3; + + /// Medium qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, mediump> mediump_u16vec4; + + + /// High qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, highp> highp_u16vec1; + + /// High qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, highp> highp_u16vec2; + + /// High qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, highp> highp_u16vec3; + + /// High qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, highp> highp_u16vec4; + + + + + /// Default qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, defaultp> u16vec1; + + /// Default qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, defaultp> u16vec2; + + /// Default qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, defaultp> u16vec3; + + /// Default qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, defaultp> u16vec4; + + + + /// Low qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, lowp> lowp_u32vec1; + + /// Low qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, lowp> lowp_u32vec2; + + /// Low qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, lowp> lowp_u32vec3; + + /// Low qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, lowp> lowp_u32vec4; + + + /// Medium qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, mediump> mediump_u32vec1; + + /// Medium qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, mediump> mediump_u32vec2; + + /// Medium qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, mediump> mediump_u32vec3; + + /// Medium qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, mediump> mediump_u32vec4; + + + /// High qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, highp> highp_u32vec1; + + /// High qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, highp> highp_u32vec2; + + /// High qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, highp> highp_u32vec3; + + /// High qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, highp> highp_u32vec4; + + + + /// Default qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, defaultp> u32vec1; + + /// Default qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, defaultp> u32vec2; + + /// Default qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, defaultp> u32vec3; + + /// Default qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, defaultp> u32vec4; + + + + + /// Low qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, lowp> lowp_u64vec1; + + /// Low qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, lowp> lowp_u64vec2; + + /// Low qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, lowp> lowp_u64vec3; + + /// Low qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, lowp> lowp_u64vec4; + + + /// Medium qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, mediump> mediump_u64vec1; + + /// Medium qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, mediump> mediump_u64vec2; + + /// Medium qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, mediump> mediump_u64vec3; + + /// Medium qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, mediump> mediump_u64vec4; + + + /// High qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, highp> highp_u64vec1; + + /// High qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, highp> highp_u64vec2; + + /// High qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, highp> highp_u64vec3; + + /// High qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, highp> highp_u64vec4; + + + + + /// Default qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, defaultp> u64vec1; + + /// Default qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, defaultp> u64vec2; + + /// Default qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, defaultp> u64vec3; + + /// Default qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, defaultp> u64vec4; + + + ////////////////////// + // Float vector types + + /// 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 float32_t; + + /// 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 f32; + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 float64_t; + + /// 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 f64; +# endif//GLM_FORCE_SINGLE_ONLY + + /// Single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, defaultp> fvec1; + + /// Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, defaultp> fvec2; + + /// Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, defaultp> fvec3; + + /// Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, defaultp> fvec4; + + + /// Single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, defaultp> f32vec1; + + /// Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f32, defaultp> f32vec2; + + /// Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f32, defaultp> f32vec3; + + /// Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f32, defaultp> f32vec4; + +# ifndef GLM_FORCE_SINGLE_ONLY + /// Double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, defaultp> f64vec1; + + /// Double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, defaultp> f64vec2; + + /// Double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, defaultp> f64vec3; + + /// Double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, defaultp> f64vec4; +# endif//GLM_FORCE_SINGLE_ONLY + + + ////////////////////// + // Float matrix types + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 fmat1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> fmat2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> fmat3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> fmat4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 fmat1x1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> fmat2x2; + + /// Single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, defaultp> fmat2x3; + + /// Single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, defaultp> fmat2x4; + + /// Single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, defaultp> fmat3x2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> fmat3x3; + + /// Single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, defaultp> fmat3x4; + + /// Single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, defaultp> fmat4x2; + + /// Single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, defaultp> fmat4x3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> fmat4x4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> f32mat2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> f32mat3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> f32mat4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 f32mat1x1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> f32mat2x2; + + /// Single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, defaultp> f32mat2x3; + + /// Single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, defaultp> f32mat2x4; + + /// Single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, defaultp> f32mat3x2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> f32mat3x3; + + /// Single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, defaultp> f32mat3x4; + + /// Single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, defaultp> f32mat4x2; + + /// Single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, defaultp> f32mat4x3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> f32mat4x4; + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f64mat1; + + /// Double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, defaultp> f64mat2; + + /// Double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, defaultp> f64mat3; + + /// Double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, defaultp> f64mat4; + + + /// Double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 f64mat1x1; + + /// Double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, defaultp> f64mat2x2; + + /// Double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, defaultp> f64mat2x3; + + /// Double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, defaultp> f64mat2x4; + + /// Double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, defaultp> f64mat3x2; + + /// Double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, defaultp> f64mat3x3; + + /// Double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, defaultp> f64mat3x4; + + /// Double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, defaultp> f64mat4x2; + + /// Double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, defaultp> f64mat4x3; + + /// Double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, defaultp> f64mat4x4; + +# endif//GLM_FORCE_SINGLE_ONLY + + ////////////////////////// + // Quaternion types + + /// Single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua f32quat; + + /// Low single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua lowp_f32quat; + + /// Low double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua lowp_f64quat; + + /// Medium single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua mediump_f32quat; + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Medium double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua mediump_f64quat; + + /// High single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua highp_f32quat; + + /// High double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua highp_f64quat; + + /// Double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua f64quat; + +# endif//GLM_FORCE_SINGLE_ONLY + + /// @} +}//namespace glm + +#include "type_precision.inl" diff --git a/src/GLMath/glm/gtc/type_precision.inl b/src/GLMath/glm/gtc/type_precision.inl new file mode 100644 index 0000000000000000000000000000000000000000..ae8091206bd402a59d13d86edc1998b78eadb372 --- /dev/null +++ b/src/GLMath/glm/gtc/type_precision.inl @@ -0,0 +1,6 @@ +/// @ref gtc_precision + +namespace glm +{ + +} diff --git a/src/GLMath/glm/gtc/type_ptr.hpp b/src/GLMath/glm/gtc/type_ptr.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7e625aa591719bb0c7e42db2509c48a2fc89b8e --- /dev/null +++ b/src/GLMath/glm/gtc/type_ptr.hpp @@ -0,0 +1,230 @@ +/// @ref gtc_type_ptr +/// @file glm/gtc/type_ptr.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_type_ptr GLM_GTC_type_ptr +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Handles the interaction between pointers and vector, matrix types. +/// +/// This extension defines an overloaded function, glm::value_ptr. It returns +/// a pointer to the memory layout of the object. Matrix types store their values +/// in column-major order. +/// +/// This is useful for uploading data to matrices or copying data to buffer objects. +/// +/// Example: +/// @code +/// #include +/// #include +/// +/// glm::vec3 aVector(3); +/// glm::mat4 someMatrix(1.0); +/// +/// glUniform3fv(uniformLoc, 1, glm::value_ptr(aVector)); +/// glUniformMatrix4fv(uniformMatrixLoc, 1, GL_FALSE, glm::value_ptr(someMatrix)); +/// @endcode +/// +/// need to be included to use the features of this extension. + +#pragma once + +// Dependency: +#include "../gtc/quaternion.hpp" +#include "../gtc/vec1.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_ptr extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_type_ptr + /// @{ + + /// Return the constant address to the data of the input parameter. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL typename genType::value_type const * value_ptr(genType const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, defaultp> make_vec2(T const * const ptr); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, defaultp> make_vec3(T const * const ptr); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, defaultp> make_vec4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 3, T, defaultp> make_mat2x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 4, T, defaultp> make_mat2x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 2, T, defaultp> make_mat3x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 4, T, defaultp> make_mat3x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 2, T, defaultp> make_mat4x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 3, T, defaultp> make_mat4x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4(T const * const ptr); + + /// Build a quaternion from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL qua make_quat(T const * const ptr); + + /// @} +}//namespace glm + +#include "type_ptr.inl" diff --git a/src/GLMath/glm/gtc/type_ptr.inl b/src/GLMath/glm/gtc/type_ptr.inl new file mode 100644 index 0000000000000000000000000000000000000000..71df4d30d00cb844dd0cc5bf72c69aeaabb9e5de --- /dev/null +++ b/src/GLMath/glm/gtc/type_ptr.inl @@ -0,0 +1,386 @@ +/// @ref gtc_type_ptr + +#include + +namespace glm +{ + /// @addtogroup gtc_type_ptr + /// @{ + + template + GLM_FUNC_QUALIFIER T const* value_ptr(vec<2, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<2, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const * value_ptr(vec<3, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<3, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(vec<4, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<4, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T * value_ptr(mat<4, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const * value_ptr(qua const& q) + { + return &(q[0]); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(qua& q) + { + return &(q[0]); + } + + template + inline vec<1, T, Q> make_vec1(vec<1, T, Q> const& v) + { + return v; + } + + template + inline vec<1, T, Q> make_vec1(vec<2, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + inline vec<1, T, Q> make_vec1(vec<3, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + inline vec<1, T, Q> make_vec1(vec<4, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + inline vec<2, T, Q> make_vec2(vec<1, T, Q> const& v) + { + return vec<2, T, Q>(v.x, static_cast(0)); + } + + template + inline vec<2, T, Q> make_vec2(vec<2, T, Q> const& v) + { + return v; + } + + template + inline vec<2, T, Q> make_vec2(vec<3, T, Q> const& v) + { + return vec<2, T, Q>(v); + } + + template + inline vec<2, T, Q> make_vec2(vec<4, T, Q> const& v) + { + return vec<2, T, Q>(v); + } + + template + inline vec<3, T, Q> make_vec3(vec<1, T, Q> const& v) + { + return vec<3, T, Q>(v.x, static_cast(0), static_cast(0)); + } + + template + inline vec<3, T, Q> make_vec3(vec<2, T, Q> const& v) + { + return vec<3, T, Q>(v.x, v.y, static_cast(0)); + } + + template + inline vec<3, T, Q> make_vec3(vec<3, T, Q> const& v) + { + return v; + } + + template + inline vec<3, T, Q> make_vec3(vec<4, T, Q> const& v) + { + return vec<3, T, Q>(v); + } + + template + inline vec<4, T, Q> make_vec4(vec<1, T, Q> const& v) + { + return vec<4, T, Q>(v.x, static_cast(0), static_cast(0), static_cast(1)); + } + + template + inline vec<4, T, Q> make_vec4(vec<2, T, Q> const& v) + { + return vec<4, T, Q>(v.x, v.y, static_cast(0), static_cast(1)); + } + + template + inline vec<4, T, Q> make_vec4(vec<3, T, Q> const& v) + { + return vec<4, T, Q>(v.x, v.y, v.z, static_cast(1)); + } + + template + inline vec<4, T, Q> make_vec4(vec<4, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> make_vec2(T const *const ptr) + { + vec<2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> make_vec3(T const *const ptr) + { + vec<3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, defaultp> make_vec4(T const *const ptr) + { + vec<4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2x2(T const *const ptr) + { + mat<2, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, defaultp> make_mat2x3(T const *const ptr) + { + mat<2, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, defaultp> make_mat2x4(T const *const ptr) + { + mat<2, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, defaultp> make_mat3x2(T const *const ptr) + { + mat<3, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3x3(T const *const ptr) + { + mat<3, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, defaultp> make_mat3x4(T const *const ptr) + { + mat<3, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, defaultp> make_mat4x2(T const *const ptr) + { + mat<4, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, defaultp> make_mat4x3(T const *const ptr) + { + mat<4, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4x4(T const *const ptr) + { + mat<4, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2(T const *const ptr) + { + return make_mat2x2(ptr); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3(T const *const ptr) + { + return make_mat3x3(ptr); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4(T const *const ptr) + { + return make_mat4x4(ptr); + } + + template + GLM_FUNC_QUALIFIER qua make_quat(T const *const ptr) + { + qua Result; + memcpy(value_ptr(Result), ptr, sizeof(qua)); + return Result; + } + + /// @} +}//namespace glm + diff --git a/src/GLMath/glm/gtc/ulp.hpp b/src/GLMath/glm/gtc/ulp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..01f4f11e1e4710738597c479656c85c98a52c3aa --- /dev/null +++ b/src/GLMath/glm/gtc/ulp.hpp @@ -0,0 +1,24 @@ +/// @ref gtc_ulp +/// @file glm/gtc/ulp.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_ulp GLM_GTC_ulp +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. + +#pragma once + +// Dependencies +#include "../ext/scalar_ulp.hpp" +#include "../ext/vector_ulp.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_ulp extension included") +#endif + diff --git a/src/GLMath/glm/gtc/ulp.inl b/src/GLMath/glm/gtc/ulp.inl new file mode 100644 index 0000000000000000000000000000000000000000..53f4950a96db380c727aa91a2e3fd9183e959eaf --- /dev/null +++ b/src/GLMath/glm/gtc/ulp.inl @@ -0,0 +1,3 @@ +/// @ref gtc_ulp +/// + diff --git a/src/GLMath/glm/gtc/vec1.hpp b/src/GLMath/glm/gtc/vec1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c20be87475d284821d4139fddb95f5f850710a4d --- /dev/null +++ b/src/GLMath/glm/gtc/vec1.hpp @@ -0,0 +1,30 @@ +/// @ref gtc_vec1 +/// @file glm/gtc/vec1.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_vec1 GLM_GTC_vec1 +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Add vec1, ivec1, uvec1 and bvec1 types. + +#pragma once + +// Dependency: +#include "../ext/vector_bool1.hpp" +#include "../ext/vector_bool1_precision.hpp" +#include "../ext/vector_float1.hpp" +#include "../ext/vector_float1_precision.hpp" +#include "../ext/vector_double1.hpp" +#include "../ext/vector_double1_precision.hpp" +#include "../ext/vector_int1.hpp" +#include "../ext/vector_int1_precision.hpp" +#include "../ext/vector_uint1.hpp" +#include "../ext/vector_uint1_precision.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_vec1 extension included") +#endif + diff --git a/src/GLMath/glm/gtx/associated_min_max.hpp b/src/GLMath/glm/gtx/associated_min_max.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d1a41c06baf8bdbffeec698597a73ec63bc2fe76 --- /dev/null +++ b/src/GLMath/glm/gtx/associated_min_max.hpp @@ -0,0 +1,207 @@ +/// @ref gtx_associated_min_max +/// @file glm/gtx/associated_min_max.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_associated_min_max GLM_GTX_associated_min_max +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Min and max functions that return associated values not the compared onces. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_associated_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_associated_min_max extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_associated_min_max + /// @{ + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin(T x, U a, T y, U b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec<2, U, Q> associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + T x, const vec& a, + T y, const vec& b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, U a, + vec const& y, U b); + + /// Minimum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin( + T x, U a, + T y, U b, + T z, U c); + + /// Minimum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin( + T x, U a, + T y, U b, + T z, U c, + T w, U d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax(T x, U a, T y, U b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec<2, U, Q> associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax( + T x, U a, + T y, U b, + T z, U c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax( + T x, U a, + T y, U b, + T z, U c, + T w, U d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d); + + /// @} +} //namespace glm + +#include "associated_min_max.inl" diff --git a/src/GLMath/glm/gtx/associated_min_max.inl b/src/GLMath/glm/gtx/associated_min_max.inl new file mode 100644 index 0000000000000000000000000000000000000000..5186c471c28c6da0b7070ea6ca82f1de04c75bc5 --- /dev/null +++ b/src/GLMath/glm/gtx/associated_min_max.inl @@ -0,0 +1,354 @@ +/// @ref gtx_associated_min_max + +namespace glm{ + +// Min comparison between 2 variables +template +GLM_FUNC_QUALIFIER U associatedMin(T x, U a, T y, U b) +{ + return x < y ? a : b; +} + +template +GLM_FUNC_QUALIFIER vec<2, U, Q> associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? a[i] : b[i]; + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + T x, const vec& a, + T y, const vec& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x < y ? a[i] : b[i]; + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, U a, + vec const& y, U b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? a : b; + return Result; +} + +// Min comparison between 3 variables +template +GLM_FUNC_QUALIFIER U associatedMin +( + T x, U a, + T y, U b, + T z, U c +) +{ + U Result = x < y ? (x < z ? a : c) : (y < z ? b : c); + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? (x[i] < z[i] ? a[i] : c[i]) : (y[i] < z[i] ? b[i] : c[i]); + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER U associatedMin +( + T x, U a, + T y, U b, + T z, U c, + T w, U d +) +{ + T Test1 = min(x, y); + T Test2 = min(z, w); + U Result1 = x < y ? a : b; + U Result2 = z < w ? c : d; + U Result = Test1 < Test2 ? Result1 : Result2; + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = min(x[i], y[i]); + T Test2 = min(z[i], w[i]); + U Result1 = x[i] < y[i] ? a[i] : b[i]; + U Result2 = z[i] < w[i] ? c[i] : d[i]; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d +) +{ + T Test1 = min(x, y); + T Test2 = min(z, w); + + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + U Result1 = x < y ? a[i] : b[i]; + U Result2 = z < w ? c[i] : d[i]; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = min(x[i], y[i]); + T Test2 = min(z[i], w[i]); + U Result1 = x[i] < y[i] ? a : b; + U Result2 = z[i] < w[i] ? c : d; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER U associatedMax(T x, U a, T y, U b) +{ + return x > y ? a : b; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec<2, U, Q> associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? a[i] : b[i]; + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x > y ? a[i] : b[i]; + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? a : b; + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER U associatedMax +( + T x, U a, + T y, U b, + T z, U c +) +{ + U Result = x > y ? (x > z ? a : c) : (y > z ? b : c); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a[i] : c[i]) : (y[i] > z[i] ? b[i] : c[i]); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x > y ? (x > z ? a[i] : c[i]) : (y > z ? b[i] : c[i]); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a : c) : (y[i] > z[i] ? b : c); + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER U associatedMax +( + T x, U a, + T y, U b, + T z, U c, + T w, U d +) +{ + T Test1 = max(x, y); + T Test2 = max(z, w); + U Result1 = x > y ? a : b; + U Result2 = z > w ? c : d; + U Result = Test1 > Test2 ? Result1 : Result2; + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = max(x[i], y[i]); + T Test2 = max(z[i], w[i]); + U Result1 = x[i] > y[i] ? a[i] : b[i]; + U Result2 = z[i] > w[i] ? c[i] : d[i]; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d +) +{ + T Test1 = max(x, y); + T Test2 = max(z, w); + + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + U Result1 = x > y ? a[i] : b[i]; + U Result2 = z > w ? c[i] : d[i]; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = max(x[i], y[i]); + T Test2 = max(z[i], w[i]); + U Result1 = x[i] > y[i] ? a : b; + U Result2 = z[i] > w[i] ? c : d; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} +}//namespace glm diff --git a/src/GLMath/glm/gtx/bit.hpp b/src/GLMath/glm/gtx/bit.hpp new file mode 100644 index 0000000000000000000000000000000000000000..60a7aef1b463f7c945e8e9e8cabf7f02c49343f1 --- /dev/null +++ b/src/GLMath/glm/gtx/bit.hpp @@ -0,0 +1,98 @@ +/// @ref gtx_bit +/// @file glm/gtx/bit.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_bit GLM_GTX_bit +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../gtc/bitfield.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_bit is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_bit extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_bit + /// @{ + + /// @see gtx_bit + template + GLM_FUNC_DECL genIUType highestBitValue(genIUType Value); + + /// @see gtx_bit + template + GLM_FUNC_DECL genIUType lowestBitValue(genIUType Value); + + /// Find the highest bit set to 1 in a integer variable and return its value. + /// + /// @see gtx_bit + template + GLM_FUNC_DECL vec highestBitValue(vec const& value); + + /// Return the power of two number which value is just higher the input value. + /// Deprecated, use ceilPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value); + + /// Return the power of two number which value is just higher the input value. + /// Deprecated, use ceilPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoAbove(vec const& value); + + /// Return the power of two number which value is just lower the input value. + /// Deprecated, use floorPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value); + + /// Return the power of two number which value is just lower the input value. + /// Deprecated, use floorPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoBelow(vec const& value); + + /// Return the power of two number which value is the closet to the input value. + /// Deprecated, use roundPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value); + + /// Return the power of two number which value is the closet to the input value. + /// Deprecated, use roundPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoNearest(vec const& value); + + /// @} +} //namespace glm + + +#include "bit.inl" + diff --git a/src/GLMath/glm/gtx/bit.inl b/src/GLMath/glm/gtx/bit.inl new file mode 100644 index 0000000000000000000000000000000000000000..621b6262406de7bcb462e09085fc82f2d638bdeb --- /dev/null +++ b/src/GLMath/glm/gtx/bit.inl @@ -0,0 +1,92 @@ +/// @ref gtx_bit + +namespace glm +{ + /////////////////// + // highestBitValue + + template + GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) + { + genIUType tmp = Value; + genIUType result = genIUType(0); + while(tmp) + { + result = (tmp & (~tmp + 1)); // grab lowest bit + tmp &= ~result; // clear lowest bit + } + return result; + } + + template + GLM_FUNC_QUALIFIER vec highestBitValue(vec const& v) + { + return detail::functor1::call(highestBitValue, v); + } + + /////////////////// + // lowestBitValue + + template + GLM_FUNC_QUALIFIER genIUType lowestBitValue(genIUType Value) + { + return (Value & (~Value + 1)); + } + + template + GLM_FUNC_QUALIFIER vec lowestBitValue(vec const& v) + { + return detail::functor1::call(lowestBitValue, v); + } + + /////////////////// + // powerOfTwoAbove + + template + GLM_FUNC_QUALIFIER genType powerOfTwoAbove(genType value) + { + return isPowerOfTwo(value) ? value : highestBitValue(value) << 1; + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoAbove(vec const& v) + { + return detail::functor1::call(powerOfTwoAbove, v); + } + + /////////////////// + // powerOfTwoBelow + + template + GLM_FUNC_QUALIFIER genType powerOfTwoBelow(genType value) + { + return isPowerOfTwo(value) ? value : highestBitValue(value); + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoBelow(vec const& v) + { + return detail::functor1::call(powerOfTwoBelow, v); + } + + ///////////////////// + // powerOfTwoNearest + + template + GLM_FUNC_QUALIFIER genType powerOfTwoNearest(genType value) + { + if(isPowerOfTwo(value)) + return value; + + genType const prev = highestBitValue(value); + genType const next = prev << 1; + return (next - value) < (value - prev) ? next : prev; + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoNearest(vec const& v) + { + return detail::functor1::call(powerOfTwoNearest, v); + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/closest_point.hpp b/src/GLMath/glm/gtx/closest_point.hpp new file mode 100644 index 0000000000000000000000000000000000000000..de6dbbff94470ffba44d9ddfa6badfbaa176f3a6 --- /dev/null +++ b/src/GLMath/glm/gtx/closest_point.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_closest_point +/// @file glm/gtx/closest_point.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_closest_point GLM_GTX_closest_point +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Find the point on a straight line which is the closet of a point. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_closest_point extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_closest_point + /// @{ + + /// Find the point on a straight line which is the closet of a point. + /// @see gtx_closest_point + template + GLM_FUNC_DECL vec<3, T, Q> closestPointOnLine( + vec<3, T, Q> const& point, + vec<3, T, Q> const& a, + vec<3, T, Q> const& b); + + /// 2d lines work as well + template + GLM_FUNC_DECL vec<2, T, Q> closestPointOnLine( + vec<2, T, Q> const& point, + vec<2, T, Q> const& a, + vec<2, T, Q> const& b); + + /// @} +}// namespace glm + +#include "closest_point.inl" diff --git a/src/GLMath/glm/gtx/closest_point.inl b/src/GLMath/glm/gtx/closest_point.inl new file mode 100644 index 0000000000000000000000000000000000000000..0a39b042b88c9f57052e0580f5fa8bcbba3ccfcc --- /dev/null +++ b/src/GLMath/glm/gtx/closest_point.inl @@ -0,0 +1,45 @@ +/// @ref gtx_closest_point + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> closestPointOnLine + ( + vec<3, T, Q> const& point, + vec<3, T, Q> const& a, + vec<3, T, Q> const& b + ) + { + T LineLength = distance(a, b); + vec<3, T, Q> Vector = point - a; + vec<3, T, Q> LineDirection = (b - a) / LineLength; + + // Project Vector to LineDirection to get the distance of point from a + T Distance = dot(Vector, LineDirection); + + if(Distance <= T(0)) return a; + if(Distance >= LineLength) return b; + return a + LineDirection * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> closestPointOnLine + ( + vec<2, T, Q> const& point, + vec<2, T, Q> const& a, + vec<2, T, Q> const& b + ) + { + T LineLength = distance(a, b); + vec<2, T, Q> Vector = point - a; + vec<2, T, Q> LineDirection = (b - a) / LineLength; + + // Project Vector to LineDirection to get the distance of point from a + T Distance = dot(Vector, LineDirection); + + if(Distance <= T(0)) return a; + if(Distance >= LineLength) return b; + return a + LineDirection * Distance; + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/color_encoding.hpp b/src/GLMath/glm/gtx/color_encoding.hpp new file mode 100644 index 0000000000000000000000000000000000000000..96ded2a2770ffd1e60d147c863bb26c978d93e05 --- /dev/null +++ b/src/GLMath/glm/gtx/color_encoding.hpp @@ -0,0 +1,54 @@ +/// @ref gtx_color_encoding +/// @file glm/gtx/color_encoding.hpp +/// +/// @see core (dependence) +/// @see gtx_color_encoding (dependence) +/// +/// @defgroup gtx_color_encoding GLM_GTX_color_encoding +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../vec3.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTC_color_encoding is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTC_color_encoding extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_encoding + /// @{ + + /// Convert a linear sRGB color to D65 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB); + + /// Convert a linear sRGB color to D50 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB); + + /// Convert a D65 YUV color to linear sRGB. + template + GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ); + + /// Convert a D65 YUV color to D50 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ); + + /// @} +} //namespace glm + +#include "color_encoding.inl" diff --git a/src/GLMath/glm/gtx/color_encoding.inl b/src/GLMath/glm/gtx/color_encoding.inl new file mode 100644 index 0000000000000000000000000000000000000000..e50fa3efa42c9dd0452e11e0158df443d8c7e55b --- /dev/null +++ b/src/GLMath/glm/gtx/color_encoding.inl @@ -0,0 +1,45 @@ +/// @ref gtx_color_encoding + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB) + { + vec<3, T, Q> const M(0.490f, 0.17697f, 0.2f); + vec<3, T, Q> const N(0.31f, 0.8124f, 0.01063f); + vec<3, T, Q> const O(0.490f, 0.01f, 0.99f); + + return (M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB) * static_cast(5.650675255693055f); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB) + { + vec<3, T, Q> const M(0.436030342570117f, 0.222438466210245f, 0.013897440074263f); + vec<3, T, Q> const N(0.385101860087134f, 0.716942745571917f, 0.097076381494207f); + vec<3, T, Q> const O(0.143067806654203f, 0.060618777416563f, 0.713926257896652f); + + return M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ) + { + vec<3, T, Q> const M(0.41847f, -0.091169f, 0.0009209f); + vec<3, T, Q> const N(-0.15866f, 0.25243f, 0.015708f); + vec<3, T, Q> const O(0.0009209f, -0.0025498f, 0.1786f); + + return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ) + { + vec<3, T, Q> const M(+1.047844353856414f, +0.029549007606644f, -0.009250984365223f); + vec<3, T, Q> const N(+0.022898981050086f, +0.990508028941971f, +0.015072338237051f); + vec<3, T, Q> const O(-0.050206647741605f, -0.017074711360960f, +0.751717835079977f); + + return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/color_space.hpp b/src/GLMath/glm/gtx/color_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a6343921490840150c6930ec9de0518d16103bee --- /dev/null +++ b/src/GLMath/glm/gtx/color_space.hpp @@ -0,0 +1,72 @@ +/// @ref gtx_color_space +/// @file glm/gtx/color_space.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_color_space GLM_GTX_color_space +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Related to RGB to HSV conversions and operations. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_color_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_color_space extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_space + /// @{ + + /// Converts a color from HSV color space to its color in RGB color space. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> rgbColor( + vec<3, T, Q> const& hsvValue); + + /// Converts a color from RGB color space to its color in HSV color space. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> hsvColor( + vec<3, T, Q> const& rgbValue); + + /// Build a saturation matrix. + /// @see gtx_color_space + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> saturation( + T const s); + + /// Modify the saturation of a color. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> saturation( + T const s, + vec<3, T, Q> const& color); + + /// Modify the saturation of a color. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<4, T, Q> saturation( + T const s, + vec<4, T, Q> const& color); + + /// Compute color luminosity associating ratios (0.33, 0.59, 0.11) to RGB canals. + /// @see gtx_color_space + template + GLM_FUNC_DECL T luminosity( + vec<3, T, Q> const& color); + + /// @} +}//namespace glm + +#include "color_space.inl" diff --git a/src/GLMath/glm/gtx/color_space.inl b/src/GLMath/glm/gtx/color_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..f698afe1e1b043b4f579896de7bb5cd921bc4075 --- /dev/null +++ b/src/GLMath/glm/gtx/color_space.inl @@ -0,0 +1,141 @@ +/// @ref gtx_color_space + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgbColor(const vec<3, T, Q>& hsvColor) + { + vec<3, T, Q> hsv = hsvColor; + vec<3, T, Q> rgbColor; + + if(hsv.y == static_cast(0)) + // achromatic (grey) + rgbColor = vec<3, T, Q>(hsv.z); + else + { + T sector = floor(hsv.x * (T(1) / T(60))); + T frac = (hsv.x * (T(1) / T(60))) - sector; + // factorial part of h + T o = hsv.z * (T(1) - hsv.y); + T p = hsv.z * (T(1) - hsv.y * frac); + T q = hsv.z * (T(1) - hsv.y * (T(1) - frac)); + + switch(int(sector)) + { + default: + case 0: + rgbColor.r = hsv.z; + rgbColor.g = q; + rgbColor.b = o; + break; + case 1: + rgbColor.r = p; + rgbColor.g = hsv.z; + rgbColor.b = o; + break; + case 2: + rgbColor.r = o; + rgbColor.g = hsv.z; + rgbColor.b = q; + break; + case 3: + rgbColor.r = o; + rgbColor.g = p; + rgbColor.b = hsv.z; + break; + case 4: + rgbColor.r = q; + rgbColor.g = o; + rgbColor.b = hsv.z; + break; + case 5: + rgbColor.r = hsv.z; + rgbColor.g = o; + rgbColor.b = p; + break; + } + } + + return rgbColor; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> hsvColor(const vec<3, T, Q>& rgbColor) + { + vec<3, T, Q> hsv = rgbColor; + float Min = min(min(rgbColor.r, rgbColor.g), rgbColor.b); + float Max = max(max(rgbColor.r, rgbColor.g), rgbColor.b); + float Delta = Max - Min; + + hsv.z = Max; + + if(Max != static_cast(0)) + { + hsv.y = Delta / hsv.z; + T h = static_cast(0); + + if(rgbColor.r == Max) + // between yellow & magenta + h = static_cast(0) + T(60) * (rgbColor.g - rgbColor.b) / Delta; + else if(rgbColor.g == Max) + // between cyan & yellow + h = static_cast(120) + T(60) * (rgbColor.b - rgbColor.r) / Delta; + else + // between magenta & cyan + h = static_cast(240) + T(60) * (rgbColor.r - rgbColor.g) / Delta; + + if(h < T(0)) + hsv.x = h + T(360); + else + hsv.x = h; + } + else + { + // If r = g = b = 0 then s = 0, h is undefined + hsv.y = static_cast(0); + hsv.x = static_cast(0); + } + + return hsv; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> saturation(T const s) + { + vec<3, T, defaultp> rgbw = vec<3, T, defaultp>(T(0.2126), T(0.7152), T(0.0722)); + + vec<3, T, defaultp> const col((T(1) - s) * rgbw); + + mat<4, 4, T, defaultp> result(T(1)); + result[0][0] = col.x + s; + result[0][1] = col.x; + result[0][2] = col.x; + result[1][0] = col.y; + result[1][1] = col.y + s; + result[1][2] = col.y; + result[2][0] = col.z; + result[2][1] = col.z; + result[2][2] = col.z + s; + + return result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> saturation(const T s, const vec<3, T, Q>& color) + { + return vec<3, T, Q>(saturation(s) * vec<4, T, Q>(color, T(0))); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> saturation(const T s, const vec<4, T, Q>& color) + { + return saturation(s) * color; + } + + template + GLM_FUNC_QUALIFIER T luminosity(const vec<3, T, Q>& color) + { + const vec<3, T, Q> tmp = vec<3, T, Q>(0.33, 0.59, 0.11); + return dot(color, tmp); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/color_space_YCoCg.hpp b/src/GLMath/glm/gtx/color_space_YCoCg.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dd2b771693f6fed894e001da530523ed9d32b951 --- /dev/null +++ b/src/GLMath/glm/gtx/color_space_YCoCg.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_color_space_YCoCg +/// @file glm/gtx/color_space_YCoCg.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_color_space_YCoCg GLM_GTX_color_space_YCoCg +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// RGB to YCoCg conversions and operations + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_color_space_YCoCg is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_color_space_YCoCg extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_space_YCoCg + /// @{ + + /// Convert a color from RGB color space to YCoCg color space. + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCg( + vec<3, T, Q> const& rgbColor); + + /// Convert a color from YCoCg color space to RGB color space. + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> YCoCg2rgb( + vec<3, T, Q> const& YCoCgColor); + + /// Convert a color from RGB color space to YCoCgR color space. + /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCgR( + vec<3, T, Q> const& rgbColor); + + /// Convert a color from YCoCgR color space to RGB color space. + /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> YCoCgR2rgb( + vec<3, T, Q> const& YCoCgColor); + + /// @} +}//namespace glm + +#include "color_space_YCoCg.inl" diff --git a/src/GLMath/glm/gtx/color_space_YCoCg.inl b/src/GLMath/glm/gtx/color_space_YCoCg.inl new file mode 100644 index 0000000000000000000000000000000000000000..83ba857c08bd248e037e0819c9fcb74558e81a77 --- /dev/null +++ b/src/GLMath/glm/gtx/color_space_YCoCg.inl @@ -0,0 +1,107 @@ +/// @ref gtx_color_space_YCoCg + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCg + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.x/*Y */ = rgbColor.r / T(4) + rgbColor.g / T(2) + rgbColor.b / T(4); + result.y/*Co*/ = rgbColor.r / T(2) + rgbColor.g * T(0) - rgbColor.b / T(2); + result.z/*Cg*/ = - rgbColor.r / T(4) + rgbColor.g / T(2) - rgbColor.b / T(4); + return result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCg2rgb + ( + vec<3, T, Q> const& YCoCgColor + ) + { + vec<3, T, Q> result; + result.r = YCoCgColor.x + YCoCgColor.y - YCoCgColor.z; + result.g = YCoCgColor.x + YCoCgColor.z; + result.b = YCoCgColor.x - YCoCgColor.y - YCoCgColor.z; + return result; + } + + template + class compute_YCoCgR { + public: + static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.x/*Y */ = rgbColor.g * static_cast(0.5) + (rgbColor.r + rgbColor.b) * static_cast(0.25); + result.y/*Co*/ = rgbColor.r - rgbColor.b; + result.z/*Cg*/ = rgbColor.g - (rgbColor.r + rgbColor.b) * static_cast(0.5); + return result; + } + + static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + vec<3, T, Q> result; + T tmp = YCoCgRColor.x - (YCoCgRColor.z * static_cast(0.5)); + result.g = YCoCgRColor.z + tmp; + result.b = tmp - (YCoCgRColor.y * static_cast(0.5)); + result.r = result.b + YCoCgRColor.y; + return result; + } + }; + + template + class compute_YCoCgR { + public: + static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.y/*Co*/ = rgbColor.r - rgbColor.b; + T tmp = rgbColor.b + (result.y >> 1); + result.z/*Cg*/ = rgbColor.g - tmp; + result.x/*Y */ = tmp + (result.z >> 1); + return result; + } + + static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + vec<3, T, Q> result; + T tmp = YCoCgRColor.x - (YCoCgRColor.z >> 1); + result.g = YCoCgRColor.z + tmp; + result.b = tmp - (YCoCgRColor.y >> 1); + result.r = result.b + YCoCgRColor.y; + return result; + } + }; + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + return compute_YCoCgR::is_integer>::rgb2YCoCgR(rgbColor); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + return compute_YCoCgR::is_integer>::YCoCgR2rgb(YCoCgRColor); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/common.hpp b/src/GLMath/glm/gtx/common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..254ada2d769550538aefe5f91fcb413ede9543a9 --- /dev/null +++ b/src/GLMath/glm/gtx/common.hpp @@ -0,0 +1,76 @@ +/// @ref gtx_common +/// @file glm/gtx/common.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_common GLM_GTX_common +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Provide functions to increase the compatibility with Cg and HLSL languages + +#pragma once + +// Dependencies: +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../gtc/vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_common is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_common extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_common + /// @{ + + /// Returns true if x is a denormalized number + /// Numbers whose absolute value is too small to be represented in the normal format are represented in an alternate, denormalized format. + /// This format is less precise but can represent values closer to zero. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL isnan man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL typename genType::bool_type isdenormal(genType const& x); + + /// Similar to 'mod' but with a different rounding and integer support. + /// Returns 'x - y * trunc(x/y)' instead of 'x - y * floor(x/y)' + /// + /// @see GLSL mod vs HLSL fmod + /// @see GLSL mod man page + template + GLM_FUNC_DECL vec fmod(vec const& v); + + /// Returns whether vector components values are within an interval. A open interval excludes its endpoints, and is denoted with square brackets. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_relational + template + GLM_FUNC_DECL vec openBounded(vec const& Value, vec const& Min, vec const& Max); + + /// Returns whether vector components values are within an interval. A closed interval includes its endpoints, and is denoted with square brackets. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_relational + template + GLM_FUNC_DECL vec closeBounded(vec const& Value, vec const& Min, vec const& Max); + + /// @} +}//namespace glm + +#include "common.inl" diff --git a/src/GLMath/glm/gtx/common.inl b/src/GLMath/glm/gtx/common.inl new file mode 100644 index 0000000000000000000000000000000000000000..4ad2126d965d793dfd999c323039bf05c04da2d3 --- /dev/null +++ b/src/GLMath/glm/gtx/common.inl @@ -0,0 +1,125 @@ +/// @ref gtx_common + +#include +#include "../gtc/epsilon.hpp" +#include "../gtc/constants.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_fmod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + return detail::functor2::call(std::fmod, a, b); + } + }; + + template + struct compute_fmod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + return a % b; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool isdenormal(T const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::fpclassify(x) == FP_SUBNORMAL; +# else + return epsilonNotEqual(x, static_cast(0), epsilon()) && std::fabs(x) < std::numeric_limits::min(); +# endif + } + + template + GLM_FUNC_QUALIFIER typename vec<1, T, Q>::bool_type isdenormal + ( + vec<1, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<1, T, Q>::bool_type( + isdenormal(x.x)); + } + + template + GLM_FUNC_QUALIFIER typename vec<2, T, Q>::bool_type isdenormal + ( + vec<2, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<2, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y)); + } + + template + GLM_FUNC_QUALIFIER typename vec<3, T, Q>::bool_type isdenormal + ( + vec<3, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<3, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y), + isdenormal(x.z)); + } + + template + GLM_FUNC_QUALIFIER typename vec<4, T, Q>::bool_type isdenormal + ( + vec<4, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<4, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y), + isdenormal(x.z), + isdenormal(x.w)); + } + + // fmod + template + GLM_FUNC_QUALIFIER genType fmod(genType x, genType y) + { + return fmod(vec<1, genType>(x), y).x; + } + + template + GLM_FUNC_QUALIFIER vec fmod(vec const& x, T y) + { + return detail::compute_fmod::is_iec559>::call(x, vec(y)); + } + + template + GLM_FUNC_QUALIFIER vec fmod(vec const& x, vec const& y) + { + return detail::compute_fmod::is_iec559>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER vec openBounded(vec const& Value, vec const& Min, vec const& Max) + { + return greaterThan(Value, Min) && lessThan(Value, Max); + } + + template + GLM_FUNC_QUALIFIER vec closeBounded(vec const& Value, vec const& Min, vec const& Max) + { + return greaterThanEqual(Value, Min) && lessThanEqual(Value, Max); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/compatibility.hpp b/src/GLMath/glm/gtx/compatibility.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f1b00a6b39cfbe32ae1fa1b4ec76654f992fb164 --- /dev/null +++ b/src/GLMath/glm/gtx/compatibility.hpp @@ -0,0 +1,133 @@ +/// @ref gtx_compatibility +/// @file glm/gtx/compatibility.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_compatibility GLM_GTX_compatibility +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Provide functions to increase the compatibility with Cg and HLSL languages + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_compatibility is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_compatibility extension included") +# endif +#endif + +#if GLM_COMPILER & GLM_COMPILER_VC +# include +#elif GLM_COMPILER & GLM_COMPILER_GCC +# include +# if(GLM_PLATFORM & GLM_PLATFORM_ANDROID) +# undef isfinite +# endif +#endif//GLM_COMPILER + +namespace glm +{ + /// @addtogroup gtx_compatibility + /// @{ + + template GLM_FUNC_QUALIFIER T lerp(T x, T y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, const vec<2, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, const vec<3, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, const vec<4, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER T saturate(T x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> saturate(const vec<2, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> saturate(const vec<3, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> saturate(const vec<4, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER T atan2(T x, T y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> atan2(const vec<2, T, Q>& x, const vec<2, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> atan2(const vec<3, T, Q>& x, const vec<3, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> atan2(const vec<4, T, Q>& x, const vec<4, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + + template GLM_FUNC_DECL bool isfinite(genType const& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<1, bool, Q> isfinite(const vec<1, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<2, bool, Q> isfinite(const vec<2, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<3, bool, Q> isfinite(const vec<3, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<4, bool, Q> isfinite(const vec<4, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + + typedef bool bool1; //!< \brief boolean type with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, bool, highp> bool2; //!< \brief boolean type with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, bool, highp> bool3; //!< \brief boolean type with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, bool, highp> bool4; //!< \brief boolean type with 4 components. (From GLM_GTX_compatibility extension) + + typedef bool bool1x1; //!< \brief boolean matrix with 1 x 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, bool, highp> bool2x2; //!< \brief boolean matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, bool, highp> bool2x3; //!< \brief boolean matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, bool, highp> bool2x4; //!< \brief boolean matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, bool, highp> bool3x2; //!< \brief boolean matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, bool, highp> bool3x3; //!< \brief boolean matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, bool, highp> bool3x4; //!< \brief boolean matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, bool, highp> bool4x2; //!< \brief boolean matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, bool, highp> bool4x3; //!< \brief boolean matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, bool, highp> bool4x4; //!< \brief boolean matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef int int1; //!< \brief integer vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, int, highp> int2; //!< \brief integer vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, int, highp> int3; //!< \brief integer vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, int, highp> int4; //!< \brief integer vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef int int1x1; //!< \brief integer matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, int, highp> int2x2; //!< \brief integer matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, int, highp> int2x3; //!< \brief integer matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, int, highp> int2x4; //!< \brief integer matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, int, highp> int3x2; //!< \brief integer matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, int, highp> int3x3; //!< \brief integer matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, int, highp> int3x4; //!< \brief integer matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, int, highp> int4x2; //!< \brief integer matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, int, highp> int4x3; //!< \brief integer matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, int, highp> int4x4; //!< \brief integer matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef float float1; //!< \brief single-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, float, highp> float2; //!< \brief single-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, float, highp> float3; //!< \brief single-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, float, highp> float4; //!< \brief single-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef float float1x1; //!< \brief single-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, float, highp> float2x2; //!< \brief single-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, float, highp> float2x3; //!< \brief single-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, float, highp> float2x4; //!< \brief single-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, float, highp> float3x2; //!< \brief single-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, float, highp> float3x3; //!< \brief single-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, float, highp> float3x4; //!< \brief single-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, float, highp> float4x2; //!< \brief single-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, float, highp> float4x3; //!< \brief single-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, float, highp> float4x4; //!< \brief single-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef double double1; //!< \brief double-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, double, highp> double2; //!< \brief double-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, double, highp> double3; //!< \brief double-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, double, highp> double4; //!< \brief double-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef double double1x1; //!< \brief double-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, double, highp> double2x2; //!< \brief double-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, double, highp> double2x3; //!< \brief double-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, double, highp> double2x4; //!< \brief double-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, double, highp> double3x2; //!< \brief double-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, double, highp> double3x3; //!< \brief double-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, double, highp> double3x4; //!< \brief double-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, double, highp> double4x2; //!< \brief double-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, double, highp> double4x3; //!< \brief double-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, double, highp> double4x4; //!< \brief double-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + /// @} +}//namespace glm + +#include "compatibility.inl" diff --git a/src/GLMath/glm/gtx/compatibility.inl b/src/GLMath/glm/gtx/compatibility.inl new file mode 100644 index 0000000000000000000000000000000000000000..1d49496b6c6e817f67f416cac7f3881d8b54ece1 --- /dev/null +++ b/src/GLMath/glm/gtx/compatibility.inl @@ -0,0 +1,62 @@ +#include + +namespace glm +{ + // isfinite + template + GLM_FUNC_QUALIFIER bool isfinite( + genType const& x) + { +# if GLM_HAS_CXX11_STL + return std::isfinite(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_VC + return _finite(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_GCC && GLM_PLATFORM & GLM_PLATFORM_ANDROID + return _isfinite(x) != 0; +# else + if (std::numeric_limits::is_integer || std::denorm_absent == std::numeric_limits::has_denorm) + return std::numeric_limits::min() <= x && std::numeric_limits::max() >= x; + else + return -std::numeric_limits::max() <= x && std::numeric_limits::max() >= x; +# endif + } + + template + GLM_FUNC_QUALIFIER vec<1, bool, Q> isfinite( + vec<1, T, Q> const& x) + { + return vec<1, bool, Q>( + isfinite(x.x)); + } + + template + GLM_FUNC_QUALIFIER vec<2, bool, Q> isfinite( + vec<2, T, Q> const& x) + { + return vec<2, bool, Q>( + isfinite(x.x), + isfinite(x.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, bool, Q> isfinite( + vec<3, T, Q> const& x) + { + return vec<3, bool, Q>( + isfinite(x.x), + isfinite(x.y), + isfinite(x.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isfinite( + vec<4, T, Q> const& x) + { + return vec<4, bool, Q>( + isfinite(x.x), + isfinite(x.y), + isfinite(x.z), + isfinite(x.w)); + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/component_wise.hpp b/src/GLMath/glm/gtx/component_wise.hpp new file mode 100644 index 0000000000000000000000000000000000000000..34a2b0a37517023bd31f7466a356924ce6312e0b --- /dev/null +++ b/src/GLMath/glm/gtx/component_wise.hpp @@ -0,0 +1,69 @@ +/// @ref gtx_component_wise +/// @file glm/gtx/component_wise.hpp +/// @date 2007-05-21 / 2011-06-07 +/// @author Christophe Riccio +/// +/// @see core (dependence) +/// +/// @defgroup gtx_component_wise GLM_GTX_component_wise +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Operations between components of a type + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_component_wise is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_component_wise extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_component_wise + /// @{ + + /// Convert an integer vector to a normalized float vector. + /// If the parameter value type is already a floating qualifier type, the value is passed through. + /// @see gtx_component_wise + template + GLM_FUNC_DECL vec compNormalize(vec const& v); + + /// Convert a normalized float vector to an integer vector. + /// If the parameter value type is already a floating qualifier type, the value is passed through. + /// @see gtx_component_wise + template + GLM_FUNC_DECL vec compScale(vec const& v); + + /// Add all vector components together. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compAdd(genType const& v); + + /// Multiply all vector components together. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMul(genType const& v); + + /// Find the minimum value between single vector components. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMin(genType const& v); + + /// Find the maximum value between single vector components. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMax(genType const& v); + + /// @} +}//namespace glm + +#include "component_wise.inl" diff --git a/src/GLMath/glm/gtx/component_wise.inl b/src/GLMath/glm/gtx/component_wise.inl new file mode 100644 index 0000000000000000000000000000000000000000..cbbc7d41ec007021d1f199eb106c87396a5fc03a --- /dev/null +++ b/src/GLMath/glm/gtx/component_wise.inl @@ -0,0 +1,127 @@ +/// @ref gtx_component_wise + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_compNormalize + {}; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + floatType const Min = static_cast(std::numeric_limits::min()); + floatType const Max = static_cast(std::numeric_limits::max()); + return (vec(v) - Min) / (Max - Min) * static_cast(2) - static_cast(1); + } + }; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return vec(v) / static_cast(std::numeric_limits::max()); + } + }; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return v; + } + }; + + template + struct compute_compScale + {}; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + floatType const Max = static_cast(std::numeric_limits::max()) + static_cast(0.5); + vec const Scaled(v * Max); + vec const Result(Scaled - static_cast(0.5)); + return Result; + } + }; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return vec(vec(v) * static_cast(std::numeric_limits::max())); + } + }; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return v; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER vec compNormalize(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compNormalize' accepts only floating-point types for 'floatType' template parameter"); + + return detail::compute_compNormalize::is_integer, std::numeric_limits::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER vec compScale(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compScale' accepts only floating-point types for 'floatType' template parameter"); + + return detail::compute_compScale::is_integer, std::numeric_limits::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER T compAdd(vec const& v) + { + T Result(0); + for(length_t i = 0, n = v.length(); i < n; ++i) + Result += v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMul(vec const& v) + { + T Result(1); + for(length_t i = 0, n = v.length(); i < n; ++i) + Result *= v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMin(vec const& v) + { + T Result(v[0]); + for(length_t i = 1, n = v.length(); i < n; ++i) + Result = min(Result, v[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMax(vec const& v) + { + T Result(v[0]); + for(length_t i = 1, n = v.length(); i < n; ++i) + Result = max(Result, v[i]); + return Result; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/dual_quaternion.hpp b/src/GLMath/glm/gtx/dual_quaternion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6a51ab7d39ffd673cb7bb70d48b46b1c7e8b4c03 --- /dev/null +++ b/src/GLMath/glm/gtx/dual_quaternion.hpp @@ -0,0 +1,274 @@ +/// @ref gtx_dual_quaternion +/// @file glm/gtx/dual_quaternion.hpp +/// @author Maksim Vorobiev (msomeone@gmail.com) +/// +/// @see core (dependence) +/// @see gtc_constants (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_dual_quaternion GLM_GTX_dual_quaternion +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines a templated dual-quaternion type and several dual-quaternion operations. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_dual_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_dual_quaternion extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_dual_quaternion + /// @{ + + template + struct tdualquat + { + // -- Implementation detail -- + + typedef T value_type; + typedef qua part_type; + + // -- Data -- + + qua real, dual; + + // -- Component accesses -- + + typedef length_t length_type; + /// Return the count of components of a dual quaternion + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} + + GLM_FUNC_DECL part_type & operator[](length_type i); + GLM_FUNC_DECL part_type const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real); + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& orientation, vec<3, T, Q> const& translation); + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real, qua const& dual); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT tdualquat(tdualquat const& q); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<2, 4, T, Q> const& holder_mat); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<3, 4, T, Q> const& aug_mat); + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m) GLM_DEFAULT; + + template + GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m); + template + GLM_FUNC_DECL tdualquat & operator*=(U s); + template + GLM_FUNC_DECL tdualquat & operator/=(U s); + }; + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL tdualquat operator+(tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator-(tdualquat const& q); + + // -- Binary operators -- + + template + GLM_FUNC_DECL tdualquat operator+(tdualquat const& q, tdualquat const& p); + + template + GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, tdualquat const& p); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, T const& s); + + template + GLM_FUNC_DECL tdualquat operator*(T const& s, tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator/(tdualquat const& q, T const& s); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(tdualquat const& q1, tdualquat const& q2); + + template + GLM_FUNC_DECL bool operator!=(tdualquat const& q1, tdualquat const& q2); + + /// Creates an identity dual quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dual_quat_identity(); + + /// Returns the normalized quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat normalize(tdualquat const& q); + + /// Returns the linear interpolation of two dual quaternion. + /// + /// @see gtc_dual_quaternion + template + GLM_FUNC_DECL tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a); + + /// Returns the q inverse. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat inverse(tdualquat const& q); + + /// Converts a quaternion to a 2 * 4 matrix. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x); + + /// Converts a quaternion to a 3 * 4 matrix. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x); + + /// Converts a 2 * 4 matrix (matrix which holds real and dual parts) to a quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dualquat_cast(mat<2, 4, T, Q> const& x); + + /// Converts a 3 * 4 matrix (augmented matrix rotation + translation) to a quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dualquat_cast(mat<3, 4, T, Q> const& x); + + + /// Dual-quaternion of low single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_dualquat; + + /// Dual-quaternion of medium single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_dualquat; + + /// Dual-quaternion of high single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_dualquat; + + + /// Dual-quaternion of low single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_fdualquat; + + /// Dual-quaternion of medium single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_fdualquat; + + /// Dual-quaternion of high single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_fdualquat; + + + /// Dual-quaternion of low double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_ddualquat; + + /// Dual-quaternion of medium double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_ddualquat; + + /// Dual-quaternion of high double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_ddualquat; + + +#if(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + /// Dual-quaternion of floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_fdualquat dualquat; + + /// Dual-quaternion of single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_fdualquat fdualquat; +#elif(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + typedef highp_fdualquat dualquat; + typedef highp_fdualquat fdualquat; +#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + typedef mediump_fdualquat dualquat; + typedef mediump_fdualquat fdualquat; +#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT)) + typedef lowp_fdualquat dualquat; + typedef lowp_fdualquat fdualquat; +#else +# error "GLM error: multiple default precision requested for single-precision floating-point types" +#endif + + +#if(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + /// Dual-quaternion of default double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_ddualquat ddualquat; +#elif(defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef highp_ddualquat ddualquat; +#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef mediump_ddualquat ddualquat; +#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef lowp_ddualquat ddualquat; +#else +# error "GLM error: Multiple default precision requested for double-precision floating-point types" +#endif + + /// @} +} //namespace glm + +#include "dual_quaternion.inl" diff --git a/src/GLMath/glm/gtx/dual_quaternion.inl b/src/GLMath/glm/gtx/dual_quaternion.inl new file mode 100644 index 0000000000000000000000000000000000000000..fad07ea842c1f86ce0aba7e7c78bb85c3781fafe --- /dev/null +++ b/src/GLMath/glm/gtx/dual_quaternion.inl @@ -0,0 +1,352 @@ +/// @ref gtx_dual_quaternion + +#include "../geometric.hpp" +#include + +namespace glm +{ + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER typename tdualquat::part_type & tdualquat::operator[](typename tdualquat::length_type i) + { + assert(i >= 0 && i < this->length()); + return (&real)[i]; + } + + template + GLM_FUNC_QUALIFIER typename tdualquat::part_type const& tdualquat::operator[](typename tdualquat::length_type i) const + { + assert(i >= 0 && i < this->length()); + return (&real)[i]; + } + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat() +# if GLM_CONFIG_DEFAULTED_FUNCTIONS != GLM_DISABLE + : real(qua()) + , dual(qua(0, 0, 0, 0)) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) + : real(d.real) + , dual(d.dual) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) + : real(d.real) + , dual(d.dual) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r) + : real(r), dual(qua(0, 0, 0, 0)) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& q, vec<3, T, Q> const& p) + : real(q), dual( + T(-0.5) * ( p.x*q.x + p.y*q.y + p.z*q.z), + T(+0.5) * ( p.x*q.w + p.y*q.z - p.z*q.y), + T(+0.5) * (-p.x*q.z + p.y*q.w + p.z*q.x), + T(+0.5) * ( p.x*q.y - p.y*q.x + p.z*q.w)) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r, qua const& d) + : real(r), dual(d) + {} + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& q) + : real(q.real) + , dual(q.dual) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<2, 4, T, Q> const& m) + { + *this = dualquat_cast(m); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<3, 4, T, Q> const& m) + { + *this = dualquat_cast(m); + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) + { + this->real = q.real; + this->dual = q.dual; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) + { + this->real = q.real; + this->dual = q.dual; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator*=(U s) + { + this->real *= static_cast(s); + this->dual *= static_cast(s); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator/=(U s) + { + this->real /= static_cast(s); + this->dual /= static_cast(s); + return *this; + } + + // -- Unary bit operators -- + + template + GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q) + { + return q; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator-(tdualquat const& q) + { + return tdualquat(-q.real, -q.dual); + } + + // -- Binary operators -- + + template + GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q, tdualquat const& p) + { + return tdualquat(q.real + p.real,q.dual + p.dual); + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& p, tdualquat const& o) + { + return tdualquat(p.real * o.real,p.real * o.dual + p.dual * o.real); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v) + { + vec<3, T, Q> const real_v3(q.real.x,q.real.y,q.real.z); + vec<3, T, Q> const dual_v3(q.dual.x,q.dual.y,q.dual.z); + return (cross(real_v3, cross(real_v3,v) + v * q.real.w + dual_v3) + dual_v3 * q.real.w - real_v3 * q.dual.w) * T(2) + v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& q, T const& s) + { + return tdualquat(q.real * s, q.dual * s); + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(T const& s, tdualquat const& q) + { + return q * s; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator/(tdualquat const& q, T const& s) + { + return tdualquat(q.real / s, q.dual / s); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(tdualquat const& q1, tdualquat const& q2) + { + return (q1.real == q2.real) && (q1.dual == q2.dual); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(tdualquat const& q1, tdualquat const& q2) + { + return (q1.real != q2.real) || (q1.dual != q2.dual); + } + + // -- Operations -- + + template + GLM_FUNC_QUALIFIER tdualquat dual_quat_identity() + { + return tdualquat( + qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)), + qua(static_cast(0), static_cast(0), static_cast(0), static_cast(0))); + } + + template + GLM_FUNC_QUALIFIER tdualquat normalize(tdualquat const& q) + { + return q / length(q.real); + } + + template + GLM_FUNC_QUALIFIER tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a) + { + // Dual Quaternion Linear blend aka DLB: + // Lerp is only defined in [0, 1] + assert(a >= static_cast(0)); + assert(a <= static_cast(1)); + T const k = dot(x.real,y.real) < static_cast(0) ? -a : a; + T const one(1); + return tdualquat(x * (one - a) + y * k); + } + + template + GLM_FUNC_QUALIFIER tdualquat inverse(tdualquat const& q) + { + const glm::qua real = conjugate(q.real); + const glm::qua dual = conjugate(q.dual); + return tdualquat(real, dual + (real * (-2.0f * dot(real,dual)))); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x) + { + return mat<2, 4, T, Q>( x[0].x, x[0].y, x[0].z, x[0].w, x[1].x, x[1].y, x[1].z, x[1].w ); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x) + { + qua r = x.real / length2(x.real); + + qua const rr(r.w * x.real.w, r.x * x.real.x, r.y * x.real.y, r.z * x.real.z); + r *= static_cast(2); + + T const xy = r.x * x.real.y; + T const xz = r.x * x.real.z; + T const yz = r.y * x.real.z; + T const wx = r.w * x.real.x; + T const wy = r.w * x.real.y; + T const wz = r.w * x.real.z; + + vec<4, T, Q> const a( + rr.w + rr.x - rr.y - rr.z, + xy - wz, + xz + wy, + -(x.dual.w * r.x - x.dual.x * r.w + x.dual.y * r.z - x.dual.z * r.y)); + + vec<4, T, Q> const b( + xy + wz, + rr.w + rr.y - rr.x - rr.z, + yz - wx, + -(x.dual.w * r.y - x.dual.x * r.z - x.dual.y * r.w + x.dual.z * r.x)); + + vec<4, T, Q> const c( + xz - wy, + yz + wx, + rr.w + rr.z - rr.x - rr.y, + -(x.dual.w * r.z + x.dual.x * r.y - x.dual.y * r.x - x.dual.z * r.w)); + + return mat<3, 4, T, Q>(a, b, c); + } + + template + GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<2, 4, T, Q> const& x) + { + return tdualquat( + qua( x[0].w, x[0].x, x[0].y, x[0].z ), + qua( x[1].w, x[1].x, x[1].y, x[1].z )); + } + + template + GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<3, 4, T, Q> const& x) + { + qua real; + + T const trace = x[0].x + x[1].y + x[2].z; + if(trace > static_cast(0)) + { + T const r = sqrt(T(1) + trace); + T const invr = static_cast(0.5) / r; + real.w = static_cast(0.5) * r; + real.x = (x[2].y - x[1].z) * invr; + real.y = (x[0].z - x[2].x) * invr; + real.z = (x[1].x - x[0].y) * invr; + } + else if(x[0].x > x[1].y && x[0].x > x[2].z) + { + T const r = sqrt(T(1) + x[0].x - x[1].y - x[2].z); + T const invr = static_cast(0.5) / r; + real.x = static_cast(0.5)*r; + real.y = (x[1].x + x[0].y) * invr; + real.z = (x[0].z + x[2].x) * invr; + real.w = (x[2].y - x[1].z) * invr; + } + else if(x[1].y > x[2].z) + { + T const r = sqrt(T(1) + x[1].y - x[0].x - x[2].z); + T const invr = static_cast(0.5) / r; + real.x = (x[1].x + x[0].y) * invr; + real.y = static_cast(0.5) * r; + real.z = (x[2].y + x[1].z) * invr; + real.w = (x[0].z - x[2].x) * invr; + } + else + { + T const r = sqrt(T(1) + x[2].z - x[0].x - x[1].y); + T const invr = static_cast(0.5) / r; + real.x = (x[0].z + x[2].x) * invr; + real.y = (x[2].y + x[1].z) * invr; + real.z = static_cast(0.5) * r; + real.w = (x[1].x - x[0].y) * invr; + } + + qua dual; + dual.x = static_cast(0.5) * ( x[0].w * real.w + x[1].w * real.z - x[2].w * real.y); + dual.y = static_cast(0.5) * (-x[0].w * real.z + x[1].w * real.w + x[2].w * real.x); + dual.z = static_cast(0.5) * ( x[0].w * real.y - x[1].w * real.x + x[2].w * real.w); + dual.w = -static_cast(0.5) * ( x[0].w * real.x + x[1].w * real.y + x[2].w * real.z); + return tdualquat(real, dual); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/easing.hpp b/src/GLMath/glm/gtx/easing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..57f3d61b182672fa9aac192ff78a64ee1e7df395 --- /dev/null +++ b/src/GLMath/glm/gtx/easing.hpp @@ -0,0 +1,219 @@ +/// @ref gtx_easing +/// @file glm/gtx/easing.hpp +/// @author Robert Chisholm +/// +/// @see core (dependence) +/// +/// @defgroup gtx_easing GLM_GTX_easing +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Easing functions for animations and transitons +/// All functions take a parameter x in the range [0.0,1.0] +/// +/// Based on the AHEasing project of Warren Moore (https://github.com/warrenm/AHEasing) + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_easing is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_easing extension included") +# endif +#endif + +namespace glm{ + /// @addtogroup gtx_easing + /// @{ + + /// Modelled after the line y = x + /// @see gtx_easing + template + GLM_FUNC_DECL genType linearInterpolation(genType const & a); + + /// Modelled after the parabola y = x^2 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseIn(genType const & a); + + /// Modelled after the parabola y = -x^2 + 2x + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseOut(genType const & a); + + /// Modelled after the piecewise quadratic + /// y = (1/2)((2x)^2) ; [0, 0.5) + /// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseInOut(genType const & a); + + /// Modelled after the cubic y = x^3 + template + GLM_FUNC_DECL genType cubicEaseIn(genType const & a); + + /// Modelled after the cubic y = (x - 1)^3 + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType cubicEaseOut(genType const & a); + + /// Modelled after the piecewise cubic + /// y = (1/2)((2x)^3) ; [0, 0.5) + /// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType cubicEaseInOut(genType const & a); + + /// Modelled after the quartic x^4 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseIn(genType const & a); + + /// Modelled after the quartic y = 1 - (x - 1)^4 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseOut(genType const & a); + + /// Modelled after the piecewise quartic + /// y = (1/2)((2x)^4) ; [0, 0.5) + /// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseInOut(genType const & a); + + /// Modelled after the quintic y = x^5 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseIn(genType const & a); + + /// Modelled after the quintic y = (x - 1)^5 + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseOut(genType const & a); + + /// Modelled after the piecewise quintic + /// y = (1/2)((2x)^5) ; [0, 0.5) + /// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseInOut(genType const & a); + + /// Modelled after quarter-cycle of sine wave + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseIn(genType const & a); + + /// Modelled after quarter-cycle of sine wave (different phase) + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseOut(genType const & a); + + /// Modelled after half sine wave + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseInOut(genType const & a); + + /// Modelled after shifted quadrant IV of unit circle + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseIn(genType const & a); + + /// Modelled after shifted quadrant II of unit circle + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseOut(genType const & a); + + /// Modelled after the piecewise circular function + /// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) + /// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseInOut(genType const & a); + + /// Modelled after the exponential function y = 2^(10(x - 1)) + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseIn(genType const & a); + + /// Modelled after the exponential function y = -2^(-10x) + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseOut(genType const & a); + + /// Modelled after the piecewise exponential + /// y = (1/2)2^(10(2x - 1)) ; [0,0.5) + /// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseInOut(genType const & a); + + /// Modelled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseIn(genType const & a); + + /// Modelled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseOut(genType const & a); + + /// Modelled after the piecewise exponentially-damped sine wave: + /// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) + /// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseInOut(genType const & a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseIn(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseOut(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseInOut(genType const& a); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseIn(genType const& a, genType const& o); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseOut(genType const& a, genType const& o); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseInOut(genType const& a, genType const& o); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseIn(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseOut(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseInOut(genType const& a); + + /// @} +}//namespace glm + +#include "easing.inl" diff --git a/src/GLMath/glm/gtx/easing.inl b/src/GLMath/glm/gtx/easing.inl new file mode 100644 index 0000000000000000000000000000000000000000..4b7d05b719600ab2121f5c34f945f403a556225b --- /dev/null +++ b/src/GLMath/glm/gtx/easing.inl @@ -0,0 +1,436 @@ +/// @ref gtx_easing + +#include + +namespace glm{ + + template + GLM_FUNC_QUALIFIER genType linearInterpolation(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a; + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a; + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return -(a * (a - static_cast(2))); + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(2) * a * a; + } + else + { + return (-static_cast(2) * a * a) + (4 * a) - one(); + } + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = a - one(); + return f * f * f + one(); + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if (a < static_cast(0.5)) + { + return static_cast(4) * a * a * a; + } + else + { + genType const f = ((static_cast(2) * a) - static_cast(2)); + return static_cast(0.5) * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = (a - one()); + return f * f * f * (one() - a) + one(); + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(8) * a * a * a * a; + } + else + { + genType const f = (a - one()); + return -static_cast(8) * f * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = (a - one()); + return f * f * f * f * f + one(); + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(16) * a * a * a * a * a; + } + else + { + genType const f = ((static_cast(2) * a) - static_cast(2)); + return static_cast(0.5) * f * f * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType sineEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sin((a - one()) * half_pi()) + one(); + } + + template + GLM_FUNC_QUALIFIER genType sineEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sin(a * half_pi()); + } + + template + GLM_FUNC_QUALIFIER genType sineEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return static_cast(0.5) * (one() - cos(a * pi())); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return one() - sqrt(one() - (a * a)); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sqrt((static_cast(2) - a) * a); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(0.5) * (one() - std::sqrt(one() - static_cast(4) * (a * a))); + } + else + { + return static_cast(0.5) * (std::sqrt(-((static_cast(2) * a) - static_cast(3)) * ((static_cast(2) * a) - one())) + one()); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a <= zero()) + return a; + else + { + genType const Complementary = a - one(); + genType const Two = static_cast(2); + + return glm::pow(Two, Complementary * static_cast(10)); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a >= one()) + return a; + else + { + return one() - glm::pow(static_cast(2), -static_cast(10) * a); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + return static_cast(0.5) * glm::pow(static_cast(2), (static_cast(20) * a) - static_cast(10)); + else + return -static_cast(0.5) * glm::pow(static_cast(2), (-static_cast(20) * a) + static_cast(10)) + one(); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return std::sin(static_cast(13) * half_pi() * a) * glm::pow(static_cast(2), static_cast(10) * (a - one())); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return std::sin(-static_cast(13) * half_pi() * (a + one())) * glm::pow(static_cast(2), -static_cast(10) * a) + one(); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + return static_cast(0.5) * std::sin(static_cast(13) * half_pi() * (static_cast(2) * a)) * glm::pow(static_cast(2), static_cast(10) * ((static_cast(2) * a) - one())); + else + return static_cast(0.5) * (std::sin(-static_cast(13) * half_pi() * ((static_cast(2) * a - one()) + one())) * glm::pow(static_cast(2), -static_cast(10) * (static_cast(2) * a - one())) + static_cast(2)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType z = ((o + one()) * a) - o; + return (a * a * z); + } + + template + GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType n = a - one(); + genType z = ((o + one()) * n) + o; + return (n * n * z) + one(); + } + + template + GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType s = o * static_cast(1.525); + genType x = static_cast(0.5); + genType n = a / static_cast(0.5); + + if (n < static_cast(1)) + { + genType z = ((s + static_cast(1)) * n) - s; + genType m = n * n * z; + return x * m; + } + else + { + n -= static_cast(2); + genType z = ((s + static_cast(1)) * n) + s; + genType m = (n*n*z) + static_cast(2); + return x * m; + } + } + + template + GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a) + { + return backEaseIn(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a) + { + return backEaseOut(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a) + { + return backEaseInOut(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(4.0 / 11.0)) + { + return (static_cast(121) * a * a) / static_cast(16); + } + else if(a < static_cast(8.0 / 11.0)) + { + return (static_cast(363.0 / 40.0) * a * a) - (static_cast(99.0 / 10.0) * a) + static_cast(17.0 / 5.0); + } + else if(a < static_cast(9.0 / 10.0)) + { + return (static_cast(4356.0 / 361.0) * a * a) - (static_cast(35442.0 / 1805.0) * a) + static_cast(16061.0 / 1805.0); + } + else + { + return (static_cast(54.0 / 5.0) * a * a) - (static_cast(513.0 / 25.0) * a) + static_cast(268.0 / 25.0); + } + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return one() - bounceEaseOut(one() - a); + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(0.5) * (one() - bounceEaseOut(a * static_cast(2))); + } + else + { + return static_cast(0.5) * bounceEaseOut(a * static_cast(2) - one()) + static_cast(0.5); + } + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/euler_angles.hpp b/src/GLMath/glm/gtx/euler_angles.hpp new file mode 100644 index 0000000000000000000000000000000000000000..27236973af6079a54aa1183d3d50f38d381a1ab3 --- /dev/null +++ b/src/GLMath/glm/gtx/euler_angles.hpp @@ -0,0 +1,335 @@ +/// @ref gtx_euler_angles +/// @file glm/gtx/euler_angles.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_euler_angles GLM_GTX_euler_angles +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build matrices from Euler angles. +/// +/// Extraction of Euler angles from rotation matrix. +/// Based on the original paper 2014 Mike Day - Extracting Euler Angles from a Rotation Matrix. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_euler_angles is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_euler_angles extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_euler_angles + /// @{ + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle X. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleX( + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Y. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleY( + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Z. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZ( + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about X-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleX( + T const & angleX, T const & angularVelocityX); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Y-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleY( + T const & angleY, T const & angularVelocityY); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Z-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleZ( + T const & angleZ, T const & angularVelocityZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXY( + T const& angleX, + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYX( + T const& angleY, + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZ( + T const& angleX, + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZX( + T const& angle, + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZ( + T const& angleY, + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZY( + T const& angleZ, + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYZ( + T const& t1, + T const& t2, + T const& t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXZ( + T const& yaw, + T const& pitch, + T const& roll); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYZ( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXZ( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> yawPitchRoll( + T const& yaw, + T const& pitch, + T const& roll); + + /// Creates a 2D 2 * 2 rotation matrix from an euler angle. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> orientate2(T const& angle); + + /// Creates a 2D 4 * 4 homogeneous rotation matrix from an euler angle. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> orientate3(T const& angle); + + /// Creates a 3D 3 * 3 rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<3, 3, T, Q> orientate3(vec<3, T, Q> const& angles); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, Q> orientate4(vec<3, T, Q> const& angles); + + /// Extracts the (X * Y * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * X * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Z * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Y * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * X * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * Z * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * Y * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * X * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Z * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * Z * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * Y * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * X * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// @} +}//namespace glm + +#include "euler_angles.inl" diff --git a/src/GLMath/glm/gtx/euler_angles.inl b/src/GLMath/glm/gtx/euler_angles.inl new file mode 100644 index 0000000000000000000000000000000000000000..68c50124e80eb446a454508bf925f62247cb04e5 --- /dev/null +++ b/src/GLMath/glm/gtx/euler_angles.inl @@ -0,0 +1,899 @@ +/// @ref gtx_euler_angles + +#include "compatibility.hpp" // glm::atan2 + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleX + ( + T const& angleX + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + + return mat<4, 4, T, defaultp>( + T(1), T(0), T(0), T(0), + T(0), cosX, sinX, T(0), + T(0),-sinX, cosX, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleY + ( + T const& angleY + ) + { + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, T(0), -sinY, T(0), + T(0), T(1), T(0), T(0), + sinY, T(0), cosY, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZ + ( + T const& angleZ + ) + { + T cosZ = glm::cos(angleZ); + T sinZ = glm::sin(angleZ); + + return mat<4, 4, T, defaultp>( + cosZ, sinZ, T(0), T(0), + -sinZ, cosZ, T(0), T(0), + T(0), T(0), T(1), T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleX + ( + T const & angleX, + T const & angularVelocityX + ) + { + T cosX = glm::cos(angleX) * angularVelocityX; + T sinX = glm::sin(angleX) * angularVelocityX; + + return mat<4, 4, T, defaultp>( + T(0), T(0), T(0), T(0), + T(0),-sinX, cosX, T(0), + T(0),-cosX,-sinX, T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleY + ( + T const & angleY, + T const & angularVelocityY + ) + { + T cosY = glm::cos(angleY) * angularVelocityY; + T sinY = glm::sin(angleY) * angularVelocityY; + + return mat<4, 4, T, defaultp>( + -sinY, T(0), -cosY, T(0), + T(0), T(0), T(0), T(0), + cosY, T(0), -sinY, T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleZ + ( + T const & angleZ, + T const & angularVelocityZ + ) + { + T cosZ = glm::cos(angleZ) * angularVelocityZ; + T sinZ = glm::sin(angleZ) * angularVelocityZ; + + return mat<4, 4, T, defaultp>( + -sinZ, cosZ, T(0), T(0), + -cosZ, -sinZ, T(0), T(0), + T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXY + ( + T const& angleX, + T const& angleY + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, -sinX * -sinY, cosX * -sinY, T(0), + T(0), cosX, sinX, T(0), + sinY, -sinX * cosY, cosX * cosY, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYX + ( + T const& angleY, + T const& angleX + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, 0, -sinY, T(0), + sinY * sinX, cosX, cosY * sinX, T(0), + sinY * cosX, -sinX, cosY * cosX, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZ + ( + T const& angleX, + T const& angleZ + ) + { + return eulerAngleX(angleX) * eulerAngleZ(angleZ); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZX + ( + T const& angleZ, + T const& angleX + ) + { + return eulerAngleZ(angleZ) * eulerAngleX(angleX); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZ + ( + T const& angleY, + T const& angleZ + ) + { + return eulerAngleY(angleY) * eulerAngleZ(angleZ); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZY + ( + T const& angleZ, + T const& angleY + ) + { + return eulerAngleZ(angleZ) * eulerAngleY(angleY); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYZ + ( + T const& t1, + T const& t2, + T const& t3 + ) + { + T c1 = glm::cos(-t1); + T c2 = glm::cos(-t2); + T c3 = glm::cos(-t3); + T s1 = glm::sin(-t1); + T s2 = glm::sin(-t2); + T s3 = glm::sin(-t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2 * c3; + Result[0][1] =-c1 * s3 + s1 * s2 * c3; + Result[0][2] = s1 * s3 + c1 * s2 * c3; + Result[0][3] = static_cast(0); + Result[1][0] = c2 * s3; + Result[1][1] = c1 * c3 + s1 * s2 * s3; + Result[1][2] =-s1 * c3 + c1 * s2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] =-s2; + Result[2][1] = s1 * c2; + Result[2][2] = c1 * c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXZ + ( + T const& yaw, + T const& pitch, + T const& roll + ) + { + T tmp_ch = glm::cos(yaw); + T tmp_sh = glm::sin(yaw); + T tmp_cp = glm::cos(pitch); + T tmp_sp = glm::sin(pitch); + T tmp_cb = glm::cos(roll); + T tmp_sb = glm::sin(roll); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; + Result[0][1] = tmp_sb * tmp_cp; + Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; + Result[0][3] = static_cast(0); + Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; + Result[1][1] = tmp_cb * tmp_cp; + Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; + Result[1][3] = static_cast(0); + Result[2][0] = tmp_sh * tmp_cp; + Result[2][1] = -tmp_sp; + Result[2][2] = tmp_ch * tmp_cp; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2; + Result[0][1] = c1 * s2; + Result[0][2] = s1 * s2; + Result[0][3] = static_cast(0); + Result[1][0] =-c3 * s2; + Result[1][1] = c1 * c2 * c3 - s1 * s3; + Result[1][2] = c1 * s3 + c2 * c3 * s1; + Result[1][3] = static_cast(0); + Result[2][0] = s2 * s3; + Result[2][1] =-c3 * s1 - c1 * c2 * s3; + Result[2][2] = c1 * c3 - c2 * s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2; + Result[0][1] = s1 * s2; + Result[0][2] =-c1 * s2; + Result[0][3] = static_cast(0); + Result[1][0] = s2 * s3; + Result[1][1] = c1 * c3 - c2 * s1 * s3; + Result[1][2] = c3 * s1 + c1 * c2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s2; + Result[2][1] =-c1 * s3 - c2 * c3 * s1; + Result[2][2] = c1 * c2 * c3 - s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - c2 * s1 * s3; + Result[0][1] = s2* s3; + Result[0][2] =-c3 * s1 - c1 * c2 * s3; + Result[0][3] = static_cast(0); + Result[1][0] = s1 * s2; + Result[1][1] = c2; + Result[1][2] = c1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s3 + c2 * c3 * s1; + Result[2][1] =-c3 * s2; + Result[2][2] = c1 * c2 * c3 - s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2 * c3 - s1 * s3; + Result[0][1] = c3 * s2; + Result[0][2] =-c1 * s3 - c2 * c3 * s1; + Result[0][3] = static_cast(0); + Result[1][0] =-c1 * s2; + Result[1][1] = c2; + Result[1][2] = s1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s1 + c1 * c2 * s3; + Result[2][1] = s2 * s3; + Result[2][2] = c1 * c3 - c2 * s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYZ + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2 * c3 - s1 * s3; + Result[0][1] = c1 * s3 + c2 * c3 * s1; + Result[0][2] =-c3 * s2; + Result[0][3] = static_cast(0); + Result[1][0] =-c3 * s1 - c1 * c2 * s3; + Result[1][1] = c1 * c3 - c2 * s1 * s3; + Result[1][2] = s2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s2; + Result[2][1] = s1 * s2; + Result[2][2] = c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXZ + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - c2 * s1 * s3; + Result[0][1] = c3 * s1 + c1 * c2 * s3; + Result[0][2] = s2 *s3; + Result[0][3] = static_cast(0); + Result[1][0] =-c1 * s3 - c2 * c3 * s1; + Result[1][1] = c1 * c2 * c3 - s1 * s3; + Result[1][2] = c3 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = s1 * s2; + Result[2][1] =-c1 * s2; + Result[2][2] = c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2 * c3; + Result[0][1] = s1 * s3 + c1 * c3 * s2; + Result[0][2] = c3 * s1 * s2 - c1 * s3; + Result[0][3] = static_cast(0); + Result[1][0] =-s2; + Result[1][1] = c1 * c2; + Result[1][2] = c2 * s1; + Result[1][3] = static_cast(0); + Result[2][0] = c2 * s3; + Result[2][1] = c1 * s2 * s3 - c3 * s1; + Result[2][2] = c1 * c3 + s1 * s2 *s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2; + Result[0][1] = s2; + Result[0][2] =-c2 * s1; + Result[0][3] = static_cast(0); + Result[1][0] = s1 * s3 - c1 * c3 * s2; + Result[1][1] = c2 * c3; + Result[1][2] = c1 * s3 + c3 * s1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s1 + c1 * s2 * s3; + Result[2][1] =-c2 * s3; + Result[2][2] = c1 * c3 - s1 * s2 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2; + Result[0][1] = c2 * s1; + Result[0][2] =-s2; + Result[0][3] = static_cast(0); + Result[1][0] = c1 * s2 * s3 - c3 * s1; + Result[1][1] = c1 * c3 + s1 * s2 * s3; + Result[1][2] = c2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = s1 * s3 + c1 * c3 * s2; + Result[2][1] = c3 * s1 * s2 - c1 * s3; + Result[2][2] = c2 * c3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - s1 * s2 * s3; + Result[0][1] = c3 * s1 + c1 * s2 * s3; + Result[0][2] =-c2 * s3; + Result[0][3] = static_cast(0); + Result[1][0] =-c2 * s1; + Result[1][1] = c1 * c2; + Result[1][2] = s2; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s3 + c3 * s1 * s2; + Result[2][1] = s1 * s3 - c1 * c3 * s2; + Result[2][2] = c2 * c3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> yawPitchRoll + ( + T const& yaw, + T const& pitch, + T const& roll + ) + { + T tmp_ch = glm::cos(yaw); + T tmp_sh = glm::sin(yaw); + T tmp_cp = glm::cos(pitch); + T tmp_sp = glm::sin(pitch); + T tmp_cb = glm::cos(roll); + T tmp_sb = glm::sin(roll); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; + Result[0][1] = tmp_sb * tmp_cp; + Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; + Result[0][3] = static_cast(0); + Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; + Result[1][1] = tmp_cb * tmp_cp; + Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; + Result[1][3] = static_cast(0); + Result[2][0] = tmp_sh * tmp_cp; + Result[2][1] = -tmp_sp; + Result[2][2] = tmp_ch * tmp_cp; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> orientate2 + ( + T const& angle + ) + { + T c = glm::cos(angle); + T s = glm::sin(angle); + + mat<2, 2, T, defaultp> Result; + Result[0][0] = c; + Result[0][1] = s; + Result[1][0] = -s; + Result[1][1] = c; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> orientate3 + ( + T const& angle + ) + { + T c = glm::cos(angle); + T s = glm::sin(angle); + + mat<3, 3, T, defaultp> Result; + Result[0][0] = c; + Result[0][1] = s; + Result[0][2] = 0.0f; + Result[1][0] = -s; + Result[1][1] = c; + Result[1][2] = 0.0f; + Result[2][0] = 0.0f; + Result[2][1] = 0.0f; + Result[2][2] = 1.0f; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orientate3 + ( + vec<3, T, Q> const& angles + ) + { + return mat<3, 3, T, Q>(yawPitchRoll(angles.z, angles.x, angles.y)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientate4 + ( + vec<3, T, Q> const& angles + ) + { + return yawPitchRoll(angles.z, angles.x, angles.y); + } + + template + GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][1], M[2][2]); + T C2 = glm::sqrt(M[0][0]*M[0][0] + M[1][0]*M[1][0]); + T T2 = glm::atan2(-M[2][0], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[0][2] - C1*M[0][1], C1*M[1][1] - S1*M[1][2 ]); + t1 = -T1; + t2 = -T2; + t3 = -T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][0], M[2][2]); + T C2 = glm::sqrt(M[0][1]*M[0][1] + M[1][1]*M[1][1]); + T T2 = glm::atan2(-M[2][1], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[1][2] - C1*M[1][0], C1*M[0][0] - S1*M[0][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][2], M[0][1]); + T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(S2, M[0][0]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[1][2] - S1*M[1][1], C1*M[2][2] - S1*M[2][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][1], -M[0][2]); + T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(S2, M[0][0]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-C1*M[2][1] - S1*M[2][2], C1*M[1][1] + S1*M[1][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][0], M[1][2]); + T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(S2, M[1][1]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[2][0] - S1*M[2][2], C1*M[0][0] - S1*M[0][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][2], -M[1][0]); + T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(S2, M[1][1]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-S1*M[0][0] - C1*M[0][2], S1*M[2][0] + C1*M[2][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][1], M[2][0]); + T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); + T T2 = glm::atan2(S2, M[2][2]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[0][1] - S1*M[0][0], C1*M[1][1] - S1*M[1][0]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][0], -M[2][1]); + T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); + T T2 = glm::atan2(S2, M[2][2]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-C1*M[1][0] - S1*M[1][1], C1*M[0][0] + S1*M[0][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][2], M[1][1]); + T C2 = glm::sqrt(M[0][0]*M[0][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(-M[1][0], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[0][1] - C1*M[0][2], C1*M[2][2] - S1*M[2][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(-M[0][2], M[0][0]); + T C2 = glm::sqrt(M[1][1]*M[1][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(M[0][1], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[1][0] + C1*M[1][2], S1*M[2][0] + C1*M[2][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][1], M[0][0]); + T C2 = glm::sqrt(M[1][2]*M[1][2] + M[2][2]*M[2][2]); + T T2 = glm::atan2(-M[0][2], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[2][0] - C1*M[2][1], C1*M[1][1] - S1*M[1][0]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(-M[1][0], M[1][1]); + T C2 = glm::sqrt(M[0][2]*M[0][2] + M[2][2]*M[2][2]); + T T2 = glm::atan2(M[1][2], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[2][0] + S1*M[2][1], C1*M[0][0] + S1*M[0][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/extend.hpp b/src/GLMath/glm/gtx/extend.hpp new file mode 100644 index 0000000000000000000000000000000000000000..28b7c5c014a45222c522ef146d687ec77ce62651 --- /dev/null +++ b/src/GLMath/glm/gtx/extend.hpp @@ -0,0 +1,42 @@ +/// @ref gtx_extend +/// @file glm/gtx/extend.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_extend GLM_GTX_extend +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extend a position from a source to a position at a defined length. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extend extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_extend + /// @{ + + /// Extends of Length the Origin position using the (Source - Origin) direction. + /// @see gtx_extend + template + GLM_FUNC_DECL genType extend( + genType const& Origin, + genType const& Source, + typename genType::value_type const Length); + + /// @} +}//namespace glm + +#include "extend.inl" diff --git a/src/GLMath/glm/gtx/extend.inl b/src/GLMath/glm/gtx/extend.inl new file mode 100644 index 0000000000000000000000000000000000000000..32128eb209ac74cf9c875c501cdc2c98956a3528 --- /dev/null +++ b/src/GLMath/glm/gtx/extend.inl @@ -0,0 +1,48 @@ +/// @ref gtx_extend + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType extend + ( + genType const& Origin, + genType const& Source, + genType const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> extend + ( + vec<2, T, Q> const& Origin, + vec<2, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> extend + ( + vec<3, T, Q> const& Origin, + vec<3, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> extend + ( + vec<4, T, Q> const& Origin, + vec<4, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/extended_min_max.hpp b/src/GLMath/glm/gtx/extended_min_max.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ad23a91dcb05614590db0683980d9c53d0cced19 --- /dev/null +++ b/src/GLMath/glm/gtx/extended_min_max.hpp @@ -0,0 +1,182 @@ +/// @ref gtx_extended_min_max +/// @file glm/gtx/extended_min_max.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_extended_min_max GLM_GTX_extented_min_max +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Min and max functions for 3 to 4 parameters. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extented_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extented_min_max extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_extended_min_max + /// @{ + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T min( + T const& x, + T const& y, + T const& z); + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + typename C::T const& y, + typename C::T const& z); + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + C const& y, + C const& z); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T min( + T const& x, + T const& y, + T const& z, + T const& w); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + C const& y, + C const& z, + C const& w); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T max( + T const& x, + T const& y, + T const& z); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + typename C::T const& y, + typename C::T const& z); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + C const& y, + C const& z); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T max( + T const& x, + T const& y, + T const& z, + T const& w); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + C const& y, + C const& z, + C const& w); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL genType fmin(genType x, genType y); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam genType Floating-point; scalar or vector types. + /// + /// @see gtx_extented_min_max + /// @see std::fmax documentation + template + GLM_FUNC_DECL genType fmax(genType x, genType y); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL genType fclamp(genType x, genType minVal, genType maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL vec fclamp(vec const& x, T minVal, T maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL vec fclamp(vec const& x, vec const& minVal, vec const& maxVal); + + + /// @} +}//namespace glm + +#include "extended_min_max.inl" diff --git a/src/GLMath/glm/gtx/extended_min_max.inl b/src/GLMath/glm/gtx/extended_min_max.inl new file mode 100644 index 0000000000000000000000000000000000000000..e72d1ccf1d675537eee8109b9276330bddaadc2b --- /dev/null +++ b/src/GLMath/glm/gtx/extended_min_max.inl @@ -0,0 +1,218 @@ +/// @ref gtx_extended_min_max + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T min( + T const& x, + T const& y, + T const& z) + { + return glm::min(glm::min(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + typename C::T const& y, + typename C::T const& z + ) + { + return glm::min(glm::min(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + C const& y, + C const& z + ) + { + return glm::min(glm::min(x, y), z); + } + + template + GLM_FUNC_QUALIFIER T min + ( + T const& x, + T const& y, + T const& z, + T const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + C const& y, + C const& z, + C const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template + GLM_FUNC_QUALIFIER T max( + T const& x, + T const& y, + T const& z) + { + return glm::max(glm::max(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + typename C::T const& y, + typename C::T const& z + ) + { + return glm::max(glm::max(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + C const& y, + C const& z + ) + { + return glm::max(glm::max(x, y), z); + } + + template + GLM_FUNC_QUALIFIER T max + ( + T const& x, + T const& y, + T const& z, + T const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + C const& y, + C const& z, + C const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + // fmin +# if GLM_HAS_CXX11_STL + using std::fmin; +# else + template + GLM_FUNC_QUALIFIER genType fmin(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(x)) + return y; + if (isnan(y)) + return x; + + return min(x, y); + } +# endif + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, T b) + { + return detail::functor2::call(fmin, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b) + { + return detail::functor2::call(fmin, a, b); + } + + // fmax +# if GLM_HAS_CXX11_STL + using std::fmax; +# else + template + GLM_FUNC_QUALIFIER genType fmax(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(x)) + return y; + if (isnan(y)) + return x; + + return max(x, y); + } +# endif + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, T b) + { + return detail::functor2::call(fmax, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b) + { + return detail::functor2::call(fmax, a, b); + } + + // fclamp + template + GLM_FUNC_QUALIFIER genType fclamp(genType x, genType minVal, genType maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fclamp' only accept floating-point or integer inputs"); + return fmin(fmax(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER vec fclamp(vec const& x, T minVal, T maxVal) + { + return fmin(fmax(x, vec(minVal)), vec(maxVal)); + } + + template + GLM_FUNC_QUALIFIER vec fclamp(vec const& x, vec const& minVal, vec const& maxVal) + { + return fmin(fmax(x, minVal), maxVal); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/exterior_product.hpp b/src/GLMath/glm/gtx/exterior_product.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5522df7883c8bdaec64f287606d0a2aa526ed0d5 --- /dev/null +++ b/src/GLMath/glm/gtx/exterior_product.hpp @@ -0,0 +1,45 @@ +/// @ref gtx_exterior_product +/// @file glm/gtx/exterior_product.hpp +/// +/// @see core (dependence) +/// @see gtx_exterior_product (dependence) +/// +/// @defgroup gtx_exterior_product GLM_GTX_exterior_product +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_exterior_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_exterior_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_exterior_product + /// @{ + + /// Returns the cross product of x and y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see Exterior product + template + GLM_FUNC_DECL T cross(vec<2, T, Q> const& v, vec<2, T, Q> const& u); + + /// @} +} //namespace glm + +#include "exterior_product.inl" diff --git a/src/GLMath/glm/gtx/exterior_product.inl b/src/GLMath/glm/gtx/exterior_product.inl new file mode 100644 index 0000000000000000000000000000000000000000..93661fd3fd7f581806610df4293bdc8bf5c4a71c --- /dev/null +++ b/src/GLMath/glm/gtx/exterior_product.inl @@ -0,0 +1,26 @@ +/// @ref gtx_exterior_product + +#include + +namespace glm { +namespace detail +{ + template + struct compute_cross_vec2 + { + GLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& v, vec<2, T, Q> const& u) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); + + return v.x * u.y - u.x * v.y; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER T cross(vec<2, T, Q> const& x, vec<2, T, Q> const& y) + { + return detail::compute_cross_vec2::value>::call(x, y); + } +}//namespace glm + diff --git a/src/GLMath/glm/gtx/fast_exponential.hpp b/src/GLMath/glm/gtx/fast_exponential.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6fb7286528cf085a623f66bbfc836261159a0354 --- /dev/null +++ b/src/GLMath/glm/gtx/fast_exponential.hpp @@ -0,0 +1,95 @@ +/// @ref gtx_fast_exponential +/// @file glm/gtx/fast_exponential.hpp +/// +/// @see core (dependence) +/// @see gtx_half_float (dependence) +/// +/// @defgroup gtx_fast_exponential GLM_GTX_fast_exponential +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of exponential based functions. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_exponential is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_exponential extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_exponential + /// @{ + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL genType fastPow(genType x, genType y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastPow(vec const& x, vec const& y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL genTypeT fastPow(genTypeT x, genTypeU y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastPow(vec const& x); + + /// Faster than the common exp function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastExp(T x); + + /// Faster than the common exp function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastExp(vec const& x); + + /// Faster than the common log function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastLog(T x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastLog(vec const& x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastExp2(T x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastExp2(vec const& x); + + /// Faster than the common log2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastLog2(T x); + + /// Faster than the common log2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastLog2(vec const& x); + + /// @} +}//namespace glm + +#include "fast_exponential.inl" diff --git a/src/GLMath/glm/gtx/fast_exponential.inl b/src/GLMath/glm/gtx/fast_exponential.inl new file mode 100644 index 0000000000000000000000000000000000000000..f139e505636b6ecc187b2f544590669155ba0aec --- /dev/null +++ b/src/GLMath/glm/gtx/fast_exponential.inl @@ -0,0 +1,136 @@ +/// @ref gtx_fast_exponential + +namespace glm +{ + // fastPow: + template + GLM_FUNC_QUALIFIER genType fastPow(genType x, genType y) + { + return exp(y * log(x)); + } + + template + GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) + { + return exp(y * log(x)); + } + + template + GLM_FUNC_QUALIFIER T fastPow(T x, int y) + { + T f = static_cast(1); + for(int i = 0; i < y; ++i) + f *= x; + return f; + } + + template + GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = x.length(); i < n; ++i) + Result[i] = fastPow(x[i], y[i]); + return Result; + } + + // fastExp + // Note: This function provides accurate results only for value between -1 and 1, else avoid it. + template + GLM_FUNC_QUALIFIER T fastExp(T x) + { + // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. + // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); + T x2 = x * x; + T x3 = x2 * x; + T x4 = x3 * x; + T x5 = x4 * x; + return T(1) + x + (x2 * T(0.5)) + (x3 * T(0.1666666667)) + (x4 * T(0.041666667)) + (x5 * T(0.008333333333)); + } + /* // Try to handle all values of float... but often shower than std::exp, glm::floor and the loop kill the performance + GLM_FUNC_QUALIFIER float fastExp(float x) + { + const float e = 2.718281828f; + const float IntegerPart = floor(x); + const float FloatPart = x - IntegerPart; + float z = 1.f; + + for(int i = 0; i < int(IntegerPart); ++i) + z *= e; + + const float x2 = FloatPart * FloatPart; + const float x3 = x2 * FloatPart; + const float x4 = x3 * FloatPart; + const float x5 = x4 * FloatPart; + return z * (1.0f + FloatPart + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)); + } + + // Increase accuracy on number bigger that 1 and smaller than -1 but it's not enough for high and negative numbers + GLM_FUNC_QUALIFIER float fastExp(float x) + { + // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. + // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); + float x2 = x * x; + float x3 = x2 * x; + float x4 = x3 * x; + float x5 = x4 * x; + float x6 = x5 * x; + float x7 = x6 * x; + float x8 = x7 * x; + return 1.0f + x + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)+ (x6 * 0.00138888888888f) + (x7 * 0.000198412698f) + (x8 * 0.0000248015873f);; + } + */ + + template + GLM_FUNC_QUALIFIER vec fastExp(vec const& x) + { + return detail::functor1::call(fastExp, x); + } + + // fastLog + template + GLM_FUNC_QUALIFIER genType fastLog(genType x) + { + return std::log(x); + } + + /* Slower than the VC7.1 function... + GLM_FUNC_QUALIFIER float fastLog(float x) + { + float y1 = (x - 1.0f) / (x + 1.0f); + float y2 = y1 * y1; + return 2.0f * y1 * (1.0f + y2 * (0.3333333333f + y2 * (0.2f + y2 * 0.1428571429f))); + } + */ + + template + GLM_FUNC_QUALIFIER vec fastLog(vec const& x) + { + return detail::functor1::call(fastLog, x); + } + + //fastExp2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType fastExp2(genType x) + { + return fastExp(0.69314718055994530941723212145818f * x); + } + + template + GLM_FUNC_QUALIFIER vec fastExp2(vec const& x) + { + return detail::functor1::call(fastExp2, x); + } + + // fastLog2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType fastLog2(genType x) + { + return fastLog(x) / 0.69314718055994530941723212145818f; + } + + template + GLM_FUNC_QUALIFIER vec fastLog2(vec const& x) + { + return detail::functor1::call(fastLog2, x); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/fast_square_root.hpp b/src/GLMath/glm/gtx/fast_square_root.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9fb3f2fce0af2e6555ac65d1a7c3ce05c14de118 --- /dev/null +++ b/src/GLMath/glm/gtx/fast_square_root.hpp @@ -0,0 +1,92 @@ +/// @ref gtx_fast_square_root +/// @file glm/gtx/fast_square_root.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_fast_square_root GLM_GTX_fast_square_root +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of square root based functions. +/// - Sqrt optimisation based on Newton's method, +/// www.gamedev.net/community/forums/topic.asp?topic id=139956 + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../exponential.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_square_root is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_square_root extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_square_root + /// @{ + + /// Faster than the common sqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastSqrt(genType x); + + /// Faster than the common sqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL vec fastSqrt(vec const& x); + + /// Faster than the common inversesqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastInverseSqrt(genType x); + + /// Faster than the common inversesqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL vec fastInverseSqrt(vec const& x); + + /// Faster than the common length function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastLength(genType x); + + /// Faster than the common length function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL T fastLength(vec const& x); + + /// Faster than the common distance function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastDistance(genType x, genType y); + + /// Faster than the common distance function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL T fastDistance(vec const& x, vec const& y); + + /// Faster than the common normalize function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastNormalize(genType const& x); + + /// @} +}// namespace glm + +#include "fast_square_root.inl" diff --git a/src/GLMath/glm/gtx/fast_square_root.inl b/src/GLMath/glm/gtx/fast_square_root.inl new file mode 100644 index 0000000000000000000000000000000000000000..0bc359002420677fadc84561017312a02bf16b21 --- /dev/null +++ b/src/GLMath/glm/gtx/fast_square_root.inl @@ -0,0 +1,80 @@ +/// @ref gtx_fast_square_root + +namespace glm +{ + // fastSqrt + template + GLM_FUNC_QUALIFIER genType fastSqrt(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastSqrt' only accept floating-point input"); + + return genType(1) / fastInverseSqrt(x); + } + + template + GLM_FUNC_QUALIFIER vec fastSqrt(vec const& x) + { + return detail::functor1::call(fastSqrt, x); + } + + // fastInversesqrt + template + GLM_FUNC_QUALIFIER genType fastInverseSqrt(genType x) + { +# ifdef __CUDACC__ // Wordaround for a CUDA compiler bug up to CUDA6 + vec<1, T, Q> tmp(detail::compute_inversesqrt::value>::call(vec<1, genType, lowp>(x))); + return tmp.x; +# else + return detail::compute_inversesqrt<1, genType, lowp, detail::is_aligned::value>::call(vec<1, genType, lowp>(x)).x; +# endif + } + + template + GLM_FUNC_QUALIFIER vec fastInverseSqrt(vec const& x) + { + return detail::compute_inversesqrt::value>::call(x); + } + + // fastLength + template + GLM_FUNC_QUALIFIER genType fastLength(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); + + return abs(x); + } + + template + GLM_FUNC_QUALIFIER T fastLength(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); + + return fastSqrt(dot(x, x)); + } + + // fastDistance + template + GLM_FUNC_QUALIFIER genType fastDistance(genType x, genType y) + { + return fastLength(y - x); + } + + template + GLM_FUNC_QUALIFIER T fastDistance(vec const& x, vec const& y) + { + return fastLength(y - x); + } + + // fastNormalize + template + GLM_FUNC_QUALIFIER genType fastNormalize(genType x) + { + return x > genType(0) ? genType(1) : -genType(1); + } + + template + GLM_FUNC_QUALIFIER vec fastNormalize(vec const& x) + { + return x * fastInverseSqrt(dot(x, x)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/fast_trigonometry.hpp b/src/GLMath/glm/gtx/fast_trigonometry.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2650d6e4d6e3f0b1e12a4c44b8a046d788bcbc90 --- /dev/null +++ b/src/GLMath/glm/gtx/fast_trigonometry.hpp @@ -0,0 +1,79 @@ +/// @ref gtx_fast_trigonometry +/// @file glm/gtx/fast_trigonometry.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_fast_trigonometry GLM_GTX_fast_trigonometry +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of trigonometric functions. + +#pragma once + +// Dependency: +#include "../gtc/constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_trigonometry is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_trigonometry extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_trigonometry + /// @{ + + /// Wrap an angle to [0 2pi[ + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T wrapAngle(T angle); + + /// Faster than the common sin function but less accurate. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastSin(T angle); + + /// Faster than the common cos function but less accurate. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastCos(T angle); + + /// Faster than the common tan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastTan(T angle); + + /// Faster than the common asin function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAsin(T angle); + + /// Faster than the common acos function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAcos(T angle); + + /// Faster than the common atan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAtan(T y, T x); + + /// Faster than the common atan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAtan(T angle); + + /// @} +}//namespace glm + +#include "fast_trigonometry.inl" diff --git a/src/GLMath/glm/gtx/fast_trigonometry.inl b/src/GLMath/glm/gtx/fast_trigonometry.inl new file mode 100644 index 0000000000000000000000000000000000000000..1a710cbcd08d48ebabfaa09e6314c3397e0d0fd5 --- /dev/null +++ b/src/GLMath/glm/gtx/fast_trigonometry.inl @@ -0,0 +1,142 @@ +/// @ref gtx_fast_trigonometry + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER vec taylorCos(vec const& x) + { + return static_cast(1) + - (x * x) * (1.f / 2.f) + + ((x * x) * (x * x)) * (1.f / 24.f) + - (((x * x) * (x * x)) * (x * x)) * (1.f / 720.f) + + (((x * x) * (x * x)) * ((x * x) * (x * x))) * (1.f / 40320.f); + } + + template + GLM_FUNC_QUALIFIER T cos_52s(T x) + { + T const xx(x * x); + return (T(0.9999932946) + xx * (T(-0.4999124376) + xx * (T(0.0414877472) + xx * T(-0.0012712095)))); + } + + template + GLM_FUNC_QUALIFIER vec cos_52s(vec const& x) + { + return detail::functor1::call(cos_52s, x); + } +}//namespace detail + + // wrapAngle + template + GLM_FUNC_QUALIFIER T wrapAngle(T angle) + { + return abs(mod(angle, two_pi())); + } + + template + GLM_FUNC_QUALIFIER vec wrapAngle(vec const& x) + { + return detail::functor1::call(wrapAngle, x); + } + + // cos + template + GLM_FUNC_QUALIFIER T fastCos(T x) + { + T const angle(wrapAngle(x)); + + if(angle < half_pi()) + return detail::cos_52s(angle); + if(angle < pi()) + return -detail::cos_52s(pi() - angle); + if(angle < (T(3) * half_pi())) + return -detail::cos_52s(angle - pi()); + + return detail::cos_52s(two_pi() - angle); + } + + template + GLM_FUNC_QUALIFIER vec fastCos(vec const& x) + { + return detail::functor1::call(fastCos, x); + } + + // sin + template + GLM_FUNC_QUALIFIER T fastSin(T x) + { + return fastCos(half_pi() - x); + } + + template + GLM_FUNC_QUALIFIER vec fastSin(vec const& x) + { + return detail::functor1::call(fastSin, x); + } + + // tan + template + GLM_FUNC_QUALIFIER T fastTan(T x) + { + return x + (x * x * x * T(0.3333333333)) + (x * x * x * x * x * T(0.1333333333333)) + (x * x * x * x * x * x * x * T(0.0539682539)); + } + + template + GLM_FUNC_QUALIFIER vec fastTan(vec const& x) + { + return detail::functor1::call(fastTan, x); + } + + // asin + template + GLM_FUNC_QUALIFIER T fastAsin(T x) + { + return x + (x * x * x * T(0.166666667)) + (x * x * x * x * x * T(0.075)) + (x * x * x * x * x * x * x * T(0.0446428571)) + (x * x * x * x * x * x * x * x * x * T(0.0303819444));// + (x * x * x * x * x * x * x * x * x * x * x * T(0.022372159)); + } + + template + GLM_FUNC_QUALIFIER vec fastAsin(vec const& x) + { + return detail::functor1::call(fastAsin, x); + } + + // acos + template + GLM_FUNC_QUALIFIER T fastAcos(T x) + { + return T(1.5707963267948966192313216916398) - fastAsin(x); //(PI / 2) + } + + template + GLM_FUNC_QUALIFIER vec fastAcos(vec const& x) + { + return detail::functor1::call(fastAcos, x); + } + + // atan + template + GLM_FUNC_QUALIFIER T fastAtan(T y, T x) + { + T sgn = sign(y) * sign(x); + return abs(fastAtan(y / x)) * sgn; + } + + template + GLM_FUNC_QUALIFIER vec fastAtan(vec const& y, vec const& x) + { + return detail::functor2::call(fastAtan, y, x); + } + + template + GLM_FUNC_QUALIFIER T fastAtan(T x) + { + return x - (x * x * x * T(0.333333333333)) + (x * x * x * x * x * T(0.2)) - (x * x * x * x * x * x * x * T(0.1428571429)) + (x * x * x * x * x * x * x * x * x * T(0.111111111111)) - (x * x * x * x * x * x * x * x * x * x * x * T(0.0909090909)); + } + + template + GLM_FUNC_QUALIFIER vec fastAtan(vec const& x) + { + return detail::functor1::call(fastAtan, x); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/float_notmalize.inl b/src/GLMath/glm/gtx/float_notmalize.inl new file mode 100644 index 0000000000000000000000000000000000000000..8cdbc5aaa9c3895ea1f0e7e3a817f78b813e10c3 --- /dev/null +++ b/src/GLMath/glm/gtx/float_notmalize.inl @@ -0,0 +1,13 @@ +/// @ref gtx_float_normalize + +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec floatNormalize(vec const& v) + { + return vec(v) / static_cast(std::numeric_limits::max()); + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/functions.hpp b/src/GLMath/glm/gtx/functions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9f4166c4c1c809bc1c4e88a190e172f1f8138fc7 --- /dev/null +++ b/src/GLMath/glm/gtx/functions.hpp @@ -0,0 +1,56 @@ +/// @ref gtx_functions +/// @file glm/gtx/functions.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_functions GLM_GTX_functions +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// List of useful common functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/type_vec2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_functions is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_functions extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_functions + /// @{ + + /// 1D gauss function + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL T gauss( + T x, + T ExpectedValue, + T StandardDeviation); + + /// 2D gauss function + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL T gauss( + vec<2, T, Q> const& Coord, + vec<2, T, Q> const& ExpectedValue, + vec<2, T, Q> const& StandardDeviation); + + /// @} +}//namespace glm + +#include "functions.inl" + diff --git a/src/GLMath/glm/gtx/functions.inl b/src/GLMath/glm/gtx/functions.inl new file mode 100644 index 0000000000000000000000000000000000000000..29cbb20b80fa501931a5bf9203a52171b4a42773 --- /dev/null +++ b/src/GLMath/glm/gtx/functions.inl @@ -0,0 +1,30 @@ +/// @ref gtx_functions + +#include "../exponential.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T gauss + ( + T x, + T ExpectedValue, + T StandardDeviation + ) + { + return exp(-((x - ExpectedValue) * (x - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation)) / (StandardDeviation * sqrt(static_cast(6.28318530717958647692528676655900576))); + } + + template + GLM_FUNC_QUALIFIER T gauss + ( + vec<2, T, Q> const& Coord, + vec<2, T, Q> const& ExpectedValue, + vec<2, T, Q> const& StandardDeviation + ) + { + vec<2, T, Q> const Squared = ((Coord - ExpectedValue) * (Coord - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation); + return exp(-(Squared.x + Squared.y)); + } +}//namespace glm + diff --git a/src/GLMath/glm/gtx/gradient_paint.hpp b/src/GLMath/glm/gtx/gradient_paint.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6f85bf482d9fdd16ab823462741b98c43d337b01 --- /dev/null +++ b/src/GLMath/glm/gtx/gradient_paint.hpp @@ -0,0 +1,53 @@ +/// @ref gtx_gradient_paint +/// @file glm/gtx/gradient_paint.hpp +/// +/// @see core (dependence) +/// @see gtx_optimum_pow (dependence) +/// +/// @defgroup gtx_gradient_paint GLM_GTX_gradient_paint +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions that return the color of procedural gradient for specific coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/optimum_pow.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_gradient_paint is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_gradient_paint extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_gradient_paint + /// @{ + + /// Return a color from a radial gradient. + /// @see - gtx_gradient_paint + template + GLM_FUNC_DECL T radialGradient( + vec<2, T, Q> const& Center, + T const& Radius, + vec<2, T, Q> const& Focal, + vec<2, T, Q> const& Position); + + /// Return a color from a linear gradient. + /// @see - gtx_gradient_paint + template + GLM_FUNC_DECL T linearGradient( + vec<2, T, Q> const& Point0, + vec<2, T, Q> const& Point1, + vec<2, T, Q> const& Position); + + /// @} +}// namespace glm + +#include "gradient_paint.inl" diff --git a/src/GLMath/glm/gtx/gradient_paint.inl b/src/GLMath/glm/gtx/gradient_paint.inl new file mode 100644 index 0000000000000000000000000000000000000000..4c495e62cbffd88b88fcd7086c692c2f67f157d1 --- /dev/null +++ b/src/GLMath/glm/gtx/gradient_paint.inl @@ -0,0 +1,36 @@ +/// @ref gtx_gradient_paint + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T radialGradient + ( + vec<2, T, Q> const& Center, + T const& Radius, + vec<2, T, Q> const& Focal, + vec<2, T, Q> const& Position + ) + { + vec<2, T, Q> F = Focal - Center; + vec<2, T, Q> D = Position - Focal; + T Radius2 = pow2(Radius); + T Fx2 = pow2(F.x); + T Fy2 = pow2(F.y); + + T Numerator = (D.x * F.x + D.y * F.y) + sqrt(Radius2 * (pow2(D.x) + pow2(D.y)) - pow2(D.x * F.y - D.y * F.x)); + T Denominator = Radius2 - (Fx2 + Fy2); + return Numerator / Denominator; + } + + template + GLM_FUNC_QUALIFIER T linearGradient + ( + vec<2, T, Q> const& Point0, + vec<2, T, Q> const& Point1, + vec<2, T, Q> const& Position + ) + { + vec<2, T, Q> Dist = Point1 - Point0; + return (Dist.x * (Position.x - Point0.x) + Dist.y * (Position.y - Point0.y)) / glm::dot(Dist, Dist); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/handed_coordinate_space.hpp b/src/GLMath/glm/gtx/handed_coordinate_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3c8596892ce68ce2e463c00a5fa938004a0eef7c --- /dev/null +++ b/src/GLMath/glm/gtx/handed_coordinate_space.hpp @@ -0,0 +1,50 @@ +/// @ref gtx_handed_coordinate_space +/// @file glm/gtx/handed_coordinate_space.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_handed_coordinate_space GLM_GTX_handed_coordinate_space +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// To know if a set of three basis vectors defines a right or left-handed coordinate system. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_handed_coordinate_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_handed_coordinate_space extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_handed_coordinate_space + /// @{ + + //! Return if a trihedron right handed or not. + //! From GLM_GTX_handed_coordinate_space extension. + template + GLM_FUNC_DECL bool rightHanded( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal); + + //! Return if a trihedron left handed or not. + //! From GLM_GTX_handed_coordinate_space extension. + template + GLM_FUNC_DECL bool leftHanded( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal); + + /// @} +}// namespace glm + +#include "handed_coordinate_space.inl" diff --git a/src/GLMath/glm/gtx/handed_coordinate_space.inl b/src/GLMath/glm/gtx/handed_coordinate_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..e43c17bd3120931fff5438f5db175852896a1bbb --- /dev/null +++ b/src/GLMath/glm/gtx/handed_coordinate_space.inl @@ -0,0 +1,26 @@ +/// @ref gtx_handed_coordinate_space + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool rightHanded + ( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal + ) + { + return dot(cross(normal, tangent), binormal) > T(0); + } + + template + GLM_FUNC_QUALIFIER bool leftHanded + ( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal + ) + { + return dot(cross(normal, tangent), binormal) < T(0); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/hash.hpp b/src/GLMath/glm/gtx/hash.hpp new file mode 100644 index 0000000000000000000000000000000000000000..93b1bc2dc913570792b9d582d4c9e47c6ebd4a87 --- /dev/null +++ b/src/GLMath/glm/gtx/hash.hpp @@ -0,0 +1,142 @@ +/// @ref gtx_hash +/// @file glm/gtx/hash.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_hash GLM_GTX_hash +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add std::hash support for glm types + +#pragma once + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_hash is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_hash extension included") +# endif +#endif + +#include + +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../gtc/vec1.hpp" + +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" + +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" + +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" + +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" + +#if !GLM_HAS_CXX11_STL +# error "GLM_GTX_hash requires C++11 standard library support" +#endif + +namespace std +{ + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<1, T, Q> const& v) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<2, T, Q> const& v) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<3, T, Q> const& v) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<4, T, Q> const& v) const; + }; + + template + struct hash> + { + GLM_FUNC_DECL size_t operator()(glm::tquat const& q) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::tdualquat const& q) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 2, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 3, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 4, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 2, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 3, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 4, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 2, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 3, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 4, T,Q> const& m) const; + }; +} // namespace std + +#include "hash.inl" diff --git a/src/GLMath/glm/gtx/hash.inl b/src/GLMath/glm/gtx/hash.inl new file mode 100644 index 0000000000000000000000000000000000000000..64443ef8cd442662c81f94e070011f4a68da0544 --- /dev/null +++ b/src/GLMath/glm/gtx/hash.inl @@ -0,0 +1,184 @@ +/// @ref gtx_hash +/// +/// @see core (dependence) +/// +/// @defgroup gtx_hash GLM_GTX_hash +/// @ingroup gtx +/// +/// @brief Add std::hash support for glm types +/// +/// need to be included to use the features of this extension. + +namespace glm { +namespace detail +{ + GLM_INLINE void hash_combine(size_t &seed, size_t hash) + { + hash += 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= hash; + } +}} + +namespace std +{ + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<1, T, Q> const& v) const + { + hash hasher; + return hasher(v.x); + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<2, T, Q> const& v) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<3, T, Q> const& v) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + glm::detail::hash_combine(seed, hasher(v.z)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<4, T, Q> const& v) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + glm::detail::hash_combine(seed, hasher(v.z)); + glm::detail::hash_combine(seed, hasher(v.w)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::tquat const& q) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(q.x)); + glm::detail::hash_combine(seed, hasher(q.y)); + glm::detail::hash_combine(seed, hasher(q.z)); + glm::detail::hash_combine(seed, hasher(q.w)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::tdualquat const& q) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(q.real)); + glm::detail::hash_combine(seed, hasher(q.dual)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 2, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 3, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 4, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 2, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 3, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 4, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 2, T,Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 3, T,Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 4, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } +} diff --git a/src/GLMath/glm/gtx/integer.hpp b/src/GLMath/glm/gtx/integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d0b4c61a3fd41484952f38aec2d97c7a2db8c47d --- /dev/null +++ b/src/GLMath/glm/gtx/integer.hpp @@ -0,0 +1,76 @@ +/// @ref gtx_integer +/// @file glm/gtx/integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_integer GLM_GTX_integer +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add support for integer for core functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/integer.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_integer is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_integer extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_integer + /// @{ + + //! Returns x raised to the y power. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int pow(int x, uint y); + + //! Returns the positive square root of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int sqrt(int x); + + //! Returns the floor log2 of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL unsigned int floor_log2(unsigned int x); + + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int mod(int x, int y); + + //! Return the factorial value of a number (!12 max, integer only) + //! From GLM_GTX_integer extension. + template + GLM_FUNC_DECL genType factorial(genType const& x); + + //! 32bit signed integer. + //! From GLM_GTX_integer extension. + typedef signed int sint; + + //! Returns x raised to the y power. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint pow(uint x, uint y); + + //! Returns the positive square root of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint sqrt(uint x); + + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint mod(uint x, uint y); + + //! Returns the number of leading zeros. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint nlz(uint x); + + /// @} +}//namespace glm + +#include "integer.inl" diff --git a/src/GLMath/glm/gtx/integer.inl b/src/GLMath/glm/gtx/integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..956366b250f8c84e94d638dcd5f8a8744991bf51 --- /dev/null +++ b/src/GLMath/glm/gtx/integer.inl @@ -0,0 +1,185 @@ +/// @ref gtx_integer + +namespace glm +{ + // pow + GLM_FUNC_QUALIFIER int pow(int x, uint y) + { + if(y == 0) + return x >= 0 ? 1 : -1; + + int result = x; + for(uint i = 1; i < y; ++i) + result *= x; + return result; + } + + // sqrt: From Christopher J. Musial, An integer square root, Graphics Gems, 1990, page 387 + GLM_FUNC_QUALIFIER int sqrt(int x) + { + if(x <= 1) return x; + + int NextTrial = x >> 1; + int CurrentAnswer; + + do + { + CurrentAnswer = NextTrial; + NextTrial = (NextTrial + x / NextTrial) >> 1; + } while(NextTrial < CurrentAnswer); + + return CurrentAnswer; + } + +// Henry Gordon Dietz: http://aggregate.org/MAGIC/ +namespace detail +{ + GLM_FUNC_QUALIFIER unsigned int ones32(unsigned int x) + { + /* 32-bit recursive reduction using SWAR... + but first step is mapping 2-bit values + into sum of 2 1-bit values in sneaky way + */ + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + return(x & 0x0000003f); + } +}//namespace detail + + // Henry Gordon Dietz: http://aggregate.org/MAGIC/ +/* + GLM_FUNC_QUALIFIER unsigned int floor_log2(unsigned int x) + { + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + + return _detail::ones32(x) >> 1; + } +*/ + // mod + GLM_FUNC_QUALIFIER int mod(int x, int y) + { + return ((x % y) + y) % y; + } + + // factorial (!12 max, integer only) + template + GLM_FUNC_QUALIFIER genType factorial(genType const& x) + { + genType Temp = x; + genType Result; + for(Result = 1; Temp > 1; --Temp) + Result *= Temp; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> factorial( + vec<2, T, Q> const& x) + { + return vec<2, T, Q>( + factorial(x.x), + factorial(x.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> factorial( + vec<3, T, Q> const& x) + { + return vec<3, T, Q>( + factorial(x.x), + factorial(x.y), + factorial(x.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> factorial( + vec<4, T, Q> const& x) + { + return vec<4, T, Q>( + factorial(x.x), + factorial(x.y), + factorial(x.z), + factorial(x.w)); + } + + GLM_FUNC_QUALIFIER uint pow(uint x, uint y) + { + if (y == 0) + return 1u; + + uint result = x; + for(uint i = 1; i < y; ++i) + result *= x; + return result; + } + + GLM_FUNC_QUALIFIER uint sqrt(uint x) + { + if(x <= 1) return x; + + uint NextTrial = x >> 1; + uint CurrentAnswer; + + do + { + CurrentAnswer = NextTrial; + NextTrial = (NextTrial + x / NextTrial) >> 1; + } while(NextTrial < CurrentAnswer); + + return CurrentAnswer; + } + + GLM_FUNC_QUALIFIER uint mod(uint x, uint y) + { + return x - y * (x / y); + } + +#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC)) + + GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) + { + return 31u - findMSB(x); + } + +#else + + // Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt + GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) + { + int y, m, n; + + y = -int(x >> 16); // If left half of x is 0, + m = (y >> 16) & 16; // set n = 16. If left half + n = 16 - m; // is nonzero, set n = 0 and + x = x >> m; // shift x right 16. + // Now x is of the form 0000xxxx. + y = x - 0x100; // If positions 8-15 are 0, + m = (y >> 16) & 8; // add 8 to n and shift x left 8. + n = n + m; + x = x << m; + + y = x - 0x1000; // If positions 12-15 are 0, + m = (y >> 16) & 4; // add 4 to n and shift x left 4. + n = n + m; + x = x << m; + + y = x - 0x4000; // If positions 14-15 are 0, + m = (y >> 16) & 2; // add 2 to n and shift x left 2. + n = n + m; + x = x << m; + + y = x >> 14; // Set y = 0, 1, 2, or 3. + m = y & ~(y >> 1); // Set m = 0, 1, 2, or 2 resp. + return unsigned(n + 2 - m); + } + +#endif//(GLM_COMPILER) + +}//namespace glm diff --git a/src/GLMath/glm/gtx/intersect.hpp b/src/GLMath/glm/gtx/intersect.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3c78f2b8e22fb932060cf773cedbc8523570a961 --- /dev/null +++ b/src/GLMath/glm/gtx/intersect.hpp @@ -0,0 +1,92 @@ +/// @ref gtx_intersect +/// @file glm/gtx/intersect.hpp +/// +/// @see core (dependence) +/// @see gtx_closest_point (dependence) +/// +/// @defgroup gtx_intersect GLM_GTX_intersect +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add intersection functions + +#pragma once + +// Dependency: +#include +#include +#include "../glm.hpp" +#include "../geometric.hpp" +#include "../gtx/closest_point.hpp" +#include "../gtx/vector_query.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_closest_point extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_intersect + /// @{ + + //! Compute the intersection of a ray and a plane. + //! Ray direction and plane normal must be unit length. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRayPlane( + genType const& orig, genType const& dir, + genType const& planeOrig, genType const& planeNormal, + typename genType::value_type & intersectionDistance); + + //! Compute the intersection of a ray and a triangle. + /// Based om Tomas Möller implementation http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/ + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRayTriangle( + vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, + vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, + vec<2, T, Q>& baryPosition, T& distance); + + //! Compute the intersection of a line and a triangle. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectLineTriangle( + genType const& orig, genType const& dir, + genType const& vert0, genType const& vert1, genType const& vert2, + genType & position); + + //! Compute the intersection distance of a ray and a sphere. + //! The ray direction vector is unit length. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRaySphere( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, typename genType::value_type const sphereRadiusSquered, + typename genType::value_type & intersectionDistance); + + //! Compute the intersection of a ray and a sphere. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRaySphere( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal); + + //! Compute the intersection of a line and a sphere. + //! From GLM_GTX_intersect extension + template + GLM_FUNC_DECL bool intersectLineSphere( + genType const& point0, genType const& point1, + genType const& sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPosition1, genType & intersectionNormal1, + genType & intersectionPosition2 = genType(), genType & intersectionNormal2 = genType()); + + /// @} +}//namespace glm + +#include "intersect.inl" diff --git a/src/GLMath/glm/gtx/intersect.inl b/src/GLMath/glm/gtx/intersect.inl new file mode 100644 index 0000000000000000000000000000000000000000..e76fd628b74d8b3d01c60386be0e45e6693e2ea2 --- /dev/null +++ b/src/GLMath/glm/gtx/intersect.inl @@ -0,0 +1,197 @@ +/// @ref gtx_intersect + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool intersectRayPlane + ( + genType const& orig, genType const& dir, + genType const& planeOrig, genType const& planeNormal, + typename genType::value_type & intersectionDistance + ) + { + typename genType::value_type d = glm::dot(dir, planeNormal); + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + + if(d < -Epsilon) + { + intersectionDistance = glm::dot(planeOrig - orig, planeNormal) / d; + return true; + } + + return false; + } + + template + GLM_FUNC_QUALIFIER bool intersectRayTriangle + ( + vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, + vec<3, T, Q> const& vert0, vec<3, T, Q> const& vert1, vec<3, T, Q> const& vert2, + vec<2, T, Q>& baryPosition, T& distance + ) + { + // find vectors for two edges sharing vert0 + vec<3, T, Q> const edge1 = vert1 - vert0; + vec<3, T, Q> const edge2 = vert2 - vert0; + + // begin calculating determinant - also used to calculate U parameter + vec<3, T, Q> const p = glm::cross(dir, edge2); + + // if determinant is near zero, ray lies in plane of triangle + T const det = glm::dot(edge1, p); + + vec<3, T, Q> Perpendicular(0); + + if(det > std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + vec<3, T, Q> const dist = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(dist, p); + if(baryPosition.x < static_cast(0) || baryPosition.x > det) + return false; + + // prepare to test V parameter + Perpendicular = glm::cross(dist, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, Perpendicular); + if((baryPosition.y < static_cast(0)) || ((baryPosition.x + baryPosition.y) > det)) + return false; + } + else if(det < -std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + vec<3, T, Q> const dist = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(dist, p); + if((baryPosition.x > static_cast(0)) || (baryPosition.x < det)) + return false; + + // prepare to test V parameter + Perpendicular = glm::cross(dist, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, Perpendicular); + if((baryPosition.y > static_cast(0)) || (baryPosition.x + baryPosition.y < det)) + return false; + } + else + return false; // ray is parallel to the plane of the triangle + + T inv_det = static_cast(1) / det; + + // calculate distance, ray intersects triangle + distance = glm::dot(edge2, Perpendicular) * inv_det; + baryPosition *= inv_det; + + return true; + } + + template + GLM_FUNC_QUALIFIER bool intersectLineTriangle + ( + genType const& orig, genType const& dir, + genType const& vert0, genType const& vert1, genType const& vert2, + genType & position + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + + genType edge1 = vert1 - vert0; + genType edge2 = vert2 - vert0; + + genType Perpendicular = cross(dir, edge2); + + float det = dot(edge1, Perpendicular); + + if (det > -Epsilon && det < Epsilon) + return false; + typename genType::value_type inv_det = typename genType::value_type(1) / det; + + genType Tengant = orig - vert0; + + position.y = dot(Tengant, Perpendicular) * inv_det; + if (position.y < typename genType::value_type(0) || position.y > typename genType::value_type(1)) + return false; + + genType Cotengant = cross(Tengant, edge1); + + position.z = dot(dir, Cotengant) * inv_det; + if (position.z < typename genType::value_type(0) || position.y + position.z > typename genType::value_type(1)) + return false; + + position.x = dot(edge2, Cotengant) * inv_det; + + return true; + } + + template + GLM_FUNC_QUALIFIER bool intersectRaySphere + ( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadiusSquered, + typename genType::value_type & intersectionDistance + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + genType diff = sphereCenter - rayStarting; + typename genType::value_type t0 = dot(diff, rayNormalizedDirection); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadiusSquered ) + { + return false; + } + typename genType::value_type t1 = sqrt( sphereRadiusSquered - dSquared ); + intersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1; + return intersectionDistance > Epsilon; + } + + template + GLM_FUNC_QUALIFIER bool intersectRaySphere + ( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal + ) + { + typename genType::value_type distance; + if( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) ) + { + intersectionPosition = rayStarting + rayNormalizedDirection * distance; + intersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius; + return true; + } + return false; + } + + template + GLM_FUNC_QUALIFIER bool intersectLineSphere + ( + genType const& point0, genType const& point1, + genType const& sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPoint1, genType & intersectionNormal1, + genType & intersectionPoint2, genType & intersectionNormal2 + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + genType dir = normalize(point1 - point0); + genType diff = sphereCenter - point0; + typename genType::value_type t0 = dot(diff, dir); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadius * sphereRadius ) + { + return false; + } + typename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared ); + if( t0 < t1 + Epsilon ) + t1 = -t1; + intersectionPoint1 = point0 + dir * (t0 - t1); + intersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius; + intersectionPoint2 = point0 + dir * (t0 + t1); + intersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius; + return true; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/io.hpp b/src/GLMath/glm/gtx/io.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8d974f00456c7ff5a3f104efb244707b382e02f0 --- /dev/null +++ b/src/GLMath/glm/gtx/io.hpp @@ -0,0 +1,201 @@ +/// @ref gtx_io +/// @file glm/gtx/io.hpp +/// @author Jan P Springer (regnirpsj@gmail.com) +/// +/// @see core (dependence) +/// @see gtc_matrix_access (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_io GLM_GTX_io +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// std::[w]ostream support for glm types +/// +/// std::[w]ostream support for glm types + qualifier/width/etc. manipulators +/// based on howard hinnant's std::chrono io proposal +/// [http://home.roadrunner.com/~hinnant/bloomington/chrono_io.html] + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_io is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_io extension included") +# endif +#endif + +#include // std::basic_ostream<> (fwd) +#include // std::locale, std::locale::facet, std::locale::id +#include // std::pair<> + +namespace glm +{ + /// @addtogroup gtx_io + /// @{ + + namespace io + { + enum order_type { column_major, row_major}; + + template + class format_punct : public std::locale::facet + { + typedef CTy char_type; + + public: + + static std::locale::id id; + + bool formatted; + unsigned precision; + unsigned width; + char_type separator; + char_type delim_left; + char_type delim_right; + char_type space; + char_type newline; + order_type order; + + GLM_FUNC_DECL explicit format_punct(size_t a = 0); + GLM_FUNC_DECL explicit format_punct(format_punct const&); + }; + + template > + class basic_state_saver { + + public: + + GLM_FUNC_DECL explicit basic_state_saver(std::basic_ios&); + GLM_FUNC_DECL ~basic_state_saver(); + + private: + + typedef ::std::basic_ios state_type; + typedef typename state_type::char_type char_type; + typedef ::std::ios_base::fmtflags flags_type; + typedef ::std::streamsize streamsize_type; + typedef ::std::locale const locale_type; + + state_type& state_; + flags_type flags_; + streamsize_type precision_; + streamsize_type width_; + char_type fill_; + locale_type locale_; + + GLM_FUNC_DECL basic_state_saver& operator=(basic_state_saver const&); + }; + + typedef basic_state_saver state_saver; + typedef basic_state_saver wstate_saver; + + template > + class basic_format_saver + { + public: + + GLM_FUNC_DECL explicit basic_format_saver(std::basic_ios&); + GLM_FUNC_DECL ~basic_format_saver(); + + private: + + basic_state_saver const bss_; + + GLM_FUNC_DECL basic_format_saver& operator=(basic_format_saver const&); + }; + + typedef basic_format_saver format_saver; + typedef basic_format_saver wformat_saver; + + struct precision + { + unsigned value; + + GLM_FUNC_DECL explicit precision(unsigned); + }; + + struct width + { + unsigned value; + + GLM_FUNC_DECL explicit width(unsigned); + }; + + template + struct delimeter + { + CTy value[3]; + + GLM_FUNC_DECL explicit delimeter(CTy /* left */, CTy /* right */, CTy /* separator */ = ','); + }; + + struct order + { + order_type value; + + GLM_FUNC_DECL explicit order(order_type); + }; + + // functions, inlined (inline) + + template + FTy const& get_facet(std::basic_ios&); + template + std::basic_ios& formatted(std::basic_ios&); + template + std::basic_ios& unformattet(std::basic_ios&); + + template + std::basic_ostream& operator<<(std::basic_ostream&, precision const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, width const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, delimeter const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, order const&); + }//namespace io + + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, qua const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<1, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 4, T, Q> const&); + + template + GLM_FUNC_DECL std::basic_ostream & operator<<(std::basic_ostream &, + std::pair const, mat<4, 4, T, Q> const> const&); + + /// @} +}//namespace glm + +#include "io.inl" diff --git a/src/GLMath/glm/gtx/io.inl b/src/GLMath/glm/gtx/io.inl new file mode 100644 index 0000000000000000000000000000000000000000..a3a1bb6c26b4175373a6ec45595cada792567c1c --- /dev/null +++ b/src/GLMath/glm/gtx/io.inl @@ -0,0 +1,440 @@ +/// @ref gtx_io +/// @author Jan P Springer (regnirpsj@gmail.com) + +#include // std::fixed, std::setfill<>, std::setprecision, std::right, std::setw +#include // std::basic_ostream<> +#include "../gtc/matrix_access.hpp" // glm::col, glm::row +#include "../gtx/type_trait.hpp" // glm::type<> + +namespace glm{ +namespace io +{ + template + GLM_FUNC_QUALIFIER format_punct::format_punct(size_t a) + : std::locale::facet(a) + , formatted(true) + , precision(3) + , width(1 + 4 + 1 + precision) + , separator(',') + , delim_left('[') + , delim_right(']') + , space(' ') + , newline('\n') + , order(column_major) + {} + + template + GLM_FUNC_QUALIFIER format_punct::format_punct(format_punct const& a) + : std::locale::facet(0) + , formatted(a.formatted) + , precision(a.precision) + , width(a.width) + , separator(a.separator) + , delim_left(a.delim_left) + , delim_right(a.delim_right) + , space(a.space) + , newline(a.newline) + , order(a.order) + {} + + template std::locale::id format_punct::id; + + template + GLM_FUNC_QUALIFIER basic_state_saver::basic_state_saver(std::basic_ios& a) + : state_(a) + , flags_(a.flags()) + , precision_(a.precision()) + , width_(a.width()) + , fill_(a.fill()) + , locale_(a.getloc()) + {} + + template + GLM_FUNC_QUALIFIER basic_state_saver::~basic_state_saver() + { + state_.imbue(locale_); + state_.fill(fill_); + state_.width(width_); + state_.precision(precision_); + state_.flags(flags_); + } + + template + GLM_FUNC_QUALIFIER basic_format_saver::basic_format_saver(std::basic_ios& a) + : bss_(a) + { + a.imbue(std::locale(a.getloc(), new format_punct(get_facet >(a)))); + } + + template + GLM_FUNC_QUALIFIER + basic_format_saver::~basic_format_saver() + {} + + GLM_FUNC_QUALIFIER precision::precision(unsigned a) + : value(a) + {} + + GLM_FUNC_QUALIFIER width::width(unsigned a) + : value(a) + {} + + template + GLM_FUNC_QUALIFIER delimeter::delimeter(CTy a, CTy b, CTy c) + : value() + { + value[0] = a; + value[1] = b; + value[2] = c; + } + + GLM_FUNC_QUALIFIER order::order(order_type a) + : value(a) + {} + + template + GLM_FUNC_QUALIFIER FTy const& get_facet(std::basic_ios& ios) + { + if(!std::has_facet(ios.getloc())) + ios.imbue(std::locale(ios.getloc(), new FTy)); + + return std::use_facet(ios.getloc()); + } + + template + GLM_FUNC_QUALIFIER std::basic_ios& formatted(std::basic_ios& ios) + { + const_cast&>(get_facet >(ios)).formatted = true; + return ios; + } + + template + GLM_FUNC_QUALIFIER std::basic_ios& unformatted(std::basic_ios& ios) + { + const_cast&>(get_facet >(ios)).formatted = false; + return ios; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, precision const& a) + { + const_cast&>(get_facet >(os)).precision = a.value; + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, width const& a) + { + const_cast&>(get_facet >(os)).width = a.value; + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, delimeter const& a) + { + format_punct & fmt(const_cast&>(get_facet >(os))); + + fmt.delim_left = a.value[0]; + fmt.delim_right = a.value[1]; + fmt.separator = a.value[2]; + + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, order const& a) + { + const_cast&>(get_facet >(os)).order = a.value; + return os; + } +} // namespace io + +namespace detail +{ + template + GLM_FUNC_QUALIFIER std::basic_ostream& + print_vector_on(std::basic_ostream& os, V const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + + length_t const& components(type::components); + + if(fmt.formatted) + { + io::basic_state_saver const bss(os); + + os << std::fixed << std::right << std::setprecision(fmt.precision) << std::setfill(fmt.space) << fmt.delim_left; + + for(length_t i(0); i < components; ++i) + { + os << std::setw(fmt.width) << a[i]; + if(components-1 != i) + os << fmt.separator; + } + + os << fmt.delim_right; + } + else + { + for(length_t i(0); i < components; ++i) + { + os << a[i]; + + if(components-1 != i) + os << fmt.space; + } + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, qua const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<1, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<2, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<3, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<4, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + +namespace detail +{ + template class M, length_t C, length_t R, typename T, qualifier Q> + GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_on(std::basic_ostream& os, M const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + + length_t const& cols(type >::cols); + length_t const& rows(type >::rows); + + if(fmt.formatted) + { + os << fmt.newline << fmt.delim_left; + + switch(fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < rows; ++i) + { + if (0 != i) + os << fmt.space; + + os << row(a, i); + + if(rows-1 != i) + os << fmt.newline; + } + } + break; + + case io::row_major: + { + for(length_t i(0); i < cols; ++i) + { + if(0 != i) + os << fmt.space; + + os << column(a, i); + + if(cols-1 != i) + os << fmt.newline; + } + } + break; + } + + os << fmt.delim_right; + } + else + { + switch (fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < cols; ++i) + { + os << column(a, i); + + if(cols - 1 != i) + os << fmt.space; + } + } + break; + + case io::row_major: + { + for (length_t i(0); i < rows; ++i) + { + os << row(a, i); + + if (rows-1 != i) + os << fmt.space; + } + } + break; + } + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<3, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + +namespace detail +{ + template class M, length_t C, length_t R, typename T, qualifier Q> + GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_pair_on(std::basic_ostream& os, std::pair const, M const> const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + M const& ml(a.first); + M const& mr(a.second); + length_t const& cols(type >::cols); + length_t const& rows(type >::rows); + + if(fmt.formatted) + { + os << fmt.newline << fmt.delim_left; + + switch(fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < rows; ++i) + { + if(0 != i) + os << fmt.space; + + os << row(ml, i) << ((rows-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << row(mr, i); + + if(rows-1 != i) + os << fmt.newline; + } + } + break; + case io::row_major: + { + for(length_t i(0); i < cols; ++i) + { + if(0 != i) + os << fmt.space; + + os << column(ml, i) << ((cols-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << column(mr, i); + + if(cols-1 != i) + os << fmt.newline; + } + } + break; + } + + os << fmt.delim_right; + } + else + { + os << ml << fmt.space << mr; + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<( + std::basic_ostream & os, + std::pair const, + mat<4, 4, T, Q> const> const& a) + { + return detail::print_matrix_pair_on(os, a); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/log_base.hpp b/src/GLMath/glm/gtx/log_base.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ba28c9d7bffcb27c32dc13818eeaac4d9f231dd8 --- /dev/null +++ b/src/GLMath/glm/gtx/log_base.hpp @@ -0,0 +1,48 @@ +/// @ref gtx_log_base +/// @file glm/gtx/log_base.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_log_base GLM_GTX_log_base +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Logarithm for any base. base can be a vector or a scalar. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_log_base is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_log_base extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_log_base + /// @{ + + /// Logarithm for any base. + /// From GLM_GTX_log_base. + template + GLM_FUNC_DECL genType log( + genType const& x, + genType const& base); + + /// Logarithm for any base. + /// From GLM_GTX_log_base. + template + GLM_FUNC_DECL vec sign( + vec const& x, + vec const& base); + + /// @} +}//namespace glm + +#include "log_base.inl" diff --git a/src/GLMath/glm/gtx/log_base.inl b/src/GLMath/glm/gtx/log_base.inl new file mode 100644 index 0000000000000000000000000000000000000000..4bbb8e895abbdac32e58cc4e66f700ac86ba17a4 --- /dev/null +++ b/src/GLMath/glm/gtx/log_base.inl @@ -0,0 +1,16 @@ +/// @ref gtx_log_base + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType log(genType const& x, genType const& base) + { + return glm::log(x) / glm::log(base); + } + + template + GLM_FUNC_QUALIFIER vec log(vec const& x, vec const& base) + { + return glm::log(x) / glm::log(base); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/matrix_cross_product.hpp b/src/GLMath/glm/gtx/matrix_cross_product.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1e585f9a4ffe8e9eadae27a26c6cb9dd5f5b294b --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_cross_product.hpp @@ -0,0 +1,47 @@ +/// @ref gtx_matrix_cross_product +/// @file glm/gtx/matrix_cross_product.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_matrix_cross_product GLM_GTX_matrix_cross_product +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build cross product matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_cross_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_cross_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_cross_product + /// @{ + + //! Build a cross product matrix. + //! From GLM_GTX_matrix_cross_product extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> matrixCross3( + vec<3, T, Q> const& x); + + //! Build a cross product matrix. + //! From GLM_GTX_matrix_cross_product extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> matrixCross4( + vec<3, T, Q> const& x); + + /// @} +}//namespace glm + +#include "matrix_cross_product.inl" diff --git a/src/GLMath/glm/gtx/matrix_cross_product.inl b/src/GLMath/glm/gtx/matrix_cross_product.inl new file mode 100644 index 0000000000000000000000000000000000000000..3a153977cf59d977d3f4c318569751dee4f27331 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_cross_product.inl @@ -0,0 +1,37 @@ +/// @ref gtx_matrix_cross_product + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> matrixCross3 + ( + vec<3, T, Q> const& x + ) + { + mat<3, 3, T, Q> Result(T(0)); + Result[0][1] = x.z; + Result[1][0] = -x.z; + Result[0][2] = -x.y; + Result[2][0] = x.y; + Result[1][2] = x.x; + Result[2][1] = -x.x; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> matrixCross4 + ( + vec<3, T, Q> const& x + ) + { + mat<4, 4, T, Q> Result(T(0)); + Result[0][1] = x.z; + Result[1][0] = -x.z; + Result[0][2] = -x.y; + Result[2][0] = x.y; + Result[1][2] = x.x; + Result[2][1] = -x.x; + return Result; + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/matrix_decompose.hpp b/src/GLMath/glm/gtx/matrix_decompose.hpp new file mode 100644 index 0000000000000000000000000000000000000000..acd7a7f0681a20ffeaa34d6ad9e911508776bf7f --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_decompose.hpp @@ -0,0 +1,46 @@ +/// @ref gtx_matrix_decompose +/// @file glm/gtx/matrix_decompose.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_decompose GLM_GTX_matrix_decompose +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Decomposes a model matrix to translations, rotation and scale components + +#pragma once + +// Dependencies +#include "../mat4x4.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../geometric.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtc/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_decompose is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_decompose extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_decompose + /// @{ + + /// Decomposes a model matrix to translations, rotation and scale components + /// @see gtx_matrix_decompose + template + GLM_FUNC_DECL bool decompose( + mat<4, 4, T, Q> const& modelMatrix, + vec<3, T, Q> & scale, qua & orientation, vec<3, T, Q> & translation, vec<3, T, Q> & skew, vec<4, T, Q> & perspective); + + /// @} +}//namespace glm + +#include "matrix_decompose.inl" diff --git a/src/GLMath/glm/gtx/matrix_decompose.inl b/src/GLMath/glm/gtx/matrix_decompose.inl new file mode 100644 index 0000000000000000000000000000000000000000..694f5eca74a44945cc6d59d363fb86090258d94a --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_decompose.inl @@ -0,0 +1,186 @@ +/// @ref gtx_matrix_decompose + +#include "../gtc/constants.hpp" +#include "../gtc/epsilon.hpp" + +namespace glm{ +namespace detail +{ + /// Make a linear combination of two vectors and return the result. + // result = (a * ascl) + (b * bscl) + template + GLM_FUNC_QUALIFIER vec<3, T, Q> combine( + vec<3, T, Q> const& a, + vec<3, T, Q> const& b, + T ascl, T bscl) + { + return (a * ascl) + (b * bscl); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> scale(vec<3, T, Q> const& v, T desiredLength) + { + return v * desiredLength / length(v); + } +}//namespace detail + + // Matrix decompose + // http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp + // Decomposes the mode matrix to translations,rotation scale components + + template + GLM_FUNC_QUALIFIER bool decompose(mat<4, 4, T, Q> const& ModelMatrix, vec<3, T, Q> & Scale, qua & Orientation, vec<3, T, Q> & Translation, vec<3, T, Q> & Skew, vec<4, T, Q> & Perspective) + { + mat<4, 4, T, Q> LocalMatrix(ModelMatrix); + + // Normalize the matrix. + if(epsilonEqual(LocalMatrix[3][3], static_cast(0), epsilon())) + return false; + + for(length_t i = 0; i < 4; ++i) + for(length_t j = 0; j < 4; ++j) + LocalMatrix[i][j] /= LocalMatrix[3][3]; + + // perspectiveMatrix is used to solve for perspective, but it also provides + // an easy way to test for singularity of the upper 3x3 component. + mat<4, 4, T, Q> PerspectiveMatrix(LocalMatrix); + + for(length_t i = 0; i < 3; i++) + PerspectiveMatrix[i][3] = static_cast(0); + PerspectiveMatrix[3][3] = static_cast(1); + + /// TODO: Fixme! + if(epsilonEqual(determinant(PerspectiveMatrix), static_cast(0), epsilon())) + return false; + + // First, isolate perspective. This is the messiest. + if( + epsilonNotEqual(LocalMatrix[0][3], static_cast(0), epsilon()) || + epsilonNotEqual(LocalMatrix[1][3], static_cast(0), epsilon()) || + epsilonNotEqual(LocalMatrix[2][3], static_cast(0), epsilon())) + { + // rightHandSide is the right hand side of the equation. + vec<4, T, Q> RightHandSide; + RightHandSide[0] = LocalMatrix[0][3]; + RightHandSide[1] = LocalMatrix[1][3]; + RightHandSide[2] = LocalMatrix[2][3]; + RightHandSide[3] = LocalMatrix[3][3]; + + // Solve the equation by inverting PerspectiveMatrix and multiplying + // rightHandSide by the inverse. (This is the easiest way, not + // necessarily the best.) + mat<4, 4, T, Q> InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);// inverse(PerspectiveMatrix, inversePerspectiveMatrix); + mat<4, 4, T, Q> TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);// transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); + + Perspective = TransposedInversePerspectiveMatrix * RightHandSide; + // v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); + + // Clear the perspective partition + LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast(0); + LocalMatrix[3][3] = static_cast(1); + } + else + { + // No perspective. + Perspective = vec<4, T, Q>(0, 0, 0, 1); + } + + // Next take care of translation (easy). + Translation = vec<3, T, Q>(LocalMatrix[3]); + LocalMatrix[3] = vec<4, T, Q>(0, 0, 0, LocalMatrix[3].w); + + vec<3, T, Q> Row[3], Pdum3; + + // Now get scale and shear. + for(length_t i = 0; i < 3; ++i) + for(length_t j = 0; j < 3; ++j) + Row[i][j] = LocalMatrix[i][j]; + + // Compute X scale factor and normalize first row. + Scale.x = length(Row[0]);// v3Length(Row[0]); + + Row[0] = detail::scale(Row[0], static_cast(1)); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + Skew.z = dot(Row[0], Row[1]); + Row[1] = detail::combine(Row[1], Row[0], static_cast(1), -Skew.z); + + // Now, compute Y scale and normalize 2nd row. + Scale.y = length(Row[1]); + Row[1] = detail::scale(Row[1], static_cast(1)); + Skew.z /= Scale.y; + + // Compute XZ and YZ shears, orthogonalize 3rd row. + Skew.y = glm::dot(Row[0], Row[2]); + Row[2] = detail::combine(Row[2], Row[0], static_cast(1), -Skew.y); + Skew.x = glm::dot(Row[1], Row[2]); + Row[2] = detail::combine(Row[2], Row[1], static_cast(1), -Skew.x); + + // Next, get Z scale and normalize 3rd row. + Scale.z = length(Row[2]); + Row[2] = detail::scale(Row[2], static_cast(1)); + Skew.y /= Scale.z; + Skew.x /= Scale.z; + + // At this point, the matrix (in rows[]) is orthonormal. + // Check for a coordinate system flip. If the determinant + // is -1, then negate the matrix and the scaling factors. + Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3); + if(dot(Row[0], Pdum3) < 0) + { + for(length_t i = 0; i < 3; i++) + { + Scale[i] *= static_cast(-1); + Row[i] *= static_cast(-1); + } + } + + // Now, get the rotations out, as described in the gem. + + // FIXME - Add the ability to return either quaternions (which are + // easier to recompose with) or Euler angles (rx, ry, rz), which + // are easier for authors to deal with. The latter will only be useful + // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I + // will leave the Euler angle code here for now. + + // ret.rotateY = asin(-Row[0][2]); + // if (cos(ret.rotateY) != 0) { + // ret.rotateX = atan2(Row[1][2], Row[2][2]); + // ret.rotateZ = atan2(Row[0][1], Row[0][0]); + // } else { + // ret.rotateX = atan2(-Row[2][0], Row[1][1]); + // ret.rotateZ = 0; + // } + + int i, j, k = 0; + T root, trace = Row[0].x + Row[1].y + Row[2].z; + if(trace > static_cast(0)) + { + root = sqrt(trace + static_cast(1.0)); + Orientation.w = static_cast(0.5) * root; + root = static_cast(0.5) / root; + Orientation.x = root * (Row[1].z - Row[2].y); + Orientation.y = root * (Row[2].x - Row[0].z); + Orientation.z = root * (Row[0].y - Row[1].x); + } // End if > 0 + else + { + static int Next[3] = {1, 2, 0}; + i = 0; + if(Row[1].y > Row[0].x) i = 1; + if(Row[2].z > Row[i][i]) i = 2; + j = Next[i]; + k = Next[j]; + + root = sqrt(Row[i][i] - Row[j][j] - Row[k][k] + static_cast(1.0)); + + Orientation[i] = static_cast(0.5) * root; + root = static_cast(0.5) / root; + Orientation[j] = root * (Row[i][j] + Row[j][i]); + Orientation[k] = root * (Row[i][k] + Row[k][i]); + Orientation.w = root * (Row[j][k] - Row[k][j]); + } // End if <= 0 + + return true; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/matrix_factorisation.hpp b/src/GLMath/glm/gtx/matrix_factorisation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5a975d60b6c2ca9fb03b9a92541679ebe75f988c --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_factorisation.hpp @@ -0,0 +1,69 @@ +/// @ref gtx_matrix_factorisation +/// @file glm/gtx/matrix_factorisation.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_factorisation GLM_GTX_matrix_factorisation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions to factor matrices in various forms + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_factorisation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_factorisation extension included") +# endif +#endif + +/* +Suggestions: + - Move helper functions flipud and fliplr to another file: They may be helpful in more general circumstances. + - Implement other types of matrix factorisation, such as: QL and LQ, L(D)U, eigendecompositions, etc... +*/ + +namespace glm +{ + /// @addtogroup gtx_matrix_factorisation + /// @{ + + /// Flips the matrix rows up and down. + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL mat flipud(mat const& in); + + /// Flips the matrix columns right and left. + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL mat fliplr(mat const& in); + + /// Performs QR factorisation of a matrix. + /// Returns 2 matrices, q and r, such that the columns of q are orthonormal and span the same subspace than those of the input matrix, r is an upper triangular matrix, and q*r=in. + /// Given an n-by-m input matrix, q has dimensions min(n,m)-by-m, and r has dimensions n-by-min(n,m). + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r); + + /// Performs RQ factorisation of a matrix. + /// Returns 2 matrices, r and q, such that r is an upper triangular matrix, the rows of q are orthonormal and span the same subspace than those of the input matrix, and r*q=in. + /// Note that in the context of RQ factorisation, the diagonal is seen as starting in the lower-right corner of the matrix, instead of the usual upper-left. + /// Given an n-by-m input matrix, r has dimensions min(n,m)-by-m, and q has dimensions n-by-min(n,m). + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q); + + /// @} +} + +#include "matrix_factorisation.inl" diff --git a/src/GLMath/glm/gtx/matrix_factorisation.inl b/src/GLMath/glm/gtx/matrix_factorisation.inl new file mode 100644 index 0000000000000000000000000000000000000000..c479b8ad99094b0a301ef29b31e112e7441ea143 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_factorisation.inl @@ -0,0 +1,84 @@ +/// @ref gtx_matrix_factorisation + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat flipud(mat const& in) + { + mat tin = transpose(in); + tin = fliplr(tin); + mat out = transpose(tin); + + return out; + } + + template + GLM_FUNC_QUALIFIER mat fliplr(mat const& in) + { + mat out; + for (length_t i = 0; i < C; i++) + { + out[i] = in[(C - i) - 1]; + } + + return out; + } + + template + GLM_FUNC_QUALIFIER void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r) + { + // Uses modified Gram-Schmidt method + // Source: https://en.wikipedia.org/wiki/Gram–Schmidt_process + // And https://en.wikipedia.org/wiki/QR_decomposition + + //For all the linearly independs columns of the input... + // (there can be no more linearly independents columns than there are rows.) + for (length_t i = 0; i < (C < R ? C : R); i++) + { + //Copy in Q the input's i-th column. + q[i] = in[i]; + + //j = [0,i[ + // Make that column orthogonal to all the previous ones by substracting to it the non-orthogonal projection of all the previous columns. + // Also: Fill the zero elements of R + for (length_t j = 0; j < i; j++) + { + q[i] -= dot(q[i], q[j])*q[j]; + r[j][i] = 0; + } + + //Now, Q i-th column is orthogonal to all the previous columns. Normalize it. + q[i] = normalize(q[i]); + + //j = [i,C[ + //Finally, compute the corresponding coefficients of R by computing the projection of the resulting column on the other columns of the input. + for (length_t j = i; j < C; j++) + { + r[j][i] = dot(in[j], q[i]); + } + } + } + + template + GLM_FUNC_QUALIFIER void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q) + { + // From https://en.wikipedia.org/wiki/QR_decomposition: + // The RQ decomposition transforms a matrix A into the product of an upper triangular matrix R (also known as right-triangular) and an orthogonal matrix Q. The only difference from QR decomposition is the order of these matrices. + // QR decomposition is Gram–Schmidt orthogonalization of columns of A, started from the first column. + // RQ decomposition is Gram–Schmidt orthogonalization of rows of A, started from the last row. + + mat tin = transpose(in); + tin = fliplr(tin); + + mat tr; + mat<(C < R ? C : R), C, T, Q> tq; + qr_decompose(tin, tq, tr); + + tr = fliplr(tr); + r = transpose(tr); + r = fliplr(r); + + tq = fliplr(tq); + q = transpose(tq); + } +} //namespace glm diff --git a/src/GLMath/glm/gtx/matrix_interpolation.hpp b/src/GLMath/glm/gtx/matrix_interpolation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7d5ad4cd9ad9f1a845a9fe7327a73399d1ea58a6 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_interpolation.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_matrix_interpolation +/// @file glm/gtx/matrix_interpolation.hpp +/// @author Ghenadii Ursachi (the.asteroth@gmail.com) +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_interpolation GLM_GTX_matrix_interpolation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Allows to directly interpolate two matrices. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_interpolation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_interpolation extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_interpolation + /// @{ + + /// Get the axis and angle of the rotation from a matrix. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL void axisAngle( + mat<4, 4, T, Q> const& Mat, vec<3, T, Q> & Axis, T & Angle); + + /// Build a matrix from axis and angle. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> axisAngleMatrix( + vec<3, T, Q> const& Axis, T const Angle); + + /// Extracts the rotation part of a matrix. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> extractMatrixRotation( + mat<4, 4, T, Q> const& Mat); + + /// Build a interpolation of 4 * 4 matrixes. + /// From GLM_GTX_matrix_interpolation extension. + /// Warning! works only with rotation and/or translation matrixes, scale will generate unexpected results. + template + GLM_FUNC_DECL mat<4, 4, T, Q> interpolate( + mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const Delta); + + /// @} +}//namespace glm + +#include "matrix_interpolation.inl" diff --git a/src/GLMath/glm/gtx/matrix_interpolation.inl b/src/GLMath/glm/gtx/matrix_interpolation.inl new file mode 100644 index 0000000000000000000000000000000000000000..de40b7d745ec138797ddc47ad94bbf32a1d9ca4e --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_interpolation.inl @@ -0,0 +1,129 @@ +/// @ref gtx_matrix_interpolation + +#include "../gtc/constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER void axisAngle(mat<4, 4, T, Q> const& m, vec<3, T, Q> & axis, T& angle) + { + T epsilon = static_cast(0.01); + T epsilon2 = static_cast(0.1); + + if((abs(m[1][0] - m[0][1]) < epsilon) && (abs(m[2][0] - m[0][2]) < epsilon) && (abs(m[2][1] - m[1][2]) < epsilon)) + { + if ((abs(m[1][0] + m[0][1]) < epsilon2) && (abs(m[2][0] + m[0][2]) < epsilon2) && (abs(m[2][1] + m[1][2]) < epsilon2) && (abs(m[0][0] + m[1][1] + m[2][2] - static_cast(3.0)) < epsilon2)) + { + angle = static_cast(0.0); + axis.x = static_cast(1.0); + axis.y = static_cast(0.0); + axis.z = static_cast(0.0); + return; + } + angle = static_cast(3.1415926535897932384626433832795); + T xx = (m[0][0] + static_cast(1.0)) * static_cast(0.5); + T yy = (m[1][1] + static_cast(1.0)) * static_cast(0.5); + T zz = (m[2][2] + static_cast(1.0)) * static_cast(0.5); + T xy = (m[1][0] + m[0][1]) * static_cast(0.25); + T xz = (m[2][0] + m[0][2]) * static_cast(0.25); + T yz = (m[2][1] + m[1][2]) * static_cast(0.25); + if((xx > yy) && (xx > zz)) + { + if(xx < epsilon) + { + axis.x = static_cast(0.0); + axis.y = static_cast(0.7071); + axis.z = static_cast(0.7071); + } + else + { + axis.x = sqrt(xx); + axis.y = xy / axis.x; + axis.z = xz / axis.x; + } + } + else if (yy > zz) + { + if(yy < epsilon) + { + axis.x = static_cast(0.7071); + axis.y = static_cast(0.0); + axis.z = static_cast(0.7071); + } + else + { + axis.y = sqrt(yy); + axis.x = xy / axis.y; + axis.z = yz / axis.y; + } + } + else + { + if (zz < epsilon) + { + axis.x = static_cast(0.7071); + axis.y = static_cast(0.7071); + axis.z = static_cast(0.0); + } + else + { + axis.z = sqrt(zz); + axis.x = xz / axis.z; + axis.y = yz / axis.z; + } + } + return; + } + T s = sqrt((m[2][1] - m[1][2]) * (m[2][1] - m[1][2]) + (m[2][0] - m[0][2]) * (m[2][0] - m[0][2]) + (m[1][0] - m[0][1]) * (m[1][0] - m[0][1])); + if (glm::abs(s) < T(0.001)) + s = static_cast(1); + T const angleCos = (m[0][0] + m[1][1] + m[2][2] - static_cast(1)) * static_cast(0.5); + if(angleCos - static_cast(1) < epsilon) + angle = pi() * static_cast(0.25); + else + angle = acos(angleCos); + axis.x = (m[1][2] - m[2][1]) / s; + axis.y = (m[2][0] - m[0][2]) / s; + axis.z = (m[0][1] - m[1][0]) / s; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> axisAngleMatrix(vec<3, T, Q> const& axis, T const angle) + { + T c = cos(angle); + T s = sin(angle); + T t = static_cast(1) - c; + vec<3, T, Q> n = normalize(axis); + + return mat<4, 4, T, Q>( + t * n.x * n.x + c, t * n.x * n.y + n.z * s, t * n.x * n.z - n.y * s, static_cast(0.0), + t * n.x * n.y - n.z * s, t * n.y * n.y + c, t * n.y * n.z + n.x * s, static_cast(0.0), + t * n.x * n.z + n.y * s, t * n.y * n.z - n.x * s, t * n.z * n.z + c, static_cast(0.0), + static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> extractMatrixRotation(mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0][0], m[0][1], m[0][2], static_cast(0.0), + m[1][0], m[1][1], m[1][2], static_cast(0.0), + m[2][0], m[2][1], m[2][2], static_cast(0.0), + static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> interpolate(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const delta) + { + mat<4, 4, T, Q> m1rot = extractMatrixRotation(m1); + mat<4, 4, T, Q> dltRotation = m2 * transpose(m1rot); + vec<3, T, Q> dltAxis; + T dltAngle; + axisAngle(dltRotation, dltAxis, dltAngle); + mat<4, 4, T, Q> out = axisAngleMatrix(dltAxis, dltAngle * delta) * m1rot; + out[3][0] = m1[3][0] + delta * (m2[3][0] - m1[3][0]); + out[3][1] = m1[3][1] + delta * (m2[3][1] - m1[3][1]); + out[3][2] = m1[3][2] + delta * (m2[3][2] - m1[3][2]); + return out; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/matrix_major_storage.hpp b/src/GLMath/glm/gtx/matrix_major_storage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8c6bc22d14e96da6a01552dde90f5fecf6a2e1b8 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_major_storage.hpp @@ -0,0 +1,119 @@ +/// @ref gtx_matrix_major_storage +/// @file glm/gtx/matrix_major_storage.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_matrix_major_storage GLM_GTX_matrix_major_storage +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build matrices with specific matrix order, row or column + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_major_storage is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_major_storage extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_major_storage + /// @{ + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( + mat<2, 2, T, Q> const& m); + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( + mat<3, 3, T, Q> const& m); + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( + vec<4, T, Q> const& v1, + vec<4, T, Q> const& v2, + vec<4, T, Q> const& v3, + vec<4, T, Q> const& v4); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( + mat<4, 4, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( + mat<2, 2, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( + mat<3, 3, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( + vec<4, T, Q> const& v1, + vec<4, T, Q> const& v2, + vec<4, T, Q> const& v3, + vec<4, T, Q> const& v4); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( + mat<4, 4, T, Q> const& m); + + /// @} +}//namespace glm + +#include "matrix_major_storage.inl" diff --git a/src/GLMath/glm/gtx/matrix_major_storage.inl b/src/GLMath/glm/gtx/matrix_major_storage.inl new file mode 100644 index 0000000000000000000000000000000000000000..279dd3433d0bd6dd5509cc1da75ee5b212eac784 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_major_storage.inl @@ -0,0 +1,166 @@ +/// @ref gtx_matrix_major_storage + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2 + ( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2 + ) + { + mat<2, 2, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2( + const mat<2, 2, T, Q>& m) + { + mat<2, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( + const vec<3, T, Q>& v1, + const vec<3, T, Q>& v2, + const vec<3, T, Q>& v3) + { + mat<3, 3, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[2][0] = v1.z; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + Result[2][1] = v2.z; + Result[0][2] = v3.x; + Result[1][2] = v3.y; + Result[2][2] = v3.z; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( + const mat<3, 3, T, Q>& m) + { + mat<3, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( + const vec<4, T, Q>& v1, + const vec<4, T, Q>& v2, + const vec<4, T, Q>& v3, + const vec<4, T, Q>& v4) + { + mat<4, 4, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[2][0] = v1.z; + Result[3][0] = v1.w; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + Result[2][1] = v2.z; + Result[3][1] = v2.w; + Result[0][2] = v3.x; + Result[1][2] = v3.y; + Result[2][2] = v3.z; + Result[3][2] = v3.w; + Result[0][3] = v4.x; + Result[1][3] = v4.y; + Result[2][3] = v4.z; + Result[3][3] = v4.w; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( + const mat<4, 4, T, Q>& m) + { + mat<4, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + Result[3][3] = m[3][3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( + const vec<2, T, Q>& v1, + const vec<2, T, Q>& v2) + { + return mat<2, 2, T, Q>(v1, v2); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( + const mat<2, 2, T, Q>& m) + { + return mat<2, 2, T, Q>(m); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( + const vec<3, T, Q>& v1, + const vec<3, T, Q>& v2, + const vec<3, T, Q>& v3) + { + return mat<3, 3, T, Q>(v1, v2, v3); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( + const mat<3, 3, T, Q>& m) + { + return mat<3, 3, T, Q>(m); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( + const vec<4, T, Q>& v1, + const vec<4, T, Q>& v2, + const vec<4, T, Q>& v3, + const vec<4, T, Q>& v4) + { + return mat<4, 4, T, Q>(v1, v2, v3, v4); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( + const mat<4, 4, T, Q>& m) + { + return mat<4, 4, T, Q>(m); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/matrix_operation.hpp b/src/GLMath/glm/gtx/matrix_operation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..de6ff1f86f47f5b99d7be8d48637e97d5f98e668 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_operation.hpp @@ -0,0 +1,103 @@ +/// @ref gtx_matrix_operation +/// @file glm/gtx/matrix_operation.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_operation GLM_GTX_matrix_operation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build diagonal matrices from vectors. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_operation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_operation extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_operation + /// @{ + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> diagonal2x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 3, T, Q> diagonal2x3( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 4, T, Q> diagonal2x4( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 2, T, Q> diagonal3x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> diagonal3x3( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 4, T, Q> diagonal3x4( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 2, T, Q> diagonal4x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 3, T, Q> diagonal4x3( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> diagonal4x4( + vec<4, T, Q> const& v); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m); + + /// @} +}//namespace glm + +#include "matrix_operation.inl" diff --git a/src/GLMath/glm/gtx/matrix_operation.inl b/src/GLMath/glm/gtx/matrix_operation.inl new file mode 100644 index 0000000000000000000000000000000000000000..9de83f82367157792446e91d3eeb627c1947bb3c --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_operation.inl @@ -0,0 +1,176 @@ +/// @ref gtx_matrix_operation + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> diagonal2x2 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> diagonal2x3 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> diagonal2x4 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> diagonal3x2 + ( + vec<2, T, Q> const& v + ) + { + mat<3, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> diagonal3x3 + ( + vec<3, T, Q> const& v + ) + { + mat<3, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> diagonal3x4 + ( + vec<3, T, Q> const& v + ) + { + mat<3, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> diagonal4x4 + ( + vec<4, T, Q> const& v + ) + { + mat<4, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + Result[3][3] = v[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> diagonal4x3 + ( + vec<3, T, Q> const& v + ) + { + mat<4, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> diagonal4x2 + ( + vec<2, T, Q> const& v + ) + { + mat<4, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + +m[1][1], -m[1][0], + -m[0][1], +m[0][0]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m) + { + T const m00 = determinant(mat<2, 2, T, Q>(m[1][1], m[2][1], m[1][2], m[2][2])); + T const m01 = determinant(mat<2, 2, T, Q>(m[0][1], m[2][1], m[0][2], m[2][2])); + T const m02 = determinant(mat<2, 2, T, Q>(m[0][1], m[1][1], m[0][2], m[1][2])); + + T const m10 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][2], m[2][2])); + T const m11 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][2], m[2][2])); + T const m12 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][2], m[1][2])); + + T const m20 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][1], m[2][1])); + T const m21 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][1], m[2][1])); + T const m22 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][1], m[1][1])); + + return mat<3, 3, T, Q>( + +m00, -m01, +m02, + -m10, +m11, -m12, + +m20, -m21, +m22); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m) + { + T const m00 = determinant(mat<3, 3, T, Q>(m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); + T const m01 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); + T const m02 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][1], m[3][3])); + T const m03 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); + + T const m10 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); + T const m11 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); + T const m12 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], m[3][3])); + T const m13 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); + + T const m20 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[3][1], m[3][2], m[3][3])); + T const m21 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[3][0], m[3][2], m[3][3])); + T const m22 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[3][0], m[3][1], m[3][3])); + T const m23 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[3][0], m[3][1], m[3][2])); + + T const m30 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3])); + T const m31 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3])); + T const m32 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], m[2][3])); + T const m33 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2])); + + return mat<4, 4, T, Q>( + +m00, -m01, +m02, -m03, + -m10, +m11, -m12, +m13, + +m20, -m21, +m22, -m23, + -m30, +m31, -m32, +m33); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/matrix_query.hpp b/src/GLMath/glm/gtx/matrix_query.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8011b2b1d469efdb98c2c5f1fe98538644e2ac05 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_query.hpp @@ -0,0 +1,77 @@ +/// @ref gtx_matrix_query +/// @file glm/gtx/matrix_query.hpp +/// +/// @see core (dependence) +/// @see gtx_vector_query (dependence) +/// +/// @defgroup gtx_matrix_query GLM_GTX_matrix_query +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Query to evaluate matrix properties + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/vector_query.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_query extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_query + /// @{ + + /// Return whether a matrix a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is an identity matrix. + /// From GLM_GTX_matrix_query extension. + template class matType> + GLM_FUNC_DECL bool isIdentity(matType const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is an orthonormalized matrix. + /// From GLM_GTX_matrix_query extension. + template class matType> + GLM_FUNC_DECL bool isOrthogonal(matType const& m, T const& epsilon); + + /// @} +}//namespace glm + +#include "matrix_query.inl" diff --git a/src/GLMath/glm/gtx/matrix_query.inl b/src/GLMath/glm/gtx/matrix_query.inl new file mode 100644 index 0000000000000000000000000000000000000000..77bd23108e3bf3dd4880fc8072b8a7c9ee27e37e --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_query.inl @@ -0,0 +1,113 @@ +/// @ref gtx_matrix_query + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isIdentity(mat const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m[0].length() ; ++i) + { + for(length_t j = 0; result && j < i ; ++j) + result = abs(m[i][j]) <= epsilon; + if(result) + result = abs(m[i][i] - 1) <= epsilon; + for(length_t j = i + 1; result && j < m.length(); ++j) + result = abs(m[i][j]) <= epsilon; + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<2, 2, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<3, 3, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<4, 4, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isOrthogonal(mat const& m, T const& epsilon) + { + bool result = true; + for(length_t i(0); result && i < m.length() - 1; ++i) + for(length_t j(i + 1); result && j < m.length(); ++j) + result = areOrthogonal(m[i], m[j], epsilon); + + if(result) + { + mat tmp = transpose(m); + for(length_t i(0); result && i < m.length() - 1 ; ++i) + for(length_t j(i + 1); result && j < m.length(); ++j) + result = areOrthogonal(tmp[i], tmp[j], epsilon); + } + return result; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/matrix_transform_2d.hpp b/src/GLMath/glm/gtx/matrix_transform_2d.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5f9c540218511a9c47c79044049e534d30b9bfcb --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_transform_2d.hpp @@ -0,0 +1,81 @@ +/// @ref gtx_matrix_transform_2d +/// @file glm/gtx/matrix_transform_2d.hpp +/// @author Miguel Ãngel Pérez Martínez +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_transform_2d GLM_GTX_matrix_transform_2d +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines functions that generate common 2d transformation matrices. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" +#include "../vec2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_transform_2d is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_transform_2d extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_transform_2d + /// @{ + + /// Builds a translation 3 * 3 matrix created from a vector of 2 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a translation vector. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v); + + /// Builds a rotation 3 * 3 matrix created from an angle. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param angle Rotation angle expressed in radians. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( + mat<3, 3, T, Q> const& m, + T angle); + + /// Builds a scale 3 * 3 matrix created from a vector of 2 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a scale vector. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v); + + /// Builds an horizontal (parallel to the x axis) shear 3 * 3 matrix. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param y Shear factor. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( + mat<3, 3, T, Q> const& m, + T y); + + /// Builds a vertical (parallel to the y axis) shear 3 * 3 matrix. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param x Shear factor. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( + mat<3, 3, T, Q> const& m, + T x); + + /// @} +}//namespace glm + +#include "matrix_transform_2d.inl" diff --git a/src/GLMath/glm/gtx/matrix_transform_2d.inl b/src/GLMath/glm/gtx/matrix_transform_2d.inl new file mode 100644 index 0000000000000000000000000000000000000000..a68d24dc9825c97cf47753779ed97834ea77aba0 --- /dev/null +++ b/src/GLMath/glm/gtx/matrix_transform_2d.inl @@ -0,0 +1,68 @@ +/// @ref gtx_matrix_transform_2d +/// @author Miguel Ãngel Pérez Martínez + +#include "../trigonometric.hpp" + +namespace glm +{ + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v) + { + mat<3, 3, T, Q> Result(m); + Result[2] = m[0] * v[0] + m[1] * v[1] + m[2]; + return Result; + } + + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( + mat<3, 3, T, Q> const& m, + T angle) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + mat<3, 3, T, Q> Result; + Result[0] = m[0] * c + m[1] * s; + Result[1] = m[0] * -s + m[1] * c; + Result[2] = m[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v) + { + mat<3, 3, T, Q> Result; + Result[0] = m[0] * v[0]; + Result[1] = m[1] * v[1]; + Result[2] = m[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( + mat<3, 3, T, Q> const& m, + T y) + { + mat<3, 3, T, Q> Result(1); + Result[0][1] = y; + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( + mat<3, 3, T, Q> const& m, + T x) + { + mat<3, 3, T, Q> Result(1); + Result[1][0] = x; + return m * Result; + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/mixed_product.hpp b/src/GLMath/glm/gtx/mixed_product.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b242e357e57a1b6e4c8b837e2d90841a0d0d5f7d --- /dev/null +++ b/src/GLMath/glm/gtx/mixed_product.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_mixed_product +/// @file glm/gtx/mixed_product.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_mixed_product GLM_GTX_mixed_producte +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Mixed product of 3 vectors. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_mixed_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_mixed_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_mixed_product + /// @{ + + /// @brief Mixed product of 3 vectors (from GLM_GTX_mixed_product extension) + template + GLM_FUNC_DECL T mixedProduct( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + /// @} +}// namespace glm + +#include "mixed_product.inl" diff --git a/src/GLMath/glm/gtx/mixed_product.inl b/src/GLMath/glm/gtx/mixed_product.inl new file mode 100644 index 0000000000000000000000000000000000000000..e5cdbdb49a2bb7457dd74ca08cdac0615d26b9c4 --- /dev/null +++ b/src/GLMath/glm/gtx/mixed_product.inl @@ -0,0 +1,15 @@ +/// @ref gtx_mixed_product + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T mixedProduct + ( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3 + ) + { + return dot(cross(v1, v2), v3); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/norm.hpp b/src/GLMath/glm/gtx/norm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cdf60e05b0bc2bfe1470e7d182b5040f2bfc8031 --- /dev/null +++ b/src/GLMath/glm/gtx/norm.hpp @@ -0,0 +1,76 @@ +/// @ref gtx_norm +/// @file glm/gtx/norm.hpp +/// +/// @see core (dependence) +/// @see gtx_quaternion (dependence) +/// +/// @defgroup gtx_norm GLM_GTX_norm +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Various ways to compute vector norms. + +#pragma once + +// Dependency: +#include "../geometric.hpp" +#include "../gtx/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_norm is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_norm extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_norm + /// @{ + + /// Returns the squared length of x. + /// From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T length2(vec const& x); + + /// Returns the squared distance between p0 and p1, i.e., length2(p0 - p1). + /// From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T distance2(vec const& p0, vec const& p1); + + //! Returns the L1 norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the L1 norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& v); + + //! Returns the L2 norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the L2 norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x); + + //! Returns the L norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth); + + //! Returns the L norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, unsigned int Depth); + + /// @} +}//namespace glm + +#include "norm.inl" diff --git a/src/GLMath/glm/gtx/norm.inl b/src/GLMath/glm/gtx/norm.inl new file mode 100644 index 0000000000000000000000000000000000000000..c3f468c3aa7ce71f718fea353ac426006fa1f2a0 --- /dev/null +++ b/src/GLMath/glm/gtx/norm.inl @@ -0,0 +1,83 @@ +/// @ref gtx_norm + +#include "../detail/qualifier.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_length2 + { + GLM_FUNC_QUALIFIER static T call(vec const& v) + { + return dot(v, v); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER genType length2(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); + return x * x; + } + + template + GLM_FUNC_QUALIFIER T length2(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); + return detail::compute_length2::value>::call(v); + } + + template + GLM_FUNC_QUALIFIER T distance2(T p0, T p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); + return length2(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T distance2(vec const& p0, vec const& p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); + return length2(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z); + } + + template + GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& v) + { + return abs(v.x) + abs(v.y) + abs(v.z); + } + + template + GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b + ) + { + return length(b - a); + } + + template + GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& v) + { + return length(v); + } + + template + GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth) + { + return pow(pow(y.x - x.x, T(Depth)) + pow(y.y - x.y, T(Depth)) + pow(y.z - x.z, T(Depth)), T(1) / T(Depth)); + } + + template + GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& v, unsigned int Depth) + { + return pow(pow(v.x, T(Depth)) + pow(v.y, T(Depth)) + pow(v.z, T(Depth)), T(1) / T(Depth)); + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/normal.hpp b/src/GLMath/glm/gtx/normal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..068682f75f2dac6596b58c6bac6d1dd02a49175c --- /dev/null +++ b/src/GLMath/glm/gtx/normal.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_normal +/// @file glm/gtx/normal.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_normal GLM_GTX_normal +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Compute the normal of a triangle. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_normal is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_normal extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_normal + /// @{ + + /// Computes triangle normal from triangle points. + /// + /// @see gtx_normal + template + GLM_FUNC_DECL vec<3, T, Q> triangleNormal(vec<3, T, Q> const& p1, vec<3, T, Q> const& p2, vec<3, T, Q> const& p3); + + /// @} +}//namespace glm + +#include "normal.inl" diff --git a/src/GLMath/glm/gtx/normal.inl b/src/GLMath/glm/gtx/normal.inl new file mode 100644 index 0000000000000000000000000000000000000000..74f9fc9945854fbe607e87ef47bf506a332b8966 --- /dev/null +++ b/src/GLMath/glm/gtx/normal.inl @@ -0,0 +1,15 @@ +/// @ref gtx_normal + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> triangleNormal + ( + vec<3, T, Q> const& p1, + vec<3, T, Q> const& p2, + vec<3, T, Q> const& p3 + ) + { + return normalize(cross(p1 - p2, p1 - p3)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/normalize_dot.hpp b/src/GLMath/glm/gtx/normalize_dot.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51958023f0144f0d2b42cb1d7a1619d03c1cde04 --- /dev/null +++ b/src/GLMath/glm/gtx/normalize_dot.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_normalize_dot +/// @file glm/gtx/normalize_dot.hpp +/// +/// @see core (dependence) +/// @see gtx_fast_square_root (dependence) +/// +/// @defgroup gtx_normalize_dot GLM_GTX_normalize_dot +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Dot product of vectors that need to be normalize with a single square root. + +#pragma once + +// Dependency: +#include "../gtx/fast_square_root.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_normalize_dot is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_normalize_dot extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_normalize_dot + /// @{ + + /// Normalize parameters and returns the dot product of x and y. + /// It's faster that dot(normalize(x), normalize(y)). + /// + /// @see gtx_normalize_dot extension. + template + GLM_FUNC_DECL T normalizeDot(vec const& x, vec const& y); + + /// Normalize parameters and returns the dot product of x and y. + /// Faster that dot(fastNormalize(x), fastNormalize(y)). + /// + /// @see gtx_normalize_dot extension. + template + GLM_FUNC_DECL T fastNormalizeDot(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "normalize_dot.inl" diff --git a/src/GLMath/glm/gtx/normalize_dot.inl b/src/GLMath/glm/gtx/normalize_dot.inl new file mode 100644 index 0000000000000000000000000000000000000000..7bcd9a534a8f4df3a12118c746aadd6f264e264e --- /dev/null +++ b/src/GLMath/glm/gtx/normalize_dot.inl @@ -0,0 +1,16 @@ +/// @ref gtx_normalize_dot + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T normalizeDot(vec const& x, vec const& y) + { + return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y)); + } + + template + GLM_FUNC_QUALIFIER T fastNormalizeDot(vec const& x, vec const& y) + { + return glm::dot(x, y) * glm::fastInverseSqrt(glm::dot(x, x) * glm::dot(y, y)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/number_precision.hpp b/src/GLMath/glm/gtx/number_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3a606bda040c8d91763c57fec09ea35e5890a24d --- /dev/null +++ b/src/GLMath/glm/gtx/number_precision.hpp @@ -0,0 +1,61 @@ +/// @ref gtx_number_precision +/// @file glm/gtx/number_precision.hpp +/// +/// @see core (dependence) +/// @see gtc_type_precision (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_number_precision GLM_GTX_number_precision +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defined size types. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/type_precision.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_number_precision is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_number_precision extension included") +# endif +#endif + +namespace glm{ +namespace gtx +{ + ///////////////////////////// + // Unsigned int vector types + + /// @addtogroup gtx_number_precision + /// @{ + + typedef u8 u8vec1; //!< \brief 8bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u16 u16vec1; //!< \brief 16bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u32 u32vec1; //!< \brief 32bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u64 u64vec1; //!< \brief 64bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + + ////////////////////// + // Float vector types + + typedef f32 f32vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + + ////////////////////// + // Float matrix types + + typedef f32 f32mat1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f32 f32mat1x1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64mat1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64mat1x1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + + /// @} +}//namespace gtx +}//namespace glm + +#include "number_precision.inl" diff --git a/src/GLMath/glm/gtx/number_precision.inl b/src/GLMath/glm/gtx/number_precision.inl new file mode 100644 index 0000000000000000000000000000000000000000..b39d71c3b49d322835a883ed9e5825206c2dc354 --- /dev/null +++ b/src/GLMath/glm/gtx/number_precision.inl @@ -0,0 +1,6 @@ +/// @ref gtx_number_precision + +namespace glm +{ + +} diff --git a/src/GLMath/glm/gtx/optimum_pow.hpp b/src/GLMath/glm/gtx/optimum_pow.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9284a474d491f748dfcf43c8ccbd3578622cb04b --- /dev/null +++ b/src/GLMath/glm/gtx/optimum_pow.hpp @@ -0,0 +1,54 @@ +/// @ref gtx_optimum_pow +/// @file glm/gtx/optimum_pow.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_optimum_pow GLM_GTX_optimum_pow +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Integer exponentiation of power functions. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_optimum_pow is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_optimum_pow extension included") +# endif +#endif + +namespace glm{ +namespace gtx +{ + /// @addtogroup gtx_optimum_pow + /// @{ + + /// Returns x raised to the power of 2. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow2(genType const& x); + + /// Returns x raised to the power of 3. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow3(genType const& x); + + /// Returns x raised to the power of 4. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow4(genType const& x); + + /// @} +}//namespace gtx +}//namespace glm + +#include "optimum_pow.inl" diff --git a/src/GLMath/glm/gtx/optimum_pow.inl b/src/GLMath/glm/gtx/optimum_pow.inl new file mode 100644 index 0000000000000000000000000000000000000000..a26c19c18bfbd6b84d7c1be07d9448c6fbcb7e01 --- /dev/null +++ b/src/GLMath/glm/gtx/optimum_pow.inl @@ -0,0 +1,22 @@ +/// @ref gtx_optimum_pow + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType pow2(genType const& x) + { + return x * x; + } + + template + GLM_FUNC_QUALIFIER genType pow3(genType const& x) + { + return x * x * x; + } + + template + GLM_FUNC_QUALIFIER genType pow4(genType const& x) + { + return (x * x) * (x * x); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/orthonormalize.hpp b/src/GLMath/glm/gtx/orthonormalize.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3e004fb06f9cd2e8d68f6a1cb073017a1bacfaf0 --- /dev/null +++ b/src/GLMath/glm/gtx/orthonormalize.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_orthonormalize +/// @file glm/gtx/orthonormalize.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_orthonormalize GLM_GTX_orthonormalize +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Orthonormalize matrices. + +#pragma once + +// Dependency: +#include "../vec3.hpp" +#include "../mat3x3.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_orthonormalize is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_orthonormalize extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_orthonormalize + /// @{ + + /// Returns the orthonormalized matrix of m. + /// + /// @see gtx_orthonormalize + template + GLM_FUNC_DECL mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m); + + /// Orthonormalizes x according y. + /// + /// @see gtx_orthonormalize + template + GLM_FUNC_DECL vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + /// @} +}//namespace glm + +#include "orthonormalize.inl" diff --git a/src/GLMath/glm/gtx/orthonormalize.inl b/src/GLMath/glm/gtx/orthonormalize.inl new file mode 100644 index 0000000000000000000000000000000000000000..cb553ba62157b3fca6c704777242bf473cdbe483 --- /dev/null +++ b/src/GLMath/glm/gtx/orthonormalize.inl @@ -0,0 +1,29 @@ +/// @ref gtx_orthonormalize + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m) + { + mat<3, 3, T, Q> r = m; + + r[0] = normalize(r[0]); + + T d0 = dot(r[0], r[1]); + r[1] -= r[0] * d0; + r[1] = normalize(r[1]); + + T d1 = dot(r[1], r[2]); + d0 = dot(r[0], r[2]); + r[2] -= r[0] * d0 + r[1] * d1; + r[2] = normalize(r[2]); + + return r; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + return normalize(x - y * dot(y, x)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/perpendicular.hpp b/src/GLMath/glm/gtx/perpendicular.hpp new file mode 100644 index 0000000000000000000000000000000000000000..72b77b6e2388aada9c12070c804e0a02ba42ed86 --- /dev/null +++ b/src/GLMath/glm/gtx/perpendicular.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_perpendicular +/// @file glm/gtx/perpendicular.hpp +/// +/// @see core (dependence) +/// @see gtx_projection (dependence) +/// +/// @defgroup gtx_perpendicular GLM_GTX_perpendicular +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Perpendicular of a vector from other one + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/projection.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_perpendicular is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_perpendicular extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_perpendicular + /// @{ + + //! Projects x a perpendicular axis of Normal. + //! From GLM_GTX_perpendicular extension. + template + GLM_FUNC_DECL genType perp(genType const& x, genType const& Normal); + + /// @} +}//namespace glm + +#include "perpendicular.inl" diff --git a/src/GLMath/glm/gtx/perpendicular.inl b/src/GLMath/glm/gtx/perpendicular.inl new file mode 100644 index 0000000000000000000000000000000000000000..1e72f334230dee397361c2bae3af71600ee0a722 --- /dev/null +++ b/src/GLMath/glm/gtx/perpendicular.inl @@ -0,0 +1,10 @@ +/// @ref gtx_perpendicular + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType perp(genType const& x, genType const& Normal) + { + return x - proj(x, Normal); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/polar_coordinates.hpp b/src/GLMath/glm/gtx/polar_coordinates.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b399112577eb34e202af83da1606ec09cac82332 --- /dev/null +++ b/src/GLMath/glm/gtx/polar_coordinates.hpp @@ -0,0 +1,48 @@ +/// @ref gtx_polar_coordinates +/// @file glm/gtx/polar_coordinates.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_polar_coordinates GLM_GTX_polar_coordinates +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Conversion from Euclidean space to polar space and revert. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_polar_coordinates is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_polar_coordinates extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_polar_coordinates + /// @{ + + /// Convert Euclidean to Polar coordinates, x is the xz distance, y, the latitude and z the longitude. + /// + /// @see gtx_polar_coordinates + template + GLM_FUNC_DECL vec<3, T, Q> polar( + vec<3, T, Q> const& euclidean); + + /// Convert Polar to Euclidean coordinates. + /// + /// @see gtx_polar_coordinates + template + GLM_FUNC_DECL vec<3, T, Q> euclidean( + vec<2, T, Q> const& polar); + + /// @} +}//namespace glm + +#include "polar_coordinates.inl" diff --git a/src/GLMath/glm/gtx/polar_coordinates.inl b/src/GLMath/glm/gtx/polar_coordinates.inl new file mode 100644 index 0000000000000000000000000000000000000000..371c8dddebd1cf197ab8527b4bb8098edf733814 --- /dev/null +++ b/src/GLMath/glm/gtx/polar_coordinates.inl @@ -0,0 +1,36 @@ +/// @ref gtx_polar_coordinates + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> polar + ( + vec<3, T, Q> const& euclidean + ) + { + T const Length(length(euclidean)); + vec<3, T, Q> const tmp(euclidean / Length); + T const xz_dist(sqrt(tmp.x * tmp.x + tmp.z * tmp.z)); + + return vec<3, T, Q>( + asin(tmp.y), // latitude + atan(tmp.x, tmp.z), // longitude + xz_dist); // xz distance + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> euclidean + ( + vec<2, T, Q> const& polar + ) + { + T const latitude(polar.x); + T const longitude(polar.y); + + return vec<3, T, Q>( + cos(latitude) * sin(longitude), + sin(latitude), + cos(latitude) * cos(longitude)); + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/projection.hpp b/src/GLMath/glm/gtx/projection.hpp new file mode 100644 index 0000000000000000000000000000000000000000..678f3ad5a585f83b1a83d7d99960fae383dfb396 --- /dev/null +++ b/src/GLMath/glm/gtx/projection.hpp @@ -0,0 +1,43 @@ +/// @ref gtx_projection +/// @file glm/gtx/projection.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_projection GLM_GTX_projection +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Projection of a vector to other one + +#pragma once + +// Dependency: +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_projection is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_projection extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_projection + /// @{ + + /// Projects x on Normal. + /// + /// @param[in] x A vector to project + /// @param[in] Normal A normal that doesn't need to be of unit length. + /// + /// @see gtx_projection + template + GLM_FUNC_DECL genType proj(genType const& x, genType const& Normal); + + /// @} +}//namespace glm + +#include "projection.inl" diff --git a/src/GLMath/glm/gtx/projection.inl b/src/GLMath/glm/gtx/projection.inl new file mode 100644 index 0000000000000000000000000000000000000000..f23f884fb93a2c246d4560ec1f18c7292f9205c6 --- /dev/null +++ b/src/GLMath/glm/gtx/projection.inl @@ -0,0 +1,10 @@ +/// @ref gtx_projection + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType proj(genType const& x, genType const& Normal) + { + return glm::dot(x, Normal) / glm::dot(Normal, Normal) * Normal; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/quaternion.hpp b/src/GLMath/glm/gtx/quaternion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..05a71dfad873841954ef61d7a959a81e1e8ed151 --- /dev/null +++ b/src/GLMath/glm/gtx/quaternion.hpp @@ -0,0 +1,174 @@ +/// @ref gtx_quaternion +/// @file glm/gtx/quaternion.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_quaternion GLM_GTX_quaternion +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extented quaternion types and functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/quaternion.hpp" +#include "../ext/quaternion_exponential.hpp" +#include "../gtx/norm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_quaternion extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_quaternion + /// @{ + + /// Create an identity quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua quat_identity(); + + /// Compute a cross product between a quaternion and a vector. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> cross( + qua const& q, + vec<3, T, Q> const& v); + + //! Compute a cross product between a vector and a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> cross( + vec<3, T, Q> const& v, + qua const& q); + + //! Compute a point on a path according squad equation. + //! q1 and q2 are control points; s1 and s2 are intermediate control points. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua squad( + qua const& q1, + qua const& q2, + qua const& s1, + qua const& s2, + T const& h); + + //! Returns an intermediate control point for squad interpolation. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua intermediate( + qua const& prev, + qua const& curr, + qua const& next); + + //! Returns quarternion square root. + /// + /// @see gtx_quaternion + //template + //qua sqrt( + // qua const& q); + + //! Rotates a 3 components vector by a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> rotate( + qua const& q, + vec<3, T, Q> const& v); + + /// Rotates a 4 components vector by a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<4, T, Q> rotate( + qua const& q, + vec<4, T, Q> const& v); + + /// Extract the real component of a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL T extractRealComponent( + qua const& q); + + /// Converts a quaternion to a 3 * 3 matrix. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL mat<3, 3, T, Q> toMat3( + qua const& x){return mat3_cast(x);} + + /// Converts a quaternion to a 4 * 4 matrix. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL mat<4, 4, T, Q> toMat4( + qua const& x){return mat4_cast(x);} + + /// Converts a 3 * 3 matrix to a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua toQuat( + mat<3, 3, T, Q> const& x){return quat_cast(x);} + + /// Converts a 4 * 4 matrix to a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua toQuat( + mat<4, 4, T, Q> const& x){return quat_cast(x);} + + /// Quaternion interpolation using the rotation short path. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua shortMix( + qua const& x, + qua const& y, + T const& a); + + /// Quaternion normalized linear interpolation. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua fastMix( + qua const& x, + qua const& y, + T const& a); + + /// Compute the rotation between two vectors. + /// param orig vector, needs to be normalized + /// param dest vector, needs to be normalized + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua rotation( + vec<3, T, Q> const& orig, + vec<3, T, Q> const& dest); + + /// Returns the squared length of x. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL T length2(qua const& q); + + /// @} +}//namespace glm + +#include "quaternion.inl" diff --git a/src/GLMath/glm/gtx/quaternion.inl b/src/GLMath/glm/gtx/quaternion.inl new file mode 100644 index 0000000000000000000000000000000000000000..679b39f1e7dafc8c5175733c378d386cb7ef1eef --- /dev/null +++ b/src/GLMath/glm/gtx/quaternion.inl @@ -0,0 +1,159 @@ +/// @ref gtx_quaternion + +#include +#include "../gtc/constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua quat_identity() + { + return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& v, qua const& q) + { + return inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(qua const& q, vec<3, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER qua squad + ( + qua const& q1, + qua const& q2, + qua const& s1, + qua const& s2, + T const& h) + { + return mix(mix(q1, q2, h), mix(s1, s2, h), static_cast(2) * (static_cast(1) - h) * h); + } + + template + GLM_FUNC_QUALIFIER qua intermediate + ( + qua const& prev, + qua const& curr, + qua const& next + ) + { + qua invQuat = inverse(curr); + return exp((log(next * invQuat) + log(prev * invQuat)) / static_cast(-4)) * curr; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotate(qua const& q, vec<3, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotate(qua const& q, vec<4, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER T extractRealComponent(qua const& q) + { + T w = static_cast(1) - q.x * q.x - q.y * q.y - q.z * q.z; + if(w < T(0)) + return T(0); + else + return -sqrt(w); + } + + template + GLM_FUNC_QUALIFIER T length2(qua const& q) + { + return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + } + + template + GLM_FUNC_QUALIFIER qua shortMix(qua const& x, qua const& y, T const& a) + { + if(a <= static_cast(0)) return x; + if(a >= static_cast(1)) return y; + + T fCos = dot(x, y); + qua y2(y); //BUG!!! qua y2; + if(fCos < static_cast(0)) + { + y2 = -y; + fCos = -fCos; + } + + //if(fCos > 1.0f) // problem + T k0, k1; + if(fCos > (static_cast(1) - epsilon())) + { + k0 = static_cast(1) - a; + k1 = static_cast(0) + a; //BUG!!! 1.0f + a; + } + else + { + T fSin = sqrt(T(1) - fCos * fCos); + T fAngle = atan(fSin, fCos); + T fOneOverSin = static_cast(1) / fSin; + k0 = sin((static_cast(1) - a) * fAngle) * fOneOverSin; + k1 = sin((static_cast(0) + a) * fAngle) * fOneOverSin; + } + + return qua( + k0 * x.w + k1 * y2.w, + k0 * x.x + k1 * y2.x, + k0 * x.y + k1 * y2.y, + k0 * x.z + k1 * y2.z); + } + + template + GLM_FUNC_QUALIFIER qua fastMix(qua const& x, qua const& y, T const& a) + { + return glm::normalize(x * (static_cast(1) - a) + (y * a)); + } + + template + GLM_FUNC_QUALIFIER qua rotation(vec<3, T, Q> const& orig, vec<3, T, Q> const& dest) + { + T cosTheta = dot(orig, dest); + vec<3, T, Q> rotationAxis; + + if(cosTheta >= static_cast(1) - epsilon()) { + // orig and dest point in the same direction + return quat_identity(); + } + + if(cosTheta < static_cast(-1) + epsilon()) + { + // special case when vectors in opposite directions : + // there is no "ideal" rotation axis + // So guess one; any will do as long as it's perpendicular to start + // This implementation favors a rotation around the Up axis (Y), + // since it's often what you want to do. + rotationAxis = cross(vec<3, T, Q>(0, 0, 1), orig); + if(length2(rotationAxis) < epsilon()) // bad luck, they were parallel, try again! + rotationAxis = cross(vec<3, T, Q>(1, 0, 0), orig); + + rotationAxis = normalize(rotationAxis); + return angleAxis(pi(), rotationAxis); + } + + // Implementation from Stan Melax's Game Programming Gems 1 article + rotationAxis = cross(orig, dest); + + T s = sqrt((T(1) + cosTheta) * static_cast(2)); + T invs = static_cast(1) / s; + + return qua( + s * static_cast(0.5f), + rotationAxis.x * invs, + rotationAxis.y * invs, + rotationAxis.z * invs); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/range.hpp b/src/GLMath/glm/gtx/range.hpp new file mode 100644 index 0000000000000000000000000000000000000000..93bcb9a65a0afc615bec388fe99681b95849ea4f --- /dev/null +++ b/src/GLMath/glm/gtx/range.hpp @@ -0,0 +1,98 @@ +/// @ref gtx_range +/// @file glm/gtx/range.hpp +/// @author Joshua Moerman +/// +/// @defgroup gtx_range GLM_GTX_range +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines begin and end for vectors and matrices. Useful for range-based for loop. +/// The range is defined over the elements, not over columns or rows (e.g. mat4 has 16 elements). + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_range is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_range extension included") +# endif +#endif + +#include "../gtc/type_ptr.hpp" +#include "../gtc/vec1.hpp" + +namespace glm +{ + /// @addtogroup gtx_range + /// @{ + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +# endif + + template + inline length_t components(vec<1, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<2, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<3, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<4, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(genType const& m) + { + return m.length() * m[0].length(); + } + + template + inline typename genType::value_type const * begin(genType const& v) + { + return value_ptr(v); + } + + template + inline typename genType::value_type const * end(genType const& v) + { + return begin(v) + components(v); + } + + template + inline typename genType::value_type * begin(genType& v) + { + return value_ptr(v); + } + + template + inline typename genType::value_type * end(genType& v) + { + return begin(v) + components(v); + } + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif + + /// @} +}//namespace glm diff --git a/src/GLMath/glm/gtx/raw_data.hpp b/src/GLMath/glm/gtx/raw_data.hpp new file mode 100644 index 0000000000000000000000000000000000000000..86cbe77d9ae537ca6537a89d14f6ee0bfe50696b --- /dev/null +++ b/src/GLMath/glm/gtx/raw_data.hpp @@ -0,0 +1,51 @@ +/// @ref gtx_raw_data +/// @file glm/gtx/raw_data.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_raw_data GLM_GTX_raw_data +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Projection of a vector to other one + +#pragma once + +// Dependencies +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_raw_data is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_raw_data extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_raw_data + /// @{ + + //! Type for byte numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint8 byte; + + //! Type for word numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint16 word; + + //! Type for dword numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint32 dword; + + //! Type for qword numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint64 qword; + + /// @} +}// namespace glm + +#include "raw_data.inl" diff --git a/src/GLMath/glm/gtx/raw_data.inl b/src/GLMath/glm/gtx/raw_data.inl new file mode 100644 index 0000000000000000000000000000000000000000..c740317d334e7f08181df5ac2522aef7e85bbdb4 --- /dev/null +++ b/src/GLMath/glm/gtx/raw_data.inl @@ -0,0 +1,2 @@ +/// @ref gtx_raw_data + diff --git a/src/GLMath/glm/gtx/rotate_normalized_axis.hpp b/src/GLMath/glm/gtx/rotate_normalized_axis.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2103ca08f15ea9576b25bdb0955771ee313d6e79 --- /dev/null +++ b/src/GLMath/glm/gtx/rotate_normalized_axis.hpp @@ -0,0 +1,68 @@ +/// @ref gtx_rotate_normalized_axis +/// @file glm/gtx/rotate_normalized_axis.hpp +/// +/// @see core (dependence) +/// @see gtc_matrix_transform +/// @see gtc_quaternion +/// +/// @defgroup gtx_rotate_normalized_axis GLM_GTX_rotate_normalized_axis +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Quaternions and matrices rotations around normalized axis. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/epsilon.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_rotate_normalized_axis is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_rotate_normalized_axis extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_rotate_normalized_axis + /// @{ + + /// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle. + /// + /// @param m Input matrix multiplied by this rotation matrix. + /// @param angle Rotation angle expressed in radians. + /// @param axis Rotation axis, must be normalized. + /// @tparam T Value type used to build the matrix. Currently supported: half (not recommended), float or double. + /// + /// @see gtx_rotate_normalized_axis + /// @see - rotate(T angle, T x, T y, T z) + /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) + /// @see - rotate(T angle, vec<3, T, Q> const& v) + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotateNormalizedAxis( + mat<4, 4, T, Q> const& m, + T const& angle, + vec<3, T, Q> const& axis); + + /// Rotates a quaternion from a vector of 3 components normalized axis and an angle. + /// + /// @param q Source orientation + /// @param angle Angle expressed in radians. + /// @param axis Normalized axis of the rotation, must be normalized. + /// + /// @see gtx_rotate_normalized_axis + template + GLM_FUNC_DECL qua rotateNormalizedAxis( + qua const& q, + T const& angle, + vec<3, T, Q> const& axis); + + /// @} +}//namespace glm + +#include "rotate_normalized_axis.inl" diff --git a/src/GLMath/glm/gtx/rotate_normalized_axis.inl b/src/GLMath/glm/gtx/rotate_normalized_axis.inl new file mode 100644 index 0000000000000000000000000000000000000000..b2e9278c0ae5d18775fbe93919e410a1b963ca06 --- /dev/null +++ b/src/GLMath/glm/gtx/rotate_normalized_axis.inl @@ -0,0 +1,58 @@ +/// @ref gtx_rotate_normalized_axis + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotateNormalizedAxis + ( + mat<4, 4, T, Q> const& m, + T const& angle, + vec<3, T, Q> const& v + ) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + vec<3, T, Q> const axis(v); + + vec<3, T, Q> const temp((static_cast(1) - c) * axis); + + mat<4, 4, T, Q> Rotate; + Rotate[0][0] = c + temp[0] * axis[0]; + Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; + Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; + + Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; + Rotate[1][1] = c + temp[1] * axis[1]; + Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; + + Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; + Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; + Rotate[2][2] = c + temp[2] * axis[2]; + + mat<4, 4, T, Q> Result; + Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER qua rotateNormalizedAxis + ( + qua const& q, + T const& angle, + vec<3, T, Q> const& v + ) + { + vec<3, T, Q> const Tmp(v); + + T const AngleRad(angle); + T const Sin = sin(AngleRad * T(0.5)); + + return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); + //return gtc::quaternion::cross(q, tquat(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/rotate_vector.hpp b/src/GLMath/glm/gtx/rotate_vector.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dcd5b95a6e5b1b484cec1261e4c00e93babba754 --- /dev/null +++ b/src/GLMath/glm/gtx/rotate_vector.hpp @@ -0,0 +1,123 @@ +/// @ref gtx_rotate_vector +/// @file glm/gtx/rotate_vector.hpp +/// +/// @see core (dependence) +/// @see gtx_transform (dependence) +/// +/// @defgroup gtx_rotate_vector GLM_GTX_rotate_vector +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Function to directly rotate a vector + +#pragma once + +// Dependency: +#include "../gtx/transform.hpp" +#include "../gtc/epsilon.hpp" +#include "../ext/vector_relational.hpp" +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_rotate_vector is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_rotate_vector extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_rotate_vector + /// @{ + + /// Returns Spherical interpolation between two vectors + /// + /// @param x A first vector + /// @param y A second vector + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @see gtx_rotate_vector + template + GLM_FUNC_DECL vec<3, T, Q> slerp( + vec<3, T, Q> const& x, + vec<3, T, Q> const& y, + T const& a); + + //! Rotate a two dimensional vector. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<2, T, Q> rotate( + vec<2, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around an axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotate( + vec<3, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal); + + //! Rotate a four dimensional vector around an axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotate( + vec<4, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal); + + //! Rotate a three dimensional vector around the X axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateX( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around the Y axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateY( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around the Z axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateZ( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the X axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateX( + vec<4, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the Y axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateY( + vec<4, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the Z axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateZ( + vec<4, T, Q> const& v, + T const& angle); + + //! Build a rotation matrix from a normal and a up vector. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> orientation( + vec<3, T, Q> const& Normal, + vec<3, T, Q> const& Up); + + /// @} +}//namespace glm + +#include "rotate_vector.inl" diff --git a/src/GLMath/glm/gtx/rotate_vector.inl b/src/GLMath/glm/gtx/rotate_vector.inl new file mode 100644 index 0000000000000000000000000000000000000000..f8136e765e0567723bfcfe6b3b13c6334ab4d5c1 --- /dev/null +++ b/src/GLMath/glm/gtx/rotate_vector.inl @@ -0,0 +1,187 @@ +/// @ref gtx_rotate_vector + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> slerp + ( + vec<3, T, Q> const& x, + vec<3, T, Q> const& y, + T const& a + ) + { + // get cosine of angle between vectors (-1 -> 1) + T CosAlpha = dot(x, y); + // get angle (0 -> pi) + T Alpha = acos(CosAlpha); + // get sine of angle between vectors (0 -> 1) + T SinAlpha = sin(Alpha); + // this breaks down when SinAlpha = 0, i.e. Alpha = 0 or pi + T t1 = sin((static_cast(1) - a) * Alpha) / SinAlpha; + T t2 = sin(a * Alpha) / SinAlpha; + + // interpolate src vectors + return x * t1 + y * t2; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> rotate + ( + vec<2, T, Q> const& v, + T const& angle + ) + { + vec<2, T, Q> Result; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotate + ( + vec<3, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal + ) + { + return mat<3, 3, T, Q>(glm::rotate(angle, normal)) * v; + } + /* + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateGTX( + const vec<3, T, Q>& x, + T angle, + const vec<3, T, Q>& normal) + { + const T Cos = cos(radians(angle)); + const T Sin = sin(radians(angle)); + return x * Cos + ((x * normal) * (T(1) - Cos)) * normal + cross(x, normal) * Sin; + } + */ + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotate + ( + vec<4, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal + ) + { + return rotate(angle, normal) * v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateX + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result(v); + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.y = v.y * Cos - v.z * Sin; + Result.z = v.y * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateY + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos + v.z * Sin; + Result.z = -v.x * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateZ + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateX + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.y = v.y * Cos - v.z * Sin; + Result.z = v.y * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateY + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos + v.z * Sin; + Result.z = -v.x * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateZ + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientation + ( + vec<3, T, Q> const& Normal, + vec<3, T, Q> const& Up + ) + { + if(all(equal(Normal, Up, epsilon()))) + return mat<4, 4, T, Q>(static_cast(1)); + + vec<3, T, Q> RotationAxis = cross(Up, Normal); + T Angle = acos(dot(Normal, Up)); + + return rotate(Angle, RotationAxis); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/scalar_multiplication.hpp b/src/GLMath/glm/gtx/scalar_multiplication.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f391f8debe4047b07b9e287f26e3a98fce1ceef6 --- /dev/null +++ b/src/GLMath/glm/gtx/scalar_multiplication.hpp @@ -0,0 +1,75 @@ +/// @ref gtx +/// @file glm/gtx/scalar_multiplication.hpp +/// @author Joshua Moerman +/// +/// Include to use the features of this extension. +/// +/// Enables scalar multiplication for all types +/// +/// Since GLSL is very strict about types, the following (often used) combinations do not work: +/// double * vec4 +/// int * vec4 +/// vec4 / int +/// So we'll fix that! Of course "float * vec4" should remain the same (hence the enable_if magic) + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_scalar_multiplication is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_scalar_multiplication extension included") +# endif +#endif + +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../mat2x2.hpp" +#include + +namespace glm +{ + template + using return_type_scalar_multiplication = typename std::enable_if< + !std::is_same::value // T may not be a float + && std::is_arithmetic::value, Vec // But it may be an int or double (no vec3 or mat3, ...) + >::type; + +#define GLM_IMPLEMENT_SCAL_MULT(Vec) \ + template \ + return_type_scalar_multiplication \ + operator*(T const& s, Vec rh){ \ + return rh *= static_cast(s); \ + } \ + \ + template \ + return_type_scalar_multiplication \ + operator*(Vec lh, T const& s){ \ + return lh *= static_cast(s); \ + } \ + \ + template \ + return_type_scalar_multiplication \ + operator/(Vec lh, T const& s){ \ + return lh *= 1.0f / s; \ + } + +GLM_IMPLEMENT_SCAL_MULT(vec2) +GLM_IMPLEMENT_SCAL_MULT(vec3) +GLM_IMPLEMENT_SCAL_MULT(vec4) + +GLM_IMPLEMENT_SCAL_MULT(mat2) +GLM_IMPLEMENT_SCAL_MULT(mat2x3) +GLM_IMPLEMENT_SCAL_MULT(mat2x4) +GLM_IMPLEMENT_SCAL_MULT(mat3x2) +GLM_IMPLEMENT_SCAL_MULT(mat3) +GLM_IMPLEMENT_SCAL_MULT(mat3x4) +GLM_IMPLEMENT_SCAL_MULT(mat4x2) +GLM_IMPLEMENT_SCAL_MULT(mat4x3) +GLM_IMPLEMENT_SCAL_MULT(mat4) + +#undef GLM_IMPLEMENT_SCAL_MULT +} // namespace glm diff --git a/src/GLMath/glm/gtx/scalar_relational.hpp b/src/GLMath/glm/gtx/scalar_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8be9c57b8b3501f28e2f35b692d5397c43f3a63a --- /dev/null +++ b/src/GLMath/glm/gtx/scalar_relational.hpp @@ -0,0 +1,36 @@ +/// @ref gtx_scalar_relational +/// @file glm/gtx/scalar_relational.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_scalar_relational GLM_GTX_scalar_relational +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extend a position from a source to a position at a defined length. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extend extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_scalar_relational + /// @{ + + + + /// @} +}//namespace glm + +#include "scalar_relational.inl" diff --git a/src/GLMath/glm/gtx/scalar_relational.inl b/src/GLMath/glm/gtx/scalar_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..c2a121cff9771266eb1de59182a1dc962f9a5e54 --- /dev/null +++ b/src/GLMath/glm/gtx/scalar_relational.inl @@ -0,0 +1,88 @@ +/// @ref gtx_scalar_relational + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool lessThan + ( + T const& x, + T const& y + ) + { + return x < y; + } + + template + GLM_FUNC_QUALIFIER bool lessThanEqual + ( + T const& x, + T const& y + ) + { + return x <= y; + } + + template + GLM_FUNC_QUALIFIER bool greaterThan + ( + T const& x, + T const& y + ) + { + return x > y; + } + + template + GLM_FUNC_QUALIFIER bool greaterThanEqual + ( + T const& x, + T const& y + ) + { + return x >= y; + } + + template + GLM_FUNC_QUALIFIER bool equal + ( + T const& x, + T const& y + ) + { + return detail::compute_equal::is_iec559>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER bool notEqual + ( + T const& x, + T const& y + ) + { + return !detail::compute_equal::is_iec559>::call(x, y); + } + + GLM_FUNC_QUALIFIER bool any + ( + bool const& x + ) + { + return x; + } + + GLM_FUNC_QUALIFIER bool all + ( + bool const& x + ) + { + return x; + } + + GLM_FUNC_QUALIFIER bool not_ + ( + bool const& x + ) + { + return !x; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/spline.hpp b/src/GLMath/glm/gtx/spline.hpp new file mode 100644 index 0000000000000000000000000000000000000000..731c979e358a8f2967ab5b71da57bf68abefa94d --- /dev/null +++ b/src/GLMath/glm/gtx/spline.hpp @@ -0,0 +1,65 @@ +/// @ref gtx_spline +/// @file glm/gtx/spline.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_spline GLM_GTX_spline +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Spline functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/optimum_pow.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_spline is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_spline extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_spline + /// @{ + + /// Return a point from a catmull rom curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType catmullRom( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s); + + /// Return a point from a hermite curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType hermite( + genType const& v1, + genType const& t1, + genType const& v2, + genType const& t2, + typename genType::value_type const& s); + + /// Return a point from a cubic curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType cubic( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s); + + /// @} +}//namespace glm + +#include "spline.inl" diff --git a/src/GLMath/glm/gtx/spline.inl b/src/GLMath/glm/gtx/spline.inl new file mode 100644 index 0000000000000000000000000000000000000000..c3fd0565629139357a81ffdcae55f8e89b4831dd --- /dev/null +++ b/src/GLMath/glm/gtx/spline.inl @@ -0,0 +1,60 @@ +/// @ref gtx_spline + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType catmullRom + ( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s + ) + { + typename genType::value_type s2 = pow2(s); + typename genType::value_type s3 = pow3(s); + + typename genType::value_type f1 = -s3 + typename genType::value_type(2) * s2 - s; + typename genType::value_type f2 = typename genType::value_type(3) * s3 - typename genType::value_type(5) * s2 + typename genType::value_type(2); + typename genType::value_type f3 = typename genType::value_type(-3) * s3 + typename genType::value_type(4) * s2 + s; + typename genType::value_type f4 = s3 - s2; + + return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) / typename genType::value_type(2); + + } + + template + GLM_FUNC_QUALIFIER genType hermite + ( + genType const& v1, + genType const& t1, + genType const& v2, + genType const& t2, + typename genType::value_type const& s + ) + { + typename genType::value_type s2 = pow2(s); + typename genType::value_type s3 = pow3(s); + + typename genType::value_type f1 = typename genType::value_type(2) * s3 - typename genType::value_type(3) * s2 + typename genType::value_type(1); + typename genType::value_type f2 = typename genType::value_type(-2) * s3 + typename genType::value_type(3) * s2; + typename genType::value_type f3 = s3 - typename genType::value_type(2) * s2 + s; + typename genType::value_type f4 = s3 - s2; + + return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2; + } + + template + GLM_FUNC_QUALIFIER genType cubic + ( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s + ) + { + return ((v1 * s + v2) * s + v3) * s + v4; + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/std_based_type.hpp b/src/GLMath/glm/gtx/std_based_type.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cd3be8cb78926ab1f9620e848c30a43aa4198185 --- /dev/null +++ b/src/GLMath/glm/gtx/std_based_type.hpp @@ -0,0 +1,68 @@ +/// @ref gtx_std_based_type +/// @file glm/gtx/std_based_type.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_std_based_type GLM_GTX_std_based_type +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Adds vector types based on STL value types. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_std_based_type is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_std_based_type extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_std_based_type + /// @{ + + /// Vector type based of one std::size_t component. + /// @see GLM_GTX_std_based_type + typedef vec<1, std::size_t, defaultp> size1; + + /// Vector type based of two std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<2, std::size_t, defaultp> size2; + + /// Vector type based of three std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<3, std::size_t, defaultp> size3; + + /// Vector type based of four std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<4, std::size_t, defaultp> size4; + + /// Vector type based of one std::size_t component. + /// @see GLM_GTX_std_based_type + typedef vec<1, std::size_t, defaultp> size1_t; + + /// Vector type based of two std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<2, std::size_t, defaultp> size2_t; + + /// Vector type based of three std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<3, std::size_t, defaultp> size3_t; + + /// Vector type based of four std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<4, std::size_t, defaultp> size4_t; + + /// @} +}//namespace glm + +#include "std_based_type.inl" diff --git a/src/GLMath/glm/gtx/std_based_type.inl b/src/GLMath/glm/gtx/std_based_type.inl new file mode 100644 index 0000000000000000000000000000000000000000..9c34bdb6e0f7348895bd59a256588731bb759da5 --- /dev/null +++ b/src/GLMath/glm/gtx/std_based_type.inl @@ -0,0 +1,6 @@ +/// @ref gtx_std_based_type + +namespace glm +{ + +} diff --git a/src/GLMath/glm/gtx/string_cast.hpp b/src/GLMath/glm/gtx/string_cast.hpp new file mode 100644 index 0000000000000000000000000000000000000000..27846bf89f077a2c4000cdd58ca955ed0b86539d --- /dev/null +++ b/src/GLMath/glm/gtx/string_cast.hpp @@ -0,0 +1,52 @@ +/// @ref gtx_string_cast +/// @file glm/gtx/string_cast.hpp +/// +/// @see core (dependence) +/// @see gtx_integer (dependence) +/// @see gtx_quaternion (dependence) +/// +/// @defgroup gtx_string_cast GLM_GTX_string_cast +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Setup strings for GLM type values +/// +/// This extension is not supported with CUDA + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/type_precision.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" +#include +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_string_cast is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_string_cast extension included") +# endif +#endif + +#if(GLM_COMPILER & GLM_COMPILER_CUDA) +# error "GLM_GTX_string_cast is not supported on CUDA compiler" +#endif + +namespace glm +{ + /// @addtogroup gtx_string_cast + /// @{ + + /// Create a string from a GLM vector or matrix typed variable. + /// @see gtx_string_cast extension. + template + GLM_FUNC_DECL std::string to_string(genType const& x); + + /// @} +}//namespace glm + +#include "string_cast.inl" diff --git a/src/GLMath/glm/gtx/string_cast.inl b/src/GLMath/glm/gtx/string_cast.inl new file mode 100644 index 0000000000000000000000000000000000000000..4ba7da3be3ffbbd364a5f47fa8a36262092bc1cf --- /dev/null +++ b/src/GLMath/glm/gtx/string_cast.inl @@ -0,0 +1,492 @@ +/// @ref gtx_string_cast + +#include +#include + +namespace glm{ +namespace detail +{ + template + struct cast + { + typedef T value_type; + }; + + template <> + struct cast + { + typedef double value_type; + }; + + GLM_FUNC_QUALIFIER std::string format(const char* msg, ...) + { + std::size_t const STRING_BUFFER(4096); + char text[STRING_BUFFER]; + va_list list; + + if(msg == GLM_NULLPTR) + return std::string(); + + va_start(list, msg); +# if(GLM_COMPILER & GLM_COMPILER_VC) + vsprintf_s(text, STRING_BUFFER, msg, list); +# else// + vsprintf(text, msg, list); +# endif// + va_end(list); + + return std::string(text); + } + + static const char* LabelTrue = "true"; + static const char* LabelFalse = "false"; + + template + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%d";} + }; + + template + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%f";} + }; + +# if GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC + template<> + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} + }; + + template<> + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} + }; +# endif//GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC + + template + struct prefix{}; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "d";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "b";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u8";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i8";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u16";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i16";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u64";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i64";} + }; + + template + struct compute_to_string + {}; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<1, bool, Q> const& x) + { + return detail::format("bvec1(%s)", + x[0] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<2, bool, Q> const& x) + { + return detail::format("bvec2(%s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<3, bool, Q> const& x) + { + return detail::format("bvec3(%s, %s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse, + x[2] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<4, bool, Q> const& x) + { + return detail::format("bvec4(%s, %s, %s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse, + x[2] ? detail::LabelTrue : detail::LabelFalse, + x[3] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<1, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec1(%s)", + PrefixStr, + LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec2(%s, %s)", + PrefixStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec3(%s, %s, %s)", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1]), + static_cast::value_type>(x[2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec4(%s, %s, %s, %s)", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1]), + static_cast::value_type>(x[2]), + static_cast::value_type>(x[3])); + } + }; + + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x2((%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x3((%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x4((%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x2((%s, %s), (%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x2((%s, %s), (%s, %s), (%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2]), static_cast::value_type>(x[3][3])); + } + }; + + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(qua const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%squat(%s, {%s, %s, %s})", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[3]), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1]), + static_cast::value_type>(x[2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(tdualquat const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%sdualquat((%s, {%s, %s, %s}), (%s, {%s, %s, %s}))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x.real[3]), + static_cast::value_type>(x.real[0]), + static_cast::value_type>(x.real[1]), + static_cast::value_type>(x.real[2]), + static_cast::value_type>(x.dual[3]), + static_cast::value_type>(x.dual[0]), + static_cast::value_type>(x.dual[1]), + static_cast::value_type>(x.dual[2])); + } + }; + +}//namespace detail + +template +GLM_FUNC_QUALIFIER std::string to_string(matType const& x) +{ + return detail::compute_to_string::call(x); +} + +}//namespace glm diff --git a/src/GLMath/glm/gtx/texture.hpp b/src/GLMath/glm/gtx/texture.hpp new file mode 100644 index 0000000000000000000000000000000000000000..20585e68ce11419c27f637290beaede9b56c6cf4 --- /dev/null +++ b/src/GLMath/glm/gtx/texture.hpp @@ -0,0 +1,46 @@ +/// @ref gtx_texture +/// @file glm/gtx/texture.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_texture GLM_GTX_texture +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Wrapping mode of texture coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/integer.hpp" +#include "../gtx/component_wise.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_texture is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_texture extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_texture + /// @{ + + /// Compute the number of mipmaps levels necessary to create a mipmap complete texture + /// + /// @param Extent Extent of the texture base level mipmap + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + template + T levels(vec const& Extent); + + /// @} +}// namespace glm + +#include "texture.inl" + diff --git a/src/GLMath/glm/gtx/texture.inl b/src/GLMath/glm/gtx/texture.inl new file mode 100644 index 0000000000000000000000000000000000000000..593c826141b0e0c35b513bfbac623e9a6ecb3168 --- /dev/null +++ b/src/GLMath/glm/gtx/texture.inl @@ -0,0 +1,17 @@ +/// @ref gtx_texture + +namespace glm +{ + template + inline T levels(vec const& Extent) + { + return glm::log2(compMax(Extent)) + static_cast(1); + } + + template + inline T levels(T Extent) + { + return vec<1, T, defaultp>(Extent).x; + } +}//namespace glm + diff --git a/src/GLMath/glm/gtx/transform.hpp b/src/GLMath/glm/gtx/transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0279fc8bd329d592288a90256ce1ff7d3c711e45 --- /dev/null +++ b/src/GLMath/glm/gtx/transform.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_transform +/// @file glm/gtx/transform.hpp +/// +/// @see core (dependence) +/// @see gtc_matrix_transform (dependence) +/// @see gtx_transform +/// @see gtx_transform2 +/// +/// @defgroup gtx_transform GLM_GTX_transform +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add transformation matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_transform is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_transform extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_transform + /// @{ + + /// Transforms a matrix with a translation 4 * 4 matrix created from 3 scalars. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> translate( + vec<3, T, Q> const& v); + + /// Builds a rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotate( + T angle, + vec<3, T, Q> const& v); + + /// Transforms a matrix with a scale 4 * 4 matrix created from a vector of 3 components. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> scale( + vec<3, T, Q> const& v); + + /// @} +}// namespace glm + +#include "transform.inl" diff --git a/src/GLMath/glm/gtx/transform.inl b/src/GLMath/glm/gtx/transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..48ee6801b6515266b1cfd9f389258ea5b200c5d1 --- /dev/null +++ b/src/GLMath/glm/gtx/transform.inl @@ -0,0 +1,23 @@ +/// @ref gtx_transform + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(vec<3, T, Q> const& v) + { + return translate(mat<4, 4, T, Q>(static_cast(1)), v); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(T angle, vec<3, T, Q> const& v) + { + return rotate(mat<4, 4, T, Q>(static_cast(1)), angle, v); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(vec<3, T, Q> const& v) + { + return scale(mat<4, 4, T, Q>(static_cast(1)), v); + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/transform2.hpp b/src/GLMath/glm/gtx/transform2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0d8ba9d90bc51a7b094c87ca3fed3a61601c6138 --- /dev/null +++ b/src/GLMath/glm/gtx/transform2.hpp @@ -0,0 +1,89 @@ +/// @ref gtx_transform2 +/// @file glm/gtx/transform2.hpp +/// +/// @see core (dependence) +/// @see gtx_transform (dependence) +/// +/// @defgroup gtx_transform2 GLM_GTX_transform2 +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add extra transformation matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_transform2 is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_transform2 extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_transform2 + /// @{ + + //! Transforms a matrix with a shearing on X axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T y); + + //! Transforms a matrix with a shearing on Y axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T x); + + //! Transforms a matrix with a shearing on X axis + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T y, T z); + + //! Transforms a matrix with a shearing on Y axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T x, T z); + + //! Transforms a matrix with a shearing on Z axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T x, T y); + + //template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear(const mat<4, 4, T, Q> & m, shearPlane, planePoint, angle) + // Identity + tan(angle) * cross(Normal, OnPlaneVector) 0 + // - dot(PointOnPlane, normal) * OnPlaneVector 1 + + // Reflect functions seem to don't work + //template mat<3, 3, T, Q> reflect2D(const mat<3, 3, T, Q> & m, const vec<3, T, Q>& normal){return reflect2DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) + //template mat<4, 4, T, Q> reflect3D(const mat<4, 4, T, Q> & m, const vec<3, T, Q>& normal){return reflect3DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) + + //! Build planar projection matrix along normal axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> proj2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal); + + //! Build planar projection matrix along normal axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> proj3D(mat<4, 4, T, Q> const & m, vec<3, T, Q> const& normal); + + //! Build a scale bias matrix. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(T scale, T bias); + + //! Build a scale bias matrix. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias); + + /// @} +}// namespace glm + +#include "transform2.inl" diff --git a/src/GLMath/glm/gtx/transform2.inl b/src/GLMath/glm/gtx/transform2.inl new file mode 100644 index 0000000000000000000000000000000000000000..2b53198b3302ed45c14b7ff01a7314380663283b --- /dev/null +++ b/src/GLMath/glm/gtx/transform2.inl @@ -0,0 +1,125 @@ +/// @ref gtx_transform2 + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T s) + { + mat<3, 3, T, Q> r(1); + r[1][0] = s; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T s) + { + mat<3, 3, T, Q> r(1); + r[0][1] = s; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[0][1] = s; + r[0][2] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[1][0] = s; + r[1][2] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[2][0] = s; + r[2][1] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal) + { + mat<3, 3, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; + r[0][1] = -static_cast(2) * normal.x * normal.y; + r[1][0] = -static_cast(2) * normal.x * normal.y; + r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> reflect3D(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& normal) + { + mat<4, 4, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; + r[0][1] = -static_cast(2) * normal.x * normal.y; + r[0][2] = -static_cast(2) * normal.x * normal.z; + + r[1][0] = -static_cast(2) * normal.x * normal.y; + r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; + r[1][2] = -static_cast(2) * normal.y * normal.z; + + r[2][0] = -static_cast(2) * normal.x * normal.z; + r[2][1] = -static_cast(2) * normal.y * normal.z; + r[2][2] = static_cast(1) - static_cast(2) * normal.z * normal.z; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> proj2D( + const mat<3, 3, T, Q>& m, + const vec<3, T, Q>& normal) + { + mat<3, 3, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - normal.x * normal.x; + r[0][1] = - normal.x * normal.y; + r[1][0] = - normal.x * normal.y; + r[1][1] = static_cast(1) - normal.y * normal.y; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> proj3D( + const mat<4, 4, T, Q>& m, + const vec<3, T, Q>& normal) + { + mat<4, 4, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - normal.x * normal.x; + r[0][1] = - normal.x * normal.y; + r[0][2] = - normal.x * normal.z; + r[1][0] = - normal.x * normal.y; + r[1][1] = static_cast(1) - normal.y * normal.y; + r[1][2] = - normal.y * normal.z; + r[2][0] = - normal.x * normal.z; + r[2][1] = - normal.y * normal.z; + r[2][2] = static_cast(1) - normal.z * normal.z; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(T scale, T bias) + { + mat<4, 4, T, Q> result; + result[3] = vec<4, T, Q>(vec<3, T, Q>(bias), static_cast(1)); + result[0][0] = scale; + result[1][1] = scale; + result[2][2] = scale; + return result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias) + { + return m * scaleBias(scale, bias); + } +}//namespace glm + diff --git a/src/GLMath/glm/gtx/type_aligned.hpp b/src/GLMath/glm/gtx/type_aligned.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2ae522c1fc7e383c8b1d2a903210acd0196c10fc --- /dev/null +++ b/src/GLMath/glm/gtx/type_aligned.hpp @@ -0,0 +1,982 @@ +/// @ref gtx_type_aligned +/// @file glm/gtx/type_aligned.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_type_aligned GLM_GTX_type_aligned +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines aligned types. + +#pragma once + +// Dependency: +#include "../gtc/type_precision.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_type_aligned is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_type_aligned extension included") +# endif +#endif + +namespace glm +{ + /////////////////////////// + // Signed int vector types + + /// @addtogroup gtx_type_aligned + /// @{ + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int8, aligned_lowp_int8, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int16, aligned_lowp_int16, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int32, aligned_lowp_int32, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int64, aligned_lowp_int64, 8); + + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int8_t, aligned_lowp_int8_t, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int16_t, aligned_lowp_int16_t, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int32_t, aligned_lowp_int32_t, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int64_t, aligned_lowp_int64_t, 8); + + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i8, aligned_lowp_i8, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i16, aligned_lowp_i16, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i32, aligned_lowp_i32, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i64, aligned_lowp_i64, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int8, aligned_mediump_int8, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int16, aligned_mediump_int16, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int32, aligned_mediump_int32, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int64, aligned_mediump_int64, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int8_t, aligned_mediump_int8_t, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int16_t, aligned_mediump_int16_t, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int32_t, aligned_mediump_int32_t, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int64_t, aligned_mediump_int64_t, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i8, aligned_mediump_i8, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i16, aligned_mediump_i16, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i32, aligned_mediump_i32, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i64, aligned_mediump_i64, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int8, aligned_highp_int8, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int16, aligned_highp_int16, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int32, aligned_highp_int32, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int64, aligned_highp_int64, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int8_t, aligned_highp_int8_t, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int16_t, aligned_highp_int16_t, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int32_t, aligned_highp_int32_t, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int64_t, aligned_highp_int64_t, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i8, aligned_highp_i8, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i16, aligned_highp_i16, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i32, aligned_highp_i32, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i64, aligned_highp_i64, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int8, aligned_int8, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int16, aligned_int16, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int32, aligned_int32, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int64, aligned_int64, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int8_t, aligned_int8_t, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int16_t, aligned_int16_t, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int32_t, aligned_int32_t, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int64_t, aligned_int64_t, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8, aligned_i8, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16, aligned_i16, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32, aligned_i32, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64, aligned_i64, 8); + + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec1, aligned_ivec1, 4); + + /// Default qualifier 32 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec2, aligned_ivec2, 8); + + /// Default qualifier 32 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec3, aligned_ivec3, 16); + + /// Default qualifier 32 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec4, aligned_ivec4, 16); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec1, aligned_i8vec1, 1); + + /// Default qualifier 8 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec2, aligned_i8vec2, 2); + + /// Default qualifier 8 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec3, aligned_i8vec3, 4); + + /// Default qualifier 8 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec4, aligned_i8vec4, 4); + + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec1, aligned_i16vec1, 2); + + /// Default qualifier 16 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec2, aligned_i16vec2, 4); + + /// Default qualifier 16 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec3, aligned_i16vec3, 8); + + /// Default qualifier 16 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec4, aligned_i16vec4, 8); + + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec1, aligned_i32vec1, 4); + + /// Default qualifier 32 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec2, aligned_i32vec2, 8); + + /// Default qualifier 32 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec3, aligned_i32vec3, 16); + + /// Default qualifier 32 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec4, aligned_i32vec4, 16); + + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec1, aligned_i64vec1, 8); + + /// Default qualifier 64 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec2, aligned_i64vec2, 16); + + /// Default qualifier 64 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec3, aligned_i64vec3, 32); + + /// Default qualifier 64 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec4, aligned_i64vec4, 32); + + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint8, aligned_lowp_uint8, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint16, aligned_lowp_uint16, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint32, aligned_lowp_uint32, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint64, aligned_lowp_uint64, 8); + + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint8_t, aligned_lowp_uint8_t, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint16_t, aligned_lowp_uint16_t, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint32_t, aligned_lowp_uint32_t, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint64_t, aligned_lowp_uint64_t, 8); + + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u8, aligned_lowp_u8, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u16, aligned_lowp_u16, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u32, aligned_lowp_u32, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u64, aligned_lowp_u64, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint8, aligned_mediump_uint8, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint16, aligned_mediump_uint16, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint32, aligned_mediump_uint32, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint64, aligned_mediump_uint64, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint8_t, aligned_mediump_uint8_t, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint16_t, aligned_mediump_uint16_t, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint32_t, aligned_mediump_uint32_t, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint64_t, aligned_mediump_uint64_t, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u8, aligned_mediump_u8, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u16, aligned_mediump_u16, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u32, aligned_mediump_u32, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u64, aligned_mediump_u64, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint8, aligned_highp_uint8, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint16, aligned_highp_uint16, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint32, aligned_highp_uint32, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint64, aligned_highp_uint64, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint8_t, aligned_highp_uint8_t, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint16_t, aligned_highp_uint16_t, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint32_t, aligned_highp_uint32_t, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint64_t, aligned_highp_uint64_t, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u8, aligned_highp_u8, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u16, aligned_highp_u16, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u32, aligned_highp_u32, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u64, aligned_highp_u64, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint8, aligned_uint8, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint16, aligned_uint16, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint32, aligned_uint32, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint64, aligned_uint64, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint8_t, aligned_uint8_t, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint16_t, aligned_uint16_t, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint32_t, aligned_uint32_t, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint64_t, aligned_uint64_t, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8, aligned_u8, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16, aligned_u16, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32, aligned_u32, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64, aligned_u64, 8); + + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec1, aligned_uvec1, 4); + + /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec2, aligned_uvec2, 8); + + /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec3, aligned_uvec3, 16); + + /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec4, aligned_uvec4, 16); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec1, aligned_u8vec1, 1); + + /// Default qualifier 8 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec2, aligned_u8vec2, 2); + + /// Default qualifier 8 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec3, aligned_u8vec3, 4); + + /// Default qualifier 8 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec4, aligned_u8vec4, 4); + + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec1, aligned_u16vec1, 2); + + /// Default qualifier 16 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec2, aligned_u16vec2, 4); + + /// Default qualifier 16 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec3, aligned_u16vec3, 8); + + /// Default qualifier 16 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec4, aligned_u16vec4, 8); + + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec1, aligned_u32vec1, 4); + + /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec2, aligned_u32vec2, 8); + + /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec3, aligned_u32vec3, 16); + + /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec4, aligned_u32vec4, 16); + + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec1, aligned_u64vec1, 8); + + /// Default qualifier 64 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec2, aligned_u64vec2, 16); + + /// Default qualifier 64 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec3, aligned_u64vec3, 32); + + /// Default qualifier 64 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec4, aligned_u64vec4, 32); + + + ////////////////////// + // Float vector types + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32, aligned_float32, 4); + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32_t, aligned_float32_t, 4); + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32, aligned_f32, 4); + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64, aligned_float64, 8); + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64_t, aligned_float64_t, 8); + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64, aligned_f64, 8); + +# endif//GLM_FORCE_SINGLE_ONLY + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec1, aligned_vec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec2, aligned_vec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec3, aligned_vec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec4, aligned_vec4, 16); + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec1, aligned_fvec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec2, aligned_fvec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec3, aligned_fvec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec4, aligned_fvec4, 16); + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec1, aligned_f32vec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec2, aligned_f32vec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec3, aligned_f32vec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec4, aligned_f32vec4, 16); + + + /// Double-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec1, aligned_dvec1, 8); + + /// Double-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec2, aligned_dvec2, 16); + + /// Double-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec3, aligned_dvec3, 32); + + /// Double-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec4, aligned_dvec4, 32); + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec1, aligned_f64vec1, 8); + + /// Double-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec2, aligned_f64vec2, 16); + + /// Double-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec3, aligned_f64vec3, 32); + + /// Double-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec4, aligned_f64vec4, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + ////////////////////// + // Float matrix types + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1 mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat2, aligned_mat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat3, aligned_mat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat4, aligned_mat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat2x2, aligned_mat2x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat3x3, aligned_mat3x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat4x4, aligned_mat4x4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 fmat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f32 fmat1x1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2x2, 16); + + /// Single-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x3, aligned_fmat2x3, 16); + + /// Single-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x4, aligned_fmat2x4, 16); + + /// Single-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x2, aligned_fmat3x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3x3, 16); + + /// Single-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x4, aligned_fmat3x4, 16); + + /// Single-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x2, aligned_fmat4x2, 16); + + /// Single-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x3, aligned_fmat4x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4x4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 f32mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f32 f32mat1x1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2x2, 16); + + /// Single-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x3, aligned_f32mat2x3, 16); + + /// Single-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x4, aligned_f32mat2x4, 16); + + /// Single-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x2, aligned_f32mat3x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3x3, 16); + + /// Single-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x4, aligned_f32mat3x4, 16); + + /// Single-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x2, aligned_f32mat4x2, 16); + + /// Single-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x3, aligned_f32mat4x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4x4, 16); + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 f64mat1; + + /// Double-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2, 32); + + /// Double-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3, 32); + + /// Double-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4, 32); + + + /// Double-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f64 f64mat1x1; + + /// Double-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2x2, 32); + + /// Double-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x3, aligned_f64mat2x3, 32); + + /// Double-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x4, aligned_f64mat2x4, 32); + + /// Double-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x2, aligned_f64mat3x2, 32); + + /// Double-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3x3, 32); + + /// Double-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x4, aligned_f64mat3x4, 32); + + /// Double-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x2, aligned_f64mat4x2, 32); + + /// Double-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x3, aligned_f64mat4x3, 32); + + /// Double-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4x4, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + + ////////////////////////// + // Quaternion types + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(quat, aligned_quat, 16); + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(quat, aligned_fquat, 16); + + /// Double-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dquat, aligned_dquat, 32); + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32quat, aligned_f32quat, 16); + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64quat, aligned_f64quat, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + /// @} +}//namespace glm + +#include "type_aligned.inl" diff --git a/src/GLMath/glm/gtx/type_aligned.inl b/src/GLMath/glm/gtx/type_aligned.inl new file mode 100644 index 0000000000000000000000000000000000000000..54c1b818b64af8a03a2ce5c93853a7fce5093ea1 --- /dev/null +++ b/src/GLMath/glm/gtx/type_aligned.inl @@ -0,0 +1,6 @@ +/// @ref gtc_type_aligned + +namespace glm +{ + +} diff --git a/src/GLMath/glm/gtx/type_trait.hpp b/src/GLMath/glm/gtx/type_trait.hpp new file mode 100644 index 0000000000000000000000000000000000000000..56685c8cb98c1861d9bbc59393b888f62c18f403 --- /dev/null +++ b/src/GLMath/glm/gtx/type_trait.hpp @@ -0,0 +1,85 @@ +/// @ref gtx_type_trait +/// @file glm/gtx/type_trait.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_type_trait GLM_GTX_type_trait +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines traits for each type. + +#pragma once + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_type_trait is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_type_trait extension included") +# endif +#endif + +// Dependency: +#include "../detail/qualifier.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" + +namespace glm +{ + /// @addtogroup gtx_type_trait + /// @{ + + template + struct type + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = false; + static length_t const components = 0; + static length_t const cols = 0; + static length_t const rows = 0; + }; + + template + struct type > + { + static bool const is_vec = true; + static bool const is_mat = false; + static bool const is_quat = false; + static length_t const components = L; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = true; + static bool const is_quat = false; + static length_t const components = C; + static length_t const cols = C; + static length_t const rows = R; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = true; + static length_t const components = 4; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = true; + static length_t const components = 8; + }; + + /// @} +}//namespace glm + +#include "type_trait.inl" diff --git a/src/GLMath/glm/gtx/type_trait.inl b/src/GLMath/glm/gtx/type_trait.inl new file mode 100644 index 0000000000000000000000000000000000000000..045de959cc21dcb60ba5e96424419e9b57824435 --- /dev/null +++ b/src/GLMath/glm/gtx/type_trait.inl @@ -0,0 +1,61 @@ +/// @ref gtx_type_trait + +namespace glm +{ + template + bool const type::is_vec; + template + bool const type::is_mat; + template + bool const type::is_quat; + template + length_t const type::components; + template + length_t const type::cols; + template + length_t const type::rows; + + // vec + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + + // mat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + template + length_t const type >::cols; + template + length_t const type >::rows; + + // tquat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + + // tdualquat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; +}//namespace glm diff --git a/src/GLMath/glm/gtx/vec_swizzle.hpp b/src/GLMath/glm/gtx/vec_swizzle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1c49abcb6ad7adcac1285d3e2c2577fb83e27e72 --- /dev/null +++ b/src/GLMath/glm/gtx/vec_swizzle.hpp @@ -0,0 +1,2782 @@ +/// @ref gtx_vec_swizzle +/// @file glm/gtx/vec_swizzle.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_vec_swizzle GLM_GTX_vec_swizzle +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions to perform swizzle operation. + +#pragma once + +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vec_swizzle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vec_swizzle extension included") +# endif +#endif + +namespace glm { + // xx + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<1, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + // xy + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + // xz + template + GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.z); + } + + // xw + template + GLM_INLINE glm::vec<2, T, Q> xw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.w); + } + + // yx + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + // yy + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + // yz + template + GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.z); + } + + // yw + template + GLM_INLINE glm::vec<2, T, Q> yw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.w); + } + + // zx + template + GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.x); + } + + // zy + template + GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.y); + } + + // zz + template + GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.z); + } + + // zw + template + GLM_INLINE glm::vec<2, T, Q> zw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.w); + } + + // wx + template + GLM_INLINE glm::vec<2, T, Q> wx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.x); + } + + // wy + template + GLM_INLINE glm::vec<2, T, Q> wy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.y); + } + + // wz + template + GLM_INLINE glm::vec<2, T, Q> wz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.z); + } + + // ww + template + GLM_INLINE glm::vec<2, T, Q> ww(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.w); + } + + // xxx + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<1, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + // xxy + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + // xxz + template + GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.z); + } + + // xxw + template + GLM_INLINE glm::vec<3, T, Q> xxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.w); + } + + // xyx + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + // xyy + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + // xyz + template + GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.z); + } + + // xyw + template + GLM_INLINE glm::vec<3, T, Q> xyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.w); + } + + // xzx + template + GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.x); + } + + // xzy + template + GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.y); + } + + // xzz + template + GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.z); + } + + // xzw + template + GLM_INLINE glm::vec<3, T, Q> xzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.w); + } + + // xwx + template + GLM_INLINE glm::vec<3, T, Q> xwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.x); + } + + // xwy + template + GLM_INLINE glm::vec<3, T, Q> xwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.y); + } + + // xwz + template + GLM_INLINE glm::vec<3, T, Q> xwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.z); + } + + // xww + template + GLM_INLINE glm::vec<3, T, Q> xww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.w); + } + + // yxx + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + // yxy + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + // yxz + template + GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.z); + } + + // yxw + template + GLM_INLINE glm::vec<3, T, Q> yxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.w); + } + + // yyx + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + // yyy + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + // yyz + template + GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.z); + } + + // yyw + template + GLM_INLINE glm::vec<3, T, Q> yyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.w); + } + + // yzx + template + GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.x); + } + + // yzy + template + GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.y); + } + + // yzz + template + GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.z); + } + + // yzw + template + GLM_INLINE glm::vec<3, T, Q> yzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.w); + } + + // ywx + template + GLM_INLINE glm::vec<3, T, Q> ywx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.x); + } + + // ywy + template + GLM_INLINE glm::vec<3, T, Q> ywy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.y); + } + + // ywz + template + GLM_INLINE glm::vec<3, T, Q> ywz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.z); + } + + // yww + template + GLM_INLINE glm::vec<3, T, Q> yww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.w); + } + + // zxx + template + GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.x); + } + + // zxy + template + GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.y); + } + + // zxz + template + GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.z); + } + + // zxw + template + GLM_INLINE glm::vec<3, T, Q> zxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.w); + } + + // zyx + template + GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.x); + } + + // zyy + template + GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.y); + } + + // zyz + template + GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.z); + } + + // zyw + template + GLM_INLINE glm::vec<3, T, Q> zyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.w); + } + + // zzx + template + GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.x); + } + + // zzy + template + GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.y); + } + + // zzz + template + GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.z); + } + + // zzw + template + GLM_INLINE glm::vec<3, T, Q> zzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.w); + } + + // zwx + template + GLM_INLINE glm::vec<3, T, Q> zwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.x); + } + + // zwy + template + GLM_INLINE glm::vec<3, T, Q> zwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.y); + } + + // zwz + template + GLM_INLINE glm::vec<3, T, Q> zwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.z); + } + + // zww + template + GLM_INLINE glm::vec<3, T, Q> zww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.w); + } + + // wxx + template + GLM_INLINE glm::vec<3, T, Q> wxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.x); + } + + // wxy + template + GLM_INLINE glm::vec<3, T, Q> wxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.y); + } + + // wxz + template + GLM_INLINE glm::vec<3, T, Q> wxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.z); + } + + // wxw + template + GLM_INLINE glm::vec<3, T, Q> wxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.w); + } + + // wyx + template + GLM_INLINE glm::vec<3, T, Q> wyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.x); + } + + // wyy + template + GLM_INLINE glm::vec<3, T, Q> wyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.y); + } + + // wyz + template + GLM_INLINE glm::vec<3, T, Q> wyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.z); + } + + // wyw + template + GLM_INLINE glm::vec<3, T, Q> wyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.w); + } + + // wzx + template + GLM_INLINE glm::vec<3, T, Q> wzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.x); + } + + // wzy + template + GLM_INLINE glm::vec<3, T, Q> wzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.y); + } + + // wzz + template + GLM_INLINE glm::vec<3, T, Q> wzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.z); + } + + // wzw + template + GLM_INLINE glm::vec<3, T, Q> wzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.w); + } + + // wwx + template + GLM_INLINE glm::vec<3, T, Q> wwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.x); + } + + // wwy + template + GLM_INLINE glm::vec<3, T, Q> wwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.y); + } + + // wwz + template + GLM_INLINE glm::vec<3, T, Q> wwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.z); + } + + // www + template + GLM_INLINE glm::vec<3, T, Q> www(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.w); + } + + // xxxx + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<1, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + // xxxy + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + // xxxz + template + GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); + } + + // xxxw + template + GLM_INLINE glm::vec<4, T, Q> xxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.w); + } + + // xxyx + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + // xxyy + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + // xxyz + template + GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); + } + + // xxyw + template + GLM_INLINE glm::vec<4, T, Q> xxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.w); + } + + // xxzx + template + GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); + } + + // xxzy + template + GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); + } + + // xxzz + template + GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); + } + + // xxzw + template + GLM_INLINE glm::vec<4, T, Q> xxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.w); + } + + // xxwx + template + GLM_INLINE glm::vec<4, T, Q> xxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.x); + } + + // xxwy + template + GLM_INLINE glm::vec<4, T, Q> xxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.y); + } + + // xxwz + template + GLM_INLINE glm::vec<4, T, Q> xxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.z); + } + + // xxww + template + GLM_INLINE glm::vec<4, T, Q> xxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.w); + } + + // xyxx + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + // xyxy + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + // xyxz + template + GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); + } + + // xyxw + template + GLM_INLINE glm::vec<4, T, Q> xyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.w); + } + + // xyyx + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + // xyyy + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + // xyyz + template + GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); + } + + // xyyw + template + GLM_INLINE glm::vec<4, T, Q> xyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.w); + } + + // xyzx + template + GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); + } + + // xyzy + template + GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); + } + + // xyzz + template + GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); + } + + // xyzw + template + GLM_INLINE glm::vec<4, T, Q> xyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.w); + } + + // xywx + template + GLM_INLINE glm::vec<4, T, Q> xywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.x); + } + + // xywy + template + GLM_INLINE glm::vec<4, T, Q> xywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.y); + } + + // xywz + template + GLM_INLINE glm::vec<4, T, Q> xywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.z); + } + + // xyww + template + GLM_INLINE glm::vec<4, T, Q> xyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.w); + } + + // xzxx + template + GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); + } + + // xzxy + template + GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); + } + + // xzxz + template + GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); + } + + // xzxw + template + GLM_INLINE glm::vec<4, T, Q> xzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.w); + } + + // xzyx + template + GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); + } + + // xzyy + template + GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); + } + + // xzyz + template + GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); + } + + // xzyw + template + GLM_INLINE glm::vec<4, T, Q> xzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.w); + } + + // xzzx + template + GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); + } + + // xzzy + template + GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); + } + + // xzzz + template + GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); + } + + // xzzw + template + GLM_INLINE glm::vec<4, T, Q> xzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.w); + } + + // xzwx + template + GLM_INLINE glm::vec<4, T, Q> xzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.x); + } + + // xzwy + template + GLM_INLINE glm::vec<4, T, Q> xzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.y); + } + + // xzwz + template + GLM_INLINE glm::vec<4, T, Q> xzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.z); + } + + // xzww + template + GLM_INLINE glm::vec<4, T, Q> xzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.w); + } + + // xwxx + template + GLM_INLINE glm::vec<4, T, Q> xwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.x); + } + + // xwxy + template + GLM_INLINE glm::vec<4, T, Q> xwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.y); + } + + // xwxz + template + GLM_INLINE glm::vec<4, T, Q> xwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.z); + } + + // xwxw + template + GLM_INLINE glm::vec<4, T, Q> xwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.w); + } + + // xwyx + template + GLM_INLINE glm::vec<4, T, Q> xwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.x); + } + + // xwyy + template + GLM_INLINE glm::vec<4, T, Q> xwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.y); + } + + // xwyz + template + GLM_INLINE glm::vec<4, T, Q> xwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.z); + } + + // xwyw + template + GLM_INLINE glm::vec<4, T, Q> xwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.w); + } + + // xwzx + template + GLM_INLINE glm::vec<4, T, Q> xwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.x); + } + + // xwzy + template + GLM_INLINE glm::vec<4, T, Q> xwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.y); + } + + // xwzz + template + GLM_INLINE glm::vec<4, T, Q> xwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.z); + } + + // xwzw + template + GLM_INLINE glm::vec<4, T, Q> xwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.w); + } + + // xwwx + template + GLM_INLINE glm::vec<4, T, Q> xwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.x); + } + + // xwwy + template + GLM_INLINE glm::vec<4, T, Q> xwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.y); + } + + // xwwz + template + GLM_INLINE glm::vec<4, T, Q> xwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.z); + } + + // xwww + template + GLM_INLINE glm::vec<4, T, Q> xwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.w); + } + + // yxxx + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + // yxxy + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + // yxxz + template + GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); + } + + // yxxw + template + GLM_INLINE glm::vec<4, T, Q> yxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.w); + } + + // yxyx + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + // yxyy + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + // yxyz + template + GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); + } + + // yxyw + template + GLM_INLINE glm::vec<4, T, Q> yxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.w); + } + + // yxzx + template + GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); + } + + // yxzy + template + GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); + } + + // yxzz + template + GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); + } + + // yxzw + template + GLM_INLINE glm::vec<4, T, Q> yxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.w); + } + + // yxwx + template + GLM_INLINE glm::vec<4, T, Q> yxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.x); + } + + // yxwy + template + GLM_INLINE glm::vec<4, T, Q> yxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.y); + } + + // yxwz + template + GLM_INLINE glm::vec<4, T, Q> yxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.z); + } + + // yxww + template + GLM_INLINE glm::vec<4, T, Q> yxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.w); + } + + // yyxx + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + // yyxy + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + // yyxz + template + GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); + } + + // yyxw + template + GLM_INLINE glm::vec<4, T, Q> yyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.w); + } + + // yyyx + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + // yyyy + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + // yyyz + template + GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); + } + + // yyyw + template + GLM_INLINE glm::vec<4, T, Q> yyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.w); + } + + // yyzx + template + GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); + } + + // yyzy + template + GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); + } + + // yyzz + template + GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); + } + + // yyzw + template + GLM_INLINE glm::vec<4, T, Q> yyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.w); + } + + // yywx + template + GLM_INLINE glm::vec<4, T, Q> yywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.x); + } + + // yywy + template + GLM_INLINE glm::vec<4, T, Q> yywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.y); + } + + // yywz + template + GLM_INLINE glm::vec<4, T, Q> yywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.z); + } + + // yyww + template + GLM_INLINE glm::vec<4, T, Q> yyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.w); + } + + // yzxx + template + GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); + } + + // yzxy + template + GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); + } + + // yzxz + template + GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); + } + + // yzxw + template + GLM_INLINE glm::vec<4, T, Q> yzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.w); + } + + // yzyx + template + GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); + } + + // yzyy + template + GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); + } + + // yzyz + template + GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); + } + + // yzyw + template + GLM_INLINE glm::vec<4, T, Q> yzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.w); + } + + // yzzx + template + GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); + } + + // yzzy + template + GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); + } + + // yzzz + template + GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); + } + + // yzzw + template + GLM_INLINE glm::vec<4, T, Q> yzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.w); + } + + // yzwx + template + GLM_INLINE glm::vec<4, T, Q> yzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.x); + } + + // yzwy + template + GLM_INLINE glm::vec<4, T, Q> yzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.y); + } + + // yzwz + template + GLM_INLINE glm::vec<4, T, Q> yzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.z); + } + + // yzww + template + GLM_INLINE glm::vec<4, T, Q> yzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.w); + } + + // ywxx + template + GLM_INLINE glm::vec<4, T, Q> ywxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.x); + } + + // ywxy + template + GLM_INLINE glm::vec<4, T, Q> ywxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.y); + } + + // ywxz + template + GLM_INLINE glm::vec<4, T, Q> ywxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.z); + } + + // ywxw + template + GLM_INLINE glm::vec<4, T, Q> ywxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.w); + } + + // ywyx + template + GLM_INLINE glm::vec<4, T, Q> ywyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.x); + } + + // ywyy + template + GLM_INLINE glm::vec<4, T, Q> ywyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.y); + } + + // ywyz + template + GLM_INLINE glm::vec<4, T, Q> ywyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.z); + } + + // ywyw + template + GLM_INLINE glm::vec<4, T, Q> ywyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.w); + } + + // ywzx + template + GLM_INLINE glm::vec<4, T, Q> ywzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.x); + } + + // ywzy + template + GLM_INLINE glm::vec<4, T, Q> ywzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.y); + } + + // ywzz + template + GLM_INLINE glm::vec<4, T, Q> ywzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.z); + } + + // ywzw + template + GLM_INLINE glm::vec<4, T, Q> ywzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.w); + } + + // ywwx + template + GLM_INLINE glm::vec<4, T, Q> ywwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.x); + } + + // ywwy + template + GLM_INLINE glm::vec<4, T, Q> ywwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.y); + } + + // ywwz + template + GLM_INLINE glm::vec<4, T, Q> ywwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.z); + } + + // ywww + template + GLM_INLINE glm::vec<4, T, Q> ywww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.w); + } + + // zxxx + template + GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); + } + + // zxxy + template + GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); + } + + // zxxz + template + GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); + } + + // zxxw + template + GLM_INLINE glm::vec<4, T, Q> zxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.w); + } + + // zxyx + template + GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); + } + + // zxyy + template + GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); + } + + // zxyz + template + GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); + } + + // zxyw + template + GLM_INLINE glm::vec<4, T, Q> zxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.w); + } + + // zxzx + template + GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); + } + + // zxzy + template + GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); + } + + // zxzz + template + GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); + } + + // zxzw + template + GLM_INLINE glm::vec<4, T, Q> zxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.w); + } + + // zxwx + template + GLM_INLINE glm::vec<4, T, Q> zxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.x); + } + + // zxwy + template + GLM_INLINE glm::vec<4, T, Q> zxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.y); + } + + // zxwz + template + GLM_INLINE glm::vec<4, T, Q> zxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.z); + } + + // zxww + template + GLM_INLINE glm::vec<4, T, Q> zxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.w); + } + + // zyxx + template + GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); + } + + // zyxy + template + GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); + } + + // zyxz + template + GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); + } + + // zyxw + template + GLM_INLINE glm::vec<4, T, Q> zyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.w); + } + + // zyyx + template + GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); + } + + // zyyy + template + GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); + } + + // zyyz + template + GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); + } + + // zyyw + template + GLM_INLINE glm::vec<4, T, Q> zyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.w); + } + + // zyzx + template + GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); + } + + // zyzy + template + GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); + } + + // zyzz + template + GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); + } + + // zyzw + template + GLM_INLINE glm::vec<4, T, Q> zyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.w); + } + + // zywx + template + GLM_INLINE glm::vec<4, T, Q> zywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.x); + } + + // zywy + template + GLM_INLINE glm::vec<4, T, Q> zywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.y); + } + + // zywz + template + GLM_INLINE glm::vec<4, T, Q> zywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.z); + } + + // zyww + template + GLM_INLINE glm::vec<4, T, Q> zyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.w); + } + + // zzxx + template + GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); + } + + // zzxy + template + GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); + } + + // zzxz + template + GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); + } + + // zzxw + template + GLM_INLINE glm::vec<4, T, Q> zzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.w); + } + + // zzyx + template + GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); + } + + // zzyy + template + GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); + } + + // zzyz + template + GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); + } + + // zzyw + template + GLM_INLINE glm::vec<4, T, Q> zzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.w); + } + + // zzzx + template + GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); + } + + // zzzy + template + GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); + } + + // zzzz + template + GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); + } + + // zzzw + template + GLM_INLINE glm::vec<4, T, Q> zzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.w); + } + + // zzwx + template + GLM_INLINE glm::vec<4, T, Q> zzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.x); + } + + // zzwy + template + GLM_INLINE glm::vec<4, T, Q> zzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.y); + } + + // zzwz + template + GLM_INLINE glm::vec<4, T, Q> zzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.z); + } + + // zzww + template + GLM_INLINE glm::vec<4, T, Q> zzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.w); + } + + // zwxx + template + GLM_INLINE glm::vec<4, T, Q> zwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.x); + } + + // zwxy + template + GLM_INLINE glm::vec<4, T, Q> zwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.y); + } + + // zwxz + template + GLM_INLINE glm::vec<4, T, Q> zwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.z); + } + + // zwxw + template + GLM_INLINE glm::vec<4, T, Q> zwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.w); + } + + // zwyx + template + GLM_INLINE glm::vec<4, T, Q> zwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.x); + } + + // zwyy + template + GLM_INLINE glm::vec<4, T, Q> zwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.y); + } + + // zwyz + template + GLM_INLINE glm::vec<4, T, Q> zwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.z); + } + + // zwyw + template + GLM_INLINE glm::vec<4, T, Q> zwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.w); + } + + // zwzx + template + GLM_INLINE glm::vec<4, T, Q> zwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.x); + } + + // zwzy + template + GLM_INLINE glm::vec<4, T, Q> zwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.y); + } + + // zwzz + template + GLM_INLINE glm::vec<4, T, Q> zwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.z); + } + + // zwzw + template + GLM_INLINE glm::vec<4, T, Q> zwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.w); + } + + // zwwx + template + GLM_INLINE glm::vec<4, T, Q> zwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.x); + } + + // zwwy + template + GLM_INLINE glm::vec<4, T, Q> zwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.y); + } + + // zwwz + template + GLM_INLINE glm::vec<4, T, Q> zwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.z); + } + + // zwww + template + GLM_INLINE glm::vec<4, T, Q> zwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.w); + } + + // wxxx + template + GLM_INLINE glm::vec<4, T, Q> wxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.x); + } + + // wxxy + template + GLM_INLINE glm::vec<4, T, Q> wxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.y); + } + + // wxxz + template + GLM_INLINE glm::vec<4, T, Q> wxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.z); + } + + // wxxw + template + GLM_INLINE glm::vec<4, T, Q> wxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.w); + } + + // wxyx + template + GLM_INLINE glm::vec<4, T, Q> wxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.x); + } + + // wxyy + template + GLM_INLINE glm::vec<4, T, Q> wxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.y); + } + + // wxyz + template + GLM_INLINE glm::vec<4, T, Q> wxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.z); + } + + // wxyw + template + GLM_INLINE glm::vec<4, T, Q> wxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.w); + } + + // wxzx + template + GLM_INLINE glm::vec<4, T, Q> wxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.x); + } + + // wxzy + template + GLM_INLINE glm::vec<4, T, Q> wxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.y); + } + + // wxzz + template + GLM_INLINE glm::vec<4, T, Q> wxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.z); + } + + // wxzw + template + GLM_INLINE glm::vec<4, T, Q> wxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.w); + } + + // wxwx + template + GLM_INLINE glm::vec<4, T, Q> wxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.x); + } + + // wxwy + template + GLM_INLINE glm::vec<4, T, Q> wxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.y); + } + + // wxwz + template + GLM_INLINE glm::vec<4, T, Q> wxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.z); + } + + // wxww + template + GLM_INLINE glm::vec<4, T, Q> wxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.w); + } + + // wyxx + template + GLM_INLINE glm::vec<4, T, Q> wyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.x); + } + + // wyxy + template + GLM_INLINE glm::vec<4, T, Q> wyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.y); + } + + // wyxz + template + GLM_INLINE glm::vec<4, T, Q> wyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.z); + } + + // wyxw + template + GLM_INLINE glm::vec<4, T, Q> wyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.w); + } + + // wyyx + template + GLM_INLINE glm::vec<4, T, Q> wyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.x); + } + + // wyyy + template + GLM_INLINE glm::vec<4, T, Q> wyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.y); + } + + // wyyz + template + GLM_INLINE glm::vec<4, T, Q> wyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.z); + } + + // wyyw + template + GLM_INLINE glm::vec<4, T, Q> wyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.w); + } + + // wyzx + template + GLM_INLINE glm::vec<4, T, Q> wyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.x); + } + + // wyzy + template + GLM_INLINE glm::vec<4, T, Q> wyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.y); + } + + // wyzz + template + GLM_INLINE glm::vec<4, T, Q> wyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.z); + } + + // wyzw + template + GLM_INLINE glm::vec<4, T, Q> wyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.w); + } + + // wywx + template + GLM_INLINE glm::vec<4, T, Q> wywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.x); + } + + // wywy + template + GLM_INLINE glm::vec<4, T, Q> wywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.y); + } + + // wywz + template + GLM_INLINE glm::vec<4, T, Q> wywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.z); + } + + // wyww + template + GLM_INLINE glm::vec<4, T, Q> wyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.w); + } + + // wzxx + template + GLM_INLINE glm::vec<4, T, Q> wzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.x); + } + + // wzxy + template + GLM_INLINE glm::vec<4, T, Q> wzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.y); + } + + // wzxz + template + GLM_INLINE glm::vec<4, T, Q> wzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.z); + } + + // wzxw + template + GLM_INLINE glm::vec<4, T, Q> wzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.w); + } + + // wzyx + template + GLM_INLINE glm::vec<4, T, Q> wzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.x); + } + + // wzyy + template + GLM_INLINE glm::vec<4, T, Q> wzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.y); + } + + // wzyz + template + GLM_INLINE glm::vec<4, T, Q> wzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.z); + } + + // wzyw + template + GLM_INLINE glm::vec<4, T, Q> wzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.w); + } + + // wzzx + template + GLM_INLINE glm::vec<4, T, Q> wzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.x); + } + + // wzzy + template + GLM_INLINE glm::vec<4, T, Q> wzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.y); + } + + // wzzz + template + GLM_INLINE glm::vec<4, T, Q> wzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.z); + } + + // wzzw + template + GLM_INLINE glm::vec<4, T, Q> wzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.w); + } + + // wzwx + template + GLM_INLINE glm::vec<4, T, Q> wzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.x); + } + + // wzwy + template + GLM_INLINE glm::vec<4, T, Q> wzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.y); + } + + // wzwz + template + GLM_INLINE glm::vec<4, T, Q> wzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.z); + } + + // wzww + template + GLM_INLINE glm::vec<4, T, Q> wzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.w); + } + + // wwxx + template + GLM_INLINE glm::vec<4, T, Q> wwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.x); + } + + // wwxy + template + GLM_INLINE glm::vec<4, T, Q> wwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.y); + } + + // wwxz + template + GLM_INLINE glm::vec<4, T, Q> wwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.z); + } + + // wwxw + template + GLM_INLINE glm::vec<4, T, Q> wwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.w); + } + + // wwyx + template + GLM_INLINE glm::vec<4, T, Q> wwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.x); + } + + // wwyy + template + GLM_INLINE glm::vec<4, T, Q> wwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.y); + } + + // wwyz + template + GLM_INLINE glm::vec<4, T, Q> wwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.z); + } + + // wwyw + template + GLM_INLINE glm::vec<4, T, Q> wwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.w); + } + + // wwzx + template + GLM_INLINE glm::vec<4, T, Q> wwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.x); + } + + // wwzy + template + GLM_INLINE glm::vec<4, T, Q> wwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.y); + } + + // wwzz + template + GLM_INLINE glm::vec<4, T, Q> wwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.z); + } + + // wwzw + template + GLM_INLINE glm::vec<4, T, Q> wwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.w); + } + + // wwwx + template + GLM_INLINE glm::vec<4, T, Q> wwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.x); + } + + // wwwy + template + GLM_INLINE glm::vec<4, T, Q> wwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.y); + } + + // wwwz + template + GLM_INLINE glm::vec<4, T, Q> wwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.z); + } + + // wwww + template + GLM_INLINE glm::vec<4, T, Q> wwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.w); + } + +} diff --git a/src/GLMath/glm/gtx/vector_angle.hpp b/src/GLMath/glm/gtx/vector_angle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9ae437126b195e637c846f45549adfd8eb7e9965 --- /dev/null +++ b/src/GLMath/glm/gtx/vector_angle.hpp @@ -0,0 +1,57 @@ +/// @ref gtx_vector_angle +/// @file glm/gtx/vector_angle.hpp +/// +/// @see core (dependence) +/// @see gtx_quaternion (dependence) +/// @see gtx_epsilon (dependence) +/// +/// @defgroup gtx_vector_angle GLM_GTX_vector_angle +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Compute angle between vectors + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/epsilon.hpp" +#include "../gtx/quaternion.hpp" +#include "../gtx/rotate_vector.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vector_angle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vector_angle extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_vector_angle + /// @{ + + //! Returns the absolute angle between two vectors. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T angle(vec const& x, vec const& y); + + //! Returns the oriented angle between two 2d vectors. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y); + + //! Returns the oriented angle between two 3d vectors based from a reference axis. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref); + + /// @} +}// namespace glm + +#include "vector_angle.inl" diff --git a/src/GLMath/glm/gtx/vector_angle.inl b/src/GLMath/glm/gtx/vector_angle.inl new file mode 100644 index 0000000000000000000000000000000000000000..a1f957a594fdea0904d32a2cf76f7169a4dcf239 --- /dev/null +++ b/src/GLMath/glm/gtx/vector_angle.inl @@ -0,0 +1,44 @@ +/// @ref gtx_vector_angle + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType angle + ( + genType const& x, + genType const& y + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); + return acos(clamp(dot(x, y), genType(-1), genType(1))); + } + + template + GLM_FUNC_QUALIFIER T angle(vec const& x, vec const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); + return acos(clamp(dot(x, y), T(-1), T(1))); + } + + //! \todo epsilon is hard coded to 0.01 + template + GLM_FUNC_QUALIFIER T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); + T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); + + if(all(epsilonEqual(y, glm::rotate(x, Angle), T(0.0001)))) + return Angle; + else + return -Angle; + } + + template + GLM_FUNC_QUALIFIER T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); + + T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); + return mix(Angle, -Angle, dot(ref, cross(x, y)) < T(0)); + } +}//namespace glm diff --git a/src/GLMath/glm/gtx/vector_query.hpp b/src/GLMath/glm/gtx/vector_query.hpp new file mode 100644 index 0000000000000000000000000000000000000000..77c7b974be5159111151191608ec28f80de09c2e --- /dev/null +++ b/src/GLMath/glm/gtx/vector_query.hpp @@ -0,0 +1,66 @@ +/// @ref gtx_vector_query +/// @file glm/gtx/vector_query.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_vector_query GLM_GTX_vector_query +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Query informations of vector types + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vector_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vector_query extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_vector_query + /// @{ + + //! Check whether two vectors are collinears. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areCollinear(vec const& v0, vec const& v1, T const& epsilon); + + //! Check whether two vectors are orthogonals. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon); + + //! Check whether a vector is normalized. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool isNormalized(vec const& v, T const& epsilon); + + //! Check whether a vector is null. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool isNull(vec const& v, T const& epsilon); + + //! Check whether a each component of a vector is null. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL vec isCompNull(vec const& v, T const& epsilon); + + //! Check whether two vectors are orthonormal. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon); + + /// @} +}// namespace glm + +#include "vector_query.inl" diff --git a/src/GLMath/glm/gtx/vector_query.inl b/src/GLMath/glm/gtx/vector_query.inl new file mode 100644 index 0000000000000000000000000000000000000000..d1a5c9be46b1574a80c076d303822261e84e940a --- /dev/null +++ b/src/GLMath/glm/gtx/vector_query.inl @@ -0,0 +1,154 @@ +/// @ref gtx_vector_query + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_areCollinear{}; + + template + struct compute_areCollinear<2, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<2, T, Q> const& v0, vec<2, T, Q> const& v1, T const& epsilon) + { + return length(cross(vec<3, T, Q>(v0, static_cast(0)), vec<3, T, Q>(v1, static_cast(0)))) < epsilon; + } + }; + + template + struct compute_areCollinear<3, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, T const& epsilon) + { + return length(cross(v0, v1)) < epsilon; + } + }; + + template + struct compute_areCollinear<4, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<4, T, Q> const& v0, vec<4, T, Q> const& v1, T const& epsilon) + { + return length(cross(vec<3, T, Q>(v0), vec<3, T, Q>(v1))) < epsilon; + } + }; + + template + struct compute_isCompNull{}; + + template + struct compute_isCompNull<2, T, Q> + { + GLM_FUNC_QUALIFIER static vec<2, bool, Q> call(vec<2, T, Q> const& v, T const& epsilon) + { + return vec<2, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon)); + } + }; + + template + struct compute_isCompNull<3, T, Q> + { + GLM_FUNC_QUALIFIER static vec<3, bool, Q> call(vec<3, T, Q> const& v, T const& epsilon) + { + return vec<3, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon), + (abs(v.z) < epsilon)); + } + }; + + template + struct compute_isCompNull<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, bool, Q> call(vec<4, T, Q> const& v, T const& epsilon) + { + return vec<4, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon), + (abs(v.z) < epsilon), + (abs(v.w) < epsilon)); + } + }; + +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool areCollinear(vec const& v0, vec const& v1, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areCollinear' only accept floating-point inputs"); + + return detail::compute_areCollinear::call(v0, v1, epsilon); + } + + template + GLM_FUNC_QUALIFIER bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areOrthogonal' only accept floating-point inputs"); + + return abs(dot(v0, v1)) <= max( + static_cast(1), + length(v0)) * max(static_cast(1), length(v1)) * epsilon; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNormalized' only accept floating-point inputs"); + + return abs(length(v) - static_cast(1)) <= static_cast(2) * epsilon; + } + + template + GLM_FUNC_QUALIFIER bool isNull(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNull' only accept floating-point inputs"); + + return length(v) <= epsilon; + } + + template + GLM_FUNC_QUALIFIER vec isCompNull(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isCompNull' only accept floating-point inputs"); + + return detail::compute_isCompNull::call(v, epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<2, bool, Q> isCompNull(vec<2, T, Q> const& v, T const& epsilon) + { + return vec<2, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<3, bool, Q> isCompNull(vec<3, T, Q> const& v, T const& epsilon) + { + return vec<3, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon, + abs(v.z) < epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isCompNull(vec<4, T, Q> const& v, T const& epsilon) + { + return vec<4, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon, + abs(v.z) < epsilon, + abs(v.w) < epsilon); + } + + template + GLM_FUNC_QUALIFIER bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon) + { + return isNormalized(v0, epsilon) && isNormalized(v1, epsilon) && (abs(dot(v0, v1)) <= epsilon); + } + +}//namespace glm diff --git a/src/GLMath/glm/gtx/wrap.hpp b/src/GLMath/glm/gtx/wrap.hpp new file mode 100644 index 0000000000000000000000000000000000000000..02c51965c1e9f53a61d105274ff39fdcac9de3e9 --- /dev/null +++ b/src/GLMath/glm/gtx/wrap.hpp @@ -0,0 +1,55 @@ +/// @ref gtx_wrap +/// @file glm/gtx/wrap.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_wrap GLM_GTX_wrap +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Wrapping mode of texture coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_wrap is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_wrap extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_wrap + /// @{ + + /// Simulate GL_CLAMP OpenGL wrap mode + /// @see gtx_wrap extension. + template + GLM_FUNC_DECL genType clamp(genType const& Texcoord); + + /// Simulate GL_REPEAT OpenGL wrap mode + /// @see gtx_wrap extension. + template + GLM_FUNC_DECL genType repeat(genType const& Texcoord); + + /// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode + /// @see gtx_wrap extension. + template + GLM_FUNC_DECL genType mirrorClamp(genType const& Texcoord); + + /// Simulate GL_MIRROR_REPEAT OpenGL wrap mode + /// @see gtx_wrap extension. + template + GLM_FUNC_DECL genType mirrorRepeat(genType const& Texcoord); + + /// @} +}// namespace glm + +#include "wrap.inl" diff --git a/src/GLMath/glm/gtx/wrap.inl b/src/GLMath/glm/gtx/wrap.inl new file mode 100644 index 0000000000000000000000000000000000000000..409a316ab030c9e137bb5eb06d4e430c90a140d9 --- /dev/null +++ b/src/GLMath/glm/gtx/wrap.inl @@ -0,0 +1,57 @@ +/// @ref gtx_wrap + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec clamp(vec const& Texcoord) + { + return glm::clamp(Texcoord, vec(0), vec(1)); + } + + template + GLM_FUNC_QUALIFIER genType clamp(genType const& Texcoord) + { + return clamp(vec<1, genType, defaultp>(Texcoord)).x; + } + + template + GLM_FUNC_QUALIFIER vec repeat(vec const& Texcoord) + { + return glm::fract(Texcoord); + } + + template + GLM_FUNC_QUALIFIER genType repeat(genType const& Texcoord) + { + return repeat(vec<1, genType, defaultp>(Texcoord)).x; + } + + template + GLM_FUNC_QUALIFIER vec mirrorClamp(vec const& Texcoord) + { + return glm::fract(glm::abs(Texcoord)); + } + + template + GLM_FUNC_QUALIFIER genType mirrorClamp(genType const& Texcoord) + { + return mirrorClamp(vec<1, genType, defaultp>(Texcoord)).x; + } + + template + GLM_FUNC_QUALIFIER vec mirrorRepeat(vec const& Texcoord) + { + vec const Abs = glm::abs(Texcoord); + vec const Clamp = glm::mod(glm::floor(Abs), vec(2)); + vec const Floor = glm::floor(Abs); + vec const Rest = Abs - Floor; + vec const Mirror = Clamp + Rest; + return mix(Rest, vec(1) - Rest, glm::greaterThanEqual(Mirror, vec(1))); + } + + template + GLM_FUNC_QUALIFIER genType mirrorRepeat(genType const& Texcoord) + { + return mirrorRepeat(vec<1, genType, defaultp>(Texcoord)).x; + } +}//namespace glm diff --git a/src/GLMath/glm/integer.hpp b/src/GLMath/glm/integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8817db3f0a224f6b36a7a0ad75ffc3d895e75aaa --- /dev/null +++ b/src/GLMath/glm/integer.hpp @@ -0,0 +1,212 @@ +/// @ref core +/// @file glm/integer.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.8 Integer Functions +/// +/// @defgroup core_func_integer Integer functions +/// @ingroup core +/// +/// Provides GLSL functions on integer types +/// +/// These all operate component-wise. The description is per component. +/// The notation [a, b] means the set of bits from bit-number a through bit-number +/// b, inclusive. The lowest-order bit is bit 0. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/qualifier.hpp" +#include "common.hpp" +#include "vector_relational.hpp" + +namespace glm +{ + /// @addtogroup core_func_integer + /// @{ + + /// Adds 32-bit unsigned integer x and y, returning the sum + /// modulo pow(2, 32). The value carry is set to 0 if the sum was + /// less than pow(2, 32), or to 1 otherwise. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL uaddCarry man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec uaddCarry( + vec const& x, + vec const& y, + vec & carry); + + /// Subtracts the 32-bit unsigned integer y from x, returning + /// the difference if non-negative, or pow(2, 32) plus the difference + /// otherwise. The value borrow is set to 0 if x >= y, or to 1 otherwise. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL usubBorrow man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec usubBorrow( + vec const& x, + vec const& y, + vec & borrow); + + /// Multiplies 32-bit integers x and y, producing a 64-bit + /// result. The 32 least-significant bits are returned in lsb. + /// The 32 most-significant bits are returned in msb. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL umulExtended man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL void umulExtended( + vec const& x, + vec const& y, + vec & msb, + vec & lsb); + + /// Multiplies 32-bit integers x and y, producing a 64-bit + /// result. The 32 least-significant bits are returned in lsb. + /// The 32 most-significant bits are returned in msb. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL imulExtended man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL void imulExtended( + vec const& x, + vec const& y, + vec & msb, + vec & lsb); + + /// Extracts bits [offset, offset + bits - 1] from value, + /// returning them in the least significant bits of the result. + /// For unsigned data types, the most significant bits of the + /// result will be set to zero. For signed data types, the + /// most significant bits will be set to the value of bit offset + base - 1. + /// + /// If bits is zero, the result will be zero. The result will be + /// undefined if offset or bits is negative, or if the sum of + /// offset and bits is greater than the number of bits used + /// to store the operand. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL bitfieldExtract man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldExtract( + vec const& Value, + int Offset, + int Bits); + + /// Returns the insertion the bits least-significant bits of insert into base. + /// + /// The result will have bits [offset, offset + bits - 1] taken + /// from bits [0, bits - 1] of insert, and all other bits taken + /// directly from the corresponding bits of base. If bits is + /// zero, the result will simply be base. The result will be + /// undefined if offset or bits is negative, or if the sum of + /// offset and bits is greater than the number of bits used to + /// store the operand. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitfieldInsert man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldInsert( + vec const& Base, + vec const& Insert, + int Offset, + int Bits); + + /// Returns the reversal of the bits of value. + /// The bit numbered n of the result will be taken from bit (bits - 1) - n of value, + /// where bits is the total number of bits used to represent value. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitfieldReverse man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldReverse(vec const& v); + + /// Returns the number of bits set to 1 in the binary representation of value. + /// + /// @tparam genType Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitCount man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int bitCount(genType v); + + /// Returns the number of bits set to 1 in the binary representation of value. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitCount man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitCount(vec const& v); + + /// Returns the bit number of the least significant bit set to + /// 1 in the binary representation of value. + /// If value is zero, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see GLSL findLSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int findLSB(genIUType x); + + /// Returns the bit number of the least significant bit set to + /// 1 in the binary representation of value. + /// If value is zero, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL findLSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec findLSB(vec const& v); + + /// Returns the bit number of the most significant bit in the binary representation of value. + /// For positive integers, the result will be the bit number of the most significant bit set to 1. + /// For negative integers, the result will be the bit number of the most significant + /// bit set to 0. For a value of zero or negative one, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see GLSL findMSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int findMSB(genIUType x); + + /// Returns the bit number of the most significant bit in the binary representation of value. + /// For positive integers, the result will be the bit number of the most significant bit set to 1. + /// For negative integers, the result will be the bit number of the most significant + /// bit set to 0. For a value of zero or negative one, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL findMSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec findMSB(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_integer.inl" diff --git a/src/GLMath/glm/mat2x2.hpp b/src/GLMath/glm/mat2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..96bec96b9a63846e577ebbd0e2dd21f65ae8f353 --- /dev/null +++ b/src/GLMath/glm/mat2x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x2.hpp + +#pragma once +#include "./ext/matrix_double2x2.hpp" +#include "./ext/matrix_double2x2_precision.hpp" +#include "./ext/matrix_float2x2.hpp" +#include "./ext/matrix_float2x2_precision.hpp" + diff --git a/src/GLMath/glm/mat2x3.hpp b/src/GLMath/glm/mat2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d68dc25eda943a72429732f0cdda9080a38b4829 --- /dev/null +++ b/src/GLMath/glm/mat2x3.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x3.hpp + +#pragma once +#include "./ext/matrix_double2x3.hpp" +#include "./ext/matrix_double2x3_precision.hpp" +#include "./ext/matrix_float2x3.hpp" +#include "./ext/matrix_float2x3_precision.hpp" + diff --git a/src/GLMath/glm/mat2x4.hpp b/src/GLMath/glm/mat2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b04b7387b1a31826ce22ac25d7926586b7b6f14a --- /dev/null +++ b/src/GLMath/glm/mat2x4.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x4.hpp + +#pragma once +#include "./ext/matrix_double2x4.hpp" +#include "./ext/matrix_double2x4_precision.hpp" +#include "./ext/matrix_float2x4.hpp" +#include "./ext/matrix_float2x4_precision.hpp" + diff --git a/src/GLMath/glm/mat3x2.hpp b/src/GLMath/glm/mat3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c85315372dc02dd2d409a8e214ea587101241a43 --- /dev/null +++ b/src/GLMath/glm/mat3x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat3x2.hpp + +#pragma once +#include "./ext/matrix_double3x2.hpp" +#include "./ext/matrix_double3x2_precision.hpp" +#include "./ext/matrix_float3x2.hpp" +#include "./ext/matrix_float3x2_precision.hpp" + diff --git a/src/GLMath/glm/mat3x3.hpp b/src/GLMath/glm/mat3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fd4fa31cdee018ed6eaf4a0d5386396010f89c7f --- /dev/null +++ b/src/GLMath/glm/mat3x3.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat3x3.hpp + +#pragma once +#include "./ext/matrix_double3x3.hpp" +#include "./ext/matrix_double3x3_precision.hpp" +#include "./ext/matrix_float3x3.hpp" +#include "./ext/matrix_float3x3_precision.hpp" diff --git a/src/GLMath/glm/mat3x4.hpp b/src/GLMath/glm/mat3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6342bf5b992dc97c57b532e25c18b8262d2a2f08 --- /dev/null +++ b/src/GLMath/glm/mat3x4.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat3x4.hpp + +#pragma once +#include "./ext/matrix_double3x4.hpp" +#include "./ext/matrix_double3x4_precision.hpp" +#include "./ext/matrix_float3x4.hpp" +#include "./ext/matrix_float3x4_precision.hpp" diff --git a/src/GLMath/glm/mat4x2.hpp b/src/GLMath/glm/mat4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e013e46b9c20c136332dd71ecc4f65abf7b51cfb --- /dev/null +++ b/src/GLMath/glm/mat4x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat4x2.hpp + +#pragma once +#include "./ext/matrix_double4x2.hpp" +#include "./ext/matrix_double4x2_precision.hpp" +#include "./ext/matrix_float4x2.hpp" +#include "./ext/matrix_float4x2_precision.hpp" + diff --git a/src/GLMath/glm/mat4x3.hpp b/src/GLMath/glm/mat4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..205725abd25aa6094e140d80f3158b6a7659ea60 --- /dev/null +++ b/src/GLMath/glm/mat4x3.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat4x3.hpp + +#pragma once +#include "./ext/matrix_double4x3.hpp" +#include "./ext/matrix_double4x3_precision.hpp" +#include "./ext/matrix_float4x3.hpp" +#include "./ext/matrix_float4x3_precision.hpp" diff --git a/src/GLMath/glm/mat4x4.hpp b/src/GLMath/glm/mat4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3515f7f370bf105587316498db2459294cd52537 --- /dev/null +++ b/src/GLMath/glm/mat4x4.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat4x4.hpp + +#pragma once +#include "./ext/matrix_double4x4.hpp" +#include "./ext/matrix_double4x4_precision.hpp" +#include "./ext/matrix_float4x4.hpp" +#include "./ext/matrix_float4x4_precision.hpp" + diff --git a/src/GLMath/glm/matrix.hpp b/src/GLMath/glm/matrix.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6badf5385048cf47124a1050092bd341e3d21bc4 --- /dev/null +++ b/src/GLMath/glm/matrix.hpp @@ -0,0 +1,161 @@ +/// @ref core +/// @file glm/matrix.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions +/// +/// @defgroup core_func_matrix Matrix functions +/// @ingroup core +/// +/// Provides GLSL matrix functions. +/// +/// Include to use these core features. + +#pragma once + +// Dependencies +#include "detail/qualifier.hpp" +#include "detail/setup.hpp" +#include "vec2.hpp" +#include "vec3.hpp" +#include "vec4.hpp" +#include "mat2x2.hpp" +#include "mat2x3.hpp" +#include "mat2x4.hpp" +#include "mat3x2.hpp" +#include "mat3x3.hpp" +#include "mat3x4.hpp" +#include "mat4x2.hpp" +#include "mat4x3.hpp" +#include "mat4x4.hpp" + +namespace glm { +namespace detail +{ + template + struct outerProduct_trait{}; + + template + struct outerProduct_trait<2, 2, T, Q> + { + typedef mat<2, 2, T, Q> type; + }; + + template + struct outerProduct_trait<2, 3, T, Q> + { + typedef mat<3, 2, T, Q> type; + }; + + template + struct outerProduct_trait<2, 4, T, Q> + { + typedef mat<4, 2, T, Q> type; + }; + + template + struct outerProduct_trait<3, 2, T, Q> + { + typedef mat<2, 3, T, Q> type; + }; + + template + struct outerProduct_trait<3, 3, T, Q> + { + typedef mat<3, 3, T, Q> type; + }; + + template + struct outerProduct_trait<3, 4, T, Q> + { + typedef mat<4, 3, T, Q> type; + }; + + template + struct outerProduct_trait<4, 2, T, Q> + { + typedef mat<2, 4, T, Q> type; + }; + + template + struct outerProduct_trait<4, 3, T, Q> + { + typedef mat<3, 4, T, Q> type; + }; + + template + struct outerProduct_trait<4, 4, T, Q> + { + typedef mat<4, 4, T, Q> type; + }; +}//namespace detail + + /// @addtogroup core_func_matrix + /// @{ + + /// Multiply matrix x by matrix y component-wise, i.e., + /// result[i][j] is the scalar product of x[i][j] and y[i][j]. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL matrixCompMult man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL mat matrixCompMult(mat const& x, mat const& y); + + /// Treats the first parameter c as a column vector + /// and the second parameter r as a row vector + /// and does a linear algebraic matrix multiply c * r. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL outerProduct man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r); + + /// Returns the transposed matrix of x + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL transpose man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename mat::transpose_type transpose(mat const& x); + + /// Return the determinant of a squared matrix. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL determinant man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL T determinant(mat const& m); + + /// Return the inverse of a squared matrix. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL inverse man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL mat inverse(mat const& m); + + /// @} +}//namespace glm + +#include "detail/func_matrix.inl" diff --git a/src/GLMath/glm/packing.hpp b/src/GLMath/glm/packing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ca83ac1dec960d3ddef0127a43f9504d64772fb3 --- /dev/null +++ b/src/GLMath/glm/packing.hpp @@ -0,0 +1,173 @@ +/// @ref core +/// @file glm/packing.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions +/// @see gtc_packing +/// +/// @defgroup core_func_packing Floating-Point Pack and Unpack Functions +/// @ingroup core +/// +/// Provides GLSL functions to pack and unpack half, single and double-precision floating point values into more compact integer types. +/// +/// These functions do not operate component-wise, rather as described in each case. +/// +/// Include to use these core features. + +#pragma once + +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float4.hpp" + +namespace glm +{ + /// @addtogroup core_func_packing + /// @{ + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packUnorm2x16(vec2 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x16: round(clamp(v, -1, +1) * 32767.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packSnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packSnorm2x16(vec2 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm4x8: round(clamp(c, 0, +1) * 255.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packUnorm4x8(vec4 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm4x8: round(clamp(c, -1, +1) * 127.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packSnorm4x8(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm2x16: f / 65535.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackUnorm2x16(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm2x16: clamp(f / 32767.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackSnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackSnorm2x16(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackUnorm4x8(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm4x8: clamp(f / 127.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackSnorm4x8(uint p); + + /// Returns a double-qualifier value obtained by packing the components of v into a 64-bit value. + /// If an IEEE 754 Inf or NaN is created, it will not signal, and the resulting floating point value is unspecified. + /// Otherwise, the bit- level representation of v is preserved. + /// The first vector component specifies the 32 least significant bits; + /// the second component specifies the 32 most significant bits. + /// + /// @see GLSL packDouble2x32 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL double packDouble2x32(uvec2 const& v); + + /// Returns a two-component unsigned integer vector representation of v. + /// The bit-level representation of v is preserved. + /// The first component of the vector contains the 32 least significant bits of the double; + /// the second component consists the 32 most significant bits. + /// + /// @see GLSL unpackDouble2x32 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uvec2 unpackDouble2x32(double v); + + /// Returns an unsigned integer obtained by converting the components of a two-component floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing these two 16- bit integers into a 32-bit unsigned integer. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the second component specifies the 16 most-significant bits. + /// + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packHalf2x16(vec2 const& v); + + /// Returns a two-component floating-point vector with components obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values, + /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, + /// and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the second component is obtained from the 16 most-significant bits of v. + /// + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackHalf2x16(uint v); + + /// @} +}//namespace glm + +#include "detail/func_packing.inl" diff --git a/src/GLMath/glm/simd/common.h b/src/GLMath/glm/simd/common.h new file mode 100644 index 0000000000000000000000000000000000000000..9b017cb4256e0fc3249c6fdbf6b3cad6c5be5f5a --- /dev/null +++ b/src/GLMath/glm/simd/common.h @@ -0,0 +1,240 @@ +/// @ref simd +/// @file glm/simd/common.h + +#pragma once + +#include "platform.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_add(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_add_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_add(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_add_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sub(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_sub_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sub(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_sub_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_mul(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_mul_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_mul(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_mul_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_div_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_div(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_div_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div_lowp(glm_f32vec4 a, glm_f32vec4 b) +{ + return glm_vec4_mul(a, _mm_rcp_ps(b)); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_swizzle_xyzw(glm_f32vec4 a) +{ +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + return _mm_permute_ps(a, _MM_SHUFFLE(3, 2, 1, 0)); +# else + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 1, 0)); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) +{ +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) + return _mm_fmadd_ss(a, b, c); +# else + return _mm_add_ss(_mm_mul_ss(a, b), c); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) +{ +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) + return _mm_fmadd_ps(a, b, c); +# else + return glm_vec4_add(glm_vec4_mul(a, b), c); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_abs(glm_f32vec4 x) +{ + return _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF))); +} + +GLM_FUNC_QUALIFIER glm_ivec4 glm_ivec4_abs(glm_ivec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSSE3_BIT + return _mm_sign_epi32(x, x); +# else + glm_ivec4 const sgn0 = _mm_srai_epi32(x, 31); + glm_ivec4 const inv0 = _mm_xor_si128(x, sgn0); + glm_ivec4 const sub0 = _mm_sub_epi32(inv0, sgn0); + return sub0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sign(glm_vec4 x) +{ + glm_vec4 const zro0 = _mm_setzero_ps(); + glm_vec4 const cmp0 = _mm_cmplt_ps(x, zro0); + glm_vec4 const cmp1 = _mm_cmpgt_ps(x, zro0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(-1.0f)); + glm_vec4 const and1 = _mm_and_ps(cmp1, _mm_set1_ps(1.0f)); + glm_vec4 const or0 = _mm_or_ps(and0, and1); + return or0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_round(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_round_ps(x, _MM_FROUND_TO_NEAREST_INT); +# else + glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); + glm_vec4 const and0 = _mm_and_ps(sgn0, x); + glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); + glm_vec4 const add0 = glm_vec4_add(x, or0); + glm_vec4 const sub0 = glm_vec4_sub(add0, or0); + return sub0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_floor(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_floor_ps(x); +# else + glm_vec4 const rnd0 = glm_vec4_round(x); + glm_vec4 const cmp0 = _mm_cmplt_ps(x, rnd0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); + glm_vec4 const sub0 = glm_vec4_sub(rnd0, and0); + return sub0; +# endif +} + +/* trunc TODO +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_trunc(glm_vec4 x) +{ + return glm_vec4(); +} +*/ + +//roundEven +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_roundEven(glm_vec4 x) +{ + glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); + glm_vec4 const and0 = _mm_and_ps(sgn0, x); + glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); + glm_vec4 const add0 = glm_vec4_add(x, or0); + glm_vec4 const sub0 = glm_vec4_sub(add0, or0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_ceil(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_ceil_ps(x); +# else + glm_vec4 const rnd0 = glm_vec4_round(x); + glm_vec4 const cmp0 = _mm_cmpgt_ps(x, rnd0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); + glm_vec4 const add0 = glm_vec4_add(rnd0, and0); + return add0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_fract(glm_vec4 x) +{ + glm_vec4 const flr0 = glm_vec4_floor(x); + glm_vec4 const sub0 = glm_vec4_sub(x, flr0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mod(glm_vec4 x, glm_vec4 y) +{ + glm_vec4 const div0 = glm_vec4_div(x, y); + glm_vec4 const flr0 = glm_vec4_floor(div0); + glm_vec4 const mul0 = glm_vec4_mul(y, flr0); + glm_vec4 const sub0 = glm_vec4_sub(x, mul0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_clamp(glm_vec4 v, glm_vec4 minVal, glm_vec4 maxVal) +{ + glm_vec4 const min0 = _mm_min_ps(v, maxVal); + glm_vec4 const max0 = _mm_max_ps(min0, minVal); + return max0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mix(glm_vec4 v1, glm_vec4 v2, glm_vec4 a) +{ + glm_vec4 const sub0 = glm_vec4_sub(_mm_set1_ps(1.0f), a); + glm_vec4 const mul0 = glm_vec4_mul(v1, sub0); + glm_vec4 const mad0 = glm_vec4_fma(v2, a, mul0); + return mad0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_step(glm_vec4 edge, glm_vec4 x) +{ + glm_vec4 const cmp = _mm_cmple_ps(x, edge); + return _mm_movemask_ps(cmp) == 0 ? _mm_set1_ps(1.0f) : _mm_setzero_ps(); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_smoothstep(glm_vec4 edge0, glm_vec4 edge1, glm_vec4 x) +{ + glm_vec4 const sub0 = glm_vec4_sub(x, edge0); + glm_vec4 const sub1 = glm_vec4_sub(edge1, edge0); + glm_vec4 const div0 = glm_vec4_sub(sub0, sub1); + glm_vec4 const clp0 = glm_vec4_clamp(div0, _mm_setzero_ps(), _mm_set1_ps(1.0f)); + glm_vec4 const mul0 = glm_vec4_mul(_mm_set1_ps(2.0f), clp0); + glm_vec4 const sub2 = glm_vec4_sub(_mm_set1_ps(3.0f), mul0); + glm_vec4 const mul1 = glm_vec4_mul(clp0, clp0); + glm_vec4 const mul2 = glm_vec4_mul(mul1, sub2); + return mul2; +} + +// Agner Fog method +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_nan(glm_vec4 x) +{ + glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer + glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit + glm_ivec4 const t3 = _mm_set1_epi32(int(0xFF000000)); // exponent mask + glm_ivec4 const t4 = _mm_and_si128(t2, t3); // exponent + glm_ivec4 const t5 = _mm_andnot_si128(t3, t2); // fraction + glm_ivec4 const Equal = _mm_cmpeq_epi32(t3, t4); + glm_ivec4 const Nequal = _mm_cmpeq_epi32(t5, _mm_setzero_si128()); + glm_ivec4 const And = _mm_and_si128(Equal, Nequal); + return _mm_castsi128_ps(And); // exponent = all 1s and fraction != 0 +} + +// Agner Fog method +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_inf(glm_vec4 x) +{ + glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer + glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit + return _mm_castsi128_ps(_mm_cmpeq_epi32(t2, _mm_set1_epi32(int(0xFF000000)))); // exponent is all 1s, fraction is 0 +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/simd/exponential.h b/src/GLMath/glm/simd/exponential.h new file mode 100644 index 0000000000000000000000000000000000000000..bc351d0119b9a8a2513a23eb02a0dee5f9c03d2d --- /dev/null +++ b/src/GLMath/glm/simd/exponential.h @@ -0,0 +1,20 @@ +/// @ref simd +/// @file glm/simd/experimental.h + +#pragma once + +#include "platform.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sqrt_lowp(glm_f32vec4 x) +{ + return _mm_mul_ss(_mm_rsqrt_ss(x), x); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sqrt_lowp(glm_f32vec4 x) +{ + return _mm_mul_ps(_mm_rsqrt_ps(x), x); +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/simd/geometric.h b/src/GLMath/glm/simd/geometric.h new file mode 100644 index 0000000000000000000000000000000000000000..07d7cbcc425f2910e2dc50bcb35fe0cd7a0d9609 --- /dev/null +++ b/src/GLMath/glm/simd/geometric.h @@ -0,0 +1,124 @@ +/// @ref simd +/// @file glm/simd/geometric.h + +#pragma once + +#include "common.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_DECL glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2); +GLM_FUNC_DECL glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2); + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_length(glm_vec4 x) +{ + glm_vec4 const dot0 = glm_vec4_dot(x, x); + glm_vec4 const sqt0 = _mm_sqrt_ps(dot0); + return sqt0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_distance(glm_vec4 p0, glm_vec4 p1) +{ + glm_vec4 const sub0 = _mm_sub_ps(p0, p1); + glm_vec4 const len0 = glm_vec4_length(sub0); + return len0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2) +{ +# if GLM_ARCH & GLM_ARCH_AVX_BIT + return _mm_dp_ps(v1, v2, 0xff); +# elif GLM_ARCH & GLM_ARCH_SSE3_BIT + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const hadd0 = _mm_hadd_ps(mul0, mul0); + glm_vec4 const hadd1 = _mm_hadd_ps(hadd0, hadd0); + return hadd1; +# else + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1)); + glm_vec4 const add0 = _mm_add_ps(mul0, swp0); + glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3)); + glm_vec4 const add1 = _mm_add_ps(add0, swp1); + return add1; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2) +{ +# if GLM_ARCH & GLM_ARCH_AVX_BIT + return _mm_dp_ps(v1, v2, 0xff); +# elif GLM_ARCH & GLM_ARCH_SSE3_BIT + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const had0 = _mm_hadd_ps(mul0, mul0); + glm_vec4 const had1 = _mm_hadd_ps(had0, had0); + return had1; +# else + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const mov0 = _mm_movehl_ps(mul0, mul0); + glm_vec4 const add0 = _mm_add_ps(mov0, mul0); + glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, 1); + glm_vec4 const add1 = _mm_add_ss(add0, swp1); + return add1; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_cross(glm_vec4 v1, glm_vec4 v2) +{ + glm_vec4 const swp0 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1)); + glm_vec4 const swp1 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 1, 0, 2)); + glm_vec4 const swp2 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1)); + glm_vec4 const swp3 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 1, 0, 2)); + glm_vec4 const mul0 = _mm_mul_ps(swp0, swp3); + glm_vec4 const mul1 = _mm_mul_ps(swp1, swp2); + glm_vec4 const sub0 = _mm_sub_ps(mul0, mul1); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_normalize(glm_vec4 v) +{ + glm_vec4 const dot0 = glm_vec4_dot(v, v); + glm_vec4 const isr0 = _mm_rsqrt_ps(dot0); + glm_vec4 const mul0 = _mm_mul_ps(v, isr0); + return mul0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_faceforward(glm_vec4 N, glm_vec4 I, glm_vec4 Nref) +{ + glm_vec4 const dot0 = glm_vec4_dot(Nref, I); + glm_vec4 const sgn0 = glm_vec4_sign(dot0); + glm_vec4 const mul0 = _mm_mul_ps(sgn0, _mm_set1_ps(-1.0f)); + glm_vec4 const mul1 = _mm_mul_ps(N, mul0); + return mul1; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_reflect(glm_vec4 I, glm_vec4 N) +{ + glm_vec4 const dot0 = glm_vec4_dot(N, I); + glm_vec4 const mul0 = _mm_mul_ps(N, dot0); + glm_vec4 const mul1 = _mm_mul_ps(mul0, _mm_set1_ps(2.0f)); + glm_vec4 const sub0 = _mm_sub_ps(I, mul1); + return sub0; +} + +GLM_FUNC_QUALIFIER __m128 glm_vec4_refract(glm_vec4 I, glm_vec4 N, glm_vec4 eta) +{ + glm_vec4 const dot0 = glm_vec4_dot(N, I); + glm_vec4 const mul0 = _mm_mul_ps(eta, eta); + glm_vec4 const mul1 = _mm_mul_ps(dot0, dot0); + glm_vec4 const sub0 = _mm_sub_ps(_mm_set1_ps(1.0f), mul0); + glm_vec4 const sub1 = _mm_sub_ps(_mm_set1_ps(1.0f), mul1); + glm_vec4 const mul2 = _mm_mul_ps(sub0, sub1); + + if(_mm_movemask_ps(_mm_cmplt_ss(mul2, _mm_set1_ps(0.0f))) == 0) + return _mm_set1_ps(0.0f); + + glm_vec4 const sqt0 = _mm_sqrt_ps(mul2); + glm_vec4 const mad0 = glm_vec4_fma(eta, dot0, sqt0); + glm_vec4 const mul4 = _mm_mul_ps(mad0, N); + glm_vec4 const mul5 = _mm_mul_ps(eta, I); + glm_vec4 const sub2 = _mm_sub_ps(mul5, mul4); + + return sub2; +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/simd/integer.h b/src/GLMath/glm/simd/integer.h new file mode 100644 index 0000000000000000000000000000000000000000..93814183fe027ab62e3532062de1abbb0ffe8c9e --- /dev/null +++ b/src/GLMath/glm/simd/integer.h @@ -0,0 +1,115 @@ +/// @ref simd +/// @file glm/simd/integer.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave(glm_uvec4 x) +{ + glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); + glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); + glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); + glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); + + glm_uvec4 Reg1; + glm_uvec4 Reg2; + + // REG1 = x; + // REG2 = y; + //Reg1 = _mm_unpacklo_epi64(x, y); + Reg1 = x; + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + return Reg1; +} + +GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave2(glm_uvec4 x, glm_uvec4 y) +{ + glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); + glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); + glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); + glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); + + glm_uvec4 Reg1; + glm_uvec4 Reg2; + + // REG1 = x; + // REG2 = y; + Reg1 = _mm_unpacklo_epi64(x, y); + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + return Reg1; +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/simd/matrix.h b/src/GLMath/glm/simd/matrix.h new file mode 100644 index 0000000000000000000000000000000000000000..b6c42ea4c17cff134a492d057309a131489ef51a --- /dev/null +++ b/src/GLMath/glm/simd/matrix.h @@ -0,0 +1,1028 @@ +/// @ref simd +/// @file glm/simd/matrix.h + +#pragma once + +#include "geometric.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER void glm_mat4_matrixCompMult(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_mul_ps(in1[0], in2[0]); + out[1] = _mm_mul_ps(in1[1], in2[1]); + out[2] = _mm_mul_ps(in1[2], in2[2]); + out[3] = _mm_mul_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER void glm_mat4_add(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_add_ps(in1[0], in2[0]); + out[1] = _mm_add_ps(in1[1], in2[1]); + out[2] = _mm_add_ps(in1[2], in2[2]); + out[3] = _mm_add_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER void glm_mat4_sub(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_sub_ps(in1[0], in2[0]); + out[1] = _mm_sub_ps(in1[1], in2[1]); + out[2] = _mm_sub_ps(in1[2], in2[2]); + out[3] = _mm_sub_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_mul_vec4(glm_vec4 const m[4], glm_vec4 v) +{ + __m128 v0 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 v1 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 v2 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v3 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(m[0], v0); + __m128 m1 = _mm_mul_ps(m[1], v1); + __m128 m2 = _mm_mul_ps(m[2], v2); + __m128 m3 = _mm_mul_ps(m[3], v3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + return a2; +} + +GLM_FUNC_QUALIFIER __m128 glm_vec4_mul_mat4(glm_vec4 v, glm_vec4 const m[4]) +{ + __m128 i0 = m[0]; + __m128 i1 = m[1]; + __m128 i2 = m[2]; + __m128 i3 = m[3]; + + __m128 m0 = _mm_mul_ps(v, i0); + __m128 m1 = _mm_mul_ps(v, i1); + __m128 m2 = _mm_mul_ps(v, i2); + __m128 m3 = _mm_mul_ps(v, i3); + + __m128 u0 = _mm_unpacklo_ps(m0, m1); + __m128 u1 = _mm_unpackhi_ps(m0, m1); + __m128 a0 = _mm_add_ps(u0, u1); + + __m128 u2 = _mm_unpacklo_ps(m2, m3); + __m128 u3 = _mm_unpackhi_ps(m2, m3); + __m128 a1 = _mm_add_ps(u2, u3); + + __m128 f0 = _mm_movelh_ps(a0, a1); + __m128 f1 = _mm_movehl_ps(a1, a0); + __m128 f2 = _mm_add_ps(f0, f1); + + return f2; +} + +GLM_FUNC_QUALIFIER void glm_mat4_mul(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + { + __m128 e0 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[0] = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[1] = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[2] = a2; + } + + { + //(__m128&)_mm_shuffle_epi32(__m128i&)in2[0], _MM_SHUFFLE(3, 3, 3, 3)) + __m128 e0 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[3] = a2; + } +} + +GLM_FUNC_QUALIFIER void glm_mat4_transpose(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 tmp0 = _mm_shuffle_ps(in[0], in[1], 0x44); + __m128 tmp2 = _mm_shuffle_ps(in[0], in[1], 0xEE); + __m128 tmp1 = _mm_shuffle_ps(in[2], in[3], 0x44); + __m128 tmp3 = _mm_shuffle_ps(in[2], in[3], 0xEE); + + out[0] = _mm_shuffle_ps(tmp0, tmp1, 0x88); + out[1] = _mm_shuffle_ps(tmp0, tmp1, 0xDD); + out[2] = _mm_shuffle_ps(tmp2, tmp3, 0x88); + out[3] = _mm_shuffle_ps(tmp2, tmp3, 0xDD); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_highp(glm_vec4 const in[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + return Det0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_lowp(glm_vec4 const m[4]) +{ + // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128( + + //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + // First 2 columns + __m128 Swp2A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 1, 1, 2))); + __m128 Swp3A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(3, 2, 3, 3))); + __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); + + // Second 2 columns + __m128 Swp2B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(3, 2, 3, 3))); + __m128 Swp3B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(0, 1, 1, 2))); + __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); + + // Columns subtraction + __m128 SubE = _mm_sub_ps(MulA, MulB); + + // Last 2 rows + __m128 Swp2C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 0, 1, 2))); + __m128 Swp3C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(1, 2, 0, 0))); + __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); + __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); + + //vec<4, T, Q> DetCof( + // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + __m128 SubFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubE), _MM_SHUFFLE(2, 1, 0, 0))); + __m128 SwpFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(0, 0, 0, 1))); + __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); + + __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); + __m128 SubFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpB), _MM_SHUFFLE(3, 1, 1, 0)));//SubF[0], SubE[3], SubE[3], SubE[1]; + __m128 SwpFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(1, 1, 2, 2))); + __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); + + __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); + + __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); + __m128 SubFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpC), _MM_SHUFFLE(3, 3, 2, 0))); + __m128 SwpFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(2, 3, 3, 3))); + __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); + + __m128 AddRes = _mm_add_ps(SubRes, MulFacC); + __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); + + //return m[0][0] * DetCof[0] + // + m[0][1] * DetCof[1] + // + m[0][2] * DetCof[2] + // + m[0][3] * DetCof[3]; + + return glm_vec4_dot(m[0], DetCof); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant(glm_vec4 const m[4]) +{ + // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(add) + + //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + // First 2 columns + __m128 Swp2A = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 1, 1, 2)); + __m128 Swp3A = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(3, 2, 3, 3)); + __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); + + // Second 2 columns + __m128 Swp2B = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(3, 2, 3, 3)); + __m128 Swp3B = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(0, 1, 1, 2)); + __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); + + // Columns subtraction + __m128 SubE = _mm_sub_ps(MulA, MulB); + + // Last 2 rows + __m128 Swp2C = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 0, 1, 2)); + __m128 Swp3C = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(1, 2, 0, 0)); + __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); + __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); + + //vec<4, T, Q> DetCof( + // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + __m128 SubFacA = _mm_shuffle_ps(SubE, SubE, _MM_SHUFFLE(2, 1, 0, 0)); + __m128 SwpFacA = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(0, 0, 0, 1)); + __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); + + __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); + __m128 SubFacB = _mm_shuffle_ps(SubTmpB, SubTmpB, _MM_SHUFFLE(3, 1, 1, 0));//SubF[0], SubE[3], SubE[3], SubE[1]; + __m128 SwpFacB = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(1, 1, 2, 2)); + __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); + + __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); + + __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); + __m128 SubFacC = _mm_shuffle_ps(SubTmpC, SubTmpC, _MM_SHUFFLE(3, 3, 2, 0)); + __m128 SwpFacC = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(2, 3, 3, 3)); + __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); + + __m128 AddRes = _mm_add_ps(SubRes, MulFacC); + __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); + + //return m[0][0] * DetCof[0] + // + m[0][1] * DetCof[1] + // + m[0][2] * DetCof[2] + // + m[0][3] * DetCof[3]; + + return glm_vec4_dot(m[0], DetCof); +} + +GLM_FUNC_QUALIFIER void glm_mat4_inverse(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + __m128 Rcp0 = _mm_div_ps(_mm_set1_ps(1.0f), Det0); + //__m128 Rcp0 = _mm_rcp_ps(Det0); + + // Inverse /= Determinant; + out[0] = _mm_mul_ps(Inv0, Rcp0); + out[1] = _mm_mul_ps(Inv1, Rcp0); + out[2] = _mm_mul_ps(Inv2, Rcp0); + out[3] = _mm_mul_ps(Inv3, Rcp0); +} + +GLM_FUNC_QUALIFIER void glm_mat4_inverse_lowp(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + __m128 Rcp0 = _mm_rcp_ps(Det0); + //__m128 Rcp0 = _mm_div_ps(one, Det0); + // Inverse /= Determinant; + out[0] = _mm_mul_ps(Inv0, Rcp0); + out[1] = _mm_mul_ps(Inv1, Rcp0); + out[2] = _mm_mul_ps(Inv2, Rcp0); + out[3] = _mm_mul_ps(Inv3, Rcp0); +} +/* +GLM_FUNC_QUALIFIER void glm_mat4_rotate(__m128 const in[4], float Angle, float const v[3], __m128 out[4]) +{ + float a = glm::radians(Angle); + float c = cos(a); + float s = sin(a); + + glm::vec4 AxisA(v[0], v[1], v[2], float(0)); + __m128 AxisB = _mm_set_ps(AxisA.w, AxisA.z, AxisA.y, AxisA.x); + __m128 AxisC = detail::sse_nrm_ps(AxisB); + + __m128 Cos0 = _mm_set_ss(c); + __m128 CosA = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Sin0 = _mm_set_ss(s); + __m128 SinA = _mm_shuffle_ps(Sin0, Sin0, _MM_SHUFFLE(0, 0, 0, 0)); + + // vec<3, T, Q> temp = (valType(1) - c) * axis; + __m128 Temp0 = _mm_sub_ps(one, CosA); + __m128 Temp1 = _mm_mul_ps(Temp0, AxisC); + + //Rotate[0][0] = c + temp[0] * axis[0]; + //Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; + //Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; + __m128 Axis0 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 TmpA0 = _mm_mul_ps(Axis0, AxisC); + __m128 CosA0 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 1, 0)); + __m128 TmpA1 = _mm_add_ps(CosA0, TmpA0); + __m128 SinA0 = SinA;//_mm_set_ps(0.0f, s, -s, 0.0f); + __m128 TmpA2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 1, 2, 3)); + __m128 TmpA3 = _mm_mul_ps(SinA0, TmpA2); + __m128 TmpA4 = _mm_add_ps(TmpA1, TmpA3); + + //Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; + //Rotate[1][1] = c + temp[1] * axis[1]; + //Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; + __m128 Axis1 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 TmpB0 = _mm_mul_ps(Axis1, AxisC); + __m128 CosA1 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 0, 1)); + __m128 TmpB1 = _mm_add_ps(CosA1, TmpB0); + __m128 SinB0 = SinA;//_mm_set_ps(-s, 0.0f, s, 0.0f); + __m128 TmpB2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 0, 3, 2)); + __m128 TmpB3 = _mm_mul_ps(SinA0, TmpB2); + __m128 TmpB4 = _mm_add_ps(TmpB1, TmpB3); + + //Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; + //Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; + //Rotate[2][2] = c + temp[2] * axis[2]; + __m128 Axis2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 TmpC0 = _mm_mul_ps(Axis2, AxisC); + __m128 CosA2 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 0, 1, 1)); + __m128 TmpC1 = _mm_add_ps(CosA2, TmpC0); + __m128 SinC0 = SinA;//_mm_set_ps(s, -s, 0.0f, 0.0f); + __m128 TmpC2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 3, 0, 1)); + __m128 TmpC3 = _mm_mul_ps(SinA0, TmpC2); + __m128 TmpC4 = _mm_add_ps(TmpC1, TmpC3); + + __m128 Result[4]; + Result[0] = TmpA4; + Result[1] = TmpB4; + Result[2] = TmpC4; + Result[3] = _mm_set_ps(1, 0, 0, 0); + + //mat<4, 4, valType> Result; + //Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + //Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + //Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + //Result[3] = m[3]; + //return Result; + sse_mul_ps(in, Result, out); +} +*/ +GLM_FUNC_QUALIFIER void glm_mat4_outerProduct(__m128 const& c, __m128 const& r, __m128 out[4]) +{ + out[0] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(0, 0, 0, 0))); + out[1] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(1, 1, 1, 1))); + out[2] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(2, 2, 2, 2))); + out[3] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(3, 3, 3, 3))); +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/simd/packing.h b/src/GLMath/glm/simd/packing.h new file mode 100644 index 0000000000000000000000000000000000000000..609163eb0d77aaccd0f165fab215a703d70f91c8 --- /dev/null +++ b/src/GLMath/glm/simd/packing.h @@ -0,0 +1,8 @@ +/// @ref simd +/// @file glm/simd/packing.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/simd/platform.h b/src/GLMath/glm/simd/platform.h new file mode 100644 index 0000000000000000000000000000000000000000..c7b6afd2bf90b74b52037e5e36898d9badb6de5c --- /dev/null +++ b/src/GLMath/glm/simd/platform.h @@ -0,0 +1,366 @@ +#pragma once + +/////////////////////////////////////////////////////////////////////////////////// +// Platform + +#define GLM_PLATFORM_UNKNOWN 0x00000000 +#define GLM_PLATFORM_WINDOWS 0x00010000 +#define GLM_PLATFORM_LINUX 0x00020000 +#define GLM_PLATFORM_APPLE 0x00040000 +//#define GLM_PLATFORM_IOS 0x00080000 +#define GLM_PLATFORM_ANDROID 0x00100000 +#define GLM_PLATFORM_CHROME_NACL 0x00200000 +#define GLM_PLATFORM_UNIX 0x00400000 +#define GLM_PLATFORM_QNXNTO 0x00800000 +#define GLM_PLATFORM_WINCE 0x01000000 +#define GLM_PLATFORM_CYGWIN 0x02000000 + +#ifdef GLM_FORCE_PLATFORM_UNKNOWN +# define GLM_PLATFORM GLM_PLATFORM_UNKNOWN +#elif defined(__CYGWIN__) +# define GLM_PLATFORM GLM_PLATFORM_CYGWIN +#elif defined(__QNXNTO__) +# define GLM_PLATFORM GLM_PLATFORM_QNXNTO +#elif defined(__APPLE__) +# define GLM_PLATFORM GLM_PLATFORM_APPLE +#elif defined(WINCE) +# define GLM_PLATFORM GLM_PLATFORM_WINCE +#elif defined(_WIN32) +# define GLM_PLATFORM GLM_PLATFORM_WINDOWS +#elif defined(__native_client__) +# define GLM_PLATFORM GLM_PLATFORM_CHROME_NACL +#elif defined(__ANDROID__) +# define GLM_PLATFORM GLM_PLATFORM_ANDROID +#elif defined(__linux) +# define GLM_PLATFORM GLM_PLATFORM_LINUX +#elif defined(__unix) +# define GLM_PLATFORM GLM_PLATFORM_UNIX +#else +# define GLM_PLATFORM GLM_PLATFORM_UNKNOWN +#endif// + +/////////////////////////////////////////////////////////////////////////////////// +// Compiler + +#define GLM_COMPILER_UNKNOWN 0x00000000 + +// Intel +#define GLM_COMPILER_INTEL 0x00100000 +#define GLM_COMPILER_INTEL14 0x00100040 +#define GLM_COMPILER_INTEL15 0x00100050 +#define GLM_COMPILER_INTEL16 0x00100060 +#define GLM_COMPILER_INTEL17 0x00100070 + +// Visual C++ defines +#define GLM_COMPILER_VC 0x01000000 +#define GLM_COMPILER_VC12 0x01000001 +#define GLM_COMPILER_VC14 0x01000002 +#define GLM_COMPILER_VC15 0x01000003 +#define GLM_COMPILER_VC15_3 0x01000004 +#define GLM_COMPILER_VC15_5 0x01000005 +#define GLM_COMPILER_VC15_6 0x01000006 +#define GLM_COMPILER_VC15_7 0x01000007 + +// GCC defines +#define GLM_COMPILER_GCC 0x02000000 +#define GLM_COMPILER_GCC46 0x020000D0 +#define GLM_COMPILER_GCC47 0x020000E0 +#define GLM_COMPILER_GCC48 0x020000F0 +#define GLM_COMPILER_GCC49 0x02000100 +#define GLM_COMPILER_GCC5 0x02000200 +#define GLM_COMPILER_GCC6 0x02000300 +#define GLM_COMPILER_GCC7 0x02000400 +#define GLM_COMPILER_GCC8 0x02000500 + +// CUDA +#define GLM_COMPILER_CUDA 0x10000000 +#define GLM_COMPILER_CUDA70 0x100000A0 +#define GLM_COMPILER_CUDA75 0x100000B0 +#define GLM_COMPILER_CUDA80 0x100000C0 + +// Clang +#define GLM_COMPILER_CLANG 0x20000000 +#define GLM_COMPILER_CLANG34 0x20000050 +#define GLM_COMPILER_CLANG35 0x20000060 +#define GLM_COMPILER_CLANG36 0x20000070 +#define GLM_COMPILER_CLANG37 0x20000080 +#define GLM_COMPILER_CLANG38 0x20000090 +#define GLM_COMPILER_CLANG39 0x200000A0 +#define GLM_COMPILER_CLANG40 0x200000B0 +#define GLM_COMPILER_CLANG41 0x200000C0 +#define GLM_COMPILER_CLANG42 0x200000D0 + +// Build model +#define GLM_MODEL_32 0x00000010 +#define GLM_MODEL_64 0x00000020 + +// Force generic C++ compiler +#ifdef GLM_FORCE_COMPILER_UNKNOWN +# define GLM_COMPILER GLM_COMPILER_UNKNOWN + +#elif defined(__INTEL_COMPILER) +# if (__INTEL_COMPILER < 1400) +# error "GLM requires ICC 2013 SP1 or newer" +# elif __INTEL_COMPILER == 1400 +# define GLM_COMPILER GLM_COMPILER_INTEL14 +# elif __INTEL_COMPILER == 1500 +# define GLM_COMPILER GLM_COMPILER_INTEL15 +# elif __INTEL_COMPILER == 1600 +# define GLM_COMPILER GLM_COMPILER_INTEL16 +# elif __INTEL_COMPILER >= 1700 +# define GLM_COMPILER GLM_COMPILER_INTEL17 +# endif + +// CUDA +#elif defined(__CUDACC__) +# if !defined(CUDA_VERSION) && !defined(GLM_FORCE_CUDA) +# include // make sure version is defined since nvcc does not define it itself! +# endif +# if CUDA_VERSION < 7000 +# error "GLM requires CUDA 7.0 or higher" +# elif (CUDA_VERSION >= 7000 && CUDA_VERSION < 7500) +# define GLM_COMPILER GLM_COMPILER_CUDA70 +# elif (CUDA_VERSION >= 7500 && CUDA_VERSION < 8000) +# define GLM_COMPILER GLM_COMPILER_CUDA75 +# elif (CUDA_VERSION >= 8000) +# define GLM_COMPILER GLM_COMPILER_CUDA80 +# endif + +// Clang +#elif defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ < 6) +# error "GLM requires Clang 3.4 / Apple Clang 6.0 or higher" +# elif __clang_major__ == 6 && __clang_minor__ == 0 +# define GLM_COMPILER GLM_COMPILER_CLANG35 +# elif __clang_major__ == 6 && __clang_minor__ >= 1 +# define GLM_COMPILER GLM_COMPILER_CLANG36 +# elif __clang_major__ >= 7 +# define GLM_COMPILER GLM_COMPILER_CLANG37 +# endif +# else +# if ((__clang_major__ == 3) && (__clang_minor__ < 4)) || (__clang_major__ < 3) +# error "GLM requires Clang 3.4 or higher" +# elif __clang_major__ == 3 && __clang_minor__ == 4 +# define GLM_COMPILER GLM_COMPILER_CLANG34 +# elif __clang_major__ == 3 && __clang_minor__ == 5 +# define GLM_COMPILER GLM_COMPILER_CLANG35 +# elif __clang_major__ == 3 && __clang_minor__ == 6 +# define GLM_COMPILER GLM_COMPILER_CLANG36 +# elif __clang_major__ == 3 && __clang_minor__ == 7 +# define GLM_COMPILER GLM_COMPILER_CLANG37 +# elif __clang_major__ == 3 && __clang_minor__ == 8 +# define GLM_COMPILER GLM_COMPILER_CLANG38 +# elif __clang_major__ == 3 && __clang_minor__ >= 9 +# define GLM_COMPILER GLM_COMPILER_CLANG39 +# elif __clang_major__ == 4 && __clang_minor__ == 0 +# define GLM_COMPILER GLM_COMPILER_CLANG40 +# elif __clang_major__ == 4 && __clang_minor__ == 1 +# define GLM_COMPILER GLM_COMPILER_CLANG41 +# elif __clang_major__ == 4 && __clang_minor__ >= 2 +# define GLM_COMPILER GLM_COMPILER_CLANG42 +# elif __clang_major__ >= 4 +# define GLM_COMPILER GLM_COMPILER_CLANG42 +# endif +# endif + +// Visual C++ +#elif defined(_MSC_VER) +# if _MSC_VER < 1800 +# error "GLM requires Visual C++ 12 - 2013 or higher" +# elif _MSC_VER == 1800 +# define GLM_COMPILER GLM_COMPILER_VC12 +# elif _MSC_VER == 1900 +# define GLM_COMPILER GLM_COMPILER_VC14 +# elif _MSC_VER == 1910 +# define GLM_COMPILER GLM_COMPILER_VC15 +# elif _MSC_VER == 1911 +# define GLM_COMPILER GLM_COMPILER_VC15_3 +# elif _MSC_VER == 1912 +# define GLM_COMPILER GLM_COMPILER_VC15_5 +# elif _MSC_VER == 1913 +# define GLM_COMPILER GLM_COMPILER_VC15_6 +# elif _MSC_VER >= 1914 +# define GLM_COMPILER GLM_COMPILER_VC15_7 +# endif//_MSC_VER + +// G++ +#elif defined(__GNUC__) || defined(__MINGW32__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ < 6)) || (__GNUC__ < 4) +# error "GLM requires GCC 4.7 or higher" +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 6) +# define GLM_COMPILER (GLM_COMPILER_GCC46) +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 7) +# define GLM_COMPILER (GLM_COMPILER_GCC47) +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +# define GLM_COMPILER (GLM_COMPILER_GCC48) +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define GLM_COMPILER (GLM_COMPILER_GCC49) +# elif (__GNUC__ == 5) +# define GLM_COMPILER (GLM_COMPILER_GCC5) +# elif (__GNUC__ == 6) +# define GLM_COMPILER (GLM_COMPILER_GCC6) +# elif (__GNUC__ == 7) +# define GLM_COMPILER (GLM_COMPILER_GCC7) +# elif (__GNUC__ >= 8) +# define GLM_COMPILER (GLM_COMPILER_GCC8) +# endif + +#else +# define GLM_COMPILER GLM_COMPILER_UNKNOWN +#endif + +#ifndef GLM_COMPILER +# error "GLM_COMPILER undefined, your compiler may not be supported by GLM. Add #define GLM_COMPILER 0 to ignore this message." +#endif//GLM_COMPILER + +/////////////////////////////////////////////////////////////////////////////////// +// Instruction sets + +// User defines: GLM_FORCE_PURE GLM_FORCE_INTRINSICS GLM_FORCE_SSE2 GLM_FORCE_SSE3 GLM_FORCE_AVX GLM_FORCE_AVX2 GLM_FORCE_AVX2 + +#define GLM_ARCH_MIPS_BIT (0x10000000) +#define GLM_ARCH_PPC_BIT (0x20000000) +#define GLM_ARCH_ARM_BIT (0x40000000) +#define GLM_ARCH_X86_BIT (0x80000000) + +#define GLM_ARCH_SIMD_BIT (0x00001000) + +#define GLM_ARCH_NEON_BIT (0x00000001) +#define GLM_ARCH_SSE_BIT (0x00000002) +#define GLM_ARCH_SSE2_BIT (0x00000004) +#define GLM_ARCH_SSE3_BIT (0x00000008) +#define GLM_ARCH_SSSE3_BIT (0x00000010) +#define GLM_ARCH_SSE41_BIT (0x00000020) +#define GLM_ARCH_SSE42_BIT (0x00000040) +#define GLM_ARCH_AVX_BIT (0x00000080) +#define GLM_ARCH_AVX2_BIT (0x00000100) + +#define GLM_ARCH_UNKNOWN (0) +#define GLM_ARCH_X86 (GLM_ARCH_X86_BIT) +#define GLM_ARCH_SSE (GLM_ARCH_SSE_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_X86) +#define GLM_ARCH_SSE2 (GLM_ARCH_SSE2_BIT | GLM_ARCH_SSE) +#define GLM_ARCH_SSE3 (GLM_ARCH_SSE3_BIT | GLM_ARCH_SSE2) +#define GLM_ARCH_SSSE3 (GLM_ARCH_SSSE3_BIT | GLM_ARCH_SSE3) +#define GLM_ARCH_SSE41 (GLM_ARCH_SSE41_BIT | GLM_ARCH_SSSE3) +#define GLM_ARCH_SSE42 (GLM_ARCH_SSE42_BIT | GLM_ARCH_SSE41) +#define GLM_ARCH_AVX (GLM_ARCH_AVX_BIT | GLM_ARCH_SSE42) +#define GLM_ARCH_AVX2 (GLM_ARCH_AVX2_BIT | GLM_ARCH_AVX) +#define GLM_ARCH_ARM (GLM_ARCH_ARM_BIT) +#define GLM_ARCH_NEON (GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM) +#define GLM_ARCH_MIPS (GLM_ARCH_MIPS_BIT) +#define GLM_ARCH_PPC (GLM_ARCH_PPC_BIT) + +#if defined(GLM_FORCE_ARCH_UNKNOWN) || defined(GLM_FORCE_PURE) +# define GLM_ARCH GLM_ARCH_UNKNOWN +#elif defined(GLM_FORCE_NEON) +# define GLM_ARCH (GLM_ARCH_NEON) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_AVX2) +# define GLM_ARCH (GLM_ARCH_AVX2) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_AVX) +# define GLM_ARCH (GLM_ARCH_AVX) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE42) +# define GLM_ARCH (GLM_ARCH_SSE42) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE41) +# define GLM_ARCH (GLM_ARCH_SSE41) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSSE3) +# define GLM_ARCH (GLM_ARCH_SSSE3) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE3) +# define GLM_ARCH (GLM_ARCH_SSE3) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE2) +# define GLM_ARCH (GLM_ARCH_SSE2) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE) +# define GLM_ARCH (GLM_ARCH_SSE) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_INTRINSICS) && !defined(GLM_FORCE_XYZW_ONLY) +# if defined(__AVX2__) +# define GLM_ARCH (GLM_ARCH_AVX2) +# elif defined(__AVX__) +# define GLM_ARCH (GLM_ARCH_AVX) +# elif defined(__SSE4_2__) +# define GLM_ARCH (GLM_ARCH_SSE42) +# elif defined(__SSE4_1__) +# define GLM_ARCH (GLM_ARCH_SSE41) +# elif defined(__SSSE3__) +# define GLM_ARCH (GLM_ARCH_SSSE3) +# elif defined(__SSE3__) +# define GLM_ARCH (GLM_ARCH_SSE3) +# elif defined(__SSE2__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86_FP) +# define GLM_ARCH (GLM_ARCH_SSE2) +# elif defined(__i386__) +# define GLM_ARCH (GLM_ARCH_X86) +# elif defined(__ARM_NEON) +# define GLM_ARCH (GLM_ARCH_ARM | GLM_ARCH_NEON) +# elif defined(__arm__ ) || defined(_M_ARM) +# define GLM_ARCH (GLM_ARCH_ARM) +# elif defined(__mips__ ) +# define GLM_ARCH (GLM_ARCH_MIPS) +# elif defined(__powerpc__ ) || defined(_M_PPC) +# define GLM_ARCH (GLM_ARCH_PPC) +# else +# define GLM_ARCH (GLM_ARCH_UNKNOWN) +# endif +#else +# if defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(__i386__) +# define GLM_ARCH (GLM_ARCH_X86) +# elif defined(__arm__) || defined(_M_ARM) +# define GLM_ARCH (GLM_ARCH_ARM) +# elif defined(__powerpc__) || defined(_M_PPC) +# define GLM_ARCH (GLM_ARCH_PPC) +# elif defined(__mips__) +# define GLM_ARCH (GLM_ARCH_MIPS) +# else +# define GLM_ARCH (GLM_ARCH_UNKNOWN) +# endif +#endif + +#if GLM_ARCH & GLM_ARCH_AVX2_BIT +# include +#elif GLM_ARCH & GLM_ARCH_AVX_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE42_BIT +# if GLM_COMPILER & GLM_COMPILER_CLANG +# include +# endif +# include +#elif GLM_ARCH & GLM_ARCH_SSE41_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSSE3_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE3_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE2_BIT +# include +#endif//GLM_ARCH + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + typedef __m128 glm_f32vec4; + typedef __m128i glm_i32vec4; + typedef __m128i glm_u32vec4; + typedef __m128d glm_f64vec2; + typedef __m128i glm_i64vec2; + typedef __m128i glm_u64vec2; + + typedef glm_f32vec4 glm_vec4; + typedef glm_i32vec4 glm_ivec4; + typedef glm_u32vec4 glm_uvec4; + typedef glm_f64vec2 glm_dvec2; +#endif + +#if GLM_ARCH & GLM_ARCH_AVX_BIT + typedef __m256d glm_f64vec4; + typedef glm_f64vec4 glm_dvec4; +#endif + +#if GLM_ARCH & GLM_ARCH_AVX2_BIT + typedef __m256i glm_i64vec4; + typedef __m256i glm_u64vec4; +#endif diff --git a/src/GLMath/glm/simd/trigonometric.h b/src/GLMath/glm/simd/trigonometric.h new file mode 100644 index 0000000000000000000000000000000000000000..739b796e7e45c86f07dbe5d508ed46dd9a9c6fd4 --- /dev/null +++ b/src/GLMath/glm/simd/trigonometric.h @@ -0,0 +1,9 @@ +/// @ref simd +/// @file glm/simd/trigonometric.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/src/GLMath/glm/simd/vector_relational.h b/src/GLMath/glm/simd/vector_relational.h new file mode 100644 index 0000000000000000000000000000000000000000..f7385e9747363cf64be22d5b0b5e061983a36a12 --- /dev/null +++ b/src/GLMath/glm/simd/vector_relational.h @@ -0,0 +1,8 @@ +/// @ref simd +/// @file glm/simd/vector_relational.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/src/GLMath/glm/trigonometric.hpp b/src/GLMath/glm/trigonometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fcf07f899f8df646da5bafe825404e191524fe15 --- /dev/null +++ b/src/GLMath/glm/trigonometric.hpp @@ -0,0 +1,210 @@ +/// @ref core +/// @file glm/trigonometric.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions +/// +/// @defgroup core_func_trigonometric Angle and Trigonometry Functions +/// @ingroup core +/// +/// Function parameters specified as angle are assumed to be in units of radians. +/// In no case will any of these functions result in a divide by zero error. If +/// the divisor of a ratio is 0, then results will be undefined. +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. +/// +/// @see ext_vector_trigonometric + +#pragma once + +#include "detail/setup.hpp" +#include "detail/qualifier.hpp" + +namespace glm +{ + /// @addtogroup core_func_trigonometric + /// @{ + + /// Converts degrees to radians and returns the result. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL radians man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec radians(vec const& degrees); + + /// Converts radians to degrees and returns the result. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL degrees man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec degrees(vec const& radians); + + /// The standard trigonometric sine function. + /// The values returned by this function will range from [-1, 1]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sin man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec sin(vec const& angle); + + /// The standard trigonometric cosine function. + /// The values returned by this function will range from [-1, 1]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL cos man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec cos(vec const& angle); + + /// The standard trigonometric tangent function. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL tan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec tan(vec const& angle); + + /// Arc sine. Returns an angle whose sine is x. + /// The range of values returned by this function is [-PI/2, PI/2]. + /// Results are undefined if |x| > 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL asin man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec asin(vec const& x); + + /// Arc cosine. Returns an angle whose sine is x. + /// The range of values returned by this function is [0, PI]. + /// Results are undefined if |x| > 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL acos man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec acos(vec const& x); + + /// Arc tangent. Returns an angle whose tangent is y/x. + /// The signs of x and y are used to determine what + /// quadrant the angle is in. The range of values returned + /// by this function is [-PI, PI]. Results are undefined + /// if x and y are both 0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atan(vec const& y, vec const& x); + + /// Arc tangent. Returns an angle whose tangent is y_over_x. + /// The range of values returned by this function is [-PI/2, PI/2]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atan(vec const& y_over_x); + + /// Returns the hyperbolic sine function, (exp(x) - exp(-x)) / 2 + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sinh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec sinh(vec const& angle); + + /// Returns the hyperbolic cosine function, (exp(x) + exp(-x)) / 2 + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL cosh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec cosh(vec const& angle); + + /// Returns the hyperbolic tangent function, sinh(angle) / cosh(angle) + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL tanh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec tanh(vec const& angle); + + /// Arc hyperbolic sine; returns the inverse of sinh. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL asinh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec asinh(vec const& x); + + /// Arc hyperbolic cosine; returns the non-negative inverse + /// of cosh. Results are undefined if x < 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL acosh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec acosh(vec const& x); + + /// Arc hyperbolic tangent; returns the inverse of tanh. + /// Results are undefined if abs(x) >= 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atanh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atanh(vec const& x); + + /// @} +}//namespace glm + +#include "detail/func_trigonometric.inl" diff --git a/src/GLMath/glm/vec2.hpp b/src/GLMath/glm/vec2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..be768bf5fc0ebcc51b9c04cd8a00a4d8a64e44f1 --- /dev/null +++ b/src/GLMath/glm/vec2.hpp @@ -0,0 +1,14 @@ +/// @ref core +/// @file glm/vec2.hpp + +#pragma once +#include "./ext/vector_bool2.hpp" +#include "./ext/vector_bool2_precision.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float2_precision.hpp" +#include "./ext/vector_double2.hpp" +#include "./ext/vector_double2_precision.hpp" +#include "./ext/vector_int2.hpp" +#include "./ext/vector_int2_precision.hpp" +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_uint2_precision.hpp" diff --git a/src/GLMath/glm/vec3.hpp b/src/GLMath/glm/vec3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f57072239b95cac0e172e41375d73062af402635 --- /dev/null +++ b/src/GLMath/glm/vec3.hpp @@ -0,0 +1,14 @@ +/// @ref core +/// @file glm/vec3.hpp + +#pragma once +#include "./ext/vector_bool3.hpp" +#include "./ext/vector_bool3_precision.hpp" +#include "./ext/vector_float3.hpp" +#include "./ext/vector_float3_precision.hpp" +#include "./ext/vector_double3.hpp" +#include "./ext/vector_double3_precision.hpp" +#include "./ext/vector_int3.hpp" +#include "./ext/vector_int3_precision.hpp" +#include "./ext/vector_uint3.hpp" +#include "./ext/vector_uint3_precision.hpp" diff --git a/src/GLMath/glm/vec4.hpp b/src/GLMath/glm/vec4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9117020725c9e5768791f5a75116d985af42c4d9 --- /dev/null +++ b/src/GLMath/glm/vec4.hpp @@ -0,0 +1,15 @@ +/// @ref core +/// @file glm/vec4.hpp + +#pragma once +#include "./ext/vector_bool4.hpp" +#include "./ext/vector_bool4_precision.hpp" +#include "./ext/vector_float4.hpp" +#include "./ext/vector_float4_precision.hpp" +#include "./ext/vector_double4.hpp" +#include "./ext/vector_double4_precision.hpp" +#include "./ext/vector_int4.hpp" +#include "./ext/vector_int4_precision.hpp" +#include "./ext/vector_uint4.hpp" +#include "./ext/vector_uint4_precision.hpp" + diff --git a/src/GLMath/glm/vector_relational.hpp b/src/GLMath/glm/vector_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a0fe17eb707a4e5ba3590fe16d2704cecc3bd8ef --- /dev/null +++ b/src/GLMath/glm/vector_relational.hpp @@ -0,0 +1,121 @@ +/// @ref core +/// @file glm/vector_relational.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions +/// +/// @defgroup core_func_vector_relational Vector Relational Functions +/// @ingroup core +/// +/// Relational and equality operators (<, <=, >, >=, ==, !=) are defined to +/// operate on scalars and produce scalar Boolean results. For vector results, +/// use the following built-in functions. +/// +/// In all cases, the sizes of all the input and return vectors for any particular +/// call must match. +/// +/// Include to use these core features. +/// +/// @see ext_vector_relational + +#pragma once + +#include "detail/qualifier.hpp" +#include "detail/setup.hpp" + +namespace glm +{ + /// @addtogroup core_func_vector_relational + /// @{ + + /// Returns the component-wise comparison result of x < y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL lessThan man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x <= y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL lessThanEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x > y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL greaterThan man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x >= y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL greaterThanEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x == y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point, integer or bool scalar type. + /// + /// @see GLSL equal man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x != y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point, integer or bool scalar type. + /// + /// @see GLSL notEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y); + + /// Returns true if any component of x is true. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL any man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR bool any(vec const& v); + + /// Returns true if all components of x are true. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL all man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR bool all(vec const& v); + + /// Returns the component-wise logical complement of x. + /// /!\ Because of language incompatibilities between C++ and GLSL, GLM defines the function not but not_ instead. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL not man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec not_(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_vector_relational.inl" diff --git a/src/Gifti/GiftiDataArray.cxx b/src/Gifti/GiftiDataArray.cxx index a8fb0e34a654c79d53a1fd7a9ab98db84672b5de..74f15186e54f50f240a463a2e2a353daace018e6 100644 --- a/src/Gifti/GiftiDataArray.cxx +++ b/src/Gifti/GiftiDataArray.cxx @@ -1723,10 +1723,21 @@ const FastStatistics* GiftiDataArray::getFastStatistics() const return m_fastStatistics; } +/** + * Invalidate the histograms + */ +void +GiftiDataArray::invalidateHistograms() +{ + m_histogramNeedsUpdateFlag = true; + m_histogramLimitedValuesNeedsUpdateFlag = true; +} + const Histogram* GiftiDataArray::getHistogram(const int32_t numberOfBuckets) const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { - bool updateHistogramFlag = false; + bool updateHistogramFlag = m_histogramNeedsUpdateFlag; + m_histogramNeedsUpdateFlag = false; if (m_histogram == NULL) { m_histogram.grabNew(new Histogram(numberOfBuckets)); updateHistogramFlag = true; @@ -1788,7 +1799,8 @@ const Histogram* GiftiDataArray::getHistogram(const int32_t numberOfBuckets, const bool includeZeroValues) const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { - bool updateHistogramFlag = false; + bool updateHistogramFlag = m_histogramLimitedValuesNeedsUpdateFlag; + m_histogramLimitedValuesNeedsUpdateFlag = false; if (m_histogramLimitedValues == NULL) { m_histogramLimitedValues.grabNew(new Histogram(numberOfBuckets)); diff --git a/src/Gifti/GiftiDataArray.h b/src/Gifti/GiftiDataArray.h index e6898e4d305d94afa9a178a106e65f0d25916be5..b09c4d68d7422f2cc558327ddaa4076f03dba7d3 100644 --- a/src/Gifti/GiftiDataArray.h +++ b/src/Gifti/GiftiDataArray.h @@ -304,6 +304,8 @@ namespace caret { const float mostNegativeValueInclusive, const bool includeZeroValues) const; + void invalidateHistograms(); + protected: //validate the array @@ -412,6 +414,7 @@ namespace caret { mutable CaretPointer m_histogram; mutable int32_t m_histogramNumberOfBuckets = 100; + mutable bool m_histogramNeedsUpdateFlag = false; mutable CaretPointer m_histogramLimitedValues; mutable int32_t m_histogramLimitedValuesNumberOfBuckets = 100; @@ -420,6 +423,7 @@ namespace caret { mutable float m_histogramLimitedValuesLeastNegativeValueInclusive; mutable float m_histogramLimitedValuesMostNegativeValueInclusive; mutable bool m_histogramLimitedValuesIncludeZeroValues; + mutable bool m_histogramLimitedValuesNeedsUpdateFlag = false; /// statistics about data (DO NOT COPY) mutable DescriptiveStatistics* descriptiveStatisticsLimitedValues; diff --git a/src/Gifti/GiftiFile.cxx b/src/Gifti/GiftiFile.cxx index 84a7e8f8252ea7b376bda693c3b575ac8c5e39cb..079a8dcde53e161fc59f8028dc823cbabcb43c60 100644 --- a/src/Gifti/GiftiFile.cxx +++ b/src/Gifti/GiftiFile.cxx @@ -37,6 +37,8 @@ #include "XmlSaxParser.h" +#include + using namespace caret; /** @@ -894,13 +896,15 @@ GiftiFile::writeFile(const AString& filename) try { this->setFileName(filename); - FileInformation fileInfo(filename); + QFile::remove(filename); + + /*FileInformation fileInfo(filename); if (fileInfo.exists()) { //if (GiftiDataArrayFile.isFileOverwriteAllowed() == false) { // throw new GiftiException( // "Overwriting of existing files is currently prohibited"); //} - } + }//*/ // // Create a GIFTI Data Array File Writer diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index ab7ebacd68ef4f30e8cbc161b74e69133c36937f..2fc7e3aa17e728d622417e48a95f10f872ca09cc 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -474,9 +474,10 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) GraphicsPrimitive* primitiveToDraw = primitive; /* Conversion to window space creates a new primitive that must be deleted */ - std::unique_ptr windowSpacePrimitive; + std::unique_ptr lineConversionPrimitive; - bool workbenchLineFlag = false; + bool modelSpaceLineFlag = false; + bool windowSpaceLineFlag = false; bool millimeterPointsFlag = false; bool spheresFlag = false; switch (primitive->m_primitiveType) { @@ -503,12 +504,19 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: + modelSpaceLineFlag = true; + break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: - workbenchLineFlag = true; + windowSpaceLineFlag = true; break; case GraphicsPrimitive::PrimitiveType::SPHERES: spheresFlag = true; @@ -524,7 +532,8 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) else if (spheresFlag) { drawSpheresPrimitive(primitive); } - else if (workbenchLineFlag) { + else if (modelSpaceLineFlag + || windowSpaceLineFlag) { AString errorMessage; primitiveToDraw = GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(primitive, errorMessage); @@ -538,10 +547,22 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) #endif return; } - windowSpacePrimitive.reset(primitiveToDraw); - drawWindowSpace(PrivateDrawMode::DRAW_NORMAL, - primitiveToDraw, - NULL); + SpaceMode spaceMode = SpaceMode::WINDOW; + if (modelSpaceLineFlag) { + spaceMode = SpaceMode::MODEL; + } + else if (windowSpaceLineFlag) { + spaceMode = SpaceMode::WINDOW; + } + else { + CaretAssert(0); + } + + lineConversionPrimitive.reset(primitiveToDraw); + drawModelOrWindowSpace(spaceMode, + PrivateDrawMode::DRAW_NORMAL, + primitiveToDraw, + NULL); } else { drawPrivate(PrivateDrawMode::DRAW_NORMAL, @@ -551,8 +572,10 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) } /** - * Draw the graphics primitive in window space. + * Draw the graphics primitive in model space. * + * @param spaceMode + * Space mode: model or window * @param drawMode * Mode for drawing. * @param primitive @@ -561,25 +584,37 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) * Selection helper when draw mode is selection. */ void -GraphicsEngineDataOpenGL::drawWindowSpace(const PrivateDrawMode drawMode, - GraphicsPrimitive* primitive, - GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) +GraphicsEngineDataOpenGL::drawModelOrWindowSpace(const SpaceMode spaceMode, + const PrivateDrawMode drawMode, + GraphicsPrimitive* primitive, + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) { + bool windowSpaceFlag = false; + switch (spaceMode) { + case MODEL: + break; + case WINDOW: + windowSpaceFlag = true; + break; + } + int32_t polygonMode[2]; int32_t viewport[4]; saveOpenGLStateForWindowSpaceDrawing(polygonMode, viewport); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(viewport[0], viewport[0] + viewport[2], - viewport[1], viewport[1] + viewport[3], - 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + if (windowSpaceFlag) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(viewport[0], viewport[0] + viewport[2], + viewport[1], viewport[1] + viewport[3], + 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + } glPolygonMode(GL_FRONT, GL_FILL); - + drawPrivate(drawMode, primitive, primitiveSelectionHelper); @@ -828,6 +863,12 @@ GraphicsEngineDataOpenGL::drawWithSelection(GraphicsPrimitive* primitive, break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: + break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: break; @@ -1094,17 +1135,22 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: openGLPrimitiveType = GL_LINE_LOOP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: openGLPrimitiveType = GL_LINE_STRIP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: openGLPrimitiveType = GL_LINES; diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 6289ae561ad7c1fa33b204dc0551a2cf6508fc30..ac23f513018d4076b74594673820e66cb16b16ec 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -64,6 +64,11 @@ namespace caret { DRAW_SELECTION, }; + enum SpaceMode { + MODEL, + WINDOW, + }; + GraphicsEngineDataOpenGL(const GraphicsEngineDataOpenGL&); GraphicsEngineDataOpenGL& operator=(const GraphicsEngineDataOpenGL&); @@ -84,9 +89,14 @@ namespace caret { GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); - static void drawWindowSpace(const PrivateDrawMode drawMode, - GraphicsPrimitive* primitive, - GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); + static void drawModelOrWindowSpace(const SpaceMode spaceMode, + const PrivateDrawMode drawMode, + GraphicsPrimitive* primitive, + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); + +// static void drawWindowSpace(const PrivateDrawMode drawMode, +// GraphicsPrimitive* primitive, +// GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); static void drawPointsPrimitiveMillimeters(const GraphicsPrimitive* primitive); diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index fb24260523bf92cdd6a07bf74f84624aa497bd6d..50ce01c6591ef180b30ce65c47ee493c8a1ea04e 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -63,10 +63,12 @@ using namespace caret; * @param vertexPrimitiveRestartIndices * Contains indices at which the primitive should restart. * The primitive will stop at the index and not connect to the next index. - * @param lineThicknessPixels - * Thickness of lines in pixels. + * @param lineThickness + * Thickness of lines in (pixels when drawingSpace is WINDOW) * @param colorType * Type of color (solid or per-vertex) + * @param drawingSpace + * Drawing space * @param lineType * Type of lines drawn. * @param joinType @@ -76,16 +78,18 @@ GraphicsOpenGLPolylineTriangles::GraphicsOpenGLPolylineTriangles(const std::vect const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, + const float lineThickness, const ColorType colorType, + const DrawingSpace drawingSpace, const LineType lineType, const JoinType joinType) : m_inputXYZ(xyz), m_inputFloatRGBA(floatRGBA), m_inputByteRGBA(byteRGBA), m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), -m_lineThicknessPixels(lineThicknessPixels), +m_lineThickness(lineThickness), m_colorType(colorType), +m_drawingSpace(drawingSpace), m_lineType(lineType), m_joinType(joinType) { @@ -158,6 +162,7 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const break; } + DrawingSpace drawingSpace = DrawingSpace::WINDOW; LineType lineType = LineType::LINES; JoinType joinType = JoinType::NONE; switch (primitive->m_primitiveType) { @@ -182,6 +187,30 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + drawingSpace = DrawingSpace::MODEL_XY; + lineType = LineType::LINE_LOOP; + joinType = JoinType::BEVEL; + break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: + drawingSpace = DrawingSpace::MODEL_XY; + lineType = LineType::LINE_LOOP; + joinType = JoinType::MITER; + break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + drawingSpace = DrawingSpace::MODEL_XY; + lineType = LineType::LINE_STRIP; + joinType = JoinType::BEVEL; + break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: + drawingSpace = DrawingSpace::MODEL_XY; + lineType = LineType::LINE_STRIP; + joinType = JoinType::MITER; + break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: + drawingSpace = DrawingSpace::MODEL_XY; + lineType = LineType::LINES; + break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: lineType = LineType::LINE_LOOP; joinType = JoinType::BEVEL; @@ -216,6 +245,7 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const primitive->m_polygonalLinePrimitiveRestartIndices, lineWidthPixels, colorType, + drawingSpace, lineType, joinType); @@ -570,9 +600,18 @@ void GraphicsOpenGLPolylineTriangles::convertFromModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const { - CaretAssert(m_transformEvent); - m_transformEvent->transformPoint(modelXYZ, - windowXYZOut); + switch (m_drawingSpace) { + case DrawingSpace::MODEL_XY: + windowXYZOut[0] = modelXYZ[0]; + windowXYZOut[1] = modelXYZ[1]; + windowXYZOut[2] = modelXYZ[2]; + break; + case DrawingSpace::WINDOW: + CaretAssert(m_transformEvent); + m_transformEvent->transformPoint(modelXYZ, + windowXYZOut); + break; + } } /** @@ -635,7 +674,7 @@ GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t /* * "Width" of rectangle */ - const float halfWidth = m_lineThicknessPixels / 2.0f; + const float halfWidth = m_lineThickness / 2.0f; const float halfWidthX = perpendicularVector[0] * halfWidth; const float halfWidthY = perpendicularVector[1] * halfWidth; @@ -1046,7 +1085,7 @@ GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, /* * Miter limit is a multiple of the line thickness */ - const float miterLimit = m_lineThicknessPixels; + const float miterLimit = m_lineThickness; const float miterLimitSquared = miterLimit * miterLimit; /* diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.h b/src/Graphics/GraphicsOpenGLPolylineTriangles.h index 6916cd580f14a0593e74fe4e3ebd5f97571684a1..cd67d8c9d7be9cd43cff167c704691be45f1326e 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.h +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.h @@ -62,6 +62,23 @@ namespace caret { FLOAT_RGBA_SOLID }; + /** + * Drawing space + */ + enum class DrawingSpace { + /** + * Lines are drawn using the current modeling transformations in + * the XY plane. Z-coordinates should all be the same. + */ + MODEL_XY, + /** + * Coordinates of the lines are converted into window (pixel) coordinates + * and the lines are drawn in 'window space'. The lines always + * face the user even with rotations. + */ + WINDOW + }; + /** * Join tyupe of how connected lines are drawn to remove gaps between segments */ @@ -80,7 +97,7 @@ namespace caret { enum class LineType { /** Each pair of vertices is an independent line segment (GL_LINES) */ LINES, - /** A connected set of lines forming a loop (last is automaticall connected to first) */ + /** A connected set of lines forming a loop (last is automatically connected to first) */ LINE_LOOP, /** A connected set of lines (last is not connected to first) */ LINE_STRIP @@ -152,8 +169,9 @@ namespace caret { const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, + const float lineThickness, const ColorType colorType, + const DrawingSpace drawingSpace, const LineType lineType, const JoinType joinType); @@ -214,10 +232,12 @@ namespace caret { std::set m_vertexPrimitiveRestartIndices; - const float m_lineThicknessPixels; + const float m_lineThickness; const ColorType m_colorType; + const DrawingSpace m_drawingSpace; + const LineType m_lineType; const JoinType m_joinType; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 4b9b44a7932da1d479ba8a79811a39dd7442e467..6f526f83fe47e89f058e13450e85a2ec10d7dd8a 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -375,6 +375,8 @@ GraphicsPrimitive::isValid() const switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: if (numXYZ < 3) { @@ -382,12 +384,15 @@ GraphicsPrimitive::isValid() const } break; case PrimitiveType::OPENGL_LINE_STRIP: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: if (numXYZ < 2) { CaretLogWarning("Line strip must have at least 2 vertices."); } break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: case PrimitiveType::OPENGL_LINES: case PrimitiveType::POLYGONAL_LINES: if (numXYZ < 2) { @@ -486,6 +491,21 @@ GraphicsPrimitive::getPrimitiveTypeAsText() const case PrimitiveType::OPENGL_TRIANGLES: s = "OpenGL Triangles"; break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + s = "Model Space Polygonal Line Loop Bevel Join"; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: + s = "Model Space Polygonal Line Loop Meter Join"; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + s = "Model Space Polygonal Line Strip Bevel Join"; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: + s = "Model Space Polygonal Line Strip Miter Join"; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: + s = "Model Space Polygonal Lines"; + break; case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: s = "Polygonal Line Loop Bevel Join"; break; @@ -649,6 +669,17 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; case PrimitiveType::OPENGL_TRIANGLES: break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: + addLineWidthFlag = true; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: + addLineWidthFlag = true; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: + addLineWidthFlag = true; + break; case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: addLineWidthFlag = true; @@ -833,6 +864,25 @@ GraphicsPrimitive::addVertexProtected(const float xyz[3], } } +/** + * Get the XYZ coordinate from the given vertex. + * + * @param vertexIndex + * Index of the vertex. + * @param xyzOut + * Output containing the XYZ coordinat. + */ +void +GraphicsPrimitive::getVertexFloatXYZ(const int32_t vertexIndex, + float xyzOut[3]) const +{ + const int32_t i3 = vertexIndex * 3; + CaretAssertVectorIndex(m_xyz, i3 + 2); + xyzOut[0] = m_xyz[i3]; + xyzOut[1] = m_xyz[i3+1]; + xyzOut[2] = m_xyz[i3+2]; +} + /** * Replace the existing XYZ coordinates with the given * XYZ coordinates. The existing and new coordinates @@ -1160,6 +1210,16 @@ GraphicsPrimitive::addPrimitiveRestart() break; case PrimitiveType::OPENGL_TRIANGLES: break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: + polygonalLineFlag = true; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: + polygonalLineFlag = true; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: + break; case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: polygonalLineFlag = true; @@ -1459,6 +1519,159 @@ GraphicsPrimitive::setTextureImage(const uint8_t* imageBytesRGBA, } } +/** + * Simplify line types by removing every 'skipVertexCount' vertex. + * When 'skipVertexCount' is 2, every other point in the line is removed. + * Nothing is done when 'skipVertexCount' is less than 2 or primitive + * type is not a line. + * First and last point are alwyas preserved. + * + * @param skipVertexCount + * Number of vertices to skip. + */ +void +GraphicsPrimitive::simplfyLines(const int32_t skipVertexCount) +{ + if (skipVertexCount < 2) { + return; + } + + bool lineTypeFlag(false); + switch (m_primitiveType) { + case PrimitiveType::OPENGL_LINE_LOOP: + lineTypeFlag = true; + break; + case PrimitiveType::OPENGL_LINE_STRIP: + lineTypeFlag = true; + break; + case PrimitiveType::OPENGL_LINES: + break; + case PrimitiveType::OPENGL_POINTS: + break; + case PrimitiveType::OPENGL_TRIANGLE_FAN: + break; + case PrimitiveType::OPENGL_TRIANGLE_STRIP: + break; + case PrimitiveType::OPENGL_TRIANGLES: + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: + lineTypeFlag = true; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: + lineTypeFlag = true; + break; + case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: + lineTypeFlag = true; + break; + case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: + lineTypeFlag = true; + break; + case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: + lineTypeFlag = true; + break; + case PrimitiveType::POLYGONAL_LINES: + lineTypeFlag = true; + break; + case PrimitiveType::SPHERES: + break; + } + + if ( ! lineTypeFlag) { + return; + } + + std::vector xyz; + std::vector normals; + std::vector rgbaFloat; + std::vector rgbaByte; + std::vector textureSTR; + + const int32_t numVertices = getNumberOfVertices(); + xyz.reserve(m_xyz.size()); + normals.reserve(m_floatNormalVectorXYZ.size()); + rgbaFloat.reserve(m_floatRGBA.size()); + rgbaByte.reserve(m_unsignedByteRGBA.size()); + textureSTR.reserve(m_floatTextureSTR.size()); + + const int32_t lastIndex = numVertices - 1; + for (int32_t i = 0; i < numVertices; i++) { + bool addFlag(false); + if (i == 0) { + addFlag = true; + } + else if (i == lastIndex) { + addFlag = true; + } + else { + const int remainder = i % skipVertexCount; + if (remainder == 0) { + addFlag = true; + } + } + + if (addFlag) { + std::cout << "Adding vertex: " << i << std::endl; + + const int32_t i3 = i * 3; + const int32_t i4 = i * 4; + switch (m_vertexDataType) { + case VertexDataType::FLOAT_XYZ: + xyz.push_back(m_xyz[i3]); + xyz.push_back(m_xyz[i3+1]); + xyz.push_back(m_xyz[i3+2]); + break; + } + + switch (m_normalVectorDataType) { + case NormalVectorDataType::FLOAT_XYZ: + normals.push_back(m_floatNormalVectorXYZ[i3]); + normals.push_back(m_floatNormalVectorXYZ[i3+1]); + normals.push_back(m_floatNormalVectorXYZ[i3+2]); + break; + case NormalVectorDataType::NONE: + break; + } + + switch (m_colorDataType) { + case ColorDataType::FLOAT_RGBA: + rgbaFloat.push_back(m_floatRGBA[i4]); + rgbaFloat.push_back(m_floatRGBA[i4+1]); + rgbaFloat.push_back(m_floatRGBA[i4+2]); + rgbaFloat.push_back(m_floatRGBA[i4+3]); + break; + case ColorDataType::UNSIGNED_BYTE_RGBA: + rgbaByte.push_back(m_unsignedByteRGBA[i4]); + rgbaByte.push_back(m_unsignedByteRGBA[i4+1]); + rgbaByte.push_back(m_unsignedByteRGBA[i4+2]); + rgbaByte.push_back(m_unsignedByteRGBA[i4+3]); + break; + case ColorDataType::NONE: + break; + } + + switch (m_textureDataType) { + case TextureDataType::FLOAT_STR: + textureSTR.push_back(m_floatTextureSTR[i3]); + textureSTR.push_back(m_floatTextureSTR[i3+1]); + textureSTR.push_back(m_floatTextureSTR[i3+2]); + break; + case TextureDataType::NONE: + break; + } + } + } + + m_xyz = std::move(xyz); + m_floatNormalVectorXYZ = normals; + m_floatRGBA = rgbaFloat; + m_unsignedByteRGBA = rgbaByte; + m_floatTextureSTR = textureSTR; +} + /** * Get the OpenGL graphics engine data in this instance. * diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index b8374dcc22e4255ade52274165d4713f9d4fc179..bfc30a56e7d921a85bd46c1f79573c6840faf813 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -146,26 +146,60 @@ namespace caret { OPENGL_TRIANGLES, /** * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a BEVEL join at vertices. + * Draws in MODEL space so lines are affected by model transformations + */ + MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN, + /** + * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a MITER join at vertices + * Draws in MODEL space so lines are affected by model transformations + */ + MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN, + /** + * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a BEVEL join at vertices + * Draws in MODEL space so lines are affected by model transformations + */ + MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN, + /** + * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a MITER join at vertices + * Draws in MODEL space so lines are affected by model transformations + */ + MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN, + /** + * Like OPENGL_LINES but there is no limit on line width as it draws the lines using polygons. + * Draws in MODEL space so lines are affected by model transformations + */ + MODEL_SPACE_POLYGONAL_LINES, + /** + * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a BEVEL join at vertices. + * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_LOOP_BEVEL_JOIN, /** * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a MITER join at vertices + * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_LOOP_MITER_JOIN, /** * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a BEVEL join at vertices + * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_STRIP_BEVEL_JOIN, /** * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a MITER join at vertices + * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_STRIP_MITER_JOIN, /** * Like OPENGL_LINES but there is no limit on line width as it draws the lines using polygons. + * Lines drawn in window space so that lines always face user */ POLYGONAL_LINES, /* @@ -335,6 +369,9 @@ namespace caret { */ const std::vector& getFloatXYZ() const { return m_xyz; } + void getVertexFloatXYZ(const int32_t vertexIndex, + float xyzOut[3]) const; + void replaceFloatXYZ(const std::vector& xyz); /** @@ -395,6 +432,8 @@ namespace caret { * Clone this primitive. */ virtual GraphicsPrimitive* clone() const = 0; + + void simplfyLines(const int32_t skipVertexCount); protected: AString toStringPrivate(const bool includeAllDataFlag) const; @@ -485,14 +524,11 @@ namespace caret { std::vector m_floatTextureSTR; std::vector m_textureImageBytesRGBA; + friend class GraphicsEngineDataOpenGL; friend class GraphicsOpenGLPolylineTriangles; friend class GraphicsPrimitiveSelectionHelper; - std::vector m_dummyFloatRGBAVector; - - std::vector m_dummyUnsignedByteRGBAVector; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index e1f2a2d06b86d31f74ec7a8e568c2de2c5cda3c8..ca3397ccd7988f19e338b3bb1f76c4ae553671dc 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -74,15 +74,20 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() switch (m_parentGraphicsPrimitive->getPrimitiveType()) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: - m_numberOfVerticesPerPrimitive = numberOfVertices; + m_numberOfVerticesPerPrimitive = 1; //numberOfVertices; break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: - m_numberOfVerticesPerPrimitive = numberOfVertices; + m_numberOfVerticesPerPrimitive = 1; //numberOfVertices; break; + case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: m_numberOfVerticesPerPrimitive = 2; diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx index f9e36fa1e4943f521cc5c6f35ee4c3a36af9a4ce..06797069d88c5bf752cbdc18ef33c85a415f265b 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -118,6 +118,18 @@ GraphicsPrimitiveV3f::copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& } } +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + */ +void +GraphicsPrimitiveV3f::addVertex(const double xyz[3]) +{ + addVertex(xyz[0], xyz[1], xyz[2]); +} + /** * Add a vertex. * diff --git a/src/Graphics/GraphicsPrimitiveV3f.h b/src/Graphics/GraphicsPrimitiveV3f.h index f11925420ea9f63eb7cf2bb58935d5016574df55..ff93e641f551fad5e8b853f53656633ca80018af 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.h +++ b/src/Graphics/GraphicsPrimitiveV3f.h @@ -46,6 +46,8 @@ namespace caret { void addVertex(const float xyz[3]); + void addVertex(const double xyz[3]); + void addVertex(const float x, const float y, const float z); diff --git a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx index 2062aef84925ab896732c2f688fdf01541285b7b..e30f31957ea44b03d4ec975a4b44fde3131125d4 100644 --- a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx @@ -137,6 +137,35 @@ GraphicsPrimitiveV3fN3f::addVertex(const float xyz[3], NULL); } +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + * @param normalXYZ + * Normal vector + */ +void +GraphicsPrimitiveV3fN3f::addVertex(const double xyz[3], + const double normalXYZ[3]) +{ + const float floatXYZ[] { + static_cast(xyz[0]), + static_cast(xyz[1]), + static_cast(xyz[2]) + }; + const float floatNormalXYZ[3] { + static_cast(normalXYZ[0]), + static_cast(normalXYZ[1]), + static_cast(normalXYZ[2]) + }; + addVertexProtected(floatXYZ, + floatNormalXYZ, + m_floatSolidRGBA, + m_unsignedByteSolidRGBA, + NULL); +} + /** * Add a vertex. * diff --git a/src/Graphics/GraphicsPrimitiveV3fN3f.h b/src/Graphics/GraphicsPrimitiveV3fN3f.h index 85a49cc1f2c4706d97dbfcd6f9aa418dc7a2c1cb..444285110c31655a4332044927cffc6adcd70a85 100644 --- a/src/Graphics/GraphicsPrimitiveV3fN3f.h +++ b/src/Graphics/GraphicsPrimitiveV3fN3f.h @@ -47,6 +47,9 @@ namespace caret { void addVertex(const float xyz[3], const float normalXYZ[3]); + void addVertex(const double xyz[3], + const double normalXYZ[3]); + void addVertex(const float x, const float y, const float z, diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index dd58b47cb8360b0e0c58c824d8c27ceae7f44fee..687f8dd8be84d191459dd7624da87a9ea7899a18 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -287,6 +287,42 @@ GraphicsShape::drawEllipseOutlineByteColor(const double majorAxis, GraphicsEngineDataOpenGL::draw(primitive.get()); } +/** + * Draw an outline ellipse in the XY plane (all Z-coordinates will be zero). + * + * @param majorAxis + * Diameter of the major axis. + * @param minorAxis + * Diameter of the minor axis. + * @param rgba + * Color for drawing. + * @param lineThickness + * Thickness of the line. + */ +void +GraphicsShape::drawEllipseOutlineModelSpaceByteColor(const double majorAxis, + const double minorAxis, + const uint8_t rgba[4], + const double lineThickness) +{ + std::vector ellipseXYZ; + createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); + + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN, + rgba)); + const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); + primitive->reserveForNumberOfVertices(numVertices); + for (int32_t i = 0; i < numVertices; i++) { + primitive->addVertex(&ellipseXYZ[i * 3]); + } + + primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, + lineThickness); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(primitive.get()); +} + /** * Draw a filled ellipse. * @@ -1178,6 +1214,305 @@ GraphicsShape::updateModelMatrixToFaceViewer() glScalef(sx, sy, sz); } + +/** + * Draw an rectangle outline. + * The normal vector is computed from three consecutive vertices in the rectangle. + * + * @param bottomLeft + * Bottom left vertex of the rectangle. + * @param bottomRight + * Bottom right vertex of the rectangle. + * @param topRight + * Top right vertex of the rectangle. + * @param topLeft + * Top left vertex of the rectangle. + * @param thickness + * Thickness of the outline + * @param rgba + * RGBA color for the outline. + * @param verticesInMiddleFlag + * If true, the lines are centered around the vertices. Otherwise, + * the inner sides of the lines are tangent to the vertices. + */ +void +GraphicsShape::drawOutlineRectanglePrivate(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3], + const float thicknessIn, + const uint8_t rgba[4], + bool verticesInMiddleFlag) +{ + const double bl[3] { bottomLeft[0], bottomLeft[1], bottomLeft[2] }; + const double br[3] { bottomRight[0], bottomRight[1], bottomRight[2] }; + const double tr[3] { topRight[0], topRight[1], topRight[2] }; + const double tl[3] { topLeft[0], topLeft[1], topLeft[2] }; + + drawOutlineRectanglePrivate(bl, br, tr, tl, thicknessIn, rgba, verticesInMiddleFlag); +} + +/** + * Draw an rectangle outline. + * The normal vector is computed from three consecutive vertices in the rectangle. + * + * @param bottomLeft + * Bottom left vertex of the rectangle. + * @param bottomRight + * Bottom right vertex of the rectangle. + * @param topRight + * Top right vertex of the rectangle. + * @param topLeft + * Top left vertex of the rectangle. + * @param thickness + * Thickness of the outline + * @param rgba + * RGBA color for the outline. + * @param verticesInMiddleFlag + * If true, the lines are centered around the vertices. Otherwise, + * the inner sides of the lines are tangent to the vertices. + */ +void +GraphicsShape::drawOutlineRectanglePrivate(const double bottomLeft[3], + const double bottomRight[3], + const double topRight[3], + const double topLeft[3], + const double thicknessIn, + const uint8_t rgba[4], + bool verticesInMiddleFlag) +{ + double bottomLeftInner[3] = { bottomLeft[0], bottomLeft[1], bottomLeft[2] }; + double bottomLeftOuter[3] = { bottomLeft[0], bottomLeft[1], bottomLeft[2] }; + double bottomRightInner[3] = { bottomRight[0], bottomRight[1], bottomRight[2] }; + double bottomRightOuter[3] = { bottomRight[0], bottomRight[1], bottomRight[2] }; + double topRightInner[3] = { topRight[0], topRight[1], topRight[2] }; + double topRightOuter[3] = { topRight[0], topRight[1], topRight[2] }; + double topLeftInner[3] = { topLeft[0], topLeft[1], topLeft[2] }; + double topLeftOuter[3] = { topLeft[0], topLeft[1], topLeft[2] }; + + + /* + * Limit thickness of the outline to half of width or height + * when points in middle + */ + const double boxHeight = MathFunctions::distance3D(bottomLeft, topLeft); + const double boxWidth = MathFunctions::distance3D(bottomLeft, bottomRight); + double thickness = thicknessIn; + if (verticesInMiddleFlag) { + thickness /= 2.0; + thickness = std::min(thickness, + boxWidth / 2.0); + thickness = std::min(thickness, + boxHeight / 2.0); + } + + /* + * Horizontal contraction/expansion of vertices + */ + double horizVector[3]; + MathFunctions::subtractVectors(bottomRight, bottomLeft, horizVector); + MathFunctions::normalizeVector(horizVector); + horizVector[0] *= thickness; + horizVector[1] *= thickness; + horizVector[2] *= thickness; + + MathFunctions::subtractOffsetFromVector(bottomLeftOuter, horizVector); + MathFunctions::subtractOffsetFromVector(topLeftOuter, horizVector); + MathFunctions::addOffsetToVector(bottomRightOuter, horizVector); + MathFunctions::addOffsetToVector(topRightOuter, horizVector); + if (verticesInMiddleFlag) { + MathFunctions::subtractOffsetFromVector(bottomRightInner, horizVector); + MathFunctions::subtractOffsetFromVector(topRightInner, horizVector); + MathFunctions::addOffsetToVector(bottomLeftInner, horizVector); + MathFunctions::addOffsetToVector(topLeftInner, horizVector); + } + + /* + * Vertical contraction/expansion of vertices + */ + double vertVector[3]; + MathFunctions::subtractVectors(topLeft, bottomLeft, vertVector); + MathFunctions::normalizeVector(vertVector); + vertVector[0] *= thickness; + vertVector[1] *= thickness; + vertVector[2] *= thickness; + + MathFunctions::subtractOffsetFromVector(bottomRightOuter, vertVector); + MathFunctions::subtractOffsetFromVector(bottomLeftOuter, vertVector); + MathFunctions::addOffsetToVector(topLeftOuter, vertVector); + MathFunctions::addOffsetToVector(topRightOuter, vertVector); + if (verticesInMiddleFlag) { + MathFunctions::subtractOffsetFromVector(topLeftInner, vertVector); + MathFunctions::subtractOffsetFromVector(topRightInner, vertVector); + MathFunctions::addOffsetToVector(bottomRightInner, vertVector); + MathFunctions::addOffsetToVector(bottomLeftInner, vertVector); + } + + /* + * Use three consecutive vertices to calculate normal vector + */ + double normalVector[3]; + MathFunctions::normalVector(bottomRight, topRight, topLeft, normalVector); + + /* + * Draw the outline as triangles using a triangle strip + */ + GraphicsPrimitiveV3fN3f primitive(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, + rgba); + primitive.addVertex(bottomRightInner, normalVector); + primitive.addVertex(bottomRightOuter, normalVector); + primitive.addVertex(topRightInner, normalVector); + primitive.addVertex(topRightOuter, normalVector); + primitive.addVertex(topLeftInner, normalVector); + primitive.addVertex(topLeftOuter, normalVector); + primitive.addVertex(bottomLeftInner, normalVector); + primitive.addVertex(bottomLeftOuter, normalVector); + primitive.addVertex(bottomRightInner, normalVector); + primitive.addVertex(bottomRightOuter, normalVector); + + GraphicsEngineDataOpenGL::draw(&primitive); +} + +/** + * Draw an rectangle outline. + * The given points are in the middle of outline. + * The normal vector is computed from three consecutive vertices in the rectangle. + * + * @param bottomLeft + * Bottom left vertex of the rectangle. + * @param bottomRight + * Bottom right vertex of the rectangle. + * @param topRight + * Top right vertex of the rectangle. + * @param topLeft + * Top left vertex of the rectangle. + * @param thickness + * Thickness of the outline + * @param rgba + * RGBA color for the outline. + */ +void +GraphicsShape::drawOutlineRectangleVerticesInMiddle(const double bottomLeft[3], + const double bottomRight[3], + const double topRight[3], + const double topLeft[3], + const double thickness, + const uint8_t rgba[4]) +{ + drawOutlineRectanglePrivate(bottomLeft, + bottomRight, + topRight, + topLeft, + thickness, + rgba, + true); +} + +/** + * Draw an rectangle outline. + * The given points are in the middle of outline. + * The normal vector is computed from three consecutive vertices in the rectangle. + * + * @param bottomLeft + * Bottom left vertex of the rectangle. + * @param bottomRight + * Bottom right vertex of the rectangle. + * @param topRight + * Top right vertex of the rectangle. + * @param topLeft + * Top left vertex of the rectangle. + * @param thickness + * Thickness of the outline + * @param rgba + * RGBA color for the outline. + */ +void +GraphicsShape::drawOutlineRectangleVerticesInMiddle(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3], + const float thickness, + const uint8_t rgba[4]) +{ + drawOutlineRectanglePrivate(bottomLeft, + bottomRight, + topRight, + topLeft, + thickness, + rgba, + true); +} + +/** + * Draw an rectangle outline. + * The given points are at the inside of outline. + * The normal vector is computed from three consecutive vertices in the rectangle. + * + * @param bottomLeft + * Bottom left vertex of the rectangle. + * @param bottomRight + * Bottom right vertex of the rectangle. + * @param topRight + * Top right vertex of the rectangle. + * @param topLeft + * Top left vertex of the rectangle. + * @param thickness + * Thickness of the outline + * @param rgba + * RGBA color for the outline. + */ +void +GraphicsShape::drawOutlineRectangleVerticesAtInside(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3], + const float thickness, + const uint8_t rgba[4]) +{ + drawOutlineRectanglePrivate(bottomLeft, + bottomRight, + topRight, + topLeft, + thickness, + rgba, + false); +} + +/** + * Draw an rectangle outline. + * The given points are at the inside of outline. + * The normal vector is computed from three consecutive vertices in the rectangle. + * + * @param bottomLeft + * Bottom left vertex of the rectangle. + * @param bottomRight + * Bottom right vertex of the rectangle. + * @param topRight + * Top right vertex of the rectangle. + * @param topLeft + * Top left vertex of the rectangle. + * @param thickness + * Thickness of the outline + * @param rgba + * RGBA color for the outline. + */ +void +GraphicsShape::drawOutlineRectangleVerticesAtInside(const double bottomLeft[3], + const double bottomRight[3], + const double topRight[3], + const double topLeft[3], + const double thickness, + const uint8_t rgba[4]) +{ + drawOutlineRectanglePrivate(bottomLeft, + bottomRight, + topRight, + topLeft, + thickness, + rgba, + false); +} + /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index db9faedbeff5fcce1eb0402da6492e890af7c244..d77d6b6dde9d835cc7ab6fe459bb0bd33f720f08 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -78,6 +78,11 @@ namespace caret { const double minorAxis, const uint8_t rgba[4]); + static void drawEllipseOutlineModelSpaceByteColor(const double majorAxis, + const double minorAxis, + const uint8_t rgba[4], + const double lineThickness); + static void drawLinesByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, @@ -122,6 +127,34 @@ namespace caret { static void deleteAllPrimitives(); + static void drawOutlineRectangleVerticesInMiddle(const double bottomLeft[3], + const double bottomRight[3], + const double topRight[3], + const double topLeft[3], + const double thickness, + const uint8_t rgba[4]); + + static void drawOutlineRectangleVerticesInMiddle(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3], + const float thickness, + const uint8_t rgba[4]); + + static void drawOutlineRectangleVerticesAtInside(const double bottomLeft[3], + const double bottomRight[3], + const double topRight[3], + const double topLeft[3], + const double thickness, + const uint8_t rgba[4]); + + static void drawOutlineRectangleVerticesAtInside(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3], + const float thickness, + const uint8_t rgba[4]); + // ADD_NEW_METHODS_HERE virtual AString toString() const; @@ -195,6 +228,22 @@ namespace caret { float xyzOut[3], float normalXyzOut[3]); + static void drawOutlineRectanglePrivate(const double bottomLeft[3], + const double bottomRight[3], + const double topRight[3], + const double topLeft[3], + const double thicknessIn, + const uint8_t rgba[4], + bool verticesInMiddleFlag); + + static void drawOutlineRectanglePrivate(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3], + const float thicknessIn, + const uint8_t rgba[4], + bool verticesInMiddleFlag); + static std::unique_ptr s_byteSquarePrimitive; static std::map s_byteSpherePrimitives; diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.cxx b/src/Graphics/GraphicsUtilitiesOpenGL.cxx index 8f1b4936f2410ebcac9c6a19f478dad0f6197532..93e99ce8e8c932e46017edb53cfb5328a5fe0a71 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.cxx +++ b/src/Graphics/GraphicsUtilitiesOpenGL.cxx @@ -88,6 +88,47 @@ GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(const float p } +/** + * Converts percentage of viewport height to millimeters. + * The current transformations must be for drawing in millimeters. + * + * @param percentOfViewportHeight + * The value in percentage of viewport height. + * @return + * Millimeters + */ +float +GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(const float percentOfViewportHeight) +{ + float millimeters = -1.0f; + + EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); + EventManager::get()->sendEvent(xform.getPointer()); + if (xform.isValid()) { + const std::array viewport = xform.getViewport(); + + const float windowZ = 0.0f; + float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; + float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; + + float bottomModelXYZ[3]; + float topModelXYZ[3]; + + xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); + xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); + + const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, + topModelXYZ); + const float rangePixels = viewport[3]; + if ((rangePixels > 0) + && (rangeMillimeters > 0)) { + millimeters = (percentOfViewportHeight / 100.0) * rangeMillimeters; + } + } + + return millimeters ; +} + /** * Converts millimeters to a percentage of the viewport height. * The current transformations must be for drawing in millimeters. @@ -171,6 +212,48 @@ GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(const float pixels) return mm; } +/** + * Convert millimeters to pixels. + * The current transformations must be for drawing in millimeters. + * + * @param millimeters + * The millimeters size + * @return + * Pixels value. + */ +float +GraphicsUtilitiesOpenGL::convertMillimetersToPixels(const float millimeters) +{ + float pixels = 1.0f; + + EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); + EventManager::get()->sendEvent(xform.getPointer()); + if (xform.isValid()) { + const std::array viewport = xform.getViewport(); + + const float windowZ = 0.0f; + float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; + float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; + + float bottomModelXYZ[3]; + float topModelXYZ[3]; + + xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); + xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); + + const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, + topModelXYZ); + const float rangePixels = viewport[3]; + if ((rangePixels > 0) + && (rangeMillimeters > 0)) { + const float ratio = rangePixels / rangeMillimeters; + pixels = millimeters * ratio; + } + } + + return pixels; +} + /** * Reset and ignore any OpenGL errors. */ diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.h b/src/Graphics/GraphicsUtilitiesOpenGL.h index fda72fb2eddaebdec0064d486a6c2ba5ad39f954..9bc38f405a07bb9fd51f830b433a680340feb523 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.h +++ b/src/Graphics/GraphicsUtilitiesOpenGL.h @@ -37,6 +37,10 @@ namespace caret { static float convertMillimetersToPercentageOfViewportHeight(const float millimeters); + static float convertPercentageOfViewportHeightToMillimeters(const float percentOfViewportHeight); + + static float convertMillimetersToPixels(const float millimeters); + static float convertPixelsToPercentageOfViewportHeight(const float pixels); static float convertPixelsToMillimeters(const float pixels); diff --git a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx index aa6f28b1e813c4cbf2aa1059a3360efe114c8d8a..b54eee7c7bedcfa0952755c056a8d20715e03f9d 100644 --- a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx +++ b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx @@ -117,6 +117,9 @@ AnnotationChangeCoordinateDialog::createCurrentCoordinateWidget() switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + spaceText += m_annotation->getSpacerTabIndex().getRowColumnGuiText(); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index 0fa8a6f4afed6b8f53b19e89b80922deae7e91ad..83a4a03d67e0439298c5af6ecc6f85b18b5edb6d 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -37,6 +37,7 @@ #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "SelectionManager.h" +#include "SpacerTabContent.h" #include "Surface.h" using namespace caret; @@ -72,38 +73,12 @@ AnnotationCoordinateInformation::~AnnotationCoordinateInformation() */ void AnnotationCoordinateInformation::reset() { - m_modelXYZValid = false; - m_surfaceNodeValid = false; - m_surfaceStructure = StructureEnum::INVALID; - m_surfaceNumberOfNodes = 0; - m_surfaceNodeIndex = -1; - m_surfaceNodeOffset = 0.0; - m_surfaceNodeVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; - m_tabIndex = -1; - m_tabWidth = 0; - m_tabHeight = 0; - m_windowIndex = -1; - m_windowWidth = 0; - m_windowHeight = 0; - m_modelXYZ[0] = 0.0; - m_modelXYZ[1] = 0.0; - m_modelXYZ[2] = 0.0; - m_tabXYZ[0] = 0.0; - m_tabXYZ[1] = 0.0; - m_tabXYZ[2] = 0.0; - m_tabPixelXYZ[0] = 0.0; - m_tabPixelXYZ[1] = 0.0; - m_tabPixelXYZ[2] = 0.0; - m_windowXYZ[0] = 0.0; - m_windowXYZ[1] = 0.0; - m_windowXYZ[2] = 0.0; - m_windowPixelXYZ[0] = 0.0; - m_windowPixelXYZ[1] = 0.0; - m_windowPixelXYZ[2] = 0.0; - m_chartXYZ[0] = 0.0; - m_chartXYZ[1] = 0.0; - m_chartXYZ[2] = 0.0; - m_chartXYZValid = false; + m_modelSpaceInfo = ModelSpaceInfo(); + m_tabSpaceInfo = TabWindowSpaceInfo(); + m_windowSpaceInfo = TabWindowSpaceInfo(); + m_chartSpaceInfo = ChartSpaceInfo(); + m_surfaceSpaceInfo = SurfaceSpaceInfo(); + m_spacerTabSpaceInfo = SpacerTabSpaceInfo(); } bool @@ -113,22 +88,25 @@ AnnotationCoordinateInformation::isCoordinateSpaceValid(const AnnotationCoordina switch (space) { case AnnotationCoordinateSpaceEnum::CHART: - validSpaceFlag = m_chartXYZValid; + validSpaceFlag = m_chartSpaceInfo.m_validFlag; + break; + case AnnotationCoordinateSpaceEnum::SPACER: + validSpaceFlag = m_spacerTabSpaceInfo.m_spacerTabIndex.isValid(); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - validSpaceFlag = m_modelXYZValid; + validSpaceFlag = m_modelSpaceInfo.m_validFlag; break; case AnnotationCoordinateSpaceEnum::SURFACE: - validSpaceFlag = m_surfaceNodeValid; + validSpaceFlag = m_surfaceSpaceInfo.m_validFlag; break; case AnnotationCoordinateSpaceEnum::TAB: - validSpaceFlag = (m_tabIndex >= 0); + validSpaceFlag = (m_tabSpaceInfo.m_index >= 0); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssertMessage(0, "Should not create/move viewport annotations"); break; case AnnotationCoordinateSpaceEnum::WINDOW: - validSpaceFlag = (m_windowIndex >= 0); + validSpaceFlag = (m_windowSpaceInfo.m_index >= 0); break; } @@ -167,6 +145,7 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::CHART: + case AnnotationCoordinateSpaceEnum::SPACER: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: case AnnotationCoordinateSpaceEnum::TAB: @@ -187,39 +166,46 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi /* * Both coord info's must be in the SAME TAB */ - if (coordInfoOne->m_tabIndex != coordInfoTwo->m_tabIndex) { + if (coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) { + addItFlag = false; + } + break; + case AnnotationCoordinateSpaceEnum::SPACER: + if (coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex != coordInfoTwo->m_spacerTabSpaceInfo.m_spacerTabIndex) { addItFlag = false; } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: /* * Both coord info's must be in the SAME TAB */ - if (coordInfoOne->m_tabIndex != coordInfoTwo->m_tabIndex) { + if (coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) { addItFlag = false; } + break; case AnnotationCoordinateSpaceEnum::SURFACE: /* * Both coord info's must be on same surface and * in the SAME TAB */ - if ((coordInfoOne->m_tabIndex != coordInfoTwo->m_tabIndex) - || (coordInfoOne->m_surfaceNumberOfNodes != coordInfoTwo->m_surfaceNumberOfNodes) - || (coordInfoOne->m_surfaceStructure != coordInfoTwo->m_surfaceStructure)) { + if ((coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) + || (coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes != coordInfoTwo->m_surfaceSpaceInfo.m_numberOfNodes) + || (coordInfoOne->m_surfaceSpaceInfo.m_structure != coordInfoTwo->m_surfaceSpaceInfo.m_structure)) { addItFlag = false; } break; case AnnotationCoordinateSpaceEnum::TAB: - if (coordInfoOne->m_tabIndex != coordInfoTwo->m_tabIndex) { + if (coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) { addItFlag = false; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: -// if (coordInfoOne->m_windowIndex != coordInfoTwo->m_windowIndex) { -// addItFlag = false; -// } + //if (coordInfoOne->m_windowIndex != coordInfoTwo->m_windowIndex) { + // addItFlag = false; + //} break; case AnnotationCoordinateSpaceEnum::WINDOW: - if (coordInfoOne->m_windowIndex != coordInfoTwo->m_windowIndex) { + if (coordInfoOne->m_windowSpaceInfo.m_index != coordInfoTwo->m_windowSpaceInfo.m_index) { addItFlag = false; } break; @@ -311,21 +297,23 @@ AnnotationCoordinateInformation::createCoordinateInformationFromXY(BrainOpenGLWi SelectionItemVoxel* voxelID = idManager->getVoxelIdentification(); SelectionItemSurfaceNode* surfaceNodeIdentification = idManager->getSurfaceNodeIdentification(); if (surfaceNodeIdentification->isValid()) { - surfaceNodeIdentification->getModelXYZ(coordInfoOut.m_modelXYZ); - coordInfoOut.m_modelXYZValid = true; + surfaceNodeIdentification->getModelXYZ(coordInfoOut.m_modelSpaceInfo.m_xyz); + coordInfoOut.m_modelSpaceInfo.m_validFlag = true; const Surface* surface = surfaceNodeIdentification->getSurface(); CaretAssert(surface); - coordInfoOut.m_surfaceNumberOfNodes = surface->getNumberOfNodes(); - coordInfoOut.m_surfaceStructure = surface->getStructure(); - coordInfoOut.m_surfaceNodeIndex = surfaceNodeIdentification->getNodeNumber(); - coordInfoOut.m_surfaceNodeOffset = AnnotationCoordinate::getDefaultSurfaceOffsetLength(); - coordInfoOut.m_surfaceNodeVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; - coordInfoOut.m_surfaceNodeValid = true; + coordInfoOut.m_surfaceSpaceInfo.m_numberOfNodes = surface->getNumberOfNodes(); + coordInfoOut.m_surfaceSpaceInfo.m_structure = surface->getStructure(); + coordInfoOut.m_surfaceSpaceInfo.m_nodeIndex = surfaceNodeIdentification->getNodeNumber(); + coordInfoOut.m_surfaceSpaceInfo.m_nodeOffsetLength = AnnotationCoordinate::getDefaultSurfaceOffsetLength(); + coordInfoOut.m_surfaceSpaceInfo.m_nodeVectorOffsetType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; + surface->getNormalVector(surfaceNodeIdentification->getNodeNumber(), + coordInfoOut.m_surfaceSpaceInfo.m_nodeNormalVector); + coordInfoOut.m_surfaceSpaceInfo.m_validFlag = true; } else if (voxelID->isValid()) { - voxelID->getModelXYZ(coordInfoOut.m_modelXYZ); - coordInfoOut.m_modelXYZValid = true; + voxelID->getModelXYZ(coordInfoOut.m_modelSpaceInfo.m_xyz); + coordInfoOut.m_modelSpaceInfo.m_validFlag = true; } /* @@ -343,15 +331,15 @@ AnnotationCoordinateInformation::createCoordinateInformationFromXY(BrainOpenGLWi && (tabX < 100.0) && (tabY >= 0.0) && (tabY <= 100.0)) { - coordInfoOut.m_tabXYZ[0] = tabX; - coordInfoOut.m_tabXYZ[1] = tabY; - coordInfoOut.m_tabXYZ[2] = 0.0; - coordInfoOut.m_tabPixelXYZ[0] = (windowX - tabViewport[0]); - coordInfoOut.m_tabPixelXYZ[1] = (windowY - tabViewport[1]); - coordInfoOut.m_tabPixelXYZ[2] = 0; - coordInfoOut.m_tabIndex = tabContent->getTabNumber(); - coordInfoOut.m_tabWidth = tabViewport[2]; - coordInfoOut.m_tabHeight = tabViewport[3]; + coordInfoOut.m_tabSpaceInfo.m_xyz[0] = tabX; + coordInfoOut.m_tabSpaceInfo.m_xyz[1] = tabY; + coordInfoOut.m_tabSpaceInfo.m_xyz[2] = 0.0; + coordInfoOut.m_tabSpaceInfo.m_pixelXYZ[0] = (windowX - tabViewport[0]); + coordInfoOut.m_tabSpaceInfo.m_pixelXYZ[1] = (windowY - tabViewport[1]); + coordInfoOut.m_tabSpaceInfo.m_pixelXYZ[2] = 0.0; + coordInfoOut.m_tabSpaceInfo.m_index = tabContent->getTabNumber(); + coordInfoOut.m_tabSpaceInfo.m_width = tabViewport[2]; + coordInfoOut.m_tabSpaceInfo.m_height = tabViewport[3]; } } @@ -377,30 +365,53 @@ AnnotationCoordinateInformation::createCoordinateInformationFromXY(BrainOpenGLWi if (gluUnProject(windowX, windowY, 0.0, modelviewArray, projectionArray, viewport, &chartX, &chartY, &chartZ) == GL_TRUE) { - coordInfoOut.m_chartXYZ[0] = static_cast(chartX); - coordInfoOut.m_chartXYZ[1] = static_cast(chartY); - coordInfoOut.m_chartXYZ[2] = static_cast(chartZ); - coordInfoOut.m_chartXYZValid = true; + coordInfoOut.m_chartSpaceInfo.m_xyz[0] = static_cast(chartX); + coordInfoOut.m_chartSpaceInfo.m_xyz[1] = static_cast(chartY); + coordInfoOut.m_chartSpaceInfo.m_xyz[2] = static_cast(chartZ); + coordInfoOut.m_chartSpaceInfo.m_validFlag = true; } } } } + SpacerTabContent* spacerTabContent = viewportContent->getSpacerTabContent(); + if (spacerTabContent != NULL) { + int tabViewport[4]; + viewportContent->getModelViewport(tabViewport); + const float tabX = 100.0 * (windowX - tabViewport[0]) / static_cast(tabViewport[2]); + const float tabY = 100.0 * (windowY - tabViewport[1]) / static_cast(tabViewport[3]); + if ((tabX >= 0.0) + && (tabX < 100.0) + && (tabY >= 0.0) + && (tabY <= 100.0)) { + coordInfoOut.m_spacerTabSpaceInfo.m_xyz[0] = tabX; + coordInfoOut.m_spacerTabSpaceInfo.m_xyz[1] = tabY; + coordInfoOut.m_spacerTabSpaceInfo.m_xyz[2] = 0.0; + coordInfoOut.m_spacerTabSpaceInfo.m_pixelXYZ[0] = (windowX - tabViewport[0]); + coordInfoOut.m_spacerTabSpaceInfo.m_pixelXYZ[1] = (windowY - tabViewport[1]); + coordInfoOut.m_spacerTabSpaceInfo.m_pixelXYZ[2] = 0.0; + coordInfoOut.m_spacerTabSpaceInfo.m_spacerTabIndex = spacerTabContent->getSpacerTabIndex(); + coordInfoOut.m_spacerTabSpaceInfo.m_validFlag = spacerTabContent->getSpacerTabIndex().isValid(); + coordInfoOut.m_spacerTabSpaceInfo.m_width = tabViewport[2]; + coordInfoOut.m_spacerTabSpaceInfo.m_height = tabViewport[3]; + } + } + int windowViewport[4]; viewportContent->getWindowViewport(windowViewport); - coordInfoOut.m_windowPixelXYZ[0] = windowX - windowViewport[0]; - coordInfoOut.m_windowPixelXYZ[1] = windowY - windowViewport[1]; - coordInfoOut.m_windowPixelXYZ[2] = 0.0; - coordInfoOut.m_windowIndex = viewportContent->getWindowIndex(); - coordInfoOut.m_windowWidth = windowViewport[2]; - coordInfoOut.m_windowHeight = windowViewport[3]; + coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[0] = windowX - windowViewport[0]; + coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[1] = windowY - windowViewport[1]; + coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[2] = 0.0; + coordInfoOut.m_windowSpaceInfo.m_index = viewportContent->getWindowIndex(); + coordInfoOut.m_windowSpaceInfo.m_width = windowViewport[2]; + coordInfoOut.m_windowSpaceInfo.m_height = windowViewport[3]; /* * Normalize window coordinates (width and height range [0, 100] */ - coordInfoOut.m_windowXYZ[0] = 100.0 * (coordInfoOut.m_windowPixelXYZ[0] / windowViewport[2]); - coordInfoOut.m_windowXYZ[1] = 100.0 * (coordInfoOut.m_windowPixelXYZ[1] / windowViewport[3]); - coordInfoOut.m_windowXYZ[2] = 0.0; + coordInfoOut.m_windowSpaceInfo.m_xyz[0] = 100.0 * (coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[0] / windowViewport[2]); + coordInfoOut.m_windowSpaceInfo.m_xyz[1] = 100.0 * (coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[1] / windowViewport[3]); + coordInfoOut.m_windowSpaceInfo.m_xyz[2] = 0.0; } /** @@ -474,44 +485,78 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: - if (coordInfoOne->m_chartXYZValid) { - startCoordinate->setXYZ(coordInfoOne->m_chartXYZ); + if (coordInfoOne->m_chartSpaceInfo.m_validFlag) { + startCoordinate->setXYZ(coordInfoOne->m_chartSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); validCoordinateFlag = true; if (coordInfoTwo != NULL) { - if (coordInfoTwo->m_chartXYZValid) { + if (coordInfoTwo->m_chartSpaceInfo.m_validFlag) { if (endCoordinate != NULL) { - endCoordinate->setXYZ(coordInfoTwo->m_chartXYZ); + endCoordinate->setXYZ(coordInfoTwo->m_chartSpaceInfo.m_xyz); } } } } break; + case AnnotationCoordinateSpaceEnum::SPACER: + if (coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { + startCoordinate->setXYZ(coordInfoOne->m_spacerTabSpaceInfo.m_xyz); + annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER); + annotation->setSpacerTabIndex(coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex); + + validCoordinateFlag = true; + + + if (coordInfoTwo != NULL) { + if (coordInfoTwo->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { + if (endCoordinate != NULL) { + endCoordinate->setXYZ(coordInfoTwo->m_spacerTabSpaceInfo.m_xyz); + } + } + } + else if (endCoordinate != NULL) { + double xyz[3] = { + coordInfoOne->m_spacerTabSpaceInfo.m_xyz[0], + coordInfoOne->m_spacerTabSpaceInfo.m_xyz[1], + coordInfoOne->m_spacerTabSpaceInfo.m_xyz[2] + }; + if (xyz[1] > 50.0) { + xyz[1] -= 25.0; + endCoordinate->setXYZ(xyz); + } + else { + xyz[1] += 25.0; + endCoordinate->setXYZ(coordInfoOne->m_spacerTabSpaceInfo.m_xyz); + startCoordinate->setXYZ(xyz); + } + } + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - if (coordInfoOne->m_modelXYZValid) { - startCoordinate->setXYZ(coordInfoOne->m_modelXYZ); + if (coordInfoOne->m_modelSpaceInfo.m_validFlag) { + startCoordinate->setXYZ(coordInfoOne->m_modelSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); validCoordinateFlag = true; if (coordInfoTwo != NULL) { - if (coordInfoTwo->m_modelXYZValid) { + if (coordInfoTwo->m_modelSpaceInfo.m_validFlag) { if (endCoordinate != NULL) { - endCoordinate->setXYZ(coordInfoTwo->m_modelXYZ); + endCoordinate->setXYZ(coordInfoTwo->m_modelSpaceInfo.m_xyz); } } } } break; case AnnotationCoordinateSpaceEnum::SURFACE: - if (coordInfoOne->m_surfaceNodeValid) { + if (coordInfoOne->m_surfaceSpaceInfo.m_validFlag) { const float surfaceOffsetLength = startCoordinate->getSurfaceOffsetLength(); const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVector = startCoordinate->getSurfaceOffsetVectorType(); - startCoordinate->setSurfaceSpace(coordInfoOne->m_surfaceStructure, - coordInfoOne->m_surfaceNumberOfNodes, - coordInfoOne->m_surfaceNodeIndex, + startCoordinate->setSurfaceSpace(coordInfoOne->m_surfaceSpaceInfo.m_structure, + coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes, + coordInfoOne->m_surfaceSpaceInfo.m_nodeIndex, surfaceOffsetLength, surfaceOffsetVector); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SURFACE); @@ -519,12 +564,11 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati validCoordinateFlag = true; if (coordInfoTwo != NULL) { - if (coordInfoTwo->m_surfaceNodeValid) { + if (coordInfoTwo->m_surfaceSpaceInfo.m_validFlag) { if (endCoordinate != NULL) { - const float surfaceOffsetLength = endCoordinate->getSurfaceOffsetLength(); - endCoordinate->setSurfaceSpace(coordInfoTwo->m_surfaceStructure, - coordInfoTwo->m_surfaceNumberOfNodes, - coordInfoTwo->m_surfaceNodeIndex, + endCoordinate->setSurfaceSpace(coordInfoTwo->m_surfaceSpaceInfo.m_structure, + coordInfoTwo->m_surfaceSpaceInfo.m_numberOfNodes, + coordInfoTwo->m_surfaceSpaceInfo.m_nodeIndex, surfaceOffsetLength, surfaceOffsetVector); } @@ -533,26 +577,26 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati } break; case AnnotationCoordinateSpaceEnum::TAB: - if (coordInfoOne->m_tabIndex >= 0) { - startCoordinate->setXYZ(coordInfoOne->m_tabXYZ); + if (coordInfoOne->m_tabSpaceInfo.m_index >= 0) { + startCoordinate->setXYZ(coordInfoOne->m_tabSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - annotation->setTabIndex(coordInfoOne->m_tabIndex); + annotation->setTabIndex(coordInfoOne->m_tabSpaceInfo.m_index); validCoordinateFlag = true; if (coordInfoTwo != NULL) { - if (coordInfoTwo->m_tabIndex >= 0) { + if (coordInfoTwo->m_tabSpaceInfo.m_index >= 0) { if (endCoordinate != NULL) { - endCoordinate->setXYZ(coordInfoTwo->m_tabXYZ); + endCoordinate->setXYZ(coordInfoTwo->m_tabSpaceInfo.m_xyz); } } } else if (endCoordinate != NULL) { double xyz[3] = { - coordInfoOne->m_tabXYZ[0], - coordInfoOne->m_tabXYZ[1], - coordInfoOne->m_tabXYZ[2] + coordInfoOne->m_tabSpaceInfo.m_xyz[0], + coordInfoOne->m_tabSpaceInfo.m_xyz[1], + coordInfoOne->m_tabSpaceInfo.m_xyz[2] }; if (xyz[1] > 50.0) { xyz[1] -= 25.0; @@ -560,7 +604,7 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati } else { xyz[1] += 25.0; - endCoordinate->setXYZ(coordInfoOne->m_tabXYZ); + endCoordinate->setXYZ(coordInfoOne->m_tabSpaceInfo.m_xyz); startCoordinate->setXYZ(xyz); } } @@ -570,25 +614,25 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: - if (coordInfoOne->m_windowIndex >= 0) { - startCoordinate->setXYZ(coordInfoOne->m_windowXYZ); + if (coordInfoOne->m_windowSpaceInfo.m_index >= 0) { + startCoordinate->setXYZ(coordInfoOne->m_windowSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); - annotation->setWindowIndex(coordInfoOne->m_windowIndex); + annotation->setWindowIndex(coordInfoOne->m_windowSpaceInfo.m_index); validCoordinateFlag = true; if (coordInfoTwo != NULL) { - if (coordInfoTwo->m_windowIndex >= 0) { + if (coordInfoTwo->m_windowSpaceInfo.m_index >= 0) { if (endCoordinate != NULL) { - endCoordinate->setXYZ(coordInfoTwo->m_windowXYZ); + endCoordinate->setXYZ(coordInfoTwo->m_windowSpaceInfo.m_xyz); } } } else if (endCoordinate != NULL) { double xyz[3] = { - coordInfoOne->m_windowXYZ[0], - coordInfoOne->m_windowXYZ[1], - coordInfoOne->m_windowXYZ[2] + coordInfoOne->m_windowSpaceInfo.m_xyz[0], + coordInfoOne->m_windowSpaceInfo.m_xyz[1], + coordInfoOne->m_windowSpaceInfo.m_xyz[2] }; if (xyz[1] > 50.0) { xyz[1] -= 25.0; @@ -596,7 +640,7 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati } else { xyz[1] += 25.0; - endCoordinate->setXYZ(coordInfoOne->m_windowXYZ); + endCoordinate->setXYZ(coordInfoOne->m_windowSpaceInfo.m_xyz); startCoordinate->setXYZ(xyz); } } @@ -640,18 +684,39 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: - if (coordInfoOne->m_chartXYZValid) { - coordinate->setXYZ(coordInfoOne->m_chartXYZ); + if (coordInfoOne->m_chartSpaceInfo.m_validFlag) { + coordinate->setXYZ(coordInfoOne->m_chartSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { - if (optionalCoordInfoTwo->m_chartXYZValid) { + if (optionalCoordInfoTwo->m_chartSpaceInfo.m_validFlag) { + float centerXYZ[3] = { + (float)(coordInfoOne->m_chartSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_chartSpaceInfo.m_xyz[0]) / 2.0f, + (float)(coordInfoOne->m_chartSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_chartSpaceInfo.m_xyz[1]) / 2.0f, + (float)(coordInfoOne->m_chartSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_chartSpaceInfo.m_xyz[2]) / 2.0f + }; + coordinate->setXYZ(centerXYZ); + setWidthHeightWithTabCoordsFlag = true; + } + } + } + break; + case AnnotationCoordinateSpaceEnum::SPACER: + if (coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { + coordinate->setXYZ(coordInfoOne->m_spacerTabSpaceInfo.m_xyz); + annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER); + annotation->setSpacerTabIndex(coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex); + + validCoordinateFlag = true; + + if (optionalCoordInfoTwo != NULL) { + if (optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid() == coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { float centerXYZ[3] = { - (float)(coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, - (float)(coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, - (float)(coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f + (coordInfoOne->m_spacerTabSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_xyz[0]) / 2.0f, + (coordInfoOne->m_spacerTabSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_xyz[1]) / 2.0f, + (coordInfoOne->m_spacerTabSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; @@ -660,18 +725,18 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - if (coordInfoOne->m_modelXYZValid) { - coordinate->setXYZ(coordInfoOne->m_modelXYZ); + if (coordInfoOne->m_modelSpaceInfo.m_validFlag) { + coordinate->setXYZ(coordInfoOne->m_modelSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { - if (optionalCoordInfoTwo->m_modelXYZValid) { + if (optionalCoordInfoTwo->m_modelSpaceInfo.m_validFlag) { float centerXYZ[3] = { - (float)(coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, - (float)(coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, - (float)(coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f + (float)(coordInfoOne->m_modelSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_modelSpaceInfo.m_xyz[0]) / 2.0f, + (float)(coordInfoOne->m_modelSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_modelSpaceInfo.m_xyz[1]) / 2.0f, + (float)(coordInfoOne->m_modelSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_modelSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; @@ -680,29 +745,31 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati } break; case AnnotationCoordinateSpaceEnum::SURFACE: - if (coordInfoOne->m_surfaceNodeValid) { - coordinate->setSurfaceSpace(coordInfoOne->m_surfaceStructure, - coordInfoOne->m_surfaceNumberOfNodes, - coordInfoOne->m_surfaceNodeIndex); + if (coordInfoOne->m_surfaceSpaceInfo.m_validFlag) { + coordinate->setSurfaceSpace(coordInfoOne->m_surfaceSpaceInfo.m_structure, + coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes, + coordInfoOne->m_surfaceSpaceInfo.m_nodeIndex); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SURFACE); - + annotation->initializeSurfaceSpaceWithTangentOffsetRotation(coordInfoOne->m_surfaceSpaceInfo.m_structure, + coordInfoOne->m_surfaceSpaceInfo.m_nodeNormalVector); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { - if ((optionalCoordInfoTwo->m_surfaceNodeValid) - && (optionalCoordInfoTwo->m_surfaceStructure == coordInfoOne->m_surfaceStructure)) { - if ((optionalCoordInfoTwo->m_windowIndex == coordInfoOne->m_windowIndex) - && (coordInfoOne->m_windowIndex >= 0)) { - const float windowWidth = coordInfoOne->m_windowWidth; - const float windowHeight = coordInfoOne->m_windowHeight; - const float x1 = coordInfoOne->m_windowXYZ[0] * windowWidth; - const float y1 = coordInfoOne->m_windowXYZ[1] * windowHeight; - const float x2 = optionalCoordInfoTwo->m_windowXYZ[0] * windowWidth; - const float y2 = optionalCoordInfoTwo->m_windowXYZ[1] * windowHeight; + if ((optionalCoordInfoTwo->m_surfaceSpaceInfo.m_validFlag) + && (optionalCoordInfoTwo->m_surfaceSpaceInfo.m_structure == coordInfoOne->m_surfaceSpaceInfo.m_structure + )) { + if ((optionalCoordInfoTwo->m_windowSpaceInfo.m_index == coordInfoOne->m_windowSpaceInfo.m_index) + && (coordInfoOne->m_windowSpaceInfo.m_index >= 0)) { + const float windowWidth = coordInfoOne->m_windowSpaceInfo.m_width; + const float windowHeight = coordInfoOne->m_windowSpaceInfo.m_height; + const float x1 = coordInfoOne->m_windowSpaceInfo.m_xyz[0] * windowWidth; + const float y1 = coordInfoOne->m_windowSpaceInfo.m_xyz[1] * windowHeight; + const float x2 = optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[0] * windowWidth; + const float y2 = optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[1] * windowHeight; const int32_t windowX = static_cast((x1 + x2)) / 2.0; const int32_t windowY = static_cast((y1 + y2)) / 2.0; - EventIdentificationRequest idRequest(coordInfoOne->m_windowIndex, + EventIdentificationRequest idRequest(coordInfoOne->m_windowSpaceInfo.m_index, static_cast(windowX), static_cast(windowY)); EventManager::get()->sendEvent(idRequest.getPointer()); @@ -711,9 +778,9 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati const SelectionItemSurfaceNode* nodeID = sm->getSurfaceNodeIdentification(); CaretAssert(nodeID); if (nodeID->isValid()) { - if (nodeID->getSurface()->getStructure() == coordInfoOne->m_surfaceStructure) { - coordinate->setSurfaceSpace(coordInfoOne->m_surfaceStructure, - coordInfoOne->m_surfaceNumberOfNodes, + if (nodeID->getSurface()->getStructure() == coordInfoOne->m_surfaceSpaceInfo.m_structure) { + coordinate->setSurfaceSpace(coordInfoOne->m_surfaceSpaceInfo.m_structure, + coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes, nodeID->getNodeNumber()); setWidthHeightWithTabCoordsFlag = true; } @@ -725,19 +792,19 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati } break; case AnnotationCoordinateSpaceEnum::TAB: - if (coordInfoOne->m_tabIndex >= 0) { - coordinate->setXYZ(coordInfoOne->m_tabXYZ); + if (coordInfoOne->m_tabSpaceInfo.m_index >= 0) { + coordinate->setXYZ(coordInfoOne->m_tabSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - annotation->setTabIndex(coordInfoOne->m_tabIndex); + annotation->setTabIndex(coordInfoOne->m_tabSpaceInfo.m_index); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { - if (optionalCoordInfoTwo->m_tabIndex == coordInfoOne->m_tabIndex) { + if (optionalCoordInfoTwo->m_tabSpaceInfo.m_index == coordInfoOne->m_tabSpaceInfo.m_index) { float centerXYZ[3] = { - (coordInfoOne->m_tabXYZ[0] + optionalCoordInfoTwo->m_tabXYZ[0]) / 2.0f, - (coordInfoOne->m_tabXYZ[1] + optionalCoordInfoTwo->m_tabXYZ[1]) / 2.0f, - (coordInfoOne->m_tabXYZ[2] + optionalCoordInfoTwo->m_tabXYZ[2]) / 2.0f + (coordInfoOne->m_tabSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz[0]) / 2.0f, + (coordInfoOne->m_tabSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz[1]) / 2.0f, + (coordInfoOne->m_tabSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; @@ -749,19 +816,19 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: - if (coordInfoOne->m_windowIndex >= 0) { - coordinate->setXYZ(coordInfoOne->m_windowXYZ); + if (coordInfoOne->m_windowSpaceInfo.m_index >= 0) { + coordinate->setXYZ(coordInfoOne->m_windowSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); - annotation->setWindowIndex(coordInfoOne->m_windowIndex); + annotation->setWindowIndex(coordInfoOne->m_windowSpaceInfo.m_index); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { - if (optionalCoordInfoTwo->m_windowIndex == coordInfoOne->m_windowIndex) { + if (optionalCoordInfoTwo->m_windowSpaceInfo.m_index == coordInfoOne->m_windowSpaceInfo.m_index) { float centerXYZ[3] = { - (coordInfoOne->m_windowXYZ[0] + optionalCoordInfoTwo->m_windowXYZ[0]) / 2.0f, - (coordInfoOne->m_windowXYZ[1] + optionalCoordInfoTwo->m_windowXYZ[1]) / 2.0f, - (coordInfoOne->m_windowXYZ[2] + optionalCoordInfoTwo->m_windowXYZ[2]) / 2.0f + (coordInfoOne->m_windowSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[0]) / 2.0f, + (coordInfoOne->m_windowSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[1]) / 2.0f, + (coordInfoOne->m_windowSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithWindowCoordsFlag = true; @@ -772,47 +839,33 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati } if (setWidthHeightWithTabCoordsFlag) { - if (coordInfoOne->m_tabIndex >= 0) { + if (coordInfoOne->m_tabSpaceInfo.m_index >= 0) { if (optionalCoordInfoTwo != NULL) { - if (coordInfoOne->m_tabIndex == optionalCoordInfoTwo->m_tabIndex) { - const float tabWidth = coordInfoOne->m_tabWidth; - const float tabHeight = coordInfoOne->m_tabHeight; - - const float oneXYZ[3] = { - coordInfoOne->m_tabXYZ[0], - coordInfoOne->m_tabXYZ[1], - coordInfoOne->m_tabXYZ[2] - }; - const float twoXYZ[3] = { - optionalCoordInfoTwo->m_tabXYZ[0], - optionalCoordInfoTwo->m_tabXYZ[1], - optionalCoordInfoTwo->m_tabXYZ[2] - }; - - annotation->setWidthAndHeightFromBounds(oneXYZ, - twoXYZ, - tabWidth, - tabHeight); + if (coordInfoOne->m_tabSpaceInfo.m_index == optionalCoordInfoTwo->m_tabSpaceInfo.m_index) { + annotation->setWidthAndHeightFromBounds(coordInfoOne->m_tabSpaceInfo.m_xyz, + optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz, + coordInfoOne->m_tabSpaceInfo.m_width, + coordInfoOne->m_tabSpaceInfo.m_height); } } } } else if (setWidthHeightWithWindowCoordsFlag) { - if (coordInfoOne->m_windowIndex >= 0) { + if (coordInfoOne->m_windowSpaceInfo.m_index >= 0) { if (optionalCoordInfoTwo != NULL) { - if (coordInfoOne->m_windowIndex == optionalCoordInfoTwo->m_windowIndex) { - const float windowWidth = coordInfoOne->m_windowWidth; - const float windowHeight = coordInfoOne->m_windowHeight; + if (coordInfoOne->m_windowSpaceInfo.m_index == optionalCoordInfoTwo->m_windowSpaceInfo.m_index) { + const float windowWidth = coordInfoOne->m_windowSpaceInfo.m_width; + const float windowHeight = coordInfoOne->m_windowSpaceInfo.m_height; const float oneXYZ[3] = { - coordInfoOne->m_windowXYZ[0], - coordInfoOne->m_windowXYZ[1], - coordInfoOne->m_windowXYZ[2] + coordInfoOne->m_windowSpaceInfo.m_xyz[0], + coordInfoOne->m_windowSpaceInfo.m_xyz[1], + coordInfoOne->m_windowSpaceInfo.m_xyz[2] }; const float twoXYZ[3] = { - optionalCoordInfoTwo->m_windowXYZ[0], - optionalCoordInfoTwo->m_windowXYZ[1], - optionalCoordInfoTwo->m_windowXYZ[2] + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[0], + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[1], + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[2] }; annotation->setWidthAndHeightFromBounds(oneXYZ, diff --git a/src/GuiQt/AnnotationCoordinateInformation.h b/src/GuiQt/AnnotationCoordinateInformation.h index b951fa17055d43d65a6145f3f5cd0d1057e8165a..96daac16995d9543278556ddc01698daa429c6ce 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.h +++ b/src/GuiQt/AnnotationCoordinateInformation.h @@ -23,6 +23,7 @@ #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationSurfaceOffsetVectorTypeEnum.h" +#include "SpacerTabIndex.h" #include "StructureEnum.h" class QLabel; @@ -70,31 +71,61 @@ namespace caret { const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo); - double m_modelXYZ[3]; - bool m_modelXYZValid; + class SpaceInfo { + public: + bool m_validFlag = false; + }; + + class ModelSpaceInfo : public SpaceInfo { + public: + double m_xyz[3] = { 0.0, 0.0, 0.0 }; + }; + + class TabWindowSpaceInfo : public SpaceInfo { + public: + float m_width = 0.0f; + float m_height = 0.0f; + float m_xyz[3] = { 0.0f, 0.0f, 0.0f }; + float m_pixelXYZ[3] = { 0.0f, 0.0f, 0.0f }; + int32_t m_index = -1; + }; + + class SpacerTabSpaceInfo : public SpaceInfo { + public: + float m_width = 0.0f; + float m_height = 0.0f; + float m_xyz[3] = { 0.0f, 0.0f, 0.0f }; + float m_pixelXYZ[3] = { 0.0f, 0.0f, 0.0f }; + SpacerTabIndex m_spacerTabIndex; + }; + + class ChartSpaceInfo : public SpaceInfo { + public: + float m_xyz[3] = { 0.0f, 0.0f, 0.0f }; + }; + + class SurfaceSpaceInfo : public SpaceInfo { + public: + StructureEnum::Enum m_structure = StructureEnum::INVALID; + int32_t m_numberOfNodes = 0; + int32_t m_nodeIndex = -1; + float m_nodeOffsetLength = 0.0f; + float m_nodeNormalVector[3] = { 0.0f, 0.0f, 1.0f }; + AnnotationSurfaceOffsetVectorTypeEnum::Enum m_nodeVectorOffsetType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; + }; + + ModelSpaceInfo m_modelSpaceInfo; + + TabWindowSpaceInfo m_tabSpaceInfo; + + TabWindowSpaceInfo m_windowSpaceInfo; + + SpacerTabSpaceInfo m_spacerTabSpaceInfo; + + ChartSpaceInfo m_chartSpaceInfo; + + SurfaceSpaceInfo m_surfaceSpaceInfo; - float m_tabWidth; - float m_tabHeight; - float m_tabXYZ[3]; - float m_tabPixelXYZ[3]; - int32_t m_tabIndex; - - float m_windowWidth; - float m_windowHeight; - float m_windowXYZ[3]; - float m_windowPixelXYZ[3]; - int32_t m_windowIndex; - - StructureEnum::Enum m_surfaceStructure; - int32_t m_surfaceNumberOfNodes; - int32_t m_surfaceNodeIndex; - float m_surfaceNodeOffset; - AnnotationSurfaceOffsetVectorTypeEnum::Enum m_surfaceNodeVector; - bool m_surfaceNodeValid; - - - float m_chartXYZ[3]; - bool m_chartXYZValid; private: AnnotationCoordinateInformation(const AnnotationCoordinateInformation&); diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index 589698e4f2268baf3dfb59e423810ceb7a665888..ea3541b8f0380361e3123e106ff87054eedbfbbc 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -165,22 +165,22 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) } if (enableTabSpaceFlag) { - if (m_coordInfo.m_tabIndex < 0) { + if (m_coordInfo.m_tabSpaceInfo.m_index < 0) { enableTabSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { - if (m_optionalSecondCoordInfo->m_tabIndex < 0) { + if (m_optionalSecondCoordInfo->m_tabSpaceInfo.m_index < 0) { enableTabSpaceFlag = false; } } } if (enableChartSpaceFlag) { - if ( ! m_coordInfo.m_chartXYZValid) { + if ( ! m_coordInfo.m_chartSpaceInfo.m_validFlag) { enableChartSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { - if ( ! m_optionalSecondCoordInfo->m_chartXYZValid) { + if ( ! m_optionalSecondCoordInfo->m_chartSpaceInfo.m_validFlag) { enableChartSpaceFlag = false; } /* @@ -202,35 +202,35 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } } if (enableModelSpaceFlag) { - if ( ! m_coordInfo.m_modelXYZValid) { + if ( ! m_coordInfo.m_modelSpaceInfo.m_validFlag) { enableModelSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { - if ( ! m_optionalSecondCoordInfo->m_modelXYZValid) { + if ( ! m_optionalSecondCoordInfo->m_modelSpaceInfo.m_validFlag) { enableModelSpaceFlag = false; } /* @@ -251,24 +251,24 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } @@ -278,42 +278,42 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::TAB); rb->setText(rb->text() + " " - + AString::number(m_coordInfo.m_tabIndex + 1)); + + AString::number(m_coordInfo.m_tabSpaceInfo.m_index + 1)); m_spaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::TAB)); const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } } if (enableWindowSpaceFlag) { - if (m_coordInfo.m_windowIndex < 0) { + if (m_coordInfo.m_windowSpaceInfo.m_index < 0) { enableWindowSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { - if (m_optionalSecondCoordInfo->m_windowIndex < 0) { + if (m_optionalSecondCoordInfo->m_windowSpaceInfo.m_index < 0) { enableWindowSpaceFlag = false; } } @@ -322,7 +322,7 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::WINDOW); rb->setText(rb->text() + " " - + AString::number(m_coordInfo.m_windowIndex + 1)); + + AString::number(m_coordInfo.m_windowSpaceInfo.m_index + 1)); m_spaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::WINDOW)); @@ -330,35 +330,35 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowXYZ[0], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowXYZ[1], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); - gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowXYZ[2], 'f', 1)), + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } } if (enableSurfaceSpaceFlag) { - if ( ! m_coordInfo.m_surfaceNodeValid) { + if ( ! m_coordInfo.m_surfaceSpaceInfo.m_validFlag) { enableSurfaceSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { - if ( ! m_optionalSecondCoordInfo->m_surfaceNodeValid) { + if ( ! m_optionalSecondCoordInfo->m_surfaceSpaceInfo.m_validFlag) { enableSurfaceSpaceFlag = false; } } @@ -381,17 +381,17 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); - const AString infoText(StructureEnum::toGuiName(m_coordInfo.m_surfaceStructure) + const AString infoText(StructureEnum::toGuiName(m_coordInfo.m_surfaceSpaceInfo.m_structure) + " Vertex: " - +AString::number(m_coordInfo.m_surfaceNodeIndex)); + +AString::number(m_coordInfo.m_surfaceSpaceInfo.m_nodeIndex)); gridLayout->addWidget(new QLabel(infoText), rowNum, COLUMN_COORD_X, 1, 4); if (m_optionalSecondCoordInfo != NULL) { const int rowNum = gridLayout->rowCount(); - const AString infoText(StructureEnum::toGuiName(m_optionalSecondCoordInfo->m_surfaceStructure) + const AString infoText(StructureEnum::toGuiName(m_optionalSecondCoordInfo->m_surfaceSpaceInfo.m_structure) + " Vertex 2: " - +AString::number(m_optionalSecondCoordInfo->m_surfaceNodeIndex)); + +AString::number(m_optionalSecondCoordInfo->m_surfaceSpaceInfo.m_nodeIndex)); gridLayout->addWidget(new QLabel(infoText), rowNum, COLUMN_COORD_X, 1, 4); } @@ -551,22 +551,25 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno float oldViewportHeight = 0.0; switch (oldSpace) { case AnnotationCoordinateSpaceEnum::CHART: - oldViewportHeight = m_coordInfo.m_tabHeight; + oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; + break; + case AnnotationCoordinateSpaceEnum::SPACER: + oldViewportHeight = m_coordInfo.m_spacerTabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - oldViewportHeight = m_coordInfo.m_tabHeight; + oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::SURFACE: - oldViewportHeight = m_coordInfo.m_tabHeight; + oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::TAB: - oldViewportHeight = m_coordInfo.m_tabHeight; + oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: - oldViewportHeight = m_coordInfo.m_windowHeight; + oldViewportHeight = m_coordInfo.m_windowSpaceInfo.m_height; break; } @@ -588,6 +591,9 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno case AnnotationCoordinateSpaceEnum::CHART: diffXyzValid = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + diffXyzValid = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -614,33 +620,40 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno bool setOtherCoordinateFlag = false; switch (newSpace) { case AnnotationCoordinateSpaceEnum::CHART: - if (m_coordInfo.m_chartXYZValid) { - coordinate->setXYZ(m_coordInfo.m_chartXYZ); + if (m_coordInfo.m_chartSpaceInfo.m_validFlag) { + coordinate->setXYZ(m_coordInfo.m_chartSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); - newViewportHeight = m_coordInfo.m_tabHeight; + newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; + } + break; + case AnnotationCoordinateSpaceEnum::SPACER: + if (m_coordInfo.m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { + coordinate->setXYZ(m_coordInfo.m_spacerTabSpaceInfo.m_xyz); + redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER); + newViewportHeight = m_coordInfo.m_spacerTabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - if (m_coordInfo.m_modelXYZValid) { - coordinate->setXYZ(m_coordInfo.m_modelXYZ); + if (m_coordInfo.m_modelSpaceInfo.m_validFlag) { + coordinate->setXYZ(m_coordInfo.m_modelSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); - newViewportHeight = m_coordInfo.m_tabHeight; + newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::SURFACE: - if (m_coordInfo.m_surfaceNodeValid) { - coordinate->setSurfaceSpace(m_coordInfo.m_surfaceStructure, - m_coordInfo.m_surfaceNumberOfNodes, - m_coordInfo.m_surfaceNodeIndex); + if (m_coordInfo.m_surfaceSpaceInfo.m_validFlag) { + coordinate->setSurfaceSpace(m_coordInfo.m_surfaceSpaceInfo.m_structure, + m_coordInfo.m_surfaceSpaceInfo.m_numberOfNodes, + m_coordInfo.m_surfaceSpaceInfo.m_nodeIndex); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SURFACE); - newViewportHeight = m_coordInfo.m_tabHeight; + newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::TAB: - if (m_coordInfo.m_tabIndex >= 0) { + if (m_coordInfo.m_tabSpaceInfo.m_index >= 0) { const int32_t oldTabIndex = redoAnnotation->getTabIndex(); - const int32_t newTabIndex = m_coordInfo.m_tabIndex; - coordinate->setXYZ(m_coordInfo.m_tabXYZ); + const int32_t newTabIndex = m_coordInfo.m_tabSpaceInfo.m_index; + coordinate->setXYZ(m_coordInfo.m_tabSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); redoAnnotation->setTabIndex(newTabIndex); @@ -654,17 +667,17 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno setOtherCoordinateFlag = true; } } - newViewportHeight = m_coordInfo.m_tabHeight; + newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: - if (m_coordInfo.m_windowIndex >= 0) { + if (m_coordInfo.m_windowSpaceInfo.m_index >= 0) { const int32_t oldWindowIndex = redoAnnotation->getWindowIndex(); - const int32_t newWindowIndex = m_coordInfo.m_windowIndex; - coordinate->setXYZ(m_coordInfo.m_windowXYZ); + const int32_t newWindowIndex = m_coordInfo.m_windowSpaceInfo.m_index; + coordinate->setXYZ(m_coordInfo.m_windowSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); redoAnnotation->setWindowIndex(newWindowIndex); @@ -679,7 +692,7 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno setOtherCoordinateFlag = true; } } - newViewportHeight = m_coordInfo.m_windowHeight; + newViewportHeight = m_coordInfo.m_windowSpaceInfo.m_height; } break; } @@ -783,14 +796,12 @@ AnnotationCoordinateSelectionWidget::setCoordinateForNewAnnotation(Annotation* a coordinateSpace, &m_coordInfo, m_optionalSecondCoordInfo); -// setOneDimAnnotationCoordinates(oneDimAnn); } else if (twoDimAnn != NULL) { validCoordsFlag = AnnotationCoordinateInformation::setAnnotationCoordinatesForSpace(twoDimAnn, coordinateSpace, &m_coordInfo, m_optionalSecondCoordInfo); -// setTwoDimAnnotationCoordinates(twoDimAnn); } else { const QString msg("PROGRAM ERROR: Annotation is neither one nor two dimensional"); @@ -829,27 +840,31 @@ AnnotationCoordinateSelectionWidget::setWidthAndHeightForImage(AnnotationImage* float vpHeight = 0.0; switch (imageAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: - vpWidth = m_coordInfo.m_tabWidth; - vpHeight = m_coordInfo.m_tabHeight; + vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; + vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; + break; + case AnnotationCoordinateSpaceEnum::SPACER: + vpWidth = m_coordInfo.m_spacerTabSpaceInfo.m_width; + vpHeight = m_coordInfo.m_spacerTabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - vpWidth = m_coordInfo.m_tabWidth; - vpHeight = m_coordInfo.m_tabHeight; + vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; + vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::SURFACE: - vpWidth = m_coordInfo.m_tabWidth; - vpHeight = m_coordInfo.m_tabHeight; + vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; + vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::TAB: - vpWidth = m_coordInfo.m_tabWidth; - vpHeight = m_coordInfo.m_tabHeight; + vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; + vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: - vpWidth = m_coordInfo.m_windowWidth; - vpHeight = m_coordInfo.m_windowHeight; + vpWidth = m_coordInfo.m_windowSpaceInfo.m_width; + vpHeight = m_coordInfo.m_windowSpaceInfo.m_height; break; } @@ -903,12 +918,14 @@ AnnotationCoordinateSelectionWidget::updateAnnotationDisplayProperties(const Ann switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - if (m_coordInfo.m_tabIndex >= 0) { + if (m_coordInfo.m_tabSpaceInfo.m_index >= 0) { } break; case AnnotationCoordinateSpaceEnum::SURFACE: - if (m_coordInfo.m_tabIndex >= 0) { + if (m_coordInfo.m_tabSpaceInfo.m_index >= 0) { } break; case AnnotationCoordinateSpaceEnum::TAB: diff --git a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx index 9d801ceded07d1e25799ab5a2abd8742f26fc7f2..88890fb5ab8c3b9afa96732879eae858baaab7ef 100644 --- a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx @@ -59,6 +59,7 @@ m_browserWindowIndex(browserWindowIndex) "Mouse dragging to move/resize\n" "annotations allowed in Tab or \n" "Window space only.\n" + " Ch : Chart\n" " St : Stereotaxic\n" " Sf : Surface\n" " T : Tab\n" @@ -94,7 +95,7 @@ AnnotationCoordinateSpaceWidget::updateContent(std::vector annotati CaretAssert(annotations[0]); AnnotationCoordinateSpaceEnum::Enum space = annotations[0]->getCoordinateSpace(); - std::set tabIndices; + std::set tabIndices; bool haveMultipleSpacesFlag = false; for (int32_t i = 0; i < static_cast(annotations.size()); i++) { CaretAssertVectorIndex(annotations, i); @@ -107,8 +108,27 @@ AnnotationCoordinateSpaceWidget::updateContent(std::vector annotati } if (annotations[i]->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { - tabIndices.insert(ann->getTabIndex()); + tabIndices.insert(AString::number(ann->getTabIndex() + 1)); } + + if (annotations[i]->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SPACER) { + const SpacerTabIndex sti = ann->getSpacerTabIndex(); + tabIndices.insert(AString::number(sti.getRowIndex() + 1) + + "," + + AString::number(sti.getColumnIndex() + 1)); + + } + } + + AString indicesString; + for (const auto s : tabIndices) { + if (indicesString.isEmpty()) { + indicesString.append(":"); + } + else { + indicesString.append(";"); + } + indicesString.append(s); } if (haveMultipleSpacesFlag) { @@ -119,27 +139,18 @@ AnnotationCoordinateSpaceWidget::updateContent(std::vector annotati switch (space) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + { + text = AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(AnnotationCoordinateSpaceEnum::TAB); + text.append(indicesString); + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: - { - QString tabString; - for (std::set::iterator iter = tabIndices.begin(); - iter != tabIndices.end(); - iter++) { - if (tabString.isEmpty()) { - tabString.append(":"); - } - else { - tabString.append(","); - } - tabString.append(AString::number(*iter + 1)); - } - - text.append(tabString); - } + text.append(indicesString); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index eddd54c3daaf4448826195a4cf1e9b33c85dce44..4595898a13b4c1f6b7ba51e9ea116673b63100c3 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -118,10 +118,10 @@ m_browserWindowIndex(browserWindowIndex) m_surfaceOffsetLengthSpinBox = new QDoubleSpinBox(); m_surfaceOffsetLengthSpinBox->setRange(0.0, 999.0); - m_surfaceOffsetLengthSpinBox->setSingleStep(1.0); + m_surfaceOffsetLengthSpinBox->setSingleStep(0.1); m_surfaceOffsetLengthSpinBox->setToolTip("Offset of annotation from surface vertex"); QObject::connect(m_surfaceOffsetLengthSpinBox, SIGNAL(valueChanged(double)), - this, SLOT(valueChanged())); + this, SLOT(surfaceOffsetLengthValueChanged(double))); const int digitsRightOfDecimal = 1; QLabel* xCoordLabel = new QLabel(" X" + colonString); @@ -159,14 +159,22 @@ m_browserWindowIndex(browserWindowIndex) m_yCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); m_zCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); - m_surfaceOffsetVectorTypeComboBox = new EnumComboBoxTemplate(this); - m_surfaceOffsetVectorTypeComboBox->setup(); - QObject::connect(m_surfaceOffsetVectorTypeComboBox, SIGNAL(itemActivated()), - this, SLOT(valueChanged())); - m_surfaceOffsetVectorTypeComboBox->getWidget()->setFixedWidth(45); - m_surfaceOffsetVectorTypeComboBox->getWidget()->setToolTip("Vector for surface offset:\n" - " C - Centroid thru Vertex\n" - " N - Vertex Normal"); + m_surfaceOffsetVectorTypeComboBox = NULL; + switch (m_whichCoordinate) { + case COORDINATE_ONE: + m_surfaceOffsetVectorTypeComboBox = new EnumComboBoxTemplate(this); + m_surfaceOffsetVectorTypeComboBox->setup(); + QObject::connect(m_surfaceOffsetVectorTypeComboBox, SIGNAL(itemActivated()), + this, SLOT(surfaceOffsetVectorTypeChanged())); + m_surfaceOffsetVectorTypeComboBox->getWidget()->setFixedWidth(45); + m_surfaceOffsetVectorTypeComboBox->getWidget()->setToolTip("Vector for surface offset:\n" + " C - Centroid thru Vertex, Faces Viewer\n" + " N - Vertex Normal, Faces Viewer\n" + " T - Tangent, Rotates with Surface"); + break; + case COORDINATE_TWO: + break; + } m_plusButtonToolTipText = ("Click the mouse to set the new location for the coordinate.\n" "After clicking the mouse, a dialog allows selection of the\n" @@ -200,7 +208,9 @@ m_browserWindowIndex(browserWindowIndex) surfaceLayout->addWidget(surfaceVertexLabel); surfaceLayout->addWidget(m_surfaceStructureComboBox->getWidget()); surfaceLayout->addWidget(m_surfaceNodeIndexSpinBox); - surfaceLayout->addWidget(m_surfaceOffsetVectorTypeComboBox->getWidget()); + if (m_surfaceOffsetVectorTypeComboBox != NULL) { + surfaceLayout->addWidget(m_surfaceOffsetVectorTypeComboBox->getWidget()); + } surfaceLayout->addWidget(m_surfaceOffsetLengthSpinBox); m_coordinateWidget = new QWidget(); @@ -391,6 +401,15 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) } } break; + case AnnotationCoordinateSpaceEnum::SPACER: + xMin = percentageMinimum; + xMax = percentageMaximum; + yMin = percentageMinimum; + yMax = percentageMaximum; + zMin = zDepthMinimum; + zMax = zDepthMaximum; + suffix = "%"; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: xMin = coordinateMinimum; xMax = coordinateMaximum; @@ -479,11 +498,16 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_surfaceNodeIndexSpinBox->setValue(surfaceNodeIndex); m_surfaceNodeIndexSpinBox->blockSignals(false); - m_surfaceOffsetVectorTypeComboBox->setSelectedItem(surfaceOffsetVector); + if (m_surfaceOffsetVectorTypeComboBox != NULL) { + m_surfaceOffsetVectorTypeComboBox->setSelectedItem(surfaceOffsetVector); + } m_surfaceOffsetLengthSpinBox->blockSignals(true); m_surfaceOffsetLengthSpinBox->setValue(surfaceOffsetLength); m_surfaceOffsetLengthSpinBox->blockSignals(false); + + AnnotationCoordinate::setUserDefautlSurfaceOffsetVectorType(surfaceOffsetVector); + AnnotationCoordinate::setUserDefaultSurfaceOffsetLength(surfaceOffsetLength); } if (viewportSpaceFlag) { @@ -501,6 +525,38 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_coordinateWidget->setVisible( ! surfaceFlag); } +/** + * Called when surface offset value changed. + * + * @param value + * New value. + */ +void +AnnotationCoordinateWidget::surfaceOffsetLengthValueChanged(double value) +{ + const AnnotationCoordinate* coordinate = getCoordinate(); + if ((m_annotation != NULL) + && (coordinate != NULL)) { + AnnotationCoordinate::setUserDefaultSurfaceOffsetLength(value); + valueChanged(); + } +} + +/** + * Called when surface offset vector type is changed. + */ +void +AnnotationCoordinateWidget::surfaceOffsetVectorTypeChanged() +{ + const AnnotationCoordinate* coordinate = getCoordinate(); + if ((m_annotation != NULL) + && (coordinate != NULL)) { + CaretAssert(m_surfaceOffsetVectorTypeComboBox); + AnnotationCoordinate::setUserDefautlSurfaceOffsetVectorType(m_surfaceOffsetVectorTypeComboBox->getSelectedItem()); + valueChanged(); + } +} + /** * Gets called when a coordinate value is changed. */ @@ -514,6 +570,8 @@ AnnotationCoordinateWidget::valueChanged() switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -547,7 +605,9 @@ AnnotationCoordinateWidget::valueChanged() surfaceNodeIndex = m_surfaceNodeIndexSpinBox->value(); surfaceOffsetLength = m_surfaceOffsetLengthSpinBox->value(); - surfaceOffsetVector = m_surfaceOffsetVectorTypeComboBox->getSelectedItem(); + if (m_surfaceOffsetVectorTypeComboBox != NULL) { + surfaceOffsetVector = m_surfaceOffsetVectorTypeComboBox->getSelectedItem(); + } coordinateCopy.setSurfaceSpace(structure, surfaceNumberOfNodes, diff --git a/src/GuiQt/AnnotationCoordinateWidget.h b/src/GuiQt/AnnotationCoordinateWidget.h index 517f6e1a35bbe697e3af7c0c215f8aae700f022c..e5822eba3b27f5478e575aba5666fe4663c33170 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.h +++ b/src/GuiQt/AnnotationCoordinateWidget.h @@ -67,6 +67,10 @@ namespace caret { void setCoordinateActionTriggered(); + void surfaceOffsetLengthValueChanged(double); + + void surfaceOffsetVectorTypeChanged(); + private: AnnotationCoordinateWidget(const AnnotationCoordinateWidget&); diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index 42636d045d2f67dc1d4b29b4ff251ae4b537be8b..042c7e75cab3dad306fd35044e275848bbfd3525 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -159,7 +159,7 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndBounds(const MouseEvent& mo Annotation* AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, const MouseEvent& mouseEvent, - const AnnotationCoordinateSpaceEnum::Enum annotationSpace, + const AnnotationCoordinateSpaceEnum::Enum annotationSpaceIn, const AnnotationTypeEnum::Enum annotationType, AnnotationFile* annotationFile) { @@ -173,7 +173,7 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, } NewAnnotationInfo newInfo(mouseEvent, - annotationSpace, + annotationSpaceIn, annotationType, useBothFlag, annotationFile); @@ -212,7 +212,7 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, } else { AString errorMessage; - Annotation* newAnn = createAnnotation(newInfo, annotationSpace, errorMessage); + Annotation* newAnn = createAnnotation(newInfo, newInfo.m_selectedSpace, /*annotationSpace,*/ errorMessage); if (newAnn != NULL) { DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->updateForNewAnnotation(newAnn); @@ -280,6 +280,8 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, case AnnotationCoordinateSpaceEnum::CHART: adjustTextPctSizeFlag = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: adjustTextPctSizeFlag = true; break; @@ -334,6 +336,8 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, case AnnotationCoordinateSpaceEnum::CHART: threeDimSpaceFlag = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: threeDimSpaceFlag = true; break; @@ -388,7 +392,7 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, finishAnnotationCreation(newAnnotationInfo.m_annotationFile, newAnnotation, newAnnotationInfo.m_mouseEvent.getBrowserWindowIndex(), - newAnnotationInfo.m_coordOneInfo.m_tabIndex); + newAnnotationInfo.m_coordOneInfo.m_tabSpaceInfo.m_index); return newAnnotation; } @@ -443,6 +447,13 @@ m_imageHeight(0) iter++) { const AnnotationCoordinateSpaceEnum::Enum space = *iter; QRadioButton* rb = new QRadioButton(AnnotationCoordinateSpaceEnum::toGuiName(space)); + if (space == AnnotationCoordinateSpaceEnum::SPACER) { + /* + * Spacer and Tab are presented as 'TAB' to the user. So show 'TAB' but + * use the integer code for 'SPACER'. + */ + rb->setText(AnnotationCoordinateSpaceEnum::toGuiName(AnnotationCoordinateSpaceEnum::TAB)); + } m_annotationSpaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(space)); coordGroupLayout->addWidget(rb); @@ -794,8 +805,6 @@ AnnotationCreateDialog::finishAnnotationCreation(AnnotationFile* annotationFile, * A new chart annotation is displayed only in the tab in which it was created */ if (annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::CHART) { - - //annotation->setItemDisplaySelectedInNoDisplayGroups(); annotation->setItemDisplaySelectedInOneTab(tabIndex); annotation->setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, tabIndex, @@ -804,66 +813,6 @@ AnnotationCreateDialog::finishAnnotationCreation(AnnotationFile* annotationFile, } -///** -// * Constructor for information used to create a new annotation. -// * -// * @param mouseEvent -// * The mouse event. -// * @param selectedSpace -// * The space selected by the user. -// * @param annotationType -// * The annotation type. -// * @param useBothCoordinatesFromMouseFlag -// * Use both coords (X/Y and pressed X/Y) -// * @param annotationFile -// * File to which annotation is added. -// */ -//AnnotationCreateDialog::NewAnnotationInfo::NewAnnotationInfo(const MouseEvent& mouseEvent, -// const AnnotationCoordinateSpaceEnum::Enum selectedSpace, -// const AnnotationTypeEnum::Enum annotationType, -// const bool useBothCoordinatesFromMouseFlag, -// AnnotationFile* annotationFile) -//: m_mouseEvent(mouseEvent), -//m_selectedSpace(selectedSpace), -//m_annotationType(annotationType), -//m_annotationFile(annotationFile) -//{ -// CaretAssert(annotationFile); -// -// m_validSpaces.clear(); -// m_coordOneInfo.reset(); -// m_coordTwoInfo.reset(); -// m_coordTwoInfoValid = false; -// m_percentageWidth = -1; -// m_percentageHeight = -1; -// -// AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, -// mouseEvent.getX(), -// mouseEvent.getY(), -// m_coordOneInfo); -// -// if (useBothCoordinatesFromMouseFlag) { -// AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, -// mouseEvent.getPressedX(), -// mouseEvent.getPressedY(), -// m_coordTwoInfo); -// -// AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, -// &m_coordTwoInfo, -// m_validSpaces); -// -// if (isValid()) { -// m_coordTwoInfoValid = true; -// -// processTwoCoordInfo(); -// } -// } -// else { -// AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, -// NULL, -// m_validSpaces); -// } -//} /** * Constructor for information used to create a new annotation. * @@ -952,10 +901,30 @@ m_annotationFile(annotationFile) NULL, m_validSpaces); } + + /* + * There is not a selection in the GUI for the user to choose 'SPACER' coordinate space. + * Instead the user uses 'TAB' space in the GUI. So, if TAB space is NOT valid, but + * SPACER space is valid, change the requested space to 'SPACER' + */ + if (m_selectedSpace == AnnotationCoordinateSpaceEnum::TAB) { + const bool haveTabFlag = (std::find(m_validSpaces.begin(), + m_validSpaces.end(), + AnnotationCoordinateSpaceEnum::TAB) != m_validSpaces.end()); + const bool haveSpacerFlag = (std::find(m_validSpaces.begin(), + m_validSpaces.end(), + AnnotationCoordinateSpaceEnum::SPACER) != m_validSpaces.end()); + + if (haveSpacerFlag) { + if ( ! haveTabFlag) { + m_selectedSpace = AnnotationCoordinateSpaceEnum::SPACER; + } + } + } } /** - * When the user drags to create an annotation, two points are + * When the user drags to create an annotation, two points are * used at opposite corners. For non-linear annotations, we * need a center, width, and height. So for these types, * convert the two points to one point with center, width, @@ -964,8 +933,8 @@ m_annotationFile(annotationFile) void AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() { - if ((m_coordOneInfo.m_windowIndex >= 0) - && (m_coordTwoInfo.m_windowIndex >= 0)) { + if ((m_coordOneInfo.m_windowSpaceInfo.m_index >= 0) + && (m_coordTwoInfo.m_windowSpaceInfo.m_index >= 0)) { bool useAverageFlag = false; bool useTextAligmentFlag = false; @@ -992,10 +961,10 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() if (useAverageFlag || useTextAligmentFlag) { - int32_t windowPixelX = m_coordOneInfo.m_windowPixelXYZ[0]; - int32_t windowPixelY = m_coordOneInfo.m_windowPixelXYZ[1]; - int32_t windowTwoPixelX = m_coordTwoInfo.m_windowPixelXYZ[0]; - int32_t windowTwoPixelY = m_coordTwoInfo.m_windowPixelXYZ[1]; + int32_t windowPixelX = m_coordOneInfo.m_windowSpaceInfo.m_pixelXYZ[0]; + int32_t windowPixelY = m_coordOneInfo.m_windowSpaceInfo.m_pixelXYZ[1]; + int32_t windowTwoPixelX = m_coordTwoInfo.m_windowSpaceInfo.m_pixelXYZ[0]; + int32_t windowTwoPixelY = m_coordTwoInfo.m_windowSpaceInfo.m_pixelXYZ[1]; if ((windowPixelX >= 0) && (windowPixelY >= 0) @@ -1033,15 +1002,20 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() viewport, subWidth, subHeight)) { -// std::cout << "Changing " -// << viewportWidth << ", " << viewportHeight << " to " -// << subWidth << ", " << subHeight << std::endl; viewportWidth = subWidth; viewportHeight = subHeight; } break; } + case AnnotationCoordinateSpaceEnum::SPACER: + { + int viewport[4]; + m_mouseEvent.getViewportContent()->getModelViewport(viewport); + viewportWidth = viewport[2]; + viewportHeight = viewport[3]; + } + break; case AnnotationCoordinateSpaceEnum::TAB: { int viewport[4]; diff --git a/src/GuiQt/AnnotationCreateDialog.h b/src/GuiQt/AnnotationCreateDialog.h index e6d79952b2efe82ab6a048119620e07215a43f2e..2aad84ba9dc18355045e7ea591bdcfdf0fd48c3e 100644 --- a/src/GuiQt/AnnotationCreateDialog.h +++ b/src/GuiQt/AnnotationCreateDialog.h @@ -91,7 +91,7 @@ namespace caret { const MouseEvent& m_mouseEvent; - const AnnotationCoordinateSpaceEnum::Enum m_selectedSpace; + AnnotationCoordinateSpaceEnum::Enum m_selectedSpace; const AnnotationTypeEnum::Enum m_annotationType; diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 14509e044330a2d53ae7d3a01fe534671bb06d72..69265393f5540b347fd3044461c02678dd5bffaf 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -284,7 +284,21 @@ AnnotationFontWidget::receiveEvent(Event* event) if (m_browserWindowIndex == redrawEvent->getBrowserWindowIndex()) { if (isVisible()) { - updateFontSizeControls(); + AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); + std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); + + if (selectedAnnotations.empty()) { + return; + } + + std::vector textAnnotations; + for (auto ann : selectedAnnotations) { + AnnotationFontAttributesInterface* textAnn = dynamic_cast(ann); + if (textAnn != NULL) { + textAnnotations.push_back(textAnn); + } + } + updateContent(textAnnotations); } } } @@ -393,6 +407,8 @@ AnnotationFontWidget::updateFontSizeControls() switch (ann->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: sizeValue /= surfaceMontageRowCount; break; @@ -443,6 +459,10 @@ AnnotationFontWidget::updateFontSizeControls() void AnnotationFontWidget::updateFontStyleControls() { + m_boldFontAction->setEnabled(false); + m_italicFontAction->setEnabled(false); + m_underlineFontAction->setEnabled(false); + if ( ! m_annotationsFontStyle.empty()) { bool boldOnFlag = true; bool italicOnFlag = true; diff --git a/src/GuiQt/AnnotationInsertNewWidget.cxx b/src/GuiQt/AnnotationInsertNewWidget.cxx index 2a60f4ee1eb9b595d46569d8b7b9feb006db70a1..b768fa26ba37858c04e0c136702277ef93047bbe 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.cxx +++ b/src/GuiQt/AnnotationInsertNewWidget.cxx @@ -101,6 +101,12 @@ m_browserWindowIndex(browserWindowIndex) m_spaceActionGroup); QToolButton* tabSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::TAB, m_spaceActionGroup); + const bool showSpacerToolButtonFlag(false); + QToolButton* spacerSpaceToolButton(NULL); + if (showSpacerToolButtonFlag) { + spacerSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::SPACER, + m_spaceActionGroup); + } QToolButton* stereotaxicSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::STEREOTAXIC, m_spaceActionGroup); QToolButton* surfaceSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::SURFACE, @@ -122,6 +128,9 @@ m_browserWindowIndex(browserWindowIndex) shapeTextToolButton->setMaximumSize(mw, mh); chartSpaceToolButton->setMaximumSize(mw, mh); + if (spacerSpaceToolButton != NULL) { + spacerSpaceToolButton->setMaximumSize(mw, mh); + } tabSpaceToolButton->setMaximumSize(mw, mh); stereotaxicSpaceToolButton->setMaximumSize(mw, mh); surfaceSpaceToolButton->setMaximumSize(mw, mh); @@ -147,8 +156,11 @@ m_browserWindowIndex(browserWindowIndex) QLabel* insertLabel = new QLabel("Insert New"); + const int32_t topColumnCount((spacerSpaceToolButton != NULL) + ? 9 + : 8); gridLayout->addWidget(insertLabel, - 0, 0, 1, 8, + 0, 0, 1, topColumnCount, Qt::AlignHCenter); gridLayout->addLayout(fileLayout, @@ -157,18 +169,23 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->setColumnMinimumWidth(1, 5); + int32_t topColumn(2); gridLayout->addWidget(spaceLabel, - 1, 2, Qt::AlignLeft); + 1, topColumn++, Qt::AlignLeft); gridLayout->addWidget(chartSpaceToolButton, - 1, 3); + 1, topColumn++); + if (spacerSpaceToolButton != NULL) { + gridLayout->addWidget(spacerSpaceToolButton, + 1, topColumn++); + } gridLayout->addWidget(stereotaxicSpaceToolButton, - 1, 4); + 1, topColumn++); gridLayout->addWidget(surfaceSpaceToolButton, - 1, 5); + 1, topColumn++); gridLayout->addWidget(tabSpaceToolButton, - 1, 6); + 1, topColumn++); gridLayout->addWidget(windowSpaceToolButton, - 1, 7); + 1, topColumn++); gridLayout->setRowMinimumHeight(2, 2); @@ -207,20 +224,22 @@ m_browserWindowIndex(browserWindowIndex) 1, 2, Qt::AlignLeft); gridLayout->addWidget(chartSpaceToolButton, 1, 3); - gridLayout->addWidget(stereotaxicSpaceToolButton, + gridLayout->addWidget(spacerSpaceToolButton, 1, 4); - gridLayout->addWidget(surfaceSpaceToolButton, + gridLayout->addWidget(stereotaxicSpaceToolButton, 1, 5); - gridLayout->addWidget(tabSpaceToolButton, + gridLayout->addWidget(surfaceSpaceToolButton, 1, 6); - gridLayout->addWidget(windowSpaceToolButton, + gridLayout->addWidget(tabSpaceToolButton, 1, 7); + gridLayout->addWidget(windowSpaceToolButton, + 1, 8); QSpacerItem* rowSpaceItem = new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); gridLayout->addItem(rowSpaceItem, - 2, 3, 1, 6); + 2, 3, 1, 7); gridLayout->addWidget(typeLabel, 3, 2, Qt::AlignLeft); @@ -298,43 +317,56 @@ AnnotationInsertNewWidget::enableDisableSpaceActions() if (window == NULL) { return; } - BrowserTabContent* tabContent = window->getBrowserTabContent(); - if (tabContent == NULL) { - return; + + std::vector allTabContent; + if (window->isTileTabsSelected()) { + window->getAllTabContent(allTabContent); } - Model* model = tabContent->getModelForDisplay(); - if (model == NULL) { - return; + else { + BrowserTabContent* tabContent = window->getBrowserTabContent(); + if (tabContent != NULL) { + allTabContent.push_back(tabContent); + } } - const ModelTypeEnum::Enum modelType = model->getModelType(); + + const bool spacerSpaceValidFlag = window->isTileTabsSelected(); + const bool tabSpaceValidFlag = ( ! allTabContent.empty()); + const bool windowSpaceValidFlag = ( ! allTabContent.empty()); bool chartSpaceValidFlag = false; bool surfaceSpaceValidFlag = false; bool stereotaxicSpaceValidFlag = false; - switch (modelType) { - case ModelTypeEnum::MODEL_TYPE_CHART: - break; - case ModelTypeEnum::MODEL_TYPE_CHART_TWO: - chartSpaceValidFlag = true; - break; - case ModelTypeEnum::MODEL_TYPE_INVALID: - break; - case ModelTypeEnum::MODEL_TYPE_SURFACE: - stereotaxicSpaceValidFlag = true; - surfaceSpaceValidFlag = true; - break; - case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: - stereotaxicSpaceValidFlag = true; - surfaceSpaceValidFlag = true; - break; - case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: - stereotaxicSpaceValidFlag = true; - break; - case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: - stereotaxicSpaceValidFlag = true; - surfaceSpaceValidFlag = true; - break; + for (auto tabContent : allTabContent) { + Model* model = tabContent->getModelForDisplay(); + if (model == NULL) { + return; + } + const ModelTypeEnum::Enum modelType = model->getModelType(); + switch (modelType) { + case ModelTypeEnum::MODEL_TYPE_CHART: + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + chartSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + stereotaxicSpaceValidFlag = true; + surfaceSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + stereotaxicSpaceValidFlag = true; + surfaceSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + stereotaxicSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + stereotaxicSpaceValidFlag = true; + surfaceSpaceValidFlag = true; + break; + } } QAction* selectedAction = m_spaceActionGroup->checkedAction(); @@ -353,6 +385,9 @@ AnnotationInsertNewWidget::enableDisableSpaceActions() case AnnotationCoordinateSpaceEnum::CHART: enableSpaceFlag = chartSpaceValidFlag; break; + case AnnotationCoordinateSpaceEnum::SPACER: + enableSpaceFlag = spacerSpaceValidFlag; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: enableSpaceFlag = stereotaxicSpaceValidFlag; break; @@ -361,12 +396,12 @@ AnnotationInsertNewWidget::enableDisableSpaceActions() break; case AnnotationCoordinateSpaceEnum::TAB: tabSpaceAction = action; - enableSpaceFlag = true; + enableSpaceFlag = tabSpaceValidFlag; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: - enableSpaceFlag = true; + enableSpaceFlag = windowSpaceValidFlag; break; } @@ -609,6 +644,8 @@ AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpace switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -687,6 +724,8 @@ AnnotationInsertNewWidget::createSpacePixmap(const QWidget* widget, switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx index 081af4789c9c4d8cf7fa948dc99101179015537d..8a9a4a2522923e1e6d9676bfd6c0fcca63d4e343 100644 --- a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx +++ b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx @@ -59,11 +59,7 @@ AnnotationLineArrowTipsWidget::AnnotationLineArrowTipsWidget(const int32_t brows m_browserWindowIndex(browserWindowIndex) { QLabel* label = new QLabel("Line"); - - const QSize toolButtonSize(24, 24); - - - + QToolButton* endArrowToolButton = new QToolButton(); m_endArrowAction = new QAction(this); m_endArrowAction->setCheckable(true); diff --git a/src/GuiQt/AnnotationPasteDialog.cxx b/src/GuiQt/AnnotationPasteDialog.cxx index 7ada21c497eebf2636015b757f7019d698609f8a..e6d7e2db232bfa1697a919ae0d4f4df310de9999 100644 --- a/src/GuiQt/AnnotationPasteDialog.cxx +++ b/src/GuiQt/AnnotationPasteDialog.cxx @@ -178,14 +178,13 @@ AnnotationPasteDialog::pasteAnnotationOnClipboardChangeSpace(const MouseEvent& m AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); if (annotationManager->isAnnotationOnClipboardValid()) { AnnotationFile* annotationFile = annotationManager->getAnnotationFileOnClipboard(); - //Annotation* annotation = annotationManager->getAnnotationOnClipboard()->clone(); AString message("Choose one of the coordinate " "spaces below to paste the annotation or press Cancel to cancel pasting " "of the annotation."); AnnotationPasteDialog pasteDialog(mouseEvent, annotationFile, - annotationManager->getAnnotationOnClipboard(), //annotation, + annotationManager->getAnnotationOnClipboard(), message, mouseEvent.getOpenGLWidget()); if (pasteDialog.exec() == AnnotationPasteDialog::Accepted) { @@ -298,6 +297,8 @@ AnnotationPasteDialog::pasteOneDimensionalShape(AnnotationOneDimensionalShape* o switch (oneDimShape->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -327,19 +328,19 @@ AnnotationPasteDialog::pasteOneDimensionalShape(AnnotationOneDimensionalShape* o }; if (tabFlag - && (coordInfo.m_tabIndex >= 0)) { - startXYZ[0] = coordInfo.m_tabXYZ[0]; - startXYZ[1] = coordInfo.m_tabXYZ[1]; - startXYZ[2] = coordInfo.m_tabXYZ[2]; - oneDimShape->setTabIndex(coordInfo.m_tabIndex); + && (coordInfo.m_tabSpaceInfo.m_index >= 0)) { + startXYZ[0] = coordInfo.m_tabSpaceInfo.m_xyz[0]; + startXYZ[1] = coordInfo.m_tabSpaceInfo.m_xyz[1]; + startXYZ[2] = coordInfo.m_tabSpaceInfo.m_xyz[2]; + oneDimShape->setTabIndex(coordInfo.m_tabSpaceInfo.m_index); validCoordsFlag = true; } else if (windowFlag - && (coordInfo.m_windowIndex >= 0)) { - startXYZ[0] = coordInfo.m_windowXYZ[0]; - startXYZ[1] = coordInfo.m_windowXYZ[1]; - startXYZ[2] = coordInfo.m_windowXYZ[2]; - oneDimShape->setWindowIndex(coordInfo.m_windowIndex); + && (coordInfo.m_windowSpaceInfo.m_index >= 0)) { + startXYZ[0] = coordInfo.m_windowSpaceInfo.m_xyz[0]; + startXYZ[1] = coordInfo.m_windowSpaceInfo.m_xyz[1]; + startXYZ[2] = coordInfo.m_windowSpaceInfo.m_xyz[2]; + oneDimShape->setWindowIndex(coordInfo.m_windowSpaceInfo.m_index); validCoordsFlag = true; } @@ -516,23 +517,6 @@ AnnotationPasteDialog::adjustTextAnnotationFontHeight(const AnnotationCoordinate heightMultiplier = 1.0 / surfaceMontageRowCount; } } - -// if (previousSpace != AnnotationCoordinateSpaceEnum::SURFACE) { -// if (annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE) { -// /* -// * Converting to surface -// */ -// heightMultiplier = surfaceMontageRowCount; -// } -// } -// else { -// if (annotation->getCoordinateSpace() != AnnotationCoordinateSpaceEnum::SURFACE) { -// /* -// * Converting from surface -// */ -// heightMultiplier = 1.0 / surfaceMontageRowCount; -// } -// } if (heightMultiplier != 0.0) { AnnotationPercentSizeText* textAnn = dynamic_cast(annotation); diff --git a/src/GuiQt/AnnotationRotationWidget.cxx b/src/GuiQt/AnnotationRotationWidget.cxx index de9a2363dd2810044975387608d37c941a58b665..0e2d17bd498f3267c8fff15ace1f9d20823f2110 100644 --- a/src/GuiQt/AnnotationRotationWidget.cxx +++ b/src/GuiQt/AnnotationRotationWidget.cxx @@ -112,6 +112,8 @@ AnnotationRotationWidget::getValidOneDimAnnotation(Annotation* annotation) switch (oneDimAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -171,6 +173,8 @@ AnnotationRotationWidget::updateContent(std::vector& annotations) switch (oneDimAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationSelectionViewController.cxx b/src/GuiQt/AnnotationSelectionViewController.cxx index 6334d6ce0f01a98ea3a3a80a9681c5fe2b57bb4e..3fc754f3bdfb18bffd98afd3153fffea8458382a 100644 --- a/src/GuiQt/AnnotationSelectionViewController.cxx +++ b/src/GuiQt/AnnotationSelectionViewController.cxx @@ -41,6 +41,7 @@ #include "GuiManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -58,17 +59,27 @@ using namespace caret; * * @param browserWindowIndex * Index of the browser window. + * @param parentObjectName + * Name of parent object * @param parent * The parent widget. */ AnnotationSelectionViewController::AnnotationSelectionViewController(const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { + const QString objectNamePrefix(parentObjectName + + ":AnnotationSelection"); + WuQMacroManager* macroManager = WuQMacroManager::instance(); + QLabel* groupLabel = new QLabel("Group"); - m_displayGroupComboBox = new DisplayGroupEnumComboBox(this); + m_displayGroupComboBox = new DisplayGroupEnumComboBox(this, + (objectNamePrefix + + ":DisplayGroup"), + "annotations"); QObject::connect(m_displayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(displayGroupSelected(const DisplayGroupEnum::Enum))); @@ -84,20 +95,33 @@ m_browserWindowIndex(browserWindowIndex) m_displayAnnotationsCheckBox->setToolTip("Disables/enables display of annotations in all windows"); QObject::connect(m_displayAnnotationsCheckBox, SIGNAL(clicked(bool)), this, SLOT(checkBoxToggled())); + m_displayAnnotationsCheckBox->setObjectName(objectNamePrefix + + "DisplayAnnotatons"); + macroManager->addMacroSupportToObject(m_displayAnnotationsCheckBox, + "Enable display of annotations"); + m_displayTextAnnotationsCheckBox = new QCheckBox("Display Text Annotations"); m_displayTextAnnotationsCheckBox->setToolTip("Disables/enables display of text annotations in all windows"); QObject::connect(m_displayTextAnnotationsCheckBox, SIGNAL(clicked(bool)), this, SLOT(checkBoxToggled())); + m_displayTextAnnotationsCheckBox->setObjectName(objectNamePrefix + + "DisplayTextAnnotatons"); + macroManager->addMacroSupportToObject(m_displayTextAnnotationsCheckBox, + "Enable display of text annotations"); m_displayWindowAnnotationInSingleTabViewsCheckBox = new QCheckBox("Show Window " + QString::number(m_browserWindowIndex + 1) + " Annotations in Single Tab View"); - const QString singTT(WuQtUtilities::createWordWrappedToolTipText("When checked, window annotations are always displayed." + const QString singTT(WuQtUtilities::createWordWrappedToolTipText("When checked, window annotations are always displayed.\n" "When unchecked, window annotations are only displayed when tile tabs is enabled.")); m_displayWindowAnnotationInSingleTabViewsCheckBox->setToolTip(singTT); QObject::connect(m_displayWindowAnnotationInSingleTabViewsCheckBox, SIGNAL(clicked(bool)), this, SLOT(checkBoxToggled())); + m_displayWindowAnnotationInSingleTabViewsCheckBox->setObjectName(objectNamePrefix + + "DisplayWindowAnnotatonsInSingleTabView"); + macroManager->addMacroSupportToObject(m_displayWindowAnnotationInSingleTabViewsCheckBox, + "Enable display window annotations in single tab view"); m_sceneAssistant = new SceneClassAssistant(); @@ -205,15 +229,12 @@ AnnotationSelectionViewController::updateAnnotationSelections() const DisplayGroupEnum::Enum displayGroup = dpa->getDisplayGroupForTab(browserTabIndex); m_displayGroupComboBox->setSelectedDisplayGroup(displayGroup); - EventGetOrSetUserInputModeProcessor inputModeEvent(m_browserWindowIndex); - EventManager::get()->sendEvent(inputModeEvent.getPointer()); - UserInputModeAbstract::UserInputMode mode = inputModeEvent.getUserInputMode(); - const bool annotationsValidFlag = (mode == UserInputModeAbstract::ANNOTATIONS); + const bool allowAnnotationSelectionFlag(true); m_selectionViewController->updateContent(fileItems, displayGroup, browserTabIndex, - annotationsValidFlag); + allowAnnotationSelectionFlag); } QWidget* diff --git a/src/GuiQt/AnnotationSelectionViewController.h b/src/GuiQt/AnnotationSelectionViewController.h index cf97c52e57c0f958df9217890d69d4ca313c63ae..ea58c720281e6353ac26bf1ff008873e20e38907 100644 --- a/src/GuiQt/AnnotationSelectionViewController.h +++ b/src/GuiQt/AnnotationSelectionViewController.h @@ -41,6 +41,7 @@ namespace caret { public: AnnotationSelectionViewController(const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent); virtual ~AnnotationSelectionViewController(); diff --git a/src/GuiQt/AnnotationTextEditorWidget.cxx b/src/GuiQt/AnnotationTextEditorWidget.cxx index 4e80d4441c8f15327150add06218b8fd1fd86d24..22e774eb10ec3e7c5e818fbd3c80b7ffde23d594 100644 --- a/src/GuiQt/AnnotationTextEditorWidget.cxx +++ b/src/GuiQt/AnnotationTextEditorWidget.cxx @@ -120,6 +120,7 @@ AnnotationTextEditorWidget::updateContent(std::vector& annotati AnnotationTextConnectTypeEnum::Enum connectValue = AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_NONE; if (m_annotationText != NULL) { connectValue = m_annotationText->getConnectToBrainordinate(); + AnnotationText::setUserDefaultConnectToBrainordinate(connectValue); } m_annotationTextConnectTypeEnumComboBox->setSelectedItem(connectValue); @@ -245,6 +246,7 @@ AnnotationTextEditorWidget::annotationTextConnectTypeEnumComboBoxItemActivated() WuQMessageBox::errorOk(this, errorMessage); } + AnnotationText::setUserDefaultConnectToBrainordinate(connectType); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } diff --git a/src/GuiQt/AnnotationTextSubstitutionViewController.cxx b/src/GuiQt/AnnotationTextSubstitutionViewController.cxx index ca4cb0e576e54f4962694f9b6b32ca8e974b531f..0a3c71c311308d4b6187f713d06aaa731919cbfc 100644 --- a/src/GuiQt/AnnotationTextSubstitutionViewController.cxx +++ b/src/GuiQt/AnnotationTextSubstitutionViewController.cxx @@ -49,6 +49,7 @@ #include "MapYokingGroupComboBox.h" #include "SceneClass.h" #include "SceneClassAssistant.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -66,11 +67,14 @@ using namespace caret; * * @param browserWindowIndex * Index of the browser window. + * @param parentObjectName + * Name of parent object for macros * @param parent * The parent widget. */ AnnotationTextSubstitutionViewController::AnnotationTextSubstitutionViewController(const int32_t browserWindowIndex, - QWidget* parent) + const QString& parentObjectName, + QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { @@ -79,6 +83,11 @@ m_browserWindowIndex(browserWindowIndex) m_enableSubstitutionsCheckBox = new QCheckBox("Enable Substitutions"); QObject::connect(m_enableSubstitutionsCheckBox, &QCheckBox::clicked, this, &AnnotationTextSubstitutionViewController::enableCheckBoxClicked); + m_enableSubstitutionsCheckBox->setObjectName(parentObjectName + + ":Substitutions:Enable"); + m_enableSubstitutionsCheckBox->setToolTip("Enable Text Annotation Substitutions"); + WuQMacroManager::instance()->addMacroSupportToObject(m_enableSubstitutionsCheckBox, + "Enable annotation subsitutions"); QButtonGroup* buttonGroup = new QButtonGroup(); @@ -97,8 +106,13 @@ m_browserWindowIndex(browserWindowIndex) QSpinBox* sb = new QSpinBox(); sb->setRange(1, 100); +#if QT_VERSION >= 0x050700 QObject::connect(sb, QOverload::of(&QSpinBox::valueChanged), [=] { valueIndexSpinBoxChanged(i); } ); +#else + QObject::connect(sb, static_cast(&QSpinBox::valueChanged), + [=] { valueIndexSpinBoxChanged(i); } ); +#endif QLabel* fl = new QLabel(); diff --git a/src/GuiQt/AnnotationTextSubstitutionViewController.h b/src/GuiQt/AnnotationTextSubstitutionViewController.h index 5fdea890935d56754d2d16e19a1934929576c992..db48e97984f3efcba8f80912b1a9cf84ee475fa5 100644 --- a/src/GuiQt/AnnotationTextSubstitutionViewController.h +++ b/src/GuiQt/AnnotationTextSubstitutionViewController.h @@ -44,7 +44,8 @@ namespace caret { public: AnnotationTextSubstitutionViewController(const int32_t browserWindowIndex, - QWidget* parent); + const QString& parentObjectName, + QWidget* parent); virtual ~AnnotationTextSubstitutionViewController(); diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 957d3494a709816cf7960ed4d0bf62ac1c05ed54..edd4393886238911301b9348b198ef18d6e38390 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -177,6 +177,9 @@ BalsaDatabaseManager::login(const AString& databaseURL, errorMessageOut = ("Login has failed.\n" "HTTP Code: " + AString::number(loginResponse.m_responseCode) + " Content: " + responseContent); + if (loginResponse.m_responseCode < 0) { + errorMessageOut.appendWithNewLine(loginResponse.m_errorMessage); + } logout(); return false; @@ -303,9 +306,10 @@ BalsaDatabaseManager::uploadFileWithCaretHttpManager(const AString& uploadURL, return verifyUploadFileResponse(uploadResponse.m_headers, - responseContentOut, - uploadResponse.m_responseCode, - errorMessageOut); + responseContentOut, + uploadResponse.m_responseCode, + uploadResponse.m_errorMessage, + errorMessageOut); } /** @@ -317,6 +321,8 @@ BalsaDatabaseManager::uploadFileWithCaretHttpManager(const AString& uploadURL, * Content from the response. * @param responseHttpCode * HTTP code from response. + * @param responseErrorMessage + * * @param errorMessageOut * Contains description of error. * @return @@ -324,19 +330,39 @@ BalsaDatabaseManager::uploadFileWithCaretHttpManager(const AString& uploadURL, */ bool BalsaDatabaseManager::verifyUploadFileResponse(const std::map& responseHeaders, - const AString& responseContent, - const int32_t responseHttpCode, - AString& errorMessageOut) const + const AString& responseContent, + const int32_t responseHttpCode, + const AString& responseErrorMessage, + AString& errorMessageOut) const { if (responseHttpCode != 200) { if (responseHttpCode == 403) { - errorMessageOut = ("Upload failed. Http Code=" + errorMessageOut = ("Upload failed. (Http Code=" + AString::number(responseHttpCode) - + ". You may not have ownership/permission to edit the study."); + + ").\n\n" + "Either you do now have ownership/permission to edit the study or " + "the study has been submitted for curation.\n\n" + "Use your web browser to login to BALSA to view the study and " + "check its permissions. If the the study has been submitted for " + "curation, there will be a 'return for revision' option on the study. " + "Selection of 'return for 'revision' will allow you to upload your data."); } else { errorMessageOut = ("Upload failed. Http Code=" - + AString::number(responseHttpCode)); + + AString::number(responseHttpCode) + + ".\n" + + responseErrorMessage); +// if (responseHttpCode < 0) { +// const QString s(responseContent.isEmpty() +// ? "Response content is empty !!!" +// : ("Response content:\n" +// + responseContent)); +// CaretLogSevere("Invalid http response=" +// + AString::number(responseHttpCode) +// + "\n" +// + s +// + "\n"); +// } } return false; } @@ -388,11 +414,13 @@ BalsaDatabaseManager::verifyUploadFileResponse(const std::map& } QJsonParseError jsonError; - QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Process upload response failed. Failed to parse JSON, error:" + jsonError.errorString() + + " Offset=" + + AString::number(jsonError.offset) + "\n\n" "Response Content: " + responseContent); @@ -520,12 +548,12 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, bool successFlag = false; try { - OperationZipSceneFile::createZipFile(sceneFileName, + OperationZipSceneFile::createZipFile(NULL, + sceneFileName, extractToDirectoryName, zipFileName, basePathName, - OperationZipSceneFile::PROGRESS_GUI_EVENT, - NULL); + OperationZipSceneFile::PROGRESS_GUI_EVENT); successFlag = true; } catch (const CaretException& e) { @@ -620,7 +648,8 @@ BalsaDatabaseManager::processUploadedFile(SceneFile* sceneFile, if (uploadResponse.m_responseCode != 200) { errorMessageOut = ("Process Upload failed code: " + QString::number(uploadResponse.m_responseCode) - + "\n"); + + ". "); + errorMessageOut.appendWithNewLine(uploadResponse.m_errorMessage); return false; } @@ -691,7 +720,7 @@ BalsaDatabaseManager::updateSceneIdsFromProcessUploadResponse(SceneFile* sceneFi AString& errorMessageOut) { QJsonParseError jsonError; - QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonContent.toLatin1(), + QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Failed to parse JSON response from procssess upload, error:" @@ -878,7 +907,8 @@ BalsaDatabaseManager::getSceneIDs(const int32_t numberOfSceneIDs, if (response.m_responseCode != 200) { errorMessageOut = ("Requesting Scene IDs failed with HTTP code=" + AString::number(response.m_responseCode) - + ". This error may be caused by failure to agree to data use terms."); + + ". This error may be caused by failure to agree to data use terms. "); + errorMessageOut.appendWithNewLine(response.m_errorMessage); return false; } @@ -977,7 +1007,8 @@ BalsaDatabaseManager::requestStudyID(const AString& databaseURL, if (studyResponse.m_responseCode != 200) { errorMessageOut = ("Requesting study ID failed with HTTP code=" + AString::number(studyResponse.m_responseCode) - + ". This error may be caused by failure to agree to data use terms."); + + ". This error may be caused by failure to agree to data use terms. "); + errorMessageOut.appendWithNewLine(studyResponse.m_errorMessage); return false; } @@ -1001,11 +1032,13 @@ BalsaDatabaseManager::requestStudyID(const AString& databaseURL, } QJsonParseError jsonError; - QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Requesting study ID failed. Failed to parse JSON, error:" - + jsonError.errorString()); + + jsonError.errorString() + + " Offset=" + + AString::number(jsonError.offset)); return false; } @@ -1104,12 +1137,14 @@ BalsaDatabaseManager::getUserRoles(BalsaUserRoles& userRolesOut, CaretHttpManager::httpRequest(caretRequest, studyResponse); if (m_debugFlag) { - std::cout << "Request rolese response Code: " << studyResponse.m_responseCode << std::endl; + std::cout << "Request roles response Code: " << studyResponse.m_responseCode << std::endl; } if (studyResponse.m_responseCode != 200) { errorMessageOut = ("Requesting roles failed with HTTP code=" - + AString::number(studyResponse.m_responseCode)); + + AString::number(studyResponse.m_responseCode) + + ". "); + errorMessageOut.appendWithNewLine(studyResponse.m_errorMessage); return false; } @@ -1133,11 +1168,13 @@ BalsaDatabaseManager::getUserRoles(BalsaUserRoles& userRolesOut, } QJsonParseError jsonError; - QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Requesting roles failed. Failed to parse JSON, error:" - + jsonError.errorString()); + + jsonError.errorString() + + " Offset=" + + AString::number(jsonError.offset)); return false; } @@ -1212,7 +1249,9 @@ BalsaDatabaseManager::getStudyExtractDirectoryPrefix(const AString& studyID, if (studyResponse.m_responseCode != 200) { errorMessageOut = ("Requesting extract directory failed with HTTP code=" - + AString::number(studyResponse.m_responseCode)); + + AString::number(studyResponse.m_responseCode) + + ". "); + errorMessageOut.appendWithNewLine(studyResponse.m_errorMessage); return false; } @@ -1283,6 +1322,15 @@ BalsaDatabaseManager::getAllStudyInformation(std::vector& CaretHttpResponse idResponse; CaretHttpManager::httpRequest(caretRequest, idResponse); + idResponse.m_body.push_back('\0'); + AString responseContent(&idResponse.m_body[0]); + CaretLogFine("Get All Study Information Response from " + + studyIdURL + + ", Response Code=" + + AString::number(idResponse.m_responseCode) + + "\nContent:\n" + + responseContent); + if (m_debugFlag) { std::cout << "Request all studies response Code: " << idResponse.m_responseCode << std::endl; } @@ -1290,7 +1338,8 @@ BalsaDatabaseManager::getAllStudyInformation(std::vector& if (idResponse.m_responseCode != 200) { errorMessageOut = ("Requesting all study information failed with HTTP code=" + AString::number(idResponse.m_responseCode) - + ". This error may be caused by failure to agree to data use terms."); + + ". This error may be caused by failure to agree to data use terms. "); + errorMessageOut.appendWithNewLine(idResponse.m_errorMessage); return false; } @@ -1306,19 +1355,19 @@ BalsaDatabaseManager::getAllStudyInformation(std::vector& return false; } - idResponse.m_body.push_back('\0'); - AString responseContent(&idResponse.m_body[0]); if (m_debugFlag) { std::cout << "Request all studies reply body:\n" << responseContent << std::endl << std::endl; } QJsonParseError jsonError; - QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Requesting all study information failed. Failed to parse JSON, error:" - + jsonError.errorString()); + + jsonError.errorString() + + " Offset=" + + AString::number(jsonError.offset)); return false; } QByteArray json = jsonDocument.toJson(); diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index f94cc98c225c34665044ff2ab34310c85899b1a4..a664a8635bb0034726cdfb0764ba19c3b0efc43b 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -140,9 +140,10 @@ namespace caret { AString& errorMessageOut); bool verifyUploadFileResponse(const std::map& responseHeaders, - const AString& responseContent, - const int32_t responseHttpCode, - AString& errorMessageOut) const; + const AString& responseContent, + const int32_t responseHttpCode, + const AString& responseErrorMessage, + AString& errorMessageOut) const; AString getHeaderValue(const CaretHttpResponse& httpResponse, const AString& headerName) const; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 406542687d52750fad7a898d3070a30c8b640a60..4241e07583f1fe56425402d3a47979a91bd53c30 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -213,7 +213,7 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() /* * Show password tool button */ - m_showPasswordAction = new QAction("Show"); + m_showPasswordAction = new QAction("Show", this); m_showPasswordAction->setCheckable(true); m_showPasswordAction->setChecked(false); QObject::connect(m_showPasswordAction, &QAction::triggered, @@ -447,9 +447,14 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QWidget* BalsaDatabaseUploadSceneFileDialog::createBalsaDatabaseSelectionWidget() { - QString hostName = SystemUtilities::getLocalHostName(); - const bool isWustlDomainFlag = hostName.endsWith(".wustl.edu"); - + bool isWustlDomainFlag = false; + /* DOES NOT WORK ON MACOS 10.14, See note in: SystemUtilities::getLocalHostName() + QString hostName = SystemUtilities::getLocalHostName(); + bool isWustlDomainFlag = hostName.endsWith(".wustl.edu"); + */ +#ifndef NDEBUG + isWustlDomainFlag = true; +#endif /* * Database selection */ diff --git a/src/GuiQt/BorderOptimizeDialog.cxx b/src/GuiQt/BorderOptimizeDialog.cxx index 21a28ae93ab8359012287e6c2dcfbc4a7545880a..88ca9d4a56af645b8c7327dad2862093e5d43c48 100644 --- a/src/GuiQt/BorderOptimizeDialog.cxx +++ b/src/GuiQt/BorderOptimizeDialog.cxx @@ -100,6 +100,7 @@ m_browserTabIndex(-1), m_upsamplingSurfaceSelectionModel(NULL), m_upsamplingSurfaceStructure(StructureEnum::INVALID) { + m_objectNamePrefix + "BorderOptimizeDialog"; m_optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE); m_optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR); m_optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES); @@ -1015,7 +1016,10 @@ BorderOptimizeDialog::isKeepBoundaryBorderSelected() const QWidget* BorderOptimizeDialog::createSurfaceSelectionWidget() { - m_surfaceSelectionControl = new SurfaceSelectionViewController(this); + m_surfaceSelectionControl = new SurfaceSelectionViewController(this, + (m_objectNamePrefix + + ":SurfaceSelectionComboBox"), + "border sampling"); QObject::connect(m_surfaceSelectionControl, SIGNAL(surfaceSelected(Surface*)), this, SLOT(gradientComputatonSurfaceSelected(Surface*))); @@ -1035,7 +1039,10 @@ QWidget* BorderOptimizeDialog::createSphericalUpsamplingWidget() { QLabel* surfaceLabel = new QLabel("Current Sphere"); - m_upsamplingSurfaceSelectionControl = new SurfaceSelectionViewController(this); + m_upsamplingSurfaceSelectionControl = new SurfaceSelectionViewController(this, + (m_objectNamePrefix + + ":UpSamplingSurfaceSelection"), + "border upsampling"); QLabel* resolutionLabel = new QLabel("Upsampling Resolution"); m_upsamplingResolutionSpinBox = new QSpinBox(); diff --git a/src/GuiQt/BorderOptimizeDialog.h b/src/GuiQt/BorderOptimizeDialog.h index 70e8277c556c03d2cbf5dcd987ad3602c5bd2311..8369305c5e33b2c2980fa5bb63127f550a94c521 100644 --- a/src/GuiQt/BorderOptimizeDialog.h +++ b/src/GuiQt/BorderOptimizeDialog.h @@ -114,6 +114,8 @@ namespace caret { void preserveDialogSizeAndPositionWhenReOpened(); + QString m_objectNamePrefix; + QWidget* m_dialogWidget; Surface* m_surface; diff --git a/src/GuiQt/BorderSelectionViewController.cxx b/src/GuiQt/BorderSelectionViewController.cxx index d669b71ee529f42268f06357631e1dd3c25815b2..862614eed860a541ce6c7133482eee4f2c9132c4 100644 --- a/src/GuiQt/BorderSelectionViewController.cxx +++ b/src/GuiQt/BorderSelectionViewController.cxx @@ -49,6 +49,7 @@ #include "SceneClass.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQTabWidget.h" #include "WuQtUtilities.h" @@ -66,13 +67,25 @@ using namespace caret; /** * Constructor. + * + * @param browserWindowIndex + * Index of browser window + * @param parentObjectName + * Name of parent object + * @param parent + * The parent object */ BorderSelectionViewController::BorderSelectionViewController(const int32_t browserWindowIndex, - QWidget* parent) -: QWidget(parent) + const QString& parentObjectName, + QWidget* parent) +: QWidget(parent), +m_objectNamePrefix(parentObjectName + + ":Borders") { m_browserWindowIndex = browserWindowIndex; + WuQMacroManager* macroManager = WuQMacroManager::instance(); + QLabel* groupLabel = new QLabel("Group"); m_bordersDisplayGroupComboBox = new DisplayGroupEnumComboBox(this); QObject::connect(m_bordersDisplayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), @@ -86,6 +99,11 @@ BorderSelectionViewController::BorderSelectionViewController(const int32_t brows m_bordersDisplayCheckBox = new QCheckBox("Display Borders"); QObject::connect(m_bordersDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_bordersDisplayCheckBox->setObjectName(m_objectNamePrefix + + ":DisplayBorders"); + m_bordersDisplayCheckBox->setToolTip("Display Borders on Surfaces"); + macroManager->addMacroSupportToObject(m_bordersDisplayCheckBox, + "Enable borders display"); QWidget* attributesWidget = this->createAttributesWidget(); QWidget* selectionWidget = this->createSelectionWidget(); @@ -97,9 +115,13 @@ BorderSelectionViewController::BorderSelectionViewController(const int32_t brows m_tabWidget->addTab(selectionWidget, "Selection"); m_tabWidget->setCurrentWidget(attributesWidget); + m_tabWidget->getTabBar()->setObjectName(m_objectNamePrefix + + ":Tab"); + macroManager->addMacroSupportToObjectWithToolTip(m_tabWidget->getTabBar(), + "Features ToolBox Borders Tab", + "Select tab"); QVBoxLayout* layout = new QVBoxLayout(this); - //WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(m_bordersDisplayCheckBox); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(groupLayout); @@ -125,7 +147,11 @@ BorderSelectionViewController::~BorderSelectionViewController() QWidget* BorderSelectionViewController::createSelectionWidget() { - m_borderClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex); + m_borderClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex, + (m_objectNamePrefix + + ":Selection"), + "borders", + this); return m_borderClassNameHierarchyViewController; } @@ -136,9 +162,16 @@ BorderSelectionViewController::createSelectionWidget() QWidget* BorderSelectionViewController::createAttributesWidget() { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + m_bordersContralateralCheckBox = new QCheckBox("Contralateral"); QObject::connect(m_bordersContralateralCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_bordersContralateralCheckBox->setObjectName(m_objectNamePrefix + + ":Contralateral"); + m_bordersContralateralCheckBox->setToolTip("Show Contralateral Borders"); + macroManager->addMacroSupportToObject(m_bordersContralateralCheckBox, + "Enable contralateral borders display"); std::vector drawingTypeEnums; BorderDrawingTypeEnum::getAllEnums(drawingTypeEnums); @@ -156,6 +189,10 @@ BorderSelectionViewController::createAttributesWidget() "Polylines are slower but have unlimited width"); QObject::connect(m_drawTypeComboBox, SIGNAL(activated(int)), this, SLOT(processAttributesChanges())); + m_drawTypeComboBox->setObjectName(m_objectNamePrefix + + ":DrawingType"); + macroManager->addMacroSupportToObject(m_drawTypeComboBox, + "Select border drawing style"); QLabel* coloringLabel = new QLabel("Coloring"); m_coloringTypeComboBox = new EnumComboBoxTemplate(this); @@ -164,24 +201,31 @@ BorderSelectionViewController::createAttributesWidget() m_coloringTypeComboBox->getWidget()->setToolTip("Select the coloring assignment for borders"); QObject::connect(m_coloringTypeComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); + m_coloringTypeComboBox->getWidget()->setObjectName(m_objectNamePrefix + + ":ColoringType"); + macroManager->addMacroSupportToObject(m_coloringTypeComboBox->getWidget(), + "Select border coloring type"); QLabel* standardColorLabel = new QLabel("Standard Color"); - m_standardColorComboBox = new CaretColorEnumComboBox(this); + m_standardColorComboBox = new CaretColorEnumComboBox("", + QIcon(), + (m_objectNamePrefix + + ":Color"), + "Set border standard color", + this); m_standardColorComboBox->getWidget()->setToolTip("Select the standard color"); QObject::connect(m_standardColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(processAttributesChanges())); - float minLineWidth = 0; + float minLineWidth = 0.1; float maxLineWidth = 1000; - //BrainOpenGL::getMinMaxLineWidth(minLineWidth, - // maxLineWidth); QLabel* lineWidthLabel = new QLabel("Line Diameter"); m_lineWidthSpinBox = WuQFactory::newDoubleSpinBox(); m_lineWidthSpinBox->setFixedWidth(80); m_lineWidthSpinBox->setRange(minLineWidth, maxLineWidth); - m_lineWidthSpinBox->setSingleStep(1.0); + m_lineWidthSpinBox->setSingleStep(0.1); m_lineWidthSpinBox->setDecimals(1); m_lineWidthSpinBox->setSuffix("px"); m_lineWidthSpinBox->setToolTip("Adjust the width of borders drawn as lines.\n" @@ -193,22 +237,35 @@ BorderSelectionViewController::createAttributesWidget() "value of this control is changing"); QObject::connect(m_lineWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_lineWidthSpinBox->setObjectName(m_objectNamePrefix + + ":LineWidth"); + macroManager->addMacroSupportToObject(m_lineWidthSpinBox, + "Set border line width"); QLabel* pointSizeLabel = new QLabel("Symbol Diameter"); m_pointSizeSpinBox = WuQFactory::newDoubleSpinBox(); m_pointSizeSpinBox->setFixedWidth(80); m_pointSizeSpinBox->setRange(minLineWidth, maxLineWidth); - m_pointSizeSpinBox->setSingleStep(1.0); + m_pointSizeSpinBox->setSingleStep(0.1); m_pointSizeSpinBox->setDecimals(1); m_pointSizeSpinBox->setToolTip("Adjust the size of borders drawn as points"); m_pointSizeSpinBox->setSuffix("mm"); QObject::connect(m_pointSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_pointSizeSpinBox->setObjectName(m_objectNamePrefix + + ":PointSize"); + macroManager->addMacroSupportToObject(m_pointSizeSpinBox, + "Set border point size"); m_enableUnstretchedLinesCheckBox = new QCheckBox("Unstretched Lines"); QObject::connect(m_enableUnstretchedLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_enableUnstretchedLinesCheckBox->setToolTip("Disable lines that are invalid due to cuts in flat surface"); + m_enableUnstretchedLinesCheckBox->setObjectName(m_objectNamePrefix + + ":UnstretchedLines"); + macroManager->addMacroSupportToObject(m_enableUnstretchedLinesCheckBox, + "Enable border unstretched lines"); m_unstretchedLinesLengthSpinBox = WuQFactory::newDoubleSpinBox(); m_unstretchedLinesLengthSpinBox->setFixedWidth(80); @@ -221,6 +278,10 @@ BorderSelectionViewController::createAttributesWidget() m_unstretchedLinesLengthSpinBox->setSuffix("mm"); QObject::connect(m_unstretchedLinesLengthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_unstretchedLinesLengthSpinBox->setObjectName(m_objectNamePrefix + + ":UnstretchedLinesLength"); + macroManager->addMacroSupportToObject(m_unstretchedLinesLengthSpinBox, + "Set border unstretched lines lenght"); QLabel* aboveSurfaceLabel = new QLabel("Above Offset"); m_aboveSurfaceOffsetSpinBox =WuQFactory::newDoubleSpinBox(); @@ -233,6 +294,10 @@ BorderSelectionViewController::createAttributesWidget() "Use with caution.")); QObject::connect(m_aboveSurfaceOffsetSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_aboveSurfaceOffsetSpinBox->setObjectName(m_objectNamePrefix + + ":AboveSurfaceOffset"); + macroManager->addMacroSupportToObject(m_aboveSurfaceOffsetSpinBox, + "Set border above surface offset"); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); diff --git a/src/GuiQt/BorderSelectionViewController.h b/src/GuiQt/BorderSelectionViewController.h index 2ee174e8d247704218cb753934dc8e443324e187..cc962597c84ec3e669bbe24149fc416a824e051b 100644 --- a/src/GuiQt/BorderSelectionViewController.h +++ b/src/GuiQt/BorderSelectionViewController.h @@ -49,7 +49,8 @@ namespace caret { public: BorderSelectionViewController(const int32_t browserWindowIndex, - QWidget* parent = 0); + const QString& parentObjectName, + QWidget* parent = 0); virtual ~BorderSelectionViewController(); @@ -83,6 +84,8 @@ namespace caret { QWidget* createAttributesWidget(); + const QString m_objectNamePrefix; + int32_t m_browserWindowIndex; GroupAndNameHierarchyViewController* m_borderClassNameHierarchyViewController; diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index d42c19a1c875850a09ca28356be7225f03e6d3ea..7d457a1ec4eeb9d1e261011b264fc2e713f3591b 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -34,6 +34,9 @@ #include #include #include +#ifdef HAVE_WEBKIT +#include +#endif #define __BRAIN_BROWSER_WINDOW_DECLARE__ #include "BrainBrowserWindow.h" @@ -67,15 +70,18 @@ #include "EventGetViewportSize.h" #include "EventBrowserWindowCreateTabs.h" #include "EventBrowserWindowContent.h" +#include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" #include "EventDataFileRead.h" #include "EventMacDockMenuUpdate.h" #include "EventManager.h" #include "EventModelGetAll.h" +#include "EventGetOrSetUserInputModeProcessor.h" +#include "EventGraphicsTimingOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventSpecFileReadDataFiles.h" #include "EventSurfaceColoringInvalidate.h" -#include "EventGetOrSetUserInputModeProcessor.h" +#include "EventTileTabsConfigurationModification.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "FociProjectionDialog.h" @@ -93,8 +99,10 @@ #include "SceneClassAssistant.h" #include "SceneEnumeratedType.h" #include "SceneFile.h" +#include "SceneFileXmlStreamFormatTester.h" #include "SceneWindowGeometry.h" #include "SessionManager.h" +#include "SpacerTabContent.h" #include "SpecFile.h" #include "SpecFileManagementDialog.h" #include "StructureEnumComboBox.h" @@ -102,9 +110,13 @@ #include "SurfaceMontageConfigurationAbstract.h" #include "SurfaceSelectionViewController.h" #include "TileTabsConfiguration.h" +#include "TileTabsConfigurationModifier.h" #include "WuQDataEntryDialog.h" #include "WuQDoubleSpinBox.h" +#include "WuQMacroManager.h" +#include "WuQMacroMenu.h" #include "WuQMessageBox.h" +#include "WuQTabBar.h" #include "WuQtUtilities.h" #include "WuQTextEditorDialog.h" #include "VtkFileExporter.h" @@ -134,6 +146,8 @@ m_browserWindowIndex(browserWindowIndex) { m_developMenuAction = NULL; + m_objectNamePrefix = QString("Window%1").arg((int)(browserWindowIndex + 1), 2, 10, QLatin1Char('0')); + std::unique_ptr bwc = EventBrowserWindowContent::newWindowContent(m_browserWindowIndex); EventManager::get()->sendEvent(bwc->getPointer()); @@ -173,6 +187,7 @@ m_browserWindowIndex(browserWindowIndex) new BrainBrowserWindowOrientedToolBox(m_browserWindowIndex, "Overlay ToolBox", BrainBrowserWindowOrientedToolBox::TOOL_BOX_OVERLAYS_VERTICAL, + m_objectNamePrefix, this); m_overlayVerticalToolBox->setAllowedAreas(Qt::LeftDockWidgetArea); @@ -180,6 +195,7 @@ m_browserWindowIndex(browserWindowIndex) new BrainBrowserWindowOrientedToolBox(m_browserWindowIndex, "Overlay ToolBox ", BrainBrowserWindowOrientedToolBox::TOOL_BOX_OVERLAYS_HORIZONTAL, + m_objectNamePrefix, this); m_overlayHorizontalToolBox->setAllowedAreas(Qt::BottomDockWidgetArea); @@ -203,6 +219,7 @@ m_browserWindowIndex(browserWindowIndex) new BrainBrowserWindowOrientedToolBox(m_browserWindowIndex, "Features ToolBox", BrainBrowserWindowOrientedToolBox::TOOL_BOX_FEATURES, + m_objectNamePrefix, this); m_featuresToolBox->setAllowedAreas(Qt::RightDockWidgetArea); addDockWidget(Qt::RightDockWidgetArea, m_featuresToolBox); @@ -220,14 +237,21 @@ m_browserWindowIndex(browserWindowIndex) m_overlayToolBoxAction, m_featuresToolBoxAction, m_toolBarLockWindowAndAllTabAspectRatioButton, - this); + m_objectNamePrefix, + this); m_showToolBarAction = m_toolbar->toolBarToolButtonAction; addToolBar(m_toolbar); createActions(); createMenus(); - + + if (s_enableMacDuplicateMenuBarFlag) { + s_enableMacDuplicateMenuBarFlag = false; + + m_toolbar->insertDuplicateMenuBar(this); + } + m_toolbar->updateToolBar(); processShowOverlayToolBox(m_overlayToolBoxAction->isChecked()); @@ -246,9 +270,11 @@ m_browserWindowIndex(browserWindowIndex) m_defaultWindowComponentStatus.isToolBarDisplayed = m_showToolBarAction->isChecked(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_VIEWPORT_SIZE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_TILE_TABS_MODIFICATION); if (m_overlayHorizontalToolBox == m_overlayActiveToolBox) { /* @@ -273,6 +299,11 @@ m_browserWindowIndex(browserWindowIndex) gapsAndMargins->setSurfaceMontageVerticalGapForWindow(m_browserWindowIndex, 0.0f); gapsAndMargins->setVolumeMontageHorizontalGapForWindow(m_browserWindowIndex, 0.0f); gapsAndMargins->setVolumeMontageVerticalGapForWindow(m_browserWindowIndex, 0.0f); + + /* + * Allows keyboard events + */ + setFocusPolicy(Qt::StrongFocus); } /** @@ -310,6 +341,31 @@ BrainBrowserWindow::receiveEvent(Event* event) event->setEventProcessed(); } } + else if (event->getEventType()== EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS) { + EventCaretMappableDataFilesAndMapsInDisplayedOverlays* filesEvent = dynamic_cast(event); + CaretAssert(filesEvent); + + /* + * If true, all tabs are included even if tile tabs is off + */ + const bool useAllTabsFlag(true); + + std::vector tabContent; + if (isTileTabsSelected() + || useAllTabsFlag) { + m_toolbar->getAllTabContent(tabContent); + } + else { + BrowserTabContent* btc = m_toolbar->getTabContentFromSelectedTab(); + if (btc != NULL) { + tabContent.push_back(btc); + } + } + + for (auto btc : tabContent) { + btc->getFilesAndMapIndicesInOverlays(filesEvent); + } + } else if (event->getEventType() == EventTypeEnum::EVENT_GET_VIEWPORT_SIZE) { EventGetViewportSize* viewportSizeEvent = dynamic_cast(event); CaretAssert(viewportSizeEvent); @@ -323,6 +379,24 @@ BrainBrowserWindow::receiveEvent(Event* event) bool notBestViewportValid = false; switch (viewportSizeEvent->getMode()) { + case EventGetViewportSize::MODE_SPACER_TAB_INDEX: + for (std::vector::iterator vpIter = allViewportContent.begin(); + vpIter != allViewportContent.end(); + vpIter++) { + const SpacerTabIndex requestedSpacerTabIndex = viewportSizeEvent->getSpacerTabIndex(); + const BrainOpenGLViewportContent* vpContent = *vpIter; + if (vpContent != NULL) { + SpacerTabContent* stc = vpContent->getSpacerTabContent(); + if (stc != NULL) { + if (requestedSpacerTabIndex == stc->getSpacerTabIndex()) { + vpContent->getTabViewportBeforeApplyingMargins(viewport); + viewportValid = true; + break; + } + } + } + } + break; case EventGetViewportSize::MODE_SURFACE_MONTAGE: if (viewportSizeEvent->getIndex() == m_browserWindowIndex) { /* @@ -353,15 +427,17 @@ BrainBrowserWindow::receiveEvent(Event* event) const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); - if (btc->getTabNumber() == viewportSizeEvent->getIndex()) { - for (std::vector::const_iterator vpIter = allViewportContent.begin(); - vpIter != allViewportContent.end(); - vpIter++) { - const BrainOpenGLViewportContent* vpContent = *vpIter; - if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { - vpContent->getTabViewportBeforeApplyingMargins(viewport); - viewportValid = true; - break; + if (btc != NULL) { + if (btc->getTabNumber() == viewportSizeEvent->getIndex()) { + for (std::vector::const_iterator vpIter = allViewportContent.begin(); + vpIter != allViewportContent.end(); + vpIter++) { + const BrainOpenGLViewportContent* vpContent = *vpIter; + if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { + vpContent->getTabViewportBeforeApplyingMargins(viewport); + viewportValid = true; + break; + } } } } @@ -375,15 +451,17 @@ BrainBrowserWindow::receiveEvent(Event* event) const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); - if (btc->getTabNumber() == viewportSizeEvent->getIndex()) { - for (std::vector::const_iterator vpIter = allViewportContent.begin(); - vpIter != allViewportContent.end(); - vpIter++) { - const BrainOpenGLViewportContent* vpContent = *vpIter; - if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { - vpContent->getModelViewport(viewport); - viewportValid = true; - break; + if (btc != NULL) { + if (btc->getTabNumber() == viewportSizeEvent->getIndex()) { + for (std::vector::const_iterator vpIter = allViewportContent.begin(); + vpIter != allViewportContent.end(); + vpIter++) { + const BrainOpenGLViewportContent* vpContent = *vpIter; + if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { + vpContent->getModelViewport(viewport); + viewportValid = true; + break; + } } } } @@ -459,6 +537,14 @@ BrainBrowserWindow::receiveEvent(Event* event) viewportSizeEvent->setViewportSize(viewport); } } + else if (event->getEventType() == EventTypeEnum::EVENT_TILE_TABS_MODIFICATION) { + EventTileTabsConfigurationModification* modEvent = dynamic_cast(event); + CaretAssert(modEvent); + + if (modEvent->getWindowIndex() == this->m_browserWindowIndex) { + modifyTileTabsConfiguration(modEvent); + } + } else if ((event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) || (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS)) { /* @@ -695,6 +781,20 @@ BrainBrowserWindow::closeEvent(QCloseEvent* event) void BrainBrowserWindow::keyPressEvent(QKeyEvent* event) { + /* + * When there is a key press, it may take time to process such + * as when a macro runs. If the macro calls QApplication::processEvents(), + * it may result in this method getting called again by Qt + * before the macro has completed from a previous key press event. + * This flag will ignore key press events until a macro + * has had time to finish + */ + if (m_keyEventProcessingFlag) { + return; + } + m_keyEventProcessingFlag = true; + + bool keyEventWasProcessed = false; /* @@ -709,6 +809,11 @@ BrainBrowserWindow::keyPressEvent(QKeyEvent* event) } } + if ( ! keyEventWasProcessed) { + keyEventWasProcessed = WuQMacroManager::instance()->runMacroWithShortCutKeyEvent(this, + event); + } + /* * According to the documentation, if the key event was not acted upon, * pass it on the base class implementation. @@ -716,6 +821,8 @@ BrainBrowserWindow::keyPressEvent(QKeyEvent* event) if ( ! keyEventWasProcessed) { QMainWindow::keyPressEvent(event); } + + m_keyEventProcessingFlag = false; } /** @@ -753,6 +860,10 @@ BrainBrowserWindow::createActionsUsedByToolBar() else { m_overlayToolBoxAction->setIconText("OT"); } + m_overlayToolBoxAction->setObjectName(m_objectNamePrefix + + ":ToolBar:ShowOverlayToolBox"); + WuQMacroManager::instance()->addMacroSupportToObject(m_overlayToolBoxAction, + ("Show overlay toolbox in window " + QString::number(m_browserWindowIndex + 1))); /* * Note: The name of a dock widget becomes its @@ -771,8 +882,10 @@ BrainBrowserWindow::createActionsUsedByToolBar() else { m_featuresToolBoxAction->setIconText("LT"); } - - + m_featuresToolBoxAction->setObjectName(m_objectNamePrefix + + ":ToolBar:ShowFeaturesToolBox"); + WuQMacroManager::instance()->addMacroSupportToObject(m_featuresToolBoxAction, + ("Show features toolbox in window " + QString::number(m_browserWindowIndex + 1))); m_windowMenuLockWindowAspectRatioAction = new QAction(this); m_windowMenuLockWindowAspectRatioAction->setCheckable(true); @@ -808,6 +921,10 @@ BrainBrowserWindow::createActionsUsedByToolBar() m_toolBarLockWindowAndAllTabAspectRatioAction->setToolTip(aspectButtonToolTipText); QObject::connect(m_toolBarLockWindowAndAllTabAspectRatioAction, &QAction::triggered, this, &BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectTriggered); + m_toolBarLockWindowAndAllTabAspectRatioAction->setObjectName(m_objectNamePrefix + + ":ToolBar:LockAspectRatio"); + WuQMacroManager::instance()->addMacroSupportToObject(m_toolBarLockWindowAndAllTabAspectRatioAction, + ("Lock aspect ratio in window " + QString::number(m_browserWindowIndex + 1))); /* * Button for locking aspect is passed to ToolBar's constructor @@ -830,7 +947,7 @@ BrainBrowserWindow::createActionsUsedByToolBar() bool BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog() { - LockAspectWarningDialog::Result result = LockAspectWarningDialog::runDialog(m_browserWindowIndex); + LockAspectWarningDialog::Result result = LockAspectWarningDialog::runDialogEnterAnnotationsMode(m_browserWindowIndex); bool okFlag = true; @@ -839,7 +956,7 @@ BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog() okFlag = false; break; case LockAspectWarningDialog::Result::LOCK_ASPECT: - processToolBarLockWindowAndAllTabAspectTriggered(true); + processToolBarLockWindowAndAllTabAspectsRatios(true); break; case LockAspectWarningDialog::Result::NO_CHANGES: break; @@ -928,6 +1045,31 @@ BrainBrowserWindow::lockAllTabAspectRatios(const bool checked) */ void BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectTriggered(bool checked) +{ + if (checked) { + std::vector allTabContent; + m_toolbar->getAllTabContent(allTabContent); + const int32_t tabCount = static_cast(allTabContent.size()); + + const bool lockFlag = LockAspectWarningDialog::runDialogToolBarLockAspect(this, + tabCount); + if ( ! lockFlag) { + m_toolBarLockWindowAndAllTabAspectRatioAction->setChecked(false); + return; + } + } + + processToolBarLockWindowAndAllTabAspectsRatios(checked); +} + +/** + * Called when the toolbar's lock window and all tab aspect is triggered + * + * @param checked + * True if checked, false if unchecked + */ +void +BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectsRatios(bool checked) { lockWindowAspectRatio(checked); lockAllTabAspectRatios(checked); @@ -1143,6 +1285,15 @@ BrainBrowserWindow::processShowSurfacePropertiesDialog() GuiManager::get()->processShowSurfacePropertiesEditorDialog(this); } +/** + * Show the volume properties editor dialog. + */ +void +BrainBrowserWindow::processShowVolumePropertiesDialog() +{ + GuiManager::get()->processShowVolumePropertiesEditorDialog(this); +} + /** * Create actions for this window. * NOTE: This is called AFTER the toolbar is created. @@ -1176,7 +1327,11 @@ BrainBrowserWindow::createActions() this, this, SLOT(processNewTab())); - + m_newTabAction->setObjectName(m_objectNamePrefix + + ":Menu:NewTabAction"); + WuQMacroManager::instance()->addMacroSupportToObject(m_newTabAction, + ("Create new tab in Window " + QString::number(m_browserWindowIndex + 1))); + m_duplicateTabAction = WuQtUtilities::createAction("Duplicate Tab", "Create a new tab (window pane) that duplicates the selected tab in the window", @@ -1184,7 +1339,11 @@ BrainBrowserWindow::createActions() this, this, SLOT(processDuplicateTab())); - + m_duplicateTabAction->setObjectName(m_objectNamePrefix + + ":Menu:DuplicateTabAction"); + WuQMacroManager::instance()->addMacroSupportToObject(m_duplicateTabAction, + ("Duplicate tab in Window " + QString::number(m_browserWindowIndex + 1))); + m_openFileAction = WuQtUtilities::createAction("Open File...", "Open a data file including a spec file located on the computer", @@ -1245,8 +1404,15 @@ BrainBrowserWindow::createActions() this, SLOT(processCaptureImage())); - m_recordMovieAction = - WuQtUtilities::createAction("Animation Control...", + m_movieRecordingAction = + WuQtUtilities::createAction("Movie Recording...", + "Record the windows content", + this, + this, + SLOT(processMovieRecording())); + + m_recordMovieAction = + WuQtUtilities::createAction("(obsolete)Animation Control...", "Animate Brain Surface", this, this, @@ -1287,7 +1453,12 @@ BrainBrowserWindow::createActions() this); QObject::connect(m_viewFullScreenAction, SIGNAL(triggered()), this, SLOT(processViewFullScreenSelected())); - + /* + * "Full Screen" Fix on MacOS with Qt 5.12: + * Without this, the menu item may disappear on MacOS + */ + m_viewFullScreenAction->setMenuRole(QAction::NoRole); + /* * Note: If shortcut key is changed, also change the shortcut key * for the tile tabs configuration dialog menu item to match. @@ -1298,7 +1469,14 @@ BrainBrowserWindow::createActions() this); QObject::connect(m_viewTileTabsAction, SIGNAL(triggered()), this, SLOT(processViewTileTabs())); - + /* + * Fix on MacOS with Qt 5.12: + * Set role to 'NoRole' or else Qt may interpret + * "Enter Tile Tabs" and "Exit Tile Tabs" as "Enter + * Full Screen" and remove this item from the menu + */ + m_viewTileTabsAction->setMenuRole(QAction::NoRole); + m_viewTileTabsConfigurationDialogAction = WuQtUtilities::createAction("Edit Tile Tabs Configurations...", "", this, @@ -1471,6 +1649,9 @@ BrainBrowserWindow::createMenus() menubar->addMenu(connectMenu); } + menubar->addMenu(new WuQMacroMenu(this, + menubar)); + QMenu* developMenu = createMenuDevelop(); m_developMenuAction = menubar->addMenu(developMenu); m_developMenuAction->setVisible(prefs->isDevelopMenuEnabled()); @@ -1512,15 +1693,24 @@ BrainBrowserWindow::createMenuDevelop() QObject::connect(m_developerFlagsActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(developerMenuFlagTriggered(QAction*))); + bool lastItemCheckableFlag(true); for (std::vector::iterator iter = developerFlags.begin(); iter != developerFlags.end(); iter++) { const DeveloperFlagsEnum::Enum flag = *iter; - + + const bool itemCheckableFlag = DeveloperFlagsEnum::isCheckable(flag); + if (itemCheckableFlag != lastItemCheckableFlag) { + menu->addSeparator(); + } + QAction* action = menu->addAction(DeveloperFlagsEnum::toGuiName(flag)); - action->setCheckable(true); + action->setMenuRole(QAction::NoRole); // Menu item containing "Setup" is moved by Qt, see QTBUG-43588 + action->setCheckable(itemCheckableFlag); action->setData(static_cast(DeveloperFlagsEnum::toIntegerCode(flag))); m_developerFlagsActionGroup->addAction(action); + + lastItemCheckableFlag = itemCheckableFlag; } } @@ -1574,12 +1764,40 @@ BrainBrowserWindow::developerMenuFlagTriggered(QAction* action) DeveloperFlagsEnum::setFlag(enumValue, action->isChecked()); + /* + * If a developer flag is "not checkable" and should call a function + * test for the flag here and call the function + * + * if (enumValue == DeveloperFlagsEnum::) { + * someFunction(); + * } + */ +#ifdef HAVE_WEBKIT + if (enumValue == DeveloperFlagsEnum::DEVELOPER_FLAG_BALSA) { + static WuQDialogModal* balsaDialog(NULL); + if (balsaDialog == NULL) { + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + balsaDialog = new WuQDialogModal("BALSA", + this); + QWebEngineView* webView = new QWebEngineView(); + balsaDialog->setCentralWidget(webView, WuQDialogModal::SCROLL_AREA_NEVER); + webView->setUrl(QUrl(QStringLiteral("https://balsa.wustl.edu"))); + webView->resize(600, 800); + } + CaretAssert(balsaDialog); + balsaDialog->show(); + } + /* * Update graphics and GUI */ EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +#else + WuQMessageBox::informationOk(this, + "Software was built without Qt WebKit, see src/CMakeLists.txt"); +#endif } else { CaretLogSevere("Failed to find develper flag for reading menu: " @@ -1631,6 +1849,7 @@ BrainBrowserWindow::createMenuFile() menu->addSeparator(); menu->addAction(m_recordMovieAction); menu->addAction(m_captureImageAction); + menu->addAction(m_movieRecordingAction); menu->addSeparator(); menu->addAction(m_closeTabAction); menu->addAction(m_closeWindowAction); @@ -2068,6 +2287,8 @@ BrainBrowserWindow::processRecentSpecFileMenuSelection(QAction* itemAction) SpecFile specFile; try { specFile.readFile(specFileName); + SessionManager::get()->getCaretPreferences()->addToPreviousSpecFiles(specFileName); + if (m_recentSpecFileMenu->title() == m_recentSpecFileMenuOpenConfirmTitle) { if (GuiManager::get()->processShowOpenSpecFileDialog(&specFile, @@ -2227,17 +2448,17 @@ BrainBrowserWindow::processViewMenuAboutToShow() m_viewTileTabsAction->setText("Enter Tile Tabs"); } - m_viewAutomaticTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsConfigurationModeEnum::AUTOMATIC, + m_viewAutomaticTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsGridModeEnum::AUTOMATIC, true)); - m_viewCustomTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsConfigurationModeEnum::CUSTOM, + m_viewCustomTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsGridModeEnum::CUSTOM, true)); BrowserWindowContent* bwc = getBrowerWindowContent(); switch (bwc->getTileTabsConfigurationMode()) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: m_viewAutomaticTileTabsConfigurationAction->setChecked(true); break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: m_viewCustomTileTabsConfigurationAction->setChecked(true); break; } @@ -2253,16 +2474,16 @@ BrainBrowserWindow::processViewMenuAboutToShow() * Include the number of rows and columns. */ AString -BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsConfigurationModeEnum::Enum configurationMode, +BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum::Enum configurationMode, const bool includeRowsAndColumnsIn) const { bool includeRowsAndColumns = includeRowsAndColumnsIn; AString modeLabel; switch (configurationMode) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: modeLabel = "Automatic"; break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: modeLabel = "Custom"; break; } @@ -2274,12 +2495,12 @@ BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsConfiguratio const int32_t windowTabCount = static_cast(windowTabIndices.size()); AString errorText; switch (configurationMode) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: TileTabsConfiguration::getRowsAndColumnsForNumberOfTabs(windowTabCount, configRowCount, configColCount); break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: { const TileTabsConfiguration* customConfig = getBrowerWindowContent()->getCustomTileTabsConfiguration(); configRowCount = customConfig->getNumberOfRows(); @@ -2311,6 +2532,45 @@ BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsConfiguratio return textLabel; } +/** + * Modify the tile tabs configuration. + * + * @param modEvent + * Event with modification information. + */ +void +BrainBrowserWindow::modifyTileTabsConfiguration(EventTileTabsConfigurationModification* modEvent) +{ + CaretAssert(modEvent); + + if (modEvent->getWindowIndex() != m_browserWindowIndex) { + return; + } + + std::vector vpContent; + if (isTileTabsSelected()) { + vpContent = m_openGLWidget->getViewportContent(); + } + + TileTabsConfigurationModifier modifier(vpContent, + modEvent); + + AString errorMessage; + if (! modifier.run(errorMessage)) { + modEvent->setErrorMessage(errorMessage); + WuQMessageBox::errorOk(this, errorMessage); + } + + /* + * Update graphics and GUI + */ + EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + + modEvent->setEventProcessed(); +} + /** * Update the tile tabs configuration menu just before it is shown. */ @@ -2343,10 +2603,10 @@ BrainBrowserWindow::processViewTileTabsAutomaticCustomTriggered(QAction* action) { BrowserWindowContent* bwc = getBrowerWindowContent(); if (action == m_viewAutomaticTileTabsConfigurationAction) { - bwc->setTileTabsConfigurationMode(TileTabsConfigurationModeEnum::AUTOMATIC); + bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::AUTOMATIC); } else if (action == m_viewCustomTileTabsConfigurationAction) { - bwc->setTileTabsConfigurationMode(TileTabsConfigurationModeEnum::CUSTOM); + bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); } else { CaretAssert(0); @@ -2365,7 +2625,7 @@ BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered(QA CaretAssert(action); BrowserWindowContent* bwc = getBrowerWindowContent(); - bwc->setTileTabsConfigurationMode(TileTabsConfigurationModeEnum::CUSTOM); + bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); TileTabsConfiguration* tileTabsConfig = NULL; for (auto& config : m_viewCustomTileTabsConfigurationActions) { @@ -2649,7 +2909,13 @@ BrainBrowserWindow::processSurfaceMenuInformation() QMenu* BrainBrowserWindow::createMenuVolume() { - return NULL; + QMenu* menu = new QMenu("Volume", this); + + menu->addAction("Properties...", + this, + SLOT(processShowVolumePropertiesDialog())); + + return menu; } /** @@ -2766,16 +3032,24 @@ BrainBrowserWindow::processDevelopGraphicsTiming() ElapsedTimer et; et.start(); - const int32_t numTimes = 5; + const float numTimes(10.0); for (int32_t i = 0; i < numTimes; i++) { - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); + EventManager::get()->sendEvent(EventGraphicsTimingOneWindow(m_browserWindowIndex).getPointer()); } const float time = et.getElapsedTimeSeconds() / numTimes; const AString timeString = AString::number(time, 'f', 5); + AString fpsString; + if (time > 0.0) { + const float fps(1.0 / time); + fpsString = ("\nFrame per second: " + + AString::number(fps, 'f', 3)); + } const AString msg = ("Time to draw graphics (seconds): " - + timeString); + + timeString + + fpsString); + WuQMessageBox::informationOk(this, msg); } @@ -2884,6 +3158,15 @@ BrainBrowserWindow::processCaptureImage() GuiManager::get()->processShowImageCaptureDialog(this); } +/** + * Called when movie recording is selected. + */ +void +BrainBrowserWindow::processMovieRecording() +{ + GuiManager::get()->processShowMovieRecordingDialog(this); +} + /** * Called when capture image is selected. */ @@ -2934,6 +3217,7 @@ BrainBrowserWindow::processCloseAllFiles() CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); + prefs->invalidateSceneDataValues(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); @@ -3180,9 +3464,11 @@ BrainBrowserWindow::loadSceneFromCommandLine(const AString& sceneFileName, } if (scene != NULL) { + const bool showSceneDialogFlag(true); GuiManager::get()->processShowSceneDialogAndScene(this, sf, - scene); + scene, + showSceneDialogFlag); haveSceneError = false; break; } @@ -3352,7 +3638,15 @@ BrainBrowserWindow::loadFiles(QWidget* parentForDialogs, if (specFileName.isEmpty() == false) { SpecFile specFile; try { + FileInformation fileInfo(specFileName); + if (fileInfo.isRelative()) { + specFileName = fileInfo.getAbsoluteFilePath(); + } + if (fileInfo.exists()) { + SessionManager::get()->getCaretPreferences()->addToPreviousSpecFiles(specFileName); + } specFile.readFile(specFileName); + } catch (const DataFileException& e) { errorMessages += e.whatString(); @@ -4679,4 +4973,16 @@ BrainBrowserWindow::showDataFileReadWarningsDialog() } } +/** + * Set the enabled status for enabling mac duplicate menu bar for + * the next created toolbar. + */ +void +BrainBrowserWindow::setEnableMacDuplicateMenuBar(bool status) +{ + s_enableMacDuplicateMenuBarFlag = status; +} + + + diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index fdf5c685a1ef3ffa6db8886ca00e128920174a91..67dfd4ece040fa0646b97ebdfc733b4f1ab8245c 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -32,7 +32,7 @@ #include "DataFileTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" -#include "TileTabsConfigurationModeEnum.h" +#include "TileTabsGridModeEnum.h" class QAction; class QActionGroup; @@ -46,6 +46,7 @@ namespace caret { class BrainOpenGLWidget; class BrowserWindowContent; class BrowserTabContent; + class EventTileTabsConfigurationModification; class PlainTextStringBuilder; class SceneClassAssistant; class TileTabsConfiguration; @@ -149,11 +150,13 @@ namespace caret { bool isOpenGLContextSharingValid() const; - AString getTileTabsConfigurationLabelText(const TileTabsConfigurationModeEnum::Enum configurationMode, - const bool includeRowsAndColumns) const; + AString getTileTabsConfigurationLabelText(const TileTabsGridModeEnum::Enum configurationMode, + const bool includeRowsAndColumns) const; void resizeDockWidgets(const QList &docks, const QList &sizes, Qt::Orientation orientation); + static void setEnableMacDuplicateMenuBar(bool status); + protected: void closeEvent(QCloseEvent* event); void keyPressEvent(QKeyEvent* event); @@ -168,6 +171,7 @@ namespace caret { void processDataFileOpen(); void processManageSaveLoadedFiles(); void processCaptureImage(); + void processMovieRecording(); void processRecordMovie(); void processEditPreferences(); void processCloseAllFiles(); @@ -224,6 +228,7 @@ namespace caret { void processReportWorkbenchBug(); void processShowSurfacePropertiesDialog(); + void processShowVolumePropertiesDialog(); void processDevelopGraphicsTiming(); @@ -321,6 +326,8 @@ namespace caret { void lockAllTabAspectRatios(const bool checked); void updateActionsForLockingAspectRatios(); + void processToolBarLockWindowAndAllTabAspectsRatios(bool checked); + float getAspectRatioFromDialog(const AspectRatioMode aspectRatioMode, const QString& title, const float aspectRatio, @@ -328,6 +335,8 @@ namespace caret { void saveBrowserWindowContentForScene(); + void modifyTileTabsConfiguration(EventTileTabsConfigurationModification* modEvent); + /** Index of this window */ const int32_t m_browserWindowIndex; @@ -362,6 +371,8 @@ namespace caret { QAction* m_captureImageAction; + QAction* m_movieRecordingAction; + QAction* m_recordMovieAction; QAction* m_preferencesAction; @@ -461,6 +472,13 @@ namespace caret { static int32_t s_sceneFileFirstWindowY; static std::set s_brainBrowserWindows; + + QString m_objectNamePrefix; + + bool m_keyEventProcessingFlag = false; + + static bool s_enableMacDuplicateMenuBarFlag; + }; #ifdef __BRAIN_BROWSER_WINDOW_DECLARE__ std::set BrainBrowserWindow::s_brainBrowserWindows; @@ -471,6 +489,8 @@ namespace caret { bool BrainBrowserWindow::s_firstWindowFlag = true; int32_t BrainBrowserWindow::s_sceneFileFirstWindowX = -1; int32_t BrainBrowserWindow::s_sceneFileFirstWindowY = -1; + + bool BrainBrowserWindow::s_enableMacDuplicateMenuBarFlag = false; #endif // __BRAIN_BROWSER_WINDOW_DECLARE__ } diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index 4c0c416c268a4174ebc32ecc6e9a20fd8b807170..f7ee1e2c7bd3cd5aa6b47b077a77ab40b28a3ad2 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -45,6 +45,7 @@ #include "CiftiConnectivityMatrixViewController.h" #include "DeveloperFlagsEnum.h" #include "EventBrowserWindowDrawingContent.h" +#include "EventGetOrSetUserInputModeProcessor.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FiberOrientationSelectionViewController.h" @@ -56,8 +57,10 @@ #include "SceneClass.h" #include "SceneWindowGeometry.h" #include "SessionManager.h" +#include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineSetViewController.h" +#include "WuQMacroManager.h" #include "WuQTabWidgetWithSizeHint.h" #include "WuQtUtilities.h" @@ -70,12 +73,17 @@ using namespace caret; * Index of browser window that contains this toolbox. * @param title * Title for the toolbox. - * @param location - * Locations allowed for this toolbox. + * @param toolBoxType + * Type of toolbox + * @param parentObjectName + * Name of parent for macro objets + * @param parent + * The parent widget */ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32_t browserWindowIndex, const QString& title, const ToolBoxType toolBoxType, + const QString& parentObjectNamePrefix, QWidget* parent) : QDockWidget(parent) { @@ -86,8 +94,10 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 m_toolBoxTitle = title; setWindowTitle(m_toolBoxTitle); + bool isFeaturesToolBox = false; bool isOverlayToolBox = false; + QString typeSuffix; Qt::Orientation orientation = Qt::Horizontal; AString toolboxTypeName = ""; switch (toolBoxType) { @@ -96,21 +106,30 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 isFeaturesToolBox = true; toggleViewAction()->setText("Features Toolbox"); toolboxTypeName = "Features"; + typeSuffix = "Features"; break; case TOOL_BOX_OVERLAYS_HORIZONTAL: orientation = Qt::Horizontal; isOverlayToolBox = true; toolboxTypeName = "OverlayHorizontal"; + typeSuffix = "ToolBoxH"; break; case TOOL_BOX_OVERLAYS_VERTICAL: orientation = Qt::Vertical; isOverlayToolBox = true; toolboxTypeName = "OverlayVertical"; + typeSuffix = "ToolBoxV"; break; } + WuQMacroManager* macroManager = WuQMacroManager::instance(); + QString objectNamePrefix = (parentObjectNamePrefix + + ":" + + typeSuffix); + /* * Needed for saving and restoring window state in main window + * CHANGING THIS WILL BREAK SCENES !!! */ CaretAssert(toolboxTypeName.length() > 0); setObjectName("BrainBrowserWindowOrientedToolBox_" @@ -151,6 +170,9 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 break; } #endif + m_tabWidget->setObjectName(objectNamePrefix + + ":Tab"); + macroManager->addMacroSupportToObjectWithToolTip(m_tabWidget, "Toolbox tab", ""); m_annotationTabIndex = -1; m_borderTabIndex = -1; @@ -166,46 +188,59 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 if (isOverlayToolBox) { m_overlaySetViewController = new OverlaySetViewController(orientation, - browserWindowIndex, - this); + browserWindowIndex, + objectNamePrefix, + this); m_overlayTabIndex = addToTabWidget(m_overlaySetViewController, "Layers"); } if (isOverlayToolBox) { m_chartOverlaySetViewController = new ChartTwoOverlaySetViewController(orientation, - browserWindowIndex, - this); + browserWindowIndex, + objectNamePrefix, + this); m_chartOverlayTabIndex = addToTabWidget(m_chartOverlaySetViewController, "Chart Layers"); } if (isOverlayToolBox) { m_chartToolBoxViewController = new ChartToolBoxViewController(orientation, browserWindowIndex, + objectNamePrefix, this); m_chartTabIndex = addToTabWidget(m_chartToolBoxViewController, "Charting"); } if (isOverlayToolBox) { - m_connectivityMatrixViewController = new CiftiConnectivityMatrixViewController(orientation, + m_connectivityMatrixViewController = new CiftiConnectivityMatrixViewController(objectNamePrefix, this); m_connectivityTabIndex = addToTabWidget(m_connectivityMatrixViewController, "Connectivity"); } if (isFeaturesToolBox) { m_annotationViewController = new AnnotationSelectionViewController(browserWindowIndex, + objectNamePrefix, this); m_annotationTextSubstitutionViewController = new AnnotationTextSubstitutionViewController(browserWindowIndex, + objectNamePrefix, this); m_annotationTabWidget = new QTabWidget(); m_annotationTabWidget->addTab(m_annotationViewController, "Annotations"); m_annotationTabWidget->addTab(m_annotationTextSubstitutionViewController, "Substitutions"); + m_annotationTabWidget->setObjectName(objectNamePrefix + + ":AnnotationTab"); + macroManager->addMacroSupportToObjectWithToolTip(m_annotationTabWidget, + "Features ToolBox Annotation Tab", + ""); + m_annotationTabIndex = addToTabWidget(m_annotationTabWidget, "Annot"); + m_annotationTabWidget->setCurrentIndex(0); } if (isFeaturesToolBox) { m_borderSelectionViewController = new BorderSelectionViewController(browserWindowIndex, - this); + objectNamePrefix, + this); m_borderTabIndex = addToTabWidget(m_borderSelectionViewController, "Borders"); } @@ -219,6 +254,7 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 if (isFeaturesToolBox) { m_fociSelectionViewController = new FociSelectionViewController(browserWindowIndex, + objectNamePrefix, this); m_fociTabIndex = addToTabWidget(m_fociSelectionViewController, "Foci"); @@ -226,6 +262,7 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 if (isFeaturesToolBox) { m_imageSelectionViewController = new ImageSelectionViewController(browserWindowIndex, + objectNamePrefix, this); m_imageTabIndex = addToTabWidget(m_imageSelectionViewController, "Images"); @@ -233,6 +270,7 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 if (isFeaturesToolBox) { m_labelSelectionViewController = new LabelSelectionViewController(browserWindowIndex, + objectNamePrefix, this); m_labelTabIndex = addToTabWidget(m_labelSelectionViewController, "Labels"); @@ -240,7 +278,9 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 if (isOverlayToolBox) { m_volumeSurfaceOutlineSetViewController = new VolumeSurfaceOutlineSetViewController(orientation, - m_browserWindowIndex); + m_browserWindowIndex, + objectNamePrefix, + "toolbox"); m_volumeSurfaceOutlineTabIndex = addToTabWidget(m_volumeSurfaceOutlineSetViewController, "Vol/Surf Outline"); } @@ -250,7 +290,6 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 if (orientation == Qt::Horizontal) { setMinimumHeight(200); setMaximumHeight(800); - //setSizeHintHeight(200); } else { if (isOverlayToolBox) { @@ -618,6 +657,7 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) * Determine types of data this is loaded */ bool haveAnnotation = ( ! brain->getSceneAnnotationFile()->isEmpty()); + bool haveAnnSub = false; bool haveBorders = false; bool haveConnFiles = false; bool haveFibers = false; @@ -640,7 +680,7 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) haveAnnotation = true; break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: - haveAnnotation = true; + haveAnnSub = true; break; case DataFileTypeEnum::BORDER: haveBorders = true; @@ -693,6 +733,9 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + haveConnFiles = true; + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -717,6 +760,14 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) } } break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + haveConnFiles = true; +// haveVolumes = true; +// const VolumeDynamicConnectivityFile* volDynConnFile = vf->getVolumeDynamicConnectivityFile(); +// if (volDynConnFile != NULL) { +// haveConnFiles = true; +// } + break; } } @@ -776,6 +827,33 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) } } + EventGetOrSetUserInputModeProcessor inputModeEvent(m_browserWindowIndex); + EventManager::get()->sendEvent(inputModeEvent.getPointer()); + const UserInputModeEnum::Enum inputMode = inputModeEvent.getUserInputMode(); + switch (inputMode) { + case UserInputModeEnum::ANNOTATIONS: + break; + case UserInputModeEnum::BORDERS: + /* + * Enable borders tab if the input mode is 'borders' so that user + * can edit border point size while drawing a border before any + * borders exist. + */ + haveBorders = true; + break; + case UserInputModeEnum::FOCI: + break; + case UserInputModeEnum::IMAGE: + break; + case UserInputModeEnum::INVALID: + break; + case UserInputModeEnum::VIEW: + break; + case UserInputModeEnum::VOLUME_EDIT: + break; + } + + /* * Get the selected tab BEFORE enabling/disabling tabs. * Otherwise, the enabling/disabling of tabs may cause the selection @@ -794,7 +872,8 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) if (m_connectivityTabIndex >= 0) m_tabWidget->setTabEnabled(m_connectivityTabIndex, haveConnFiles); if (m_volumeSurfaceOutlineTabIndex >= 0) m_tabWidget->setTabEnabled(m_volumeSurfaceOutlineTabIndex, enableVolumeSurfaceOutline); - if (m_annotationTabIndex >= 0) m_tabWidget->setTabEnabled(m_annotationTabIndex, haveAnnotation); + if (m_annotationTabIndex >= 0) m_tabWidget->setTabEnabled(m_annotationTabIndex, (haveAnnotation + || haveAnnSub)); if (m_borderTabIndex >= 0) m_tabWidget->setTabEnabled(m_borderTabIndex, haveBorders); if (m_fiberOrientationTabIndex >= 0) m_tabWidget->setTabEnabled(m_fiberOrientationTabIndex, haveFibers); if (m_fociTabIndex >= 0) m_tabWidget->setTabEnabled(m_fociTabIndex, haveFoci); @@ -803,6 +882,21 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) if (m_overlayTabIndex >= 0) m_tabWidget->setTabEnabled(m_overlayTabIndex, enableLayers); + if (m_annotationTabWidget != NULL) { + const int32_t numTabs = m_annotationTabWidget->count(); + for (int32_t iTab = 0; iTab < numTabs; iTab++) { + if (m_annotationTabWidget->widget(iTab) == m_annotationViewController) { + m_annotationTabWidget->setTabEnabled(iTab, haveAnnotation); + } + else if (m_annotationTabWidget->widget(iTab) == m_annotationTextSubstitutionViewController) { + m_annotationTabWidget->setTabEnabled(iTab, haveAnnSub); + } + else { + CaretAssertMessage(0, "Has new annotation sub tab been added?"); + } + } + } + /* * Switch selected tab if it is not valid */ diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.h b/src/GuiQt/BrainBrowserWindowOrientedToolBox.h index 726ab312cbbad37879a0f0c2652318a8aa401f44..b051b2b389c35c62327d5060a23312eddfcdaaf0 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.h +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.h @@ -56,9 +56,10 @@ namespace caret { }; BrainBrowserWindowOrientedToolBox(const int32_t browserWindowIndex, - const QString& title, - const ToolBoxType toolBoxType, - QWidget* parent = 0); + const QString& title, + const ToolBoxType toolBoxType, + const QString& parentObjectName, + QWidget* parent = 0); ~BrainBrowserWindowOrientedToolBox(); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 3d4329805b8409181c8e913e34897cd4cafbe48e..f1fffa402c594d459c66ae7dc4ebc93493c231de 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -68,6 +67,7 @@ #include "BrainBrowserWindowToolBarTab.h" #include "BrainBrowserWindowToolBarTabPopUpMenu.h" #include "BrainBrowserWindowToolBarVolumeMontage.h" +#include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" @@ -78,6 +78,7 @@ #include "CursorDisplayScoped.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesBorders.h" +#include "EventBrowserTabNewClone.h" #include "EventBrowserTabDelete.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" @@ -93,10 +94,12 @@ #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "EventModelGetAll.h" +#include "EventSceneActive.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUpdateYokedWindows.h" #include "GuiManager.h" #include "LockAspectWarningDialog.h" +#include "MacDuplicateMenuBar.h" #include "Model.h" #include "ModelChart.h" #include "ModelChartTwo.h" @@ -107,6 +110,7 @@ #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "OverlaySet.h" +#include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneIntegerArray.h" @@ -123,7 +127,9 @@ #include "VolumeSurfaceOutlineSetModel.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQMessageBox.h" +#include "WuQTabBar.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -144,6 +150,8 @@ using namespace caret; * Action to show layers tool box. * @param toolBarLockWindowAndAllTabAspectRatioButton * Button to lock window's aspect ratio and aspect ratio of all tabs. + * @param objectNamePrefix + * Prefix for object name * @param parent * Parent for this toolbar. */ @@ -152,6 +160,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QAction* overlayToolBoxAction, QAction* layersToolBoxAction, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, + const QString& objectNamePrefix, BrainBrowserWindow* parentBrainBrowserWindow) : QToolBar(parentBrainBrowserWindow) { @@ -175,13 +184,14 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow /* * Needed for saving and restoring window state in main window */ - setObjectName("BrainBrowserWindowToolBar_" - + AString::number(browserWindowIndex)); + m_objectNamePrefix = (objectNamePrefix + + ":ToolBar"); + setObjectName(m_objectNamePrefix); /* * Create tab bar that displays models. */ - this->tabBar = new QTabBar(); + this->tabBar = new WuQTabBar(); if (WuQtUtilities::isSmallDisplay()) { this->tabBar->setStyleSheet("QTabBar::tab:selected {" " font: bold;" @@ -232,7 +242,12 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this, SLOT(tabCloseSelected(int))); QObject::connect(this->tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int))); + this->tabBar->setObjectName(m_objectNamePrefix + + ":Tab"); + WuQMacroManager::instance()->addMacroSupportToObjectWithToolTip(qobject_cast(this->tabBar), + "ToolBar Tab", + "Select Tab"); /* * Add context menu @@ -255,6 +270,10 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this, this, SLOT(customViewActionTriggered())); + this->customViewAction->setObjectName(m_objectNamePrefix + + ":CustomView"); + WuQMacroManager::instance()->addMacroSupportToObject(this->customViewAction, + "Display custom view dialog"); /* * Actions at right side of toolbar @@ -267,9 +286,52 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QToolButton* helpDialogToolButton = new QToolButton(); helpDialogToolButton->setDefaultAction(GuiManager::get()->getHelpViewerDialogDisplayAction()); - + + /* + * Scene button + */ QToolButton* sceneDialogToolButton = new QToolButton(); + sceneDialogToolButton->setText(""); + sceneDialogToolButton->setIcon(GuiManager::get()->getSceneDialogDisplayAction()->icon()); sceneDialogToolButton->setDefaultAction(GuiManager::get()->getSceneDialogDisplayAction()); + QObject::connect(sceneDialogToolButton, &QToolButton::clicked, + this, &BrainBrowserWindowToolBar::sceneToolButtonClicked); + + /* + * Movie button + */ + QIcon movieIcon; + QString movieButtonText; + if ( ! WuQtUtilities::loadIcon(":/ToolBar/movie.png", + movieIcon)) { + movieButtonText = "Movie"; + } + const QString movieButtonToolTip("Show movie recording window"); + m_movieToolButton = new QToolButton(); + m_movieToolButton->setText(movieButtonText); + m_movieToolButton->setIcon(movieIcon); + m_movieToolButton->setToolTip(movieButtonToolTip); + QObject::connect(m_movieToolButton, &QToolButton::clicked, + parentBrainBrowserWindow, &BrainBrowserWindow::processMovieRecording); + + /* + * Macros button + */ + QIcon macrosIcon; + QAction* macrosAction = new QAction(); + if (WuQtUtilities::loadIcon(":/ToolBar/macro.png", + macrosIcon)) { + macrosAction->setIcon(macrosIcon); + } + else { + macrosAction->setText("M"); + } + macrosAction->setToolTip("Show macros window"); + QObject::connect(macrosAction, &QAction::triggered, + this, &BrainBrowserWindowToolBar::showMacroDialog); + QToolButton* macrosToolButton = new QToolButton(); + macrosToolButton->setDefaultAction(macrosAction); + macrosAction->setParent(macrosToolButton); /* * Toolbar action and tool button at right of the tab bar @@ -297,6 +359,10 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->toolBarToolButtonAction->blockSignals(false); QToolButton* toolBarToolButton = new QToolButton(); toolBarToolButton->setDefaultAction(this->toolBarToolButtonAction); + toolBarToolButtonAction->setObjectName(m_objectNamePrefix + + ":ShowToolBar"); + WuQMacroManager::instance()->addMacroSupportToObject(toolBarToolButtonAction, + "Show toolbar"); /* * Toolbox control at right of the tab bar @@ -307,17 +373,25 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QToolButton* layersToolBoxToolButton = new QToolButton(); layersToolBoxToolButton->setDefaultAction(layersToolBoxAction); + QToolButton* dataToolTipsToolButton = new QToolButton(); + dataToolTipsToolButton->setDefaultAction(GuiManager::get()->getDataToolTipsAction(dataToolTipsToolButton)); + /* * Make all tool buttons the same height */ - WuQtUtilities::matchWidgetHeights(helpDialogToolButton, + WuQtUtilities::matchWidgetHeights(macrosToolButton, + m_movieToolButton, + helpDialogToolButton, informationDialogToolButton, identifyDialogToolButton, sceneDialogToolButton, toolBarToolButton, overlayToolBoxToolButton, - layersToolBoxToolButton); + layersToolBoxToolButton, + dataToolTipsToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(macrosToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_movieToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(helpDialogToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(informationDialogToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(identifyDialogToolButton); @@ -325,6 +399,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow WuQtUtilities::setToolButtonStyleForQt5Mac(toolBarToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(overlayToolBoxToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(layersToolBoxToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(dataToolTipsToolButton); /* * Tab bar and controls at far right side of toolbar @@ -333,9 +408,12 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QHBoxLayout* tabBarLayout = new QHBoxLayout(this->tabBarWidget); WuQtUtilities::setLayoutSpacingAndMargins(tabBarLayout, 2, 1); tabBarLayout->addWidget(this->tabBar, 100); + tabBarLayout->addWidget(dataToolTipsToolButton); tabBarLayout->addWidget(helpDialogToolButton); tabBarLayout->addWidget(informationDialogToolButton); tabBarLayout->addWidget(identifyDialogToolButton); + tabBarLayout->addWidget(m_movieToolButton); + tabBarLayout->addWidget(macrosToolButton); tabBarLayout->addWidget(sceneDialogToolButton); tabBarLayout->addWidget(toolBarToolButton); tabBarLayout->addWidget(overlayToolBoxToolButton); @@ -428,11 +506,11 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow * Arrange the tabbar and the toolbar vertically. */ QWidget* w = new QWidget(); - QVBoxLayout* layout = new QVBoxLayout(w); - WuQtUtilities::setLayoutSpacingAndMargins(layout, 1, 0); - layout->addWidget(this->tabBarWidget); - layout->addWidget(m_toolbarWidget); - layout->addWidget(this->userInputControlsWidget); + m_toolBarMainLayout = new QVBoxLayout(w); + WuQtUtilities::setLayoutSpacingAndMargins(m_toolBarMainLayout, 1, 0); + m_toolBarMainLayout->addWidget(this->tabBarWidget); + m_toolBarMainLayout->addWidget(m_toolbarWidget); + m_toolBarMainLayout->addWidget(this->userInputControlsWidget); this->addWidget(w); @@ -461,6 +539,11 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); + + QObject::connect(this->tabBar, &WuQTabBar::mousePressedSignal, + this, &BrainBrowserWindowToolBar::tabBarMousePressedSlot); + QObject::connect(this->tabBar, &WuQTabBar::mouseReleasedSignal, + this, &BrainBrowserWindowToolBar::tabBarMouseReleasedSlot); } /** @@ -534,6 +617,29 @@ BrainBrowserWindowToolBar::~BrainBrowserWindowToolBar() this->isDestructionInProgress = false; } +/** + * Insert a duplicate of the application's menu at the top of the toolbar. + * This is only enabled on MacOSX. + * + * @param mainWindow + * Main window whose menus are copied. + */ +void +BrainBrowserWindowToolBar::insertDuplicateMenuBar(QMainWindow* mainWindow) +{ +#ifndef CARET_OS_MACOSX + return; +#endif + MacDuplicateMenuBar* menuBar = new MacDuplicateMenuBar(mainWindow, + this); + CaretAssert(menuBar); + + /* + * Insert at top of tool bar + */ + m_toolBarMainLayout->insertWidget(0, menuBar); +} + /** * Create a new tab. NOTE: This method only creates * a new tab, it DOES NOT add the tab to the toolbar. @@ -600,16 +706,19 @@ BrainBrowserWindowToolBar::insertAndCloneTabContentAtTabBarIndex(const BrowserTa CursorDisplayScoped cursor; cursor.showWaitCursor(); - AString errorMessage; - BrowserTabContent* tabContent = this->createNewTab(errorMessage); - if (tabContent == NULL) { + EventBrowserTabNewClone cloneTabEvent(browserTabContentToBeCloned->getTabNumber()); + EventManager::get()->sendEvent(cloneTabEvent.getPointer()); + if (cloneTabEvent.isError()) { cursor.restoreCursor(); QMessageBox::critical(this, "", - errorMessage); + cloneTabEvent.getErrorMessage()); return; } + BrowserTabContent* tabContent = cloneTabEvent.getNewBrowserTab(); + CaretAssert(tabContent); + if (tabBarIndex >= 0){ insertTabContentPrivate(InsertTabMode::AT_TAB_BAR_INDEX, tabContent, @@ -621,13 +730,6 @@ BrainBrowserWindowToolBar::insertAndCloneTabContentAtTabBarIndex(const BrowserTa -1); } - if (browserTabContentToBeCloned != NULL) { - /* - * New tab is clone of tab that was displayed when the new tab was created. - */ - tabContent->cloneBrowserTabContent(const_cast(browserTabContentToBeCloned)); - } - this->updateToolBar(); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); @@ -648,6 +750,79 @@ BrainBrowserWindowToolBar::addNewTabWithContent(BrowserTabContent* tabContent) -1); } +/** + * Replace the current browser tabs with the given browser tabs. Tabs will be added + * or removed as needed. + * + * @param browserTabs + * Browser tabs for this window. + */ +void +BrainBrowserWindowToolBar::replaceBrowserTabs(const std::vector& browserTabs) +{ + const int32_t numTabs = static_cast(browserTabs.size()); + if (numTabs <= 0) { + return; + } + + QSignalBlocker blocker(this->tabBar); + + int32_t selectedTabIndex = this->tabBar->currentIndex(); + + /* + * Remove BrowserTabContent from all tabs since tabs may be + * closed and closing the tab will try to delete the BrowserTabContent + * in the tab but this BrowserTabContent may still be valid. + */ + const int32_t beforeNumTabs = this->tabBar->count(); + for (int32_t iTab = 0; iTab < beforeNumTabs; iTab++) { + this->tabBar->setTabData(iTab, + qVariantFromValue((void*)NULL)); + } + + /* + * Add/remove tabs as needed + */ + if (beforeNumTabs < numTabs) { + const int32_t numToAdd = numTabs - beforeNumTabs; + for (int32_t i = 0; i < numToAdd; i++) { + this->tabBar->addTab(""); + } + } + else if (beforeNumTabs > numTabs) { + const int32_t numToRemove = beforeNumTabs - numTabs; + for (int32_t i = 0; i < numToRemove; i++) { + const int32_t lastTabIndex = this->tabBar->count() - 1; + this->tabBar->removeTab(lastTabIndex); + } + } + CaretAssert(this->tabBar->count() == numTabs); + + /* + * Set content and update name for each tab + */ + for (int32_t iTab = 0; iTab < numTabs; iTab++) { + CaretAssertVectorIndex(browserTabs, iTab); + BrowserTabContent* btc = browserTabs[iTab]; + CaretAssert(btc); + this->tabBar->setTabData(iTab, + qVariantFromValue((void*)btc)); + this->updateTabName(iTab); + } + + + const int32_t numOpenTabs = this->tabBar->count(); + this->tabBar->setTabsClosable(numOpenTabs > 1); + + if (selectedTabIndex >= numTabs) { + selectedTabIndex = numTabs - 1; + } + if (selectedTabIndex < 0) { + selectedTabIndex = 0; + } + this->tabBar->setCurrentIndex(selectedTabIndex); +} + /** * Adds a new tab. */ @@ -736,31 +911,6 @@ BrainBrowserWindowToolBar::insertTabContentPrivate(const InsertTabMode insertTab "NewTab"); } break; - case InsertTabMode::AT_TAB_CONTENTS_INDEX: - { - const int32_t tabContentIndex = browserTabContent->getTabNumber(); - - const int32_t numTabs = this->tabBar->count(); - if (numTabs <= 0) { - newTabIndex = this->tabBar->addTab("NewTab"); - } - else { - int insertIndex = 0; - for (int32_t i = 0; i < numTabs; i++) { - if (tabContentIndex > this->getTabContentFromTab(i)->getTabNumber()) { - insertIndex = i + 1; - } - } - if (insertIndex >= numTabs) { - newTabIndex = this->tabBar->addTab("NewTab"); - } - else { - this->tabBar->insertTab(insertIndex, "NewTab"); - newTabIndex = insertIndex; - } - } - } - break; } this->tabBar->setTabData(newTabIndex, @@ -809,10 +959,10 @@ BrainBrowserWindowToolBar::allowAddingNewTab() * Automatic configuration always shows all tabs */ switch (browserWindowContent->getTileTabsConfigurationMode()) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: return true; break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: break; } @@ -851,6 +1001,16 @@ BrainBrowserWindowToolBar::allowAddingNewTab() return false; } +/** + * Show the macro dialog + */ +void +BrainBrowserWindowToolBar::showMacroDialog() +{ + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); + CaretAssert(bbw); + WuQMacroManager::instance()->showMacrosDialog(bbw); +} /** * Shows/hides the toolbar. @@ -1496,6 +1656,44 @@ BrainBrowserWindowToolBar::resetTabIndexForTileTabsHighlighting() EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->browserWindowIndex).getPointer()); } +/** + * Called when tab bar mouse pressed. + */ +void +BrainBrowserWindowToolBar::tabBarMousePressedSlot() +{ + /* + * Dragging tabs is slow because as the tab is moved, there are many graphics + * and user-interface updates each time the tab changes. So, disable these updates + * during the time the mouse is pressed and until it is released. Note that we + * block the "all windows graphics" update but not the individual window update. + * The individual window graphics update is needed to draw the box around the selected tab. + */ + EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, true); + EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, true); +} + +/** + * Called when tab bar mouse released. + */ +void +BrainBrowserWindowToolBar::tabBarMouseReleasedSlot() +{ + /* + * Enable user-interface updates and graphics drawing since any tab + * dragging has finished. + */ + EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, false); + EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, false); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); + + /** + * Causes graphics and user-interface to update. + * A box is drawn around selected tab. + */ + selectedTabChanged(tabBar->currentIndex()); +} + /** * Gets called when user closes a tab by clicking the tab's 'X'. * @@ -1826,12 +2024,51 @@ BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTab QWidget* BrainBrowserWindowToolBar::createViewWidget() { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + const QString objectNamePrefix(m_objectNamePrefix + + ":ViewMode"); + this->viewModeChartOneRadioButton = new QRadioButton("Chart Old"); + this->viewModeChartOneRadioButton->setToolTip("Show Old Chart View"); + this->viewModeChartOneRadioButton->setObjectName(objectNamePrefix + + ":ChartOld"); + macroManager->addMacroSupportToObject(this->viewModeChartOneRadioButton, + "Select Chart Old View"); + this->viewModeChartTwoRadioButton = new QRadioButton("Chart"); + this->viewModeChartTwoRadioButton->setToolTip("Show Chart View"); + this->viewModeChartTwoRadioButton->setObjectName(objectNamePrefix + + ":Chart"); + macroManager->addMacroSupportToObject(this->viewModeChartTwoRadioButton, + "Select Chart View"); + this->viewModeSurfaceRadioButton = new QRadioButton("Surface"); + this->viewModeSurfaceRadioButton->setToolTip("Show Surace View"); + this->viewModeSurfaceRadioButton->setObjectName(objectNamePrefix + + ":Surface"); + macroManager->addMacroSupportToObject(this->viewModeSurfaceRadioButton, + "Select surface view"); + this->viewModeSurfaceMontageRadioButton = new QRadioButton("Montage"); + this->viewModeSurfaceMontageRadioButton->setToolTip("Show Montage View"); + this->viewModeSurfaceMontageRadioButton->setObjectName(objectNamePrefix + + ":Montage"); + macroManager->addMacroSupportToObject(this->viewModeSurfaceMontageRadioButton, + "Select surface montage view"); + this->viewModeVolumeRadioButton = new QRadioButton("Volume"); + this->viewModeVolumeRadioButton->setToolTip("Show Volume View"); + this->viewModeVolumeRadioButton->setObjectName(objectNamePrefix + + ":Volume"); + macroManager->addMacroSupportToObject(this->viewModeVolumeRadioButton, + "Select volume view"); + this->viewModeWholeBrainRadioButton = new QRadioButton("All"); + this->viewModeWholeBrainRadioButton->setToolTip("Show All View"); + this->viewModeWholeBrainRadioButton->setObjectName(objectNamePrefix + + ":All"); + macroManager->addMacroSupportToObject(this->viewModeWholeBrainRadioButton, + "Select all view"); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); @@ -1947,6 +2184,11 @@ BrainBrowserWindowToolBar::updateViewWidget(BrowserTabContent* browserTabContent QWidget* BrainBrowserWindowToolBar::createOrientationWidget() { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + const QString objectNamePrefix(m_objectNamePrefix + + ":Orientation:"); + this->viewOrientationLeftIcon = WuQtUtilities::loadIcon(":/ToolBar/view-left.png"); this->viewOrientationRightIcon = WuQtUtilities::loadIcon(":/ToolBar/view-right.png"); this->viewOrientationAnteriorIcon = WuQtUtilities::loadIcon(":/ToolBar/view-anterior.png"); @@ -1969,6 +2211,10 @@ BrainBrowserWindowToolBar::createOrientationWidget() else { this->orientationLeftOrLateralToolButtonAction->setIconText("L"); } + this->orientationLeftOrLateralToolButtonAction->setObjectName(objectNamePrefix + + "LeftOrLateralView"); + macroManager->addMacroSupportToObject(this->orientationLeftOrLateralToolButtonAction, + "Select left or lateral orientation"); this->orientationRightOrMedialToolButtonAction = WuQtUtilities::createAction("R", "View from a RIGHT perspective", @@ -1981,6 +2227,10 @@ BrainBrowserWindowToolBar::createOrientationWidget() else { this->orientationRightOrMedialToolButtonAction->setIconText("R"); } + this->orientationRightOrMedialToolButtonAction->setObjectName(objectNamePrefix + + "RightOrMedialView"); + macroManager->addMacroSupportToObject(this->orientationRightOrMedialToolButtonAction, + "Select right or medial orientation"); this->orientationAnteriorToolButtonAction = WuQtUtilities::createAction("A", "View from an ANTERIOR perspective", @@ -1993,6 +2243,10 @@ BrainBrowserWindowToolBar::createOrientationWidget() else { this->orientationAnteriorToolButtonAction->setIconText("A"); } + this->orientationAnteriorToolButtonAction->setObjectName(objectNamePrefix + + "AnteriorView"); + macroManager->addMacroSupportToObject(this->orientationAnteriorToolButtonAction, + "Select anterior orientation"); this->orientationPosteriorToolButtonAction = WuQtUtilities::createAction("P", "View from a POSTERIOR perspective", @@ -2005,6 +2259,10 @@ BrainBrowserWindowToolBar::createOrientationWidget() else { this->orientationPosteriorToolButtonAction->setIconText("P"); } + this->orientationPosteriorToolButtonAction->setObjectName(objectNamePrefix + + "PosteriorView"); + macroManager->addMacroSupportToObject(this->orientationPosteriorToolButtonAction, + "Select posterior orientation"); this->orientationDorsalToolButtonAction = WuQtUtilities::createAction("D", "View from a DORSAL perspective", @@ -2017,6 +2275,10 @@ BrainBrowserWindowToolBar::createOrientationWidget() else { this->orientationDorsalToolButtonAction->setIconText("D"); } + this->orientationDorsalToolButtonAction->setObjectName(objectNamePrefix + + "DorsalView"); + macroManager->addMacroSupportToObject(this->orientationDorsalToolButtonAction, + "Select dorsal orientation"); this->orientationVentralToolButtonAction = WuQtUtilities::createAction("V", "View from a VENTRAL perspective", @@ -2029,6 +2291,10 @@ BrainBrowserWindowToolBar::createOrientationWidget() else { this->orientationVentralToolButtonAction->setIconText("V"); } + this->orientationVentralToolButtonAction->setObjectName(objectNamePrefix + + "VentralView"); + macroManager->addMacroSupportToObject(this->orientationVentralToolButtonAction, + "Select ventral orientation"); this->orientationLateralMedialToolButtonAction = WuQtUtilities::createAction("LM", @@ -2036,60 +2302,85 @@ BrainBrowserWindowToolBar::createOrientationWidget() this, this, SLOT(orientationLateralMedialToolButtonTriggered(bool))); + this->orientationLateralMedialToolButtonAction->setObjectName(objectNamePrefix + + "LateralMedialView"); + macroManager->addMacroSupportToObject(this->orientationLateralMedialToolButtonAction, + "Select lateral/medial orientation"); this->orientationDorsalVentralToolButtonAction = WuQtUtilities::createAction("DV", "View from a Dorsal/Ventral perspective", this, this, SLOT(orientationDorsalVentralToolButtonTriggered(bool))); + this->orientationDorsalVentralToolButtonAction->setObjectName(objectNamePrefix + + "DorsalVentralView"); + macroManager->addMacroSupportToObject(this->orientationDorsalVentralToolButtonAction, + "Select dorsal/ventral orientation"); this->orientationAnteriorPosteriorToolButtonAction = WuQtUtilities::createAction("AP", "View from a Anterior/Posterior perspective", this, this, SLOT(orientationAnteriorPosteriorToolButtonTriggered(bool))); + this->orientationAnteriorPosteriorToolButtonAction->setObjectName(objectNamePrefix + + "AnteriorPosteriorView"); + macroManager->addMacroSupportToObject(this->orientationAnteriorPosteriorToolButtonAction, + "Select anterior/posterior orientation"); this->orientationResetToolButtonAction = WuQtUtilities::createAction("R\nE\nS\nE\nT", "Reset the view to dorsal and remove any panning or zooming", this, this, SLOT(orientationResetToolButtonTriggered(bool))); + this->orientationResetToolButtonAction->setObjectName(objectNamePrefix + + "ResetView"); + macroManager->addMacroSupportToObject(this->orientationResetToolButtonAction, + "Reset to default orientation"); this->orientationLeftOrLateralToolButton = new QToolButton(); this->orientationLeftOrLateralToolButton->setDefaultAction(this->orientationLeftOrLateralToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationLeftOrLateralToolButton); + this->orientationLeftOrLateralToolButtonAction->setParent(this->orientationLeftOrLateralToolButton); this->orientationRightOrMedialToolButton = new QToolButton(); this->orientationRightOrMedialToolButton->setDefaultAction(this->orientationRightOrMedialToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationRightOrMedialToolButton); + orientationRightOrMedialToolButtonAction->setParent(orientationRightOrMedialToolButton); this->orientationAnteriorToolButton = new QToolButton(); this->orientationAnteriorToolButton->setDefaultAction(this->orientationAnteriorToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationAnteriorToolButton); + this->orientationAnteriorToolButtonAction->setParent(this->orientationAnteriorToolButton); this->orientationPosteriorToolButton = new QToolButton(); this->orientationPosteriorToolButton->setDefaultAction(this->orientationPosteriorToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationPosteriorToolButton); + this->orientationPosteriorToolButtonAction->setParent(this->orientationPosteriorToolButton); this->orientationDorsalToolButton = new QToolButton(); this->orientationDorsalToolButton->setDefaultAction(this->orientationDorsalToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationDorsalToolButton); + this->orientationDorsalToolButtonAction->setParent(this->orientationDorsalToolButton); this->orientationVentralToolButton = new QToolButton(); this->orientationVentralToolButton->setDefaultAction(this->orientationVentralToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationVentralToolButton); + this->orientationVentralToolButtonAction->setParent(this->orientationVentralToolButton); this->orientationLateralMedialToolButton = new QToolButton(); this->orientationLateralMedialToolButton->setDefaultAction(this->orientationLateralMedialToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationLateralMedialToolButton); + orientationLateralMedialToolButtonAction->setParent(orientationLateralMedialToolButton); this->orientationDorsalVentralToolButton = new QToolButton(); this->orientationDorsalVentralToolButton->setDefaultAction(this->orientationDorsalVentralToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationDorsalVentralToolButton); + orientationDorsalVentralToolButtonAction->setParent(orientationDorsalVentralToolButton); this->orientationAnteriorPosteriorToolButton = new QToolButton(); this->orientationAnteriorPosteriorToolButton->setDefaultAction(this->orientationAnteriorPosteriorToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationAnteriorPosteriorToolButton); + orientationAnteriorPosteriorToolButtonAction->setParent(orientationAnteriorPosteriorToolButton); WuQtUtilities::matchWidgetWidths(this->orientationLateralMedialToolButton, this->orientationDorsalVentralToolButton, @@ -2310,12 +2601,19 @@ BrainBrowserWindowToolBar::updateOrientationWidget(BrowserTabContent* browserTab QWidget* BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + const QString objectNamePrefix(m_objectNamePrefix + + ":All:"); this->wholeBrainSurfaceTypeComboBox = WuQFactory::newComboBox(); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceTypeComboBox, "Select the geometric type of surface for display"); QObject::connect(this->wholeBrainSurfaceTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(wholeBrainSurfaceTypeComboBoxIndexChanged(int))); + this->wholeBrainSurfaceTypeComboBox->setObjectName(objectNamePrefix + + "SurfaceType"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceTypeComboBox, + "Select all view surface type"); /* * Left @@ -2325,15 +2623,35 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() "Enable/Disable display of the left cortical surface"); QObject::connect(this->wholeBrainSurfaceLeftCheckBox, SIGNAL(stateChanged(int)), this, SLOT(wholeBrainSurfaceLeftCheckBoxStateChanged(int))); + this->wholeBrainSurfaceLeftCheckBox->setObjectName(objectNamePrefix + + "EnableLeft"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceLeftCheckBox, + "Enable all view left surface"); - QAction* leftSurfaceAction = WuQtUtilities::createAction("Left", + QToolButton* wholeBrainLeftSurfaceToolButton = new QToolButton(); + QAction* leftSurfaceAction = WuQtUtilities::createAction("Left", "Select the whole brain left surface", - this, + wholeBrainLeftSurfaceToolButton, this, SLOT(wholeBrainSurfaceLeftToolButtonTriggered(bool))); - QToolButton* wholeBrainLeftSurfaceToolButton = new QToolButton(); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainLeftSurfaceToolButton); wholeBrainLeftSurfaceToolButton->setDefaultAction(leftSurfaceAction); +// leftSurfaceAction->setObjectName(objectNamePrefix +// + "SelectLeft"); +// macroManager->addMacroSupportToObject(leftSurfaceAction, +// "Select all view left surface"); + + /* + * Left menu is displayed when tool button is clicked + */ + this->wholeBrainSurfaceLeftMenu = new QMenu(wholeBrainLeftSurfaceToolButton); + QObject::connect(this->wholeBrainSurfaceLeftMenu, &QMenu::triggered, + this, &BrainBrowserWindowToolBar::wholeBrainSurfaceLeftMenuTriggered); + this->wholeBrainSurfaceLeftMenu->setObjectName(objectNamePrefix + + "SelectLeftSurfaceMenu"); + this->wholeBrainSurfaceLeftMenu->setToolTip("Select all view left surface"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceLeftMenu, + "Select all view left surface"); /* * Right @@ -2343,15 +2661,35 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() "Enable/Disable display of the right cortical surface"); QObject::connect(this->wholeBrainSurfaceRightCheckBox, SIGNAL(stateChanged(int)), this, SLOT(wholeBrainSurfaceRightCheckBoxStateChanged(int))); + this->wholeBrainSurfaceRightCheckBox->setObjectName(objectNamePrefix + + "EnableRight"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceRightCheckBox, + "Enable all view right surface"); - QAction* rightSurfaceAction = WuQtUtilities::createAction("Right", + QToolButton* wholeBrainRightSurfaceToolButton = new QToolButton(); + QAction* rightSurfaceAction = WuQtUtilities::createAction("Right", "Select the whole brain right surface", - this, + wholeBrainRightSurfaceToolButton, this, SLOT(wholeBrainSurfaceRightToolButtonTriggered(bool))); - QToolButton* wholeBrainRightSurfaceToolButton = new QToolButton(); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainRightSurfaceToolButton); wholeBrainRightSurfaceToolButton->setDefaultAction(rightSurfaceAction); +// rightSurfaceAction->setObjectName(objectNamePrefix +// + "SelectRight"); +// macroManager->addMacroSupportToObject(rightSurfaceAction, +// "Select all view right surface"); + + /* + * Right menu is displayed when tool button is clicked + */ + this->wholeBrainSurfaceRightMenu = new QMenu(wholeBrainRightSurfaceToolButton); + QObject::connect(this->wholeBrainSurfaceRightMenu, &QMenu::triggered, + this, &BrainBrowserWindowToolBar::wholeBrainSurfaceRightMenuTriggered); + this->wholeBrainSurfaceRightMenu->setObjectName(objectNamePrefix + + "SelectRightSurfaceMenu"); + this->wholeBrainSurfaceRightMenu->setToolTip("Select all view right surface"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceRightMenu, + "Select all view right surface"); /* * Cerebellum @@ -2361,16 +2699,36 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() "Enable/Disable display of the cerebellum surface"); QObject::connect(this->wholeBrainSurfaceCerebellumCheckBox, SIGNAL(stateChanged(int)), this, SLOT(wholeBrainSurfaceCerebellumCheckBoxStateChanged(int))); + this->wholeBrainSurfaceCerebellumCheckBox->setObjectName(objectNamePrefix + + "EnableCerebellum"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceCerebellumCheckBox, + "Enable all view cerebellum"); - QAction* cerebellumSurfaceAction = WuQtUtilities::createAction("Cerebellum", + QToolButton* wholeBrainCerebellumSurfaceToolButton = new QToolButton(); + QAction* cerebellumSurfaceAction = WuQtUtilities::createAction("Cerebellum", "Select the whole brain cerebellum surface", - this, + wholeBrainCerebellumSurfaceToolButton, this, SLOT(wholeBrainSurfaceCerebellumToolButtonTriggered(bool))); - QToolButton* wholeBrainCerebellumSurfaceToolButton = new QToolButton(); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainCerebellumSurfaceToolButton); wholeBrainCerebellumSurfaceToolButton->setDefaultAction(cerebellumSurfaceAction); +// cerebellumSurfaceAction->setObjectName(objectNamePrefix +// + "SurfaceCerebellum"); +// macroManager->addMacroSupportToObject(cerebellumSurfaceAction, +// "Select all view cerebellum surface"); + /* + * Cerebellum menu is displayed when tool button is clicked + */ + this->wholeBrainSurfaceCerebellumMenu = new QMenu(wholeBrainCerebellumSurfaceToolButton); + QObject::connect(this->wholeBrainSurfaceCerebellumMenu, &QMenu::triggered, + this, &BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumMenuTriggered); + this->wholeBrainSurfaceCerebellumMenu->setObjectName(objectNamePrefix + + "SelectCerebellumSurfaceMenu"); + this->wholeBrainSurfaceCerebellumMenu->setToolTip("Select all view cerebellum surface"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceCerebellumMenu, + "Select all view cerebellum surface"); + /* * Left/Right separation */ @@ -2384,6 +2742,10 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() "Adjust the separation of the left and right cortical surfaces"); QObject::connect(this->wholeBrainSurfaceSeparationLeftRightSpinBox, SIGNAL(valueChanged(double)), this, SLOT(wholeBrainSurfaceSeparationLeftRightSpinBoxValueChanged(double))); + this->wholeBrainSurfaceSeparationLeftRightSpinBox->setObjectName(objectNamePrefix + + "LeftRightSeparation"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceSeparationLeftRightSpinBox, + "Set all view left/right separation"); /* * Cerebellum separation @@ -2397,44 +2759,40 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() "Adjust the separation of the cerebellum from the left and right cortical surfaces"); QObject::connect(this->wholeBrainSurfaceSeparationCerebellumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(wholeBrainSurfaceSeparationCerebellumSpinBoxSelected(double))); - - + this->wholeBrainSurfaceSeparationCerebellumSpinBox->setObjectName(objectNamePrefix + + "CortexCerebellumSeparation"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceSeparationCerebellumSpinBox, + "Set all view cerebral/cerebellum separation"); + + this->wholeBrainSurfaceMatchCheckBox = new QCheckBox("Match"); + WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceMatchCheckBox, + "Match position and size of all surfaces to primary anatomical. Useful for " + "animation (surface interpolation) and recording movies."); + QObject::connect(this->wholeBrainSurfaceMatchCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBar::wholeBrainSurfaceMatchCheckBoxClicked); + this->wholeBrainSurfaceMatchCheckBox->setObjectName(objectNamePrefix + + "MatchSurface"); + macroManager->addMacroSupportToObject(this->wholeBrainSurfaceMatchCheckBox, + "Match position and size of all surfaces to primary anatomical"); - QLabel* columnTwoSpaceLabel = new QLabel(" "); wholeBrainLeftSurfaceToolButton->setText("L"); wholeBrainRightSurfaceToolButton->setText("R"); wholeBrainCerebellumSurfaceToolButton->setText("C"); - bool originalFlag = false; QGridLayout* gridLayout = new QGridLayout(); - if (originalFlag) { - gridLayout->setVerticalSpacing(2); - gridLayout->setHorizontalSpacing(2); - gridLayout->addWidget(this->wholeBrainSurfaceTypeComboBox, 0, 0, 1, 6); - gridLayout->addWidget(this->wholeBrainSurfaceLeftCheckBox, 1, 0); - gridLayout->addWidget(wholeBrainLeftSurfaceToolButton, 1, 1); - gridLayout->addWidget(columnTwoSpaceLabel, 1, 2); - gridLayout->addWidget(this->wholeBrainSurfaceRightCheckBox, 1, 3); - gridLayout->addWidget(wholeBrainRightSurfaceToolButton, 1, 4); - gridLayout->addWidget(this->wholeBrainSurfaceSeparationLeftRightSpinBox, 1, 5); - gridLayout->addWidget(this->wholeBrainSurfaceCerebellumCheckBox, 2, 0); - gridLayout->addWidget(wholeBrainCerebellumSurfaceToolButton, 2, 1); - gridLayout->addWidget(this->wholeBrainSurfaceSeparationCerebellumSpinBox, 2, 5); - } - else { - gridLayout->setVerticalSpacing(2); - gridLayout->setHorizontalSpacing(2); - gridLayout->addWidget(this->wholeBrainSurfaceTypeComboBox, 0, 0, 1, 6); - gridLayout->addWidget(this->wholeBrainSurfaceLeftCheckBox, 1, 0); - gridLayout->addWidget(wholeBrainLeftSurfaceToolButton, 1, 1); - gridLayout->addWidget(this->wholeBrainSurfaceRightCheckBox, 2, 0); - gridLayout->addWidget(wholeBrainRightSurfaceToolButton, 2, 1); - gridLayout->addWidget(this->wholeBrainSurfaceCerebellumCheckBox, 3, 0); - gridLayout->addWidget(wholeBrainCerebellumSurfaceToolButton, 3, 1); - gridLayout->addWidget(this->wholeBrainSurfaceSeparationLeftRightSpinBox, 1, 2, 2, 1); - gridLayout->addWidget(this->wholeBrainSurfaceSeparationCerebellumSpinBox, 3, 2); - } - + gridLayout->setVerticalSpacing(2); + gridLayout->setHorizontalSpacing(2); + gridLayout->addWidget(this->wholeBrainSurfaceTypeComboBox, 0, 0, 1, 6); + gridLayout->addWidget(this->wholeBrainSurfaceLeftCheckBox, 1, 0); + gridLayout->addWidget(wholeBrainLeftSurfaceToolButton, 1, 1); + gridLayout->addWidget(this->wholeBrainSurfaceRightCheckBox, 2, 0); + gridLayout->addWidget(wholeBrainRightSurfaceToolButton, 2, 1); + gridLayout->addWidget(this->wholeBrainSurfaceCerebellumCheckBox, 3, 0); + gridLayout->addWidget(wholeBrainCerebellumSurfaceToolButton, 3, 1); + gridLayout->addWidget(this->wholeBrainSurfaceSeparationLeftRightSpinBox, 1, 2, 2, 1); + gridLayout->addWidget(this->wholeBrainSurfaceSeparationCerebellumSpinBox, 3, 2); + gridLayout->addWidget(this->wholeBrainSurfaceMatchCheckBox, 4, 0, 1, 6); + QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); @@ -2450,6 +2808,7 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() this->wholeBrainSurfaceOptionsWidgetGroup->add(wholeBrainCerebellumSurfaceToolButton); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceSeparationLeftRightSpinBox); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceSeparationCerebellumSpinBox); + this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceMatchCheckBox); QWidget* w = this->createToolWidget("Surface Viewing", widget, @@ -2505,8 +2864,11 @@ BrainBrowserWindowToolBar::updateWholeBrainSurfaceOptionsWidget(BrowserTabConten this->wholeBrainSurfaceRightCheckBox->setChecked(browserTabContent->isWholeBrainRightEnabled()); this->wholeBrainSurfaceCerebellumCheckBox->setChecked(browserTabContent->isWholeBrainCerebellumEnabled()); + updateAllWholeBrainSurfaceMenus(); + this->wholeBrainSurfaceSeparationLeftRightSpinBox->setValue(browserTabContent->getWholeBrainLeftRightSeparation()); this->wholeBrainSurfaceSeparationCerebellumSpinBox->setValue(browserTabContent->getWholeBrainCerebellumSeparation()); + this->wholeBrainSurfaceMatchCheckBox->setChecked(wholeBrainModel->getBrain()->isSurfaceMatchingToAnatomical()); this->wholeBrainSurfaceOptionsWidgetGroup->blockAllSignals(false); } @@ -2520,7 +2882,8 @@ BrainBrowserWindowToolBar::updateWholeBrainSurfaceOptionsWidget(BrowserTabConten QWidget* BrainBrowserWindowToolBar::createVolumeIndicesWidget() { - m_sliceSelectionComponent = new BrainBrowserWindowToolBarSliceSelection(this); + m_sliceSelectionComponent = new BrainBrowserWindowToolBarSliceSelection(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Slice Indices/Coords", m_sliceSelectionComponent, WIDGET_PLACEMENT_LEFT, @@ -2563,6 +2926,9 @@ BrainBrowserWindowToolBar::createModeWidget() QToolButton* inputModeAnnotationsToolButton = new QToolButton(); inputModeAnnotationsToolButton->setDefaultAction(this->modeInputModeAnnotationsAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeAnnotationsToolButton); + this->modeInputModeAnnotationsAction->setObjectName(m_objectNamePrefix + + ":Mode:Annotate"); + /* * Borders @@ -2574,6 +2940,8 @@ BrainBrowserWindowToolBar::createModeWidget() QToolButton* inputModeBordersToolButton = new QToolButton(); inputModeBordersToolButton->setDefaultAction(this->modeInputModeBordersAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeBordersToolButton); + this->modeInputModeBordersAction->setObjectName(m_objectNamePrefix + + ":Mode:Border"); /* * Foci @@ -2585,6 +2953,8 @@ BrainBrowserWindowToolBar::createModeWidget() QToolButton* inputModeFociToolButton = new QToolButton(); inputModeFociToolButton->setDefaultAction(this->modeInputModeFociAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeFociToolButton); + this->modeInputModeFociAction->setObjectName(m_objectNamePrefix + + ":Mode:Foci"); /* * Image @@ -2600,6 +2970,8 @@ BrainBrowserWindowToolBar::createModeWidget() inputModeImageToolButton = new QToolButton(); inputModeImageToolButton->setDefaultAction(this->modeInputModeImageAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeImageToolButton); + this->modeInputModeImageAction->setObjectName(m_objectNamePrefix + + ":Mode:Image"); } /* @@ -2612,6 +2984,8 @@ BrainBrowserWindowToolBar::createModeWidget() QToolButton* inputModeVolumeEditButton = new QToolButton(); inputModeVolumeEditButton->setDefaultAction(this->modeInputVolumeEditAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeVolumeEditButton); + this->modeInputVolumeEditAction->setObjectName(m_objectNamePrefix + + ":Mode:Volume"); /* * View Mode @@ -2637,6 +3011,8 @@ BrainBrowserWindowToolBar::createModeWidget() QToolButton* inputModeViewToolButton = new QToolButton(); inputModeViewToolButton->setDefaultAction(this->modeInputModeViewAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeViewToolButton); + this->modeInputModeViewAction->setObjectName(m_objectNamePrefix + + ":Mode:View"); WuQtUtilities::matchWidgetWidths(inputModeAnnotationsToolButton, inputModeBordersToolButton, @@ -2686,6 +3062,25 @@ BrainBrowserWindowToolBar::createModeWidget() this, SLOT(modeInputModeActionTriggered(QAction*))); this->modeInputModeActionGroup->setExclusive(true); + WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeAnnotationsAction, + "Select annotate mode"); + WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeBordersAction, + "Select border mode"); + WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeFociAction, + "Select foci mode"); + if (modeInputModeImageAction != NULL) { + WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeImageAction, + "Select image mode"); + } + WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeViewAction, + "Select view mode"); + WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputVolumeEditAction, + "Select volume mode"); +// this->modeInputModeActionGroup->setObjectName(m_objectNamePrefix +// + ":Mode_Action_Group"); +// WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeActionGroup, +// "Selects Mode for Mouse Operations"); + QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); @@ -2718,12 +3113,12 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) EventGetOrSetUserInputModeProcessor getInputModeEvent(this->browserWindowIndex); EventManager::get()->sendEvent(getInputModeEvent.getPointer()); - const UserInputModeAbstract::UserInputMode currentMode = getInputModeEvent.getUserInputMode(); + const UserInputModeEnum::Enum currentMode = getInputModeEvent.getUserInputMode(); - UserInputModeAbstract::UserInputMode inputMode = UserInputModeAbstract::INVALID; + UserInputModeEnum::Enum inputMode = UserInputModeEnum::INVALID; if (action == this->modeInputModeAnnotationsAction) { - if (currentMode != UserInputModeAbstract::ANNOTATIONS) { + if (currentMode != UserInputModeEnum::ANNOTATIONS) { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); CaretAssert(bbw); if ( ! bbw->changeInputModeToAnnotationsWarningDialog()) { @@ -2734,10 +3129,10 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) return; } } - inputMode = UserInputModeAbstract::ANNOTATIONS; + inputMode = UserInputModeEnum::ANNOTATIONS; } else if (action == this->modeInputModeBordersAction) { - inputMode = UserInputModeAbstract::BORDERS; + inputMode = UserInputModeEnum::BORDERS; /* * If borders are not displayed, display them @@ -2755,17 +3150,17 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) } } else if (action == this->modeInputModeFociAction) { - inputMode = UserInputModeAbstract::FOCI; + inputMode = UserInputModeEnum::FOCI; } else if ((action == this->modeInputModeImageAction) && (this->modeInputModeImageAction != NULL)) { - inputMode = UserInputModeAbstract::IMAGE; + inputMode = UserInputModeEnum::IMAGE; } else if (action == this->modeInputVolumeEditAction) { - inputMode = UserInputModeAbstract::VOLUME_EDIT; + inputMode = UserInputModeEnum::VOLUME_EDIT; } else if (action == this->modeInputModeViewAction) { - inputMode = UserInputModeAbstract::VIEW; + inputMode = UserInputModeEnum::VIEW; } else { CaretAssertMessage(0, "Tools input mode action is invalid, new action added???"); @@ -2798,27 +3193,27 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte EventManager::get()->sendEvent(getInputModeEvent.getPointer()); switch (getInputModeEvent.getUserInputMode()) { - case UserInputModeAbstract::INVALID: + case UserInputModeEnum::INVALID: /* may get here when program is exiting and widgets are being destroyed */ break; - case UserInputModeAbstract::ANNOTATIONS: + case UserInputModeEnum::ANNOTATIONS: this->modeInputModeAnnotationsAction->setChecked(true); break; - case UserInputModeAbstract::BORDERS: + case UserInputModeEnum::BORDERS: this->modeInputModeBordersAction->setChecked(true); break; - case UserInputModeAbstract::FOCI: + case UserInputModeEnum::FOCI: this->modeInputModeFociAction->setChecked(true); break; - case UserInputModeAbstract::IMAGE: + case UserInputModeEnum::IMAGE: if (this->modeInputModeImageAction != NULL) { this->modeInputModeImageAction->setChecked(true); } break; - case UserInputModeAbstract::VOLUME_EDIT: + case UserInputModeEnum::VOLUME_EDIT: this->modeInputVolumeEditAction->setChecked(true); break; - case UserInputModeAbstract::VIEW: + case UserInputModeEnum::VIEW: this->modeInputModeViewAction->setChecked(true); break; } @@ -2884,7 +3279,7 @@ BrainBrowserWindowToolBar::updateDisplayedModeUserInputWidget() } } - if (userInputProcessor->getUserInputMode() != UserInputModeAbstract::ANNOTATIONS) { + if (userInputProcessor->getUserInputMode() != UserInputModeEnum::ANNOTATIONS) { /* * Delete all selected annotations and update graphics and UI. */ @@ -2906,7 +3301,8 @@ BrainBrowserWindowToolBar::createTabOptionsWidget(QToolButton* toolBarLockWindow { m_tabOptionsComponent = new BrainBrowserWindowToolBarTab(this->browserWindowIndex, toolBarLockWindowAndAllTabAspectRatioButton, - this); + this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Tab", m_tabOptionsComponent, @@ -2942,7 +3338,8 @@ BrainBrowserWindowToolBar::updateTabOptionsWidget(BrowserTabContent* browserTabC QWidget* BrainBrowserWindowToolBar::createChartTypeWidget() { - m_chartTypeToolBarComponent = new BrainBrowserWindowToolBarChartType(this); + m_chartTypeToolBarComponent = new BrainBrowserWindowToolBarChartType(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Type (OLD)", m_chartTypeToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -2977,7 +3374,8 @@ BrainBrowserWindowToolBar::updateChartTypeWidget(BrowserTabContent* browserTabCo QWidget* BrainBrowserWindowToolBar::createChartTwoTitleWidget() { - m_chartTwoTitleToolBarComponent = new BrainBrowserWindowToolBarChartTwoTitle(this); + m_chartTwoTitleToolBarComponent = new BrainBrowserWindowToolBarChartTwoTitle(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Title", m_chartTwoTitleToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3012,7 +3410,8 @@ BrainBrowserWindowToolBar::updateChartTwoTitleWidget(BrowserTabContent* browserT QWidget* BrainBrowserWindowToolBar::createChartTypeTwoWidget() { - m_chartTwoTypeToolBarComponent = new BrainBrowserWindowToolBarChartTwoType(this); + m_chartTwoTypeToolBarComponent = new BrainBrowserWindowToolBarChartTwoType(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Type", m_chartTwoTypeToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3047,7 +3446,8 @@ BrainBrowserWindowToolBar::updateChartTypeTwoWidget(BrowserTabContent* browserTa QWidget* BrainBrowserWindowToolBar::createChartAxesWidget() { - m_chartAxisToolBarComponent = new BrainBrowserWindowToolBarChartAxes(this); + m_chartAxisToolBarComponent = new BrainBrowserWindowToolBarChartAxes(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Axes", m_chartAxisToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3082,7 +3482,8 @@ BrainBrowserWindowToolBar::updateChartAxesWidget(BrowserTabContent* browserTabCo QWidget* BrainBrowserWindowToolBar::createChartAttributesWidget() { - m_chartAttributesToolBarComponent = new BrainBrowserWindowToolBarChartAttributes(this); + m_chartAttributesToolBarComponent = new BrainBrowserWindowToolBarChartAttributes(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Attributes", m_chartAttributesToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3116,7 +3517,8 @@ BrainBrowserWindowToolBar::updateChartAttributesWidget(BrowserTabContent* browse QWidget* BrainBrowserWindowToolBar::createChartTwoOrientationWidget() { - m_chartTwoOrientationToolBarComponent = new BrainBrowserWindowToolBarChartTwoOrientation(this); + m_chartTwoOrientationToolBarComponent = new BrainBrowserWindowToolBarChartTwoOrientation(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart
Orientation", m_chartTwoOrientationToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3150,7 +3552,8 @@ BrainBrowserWindowToolBar::updateChartTwoOrientationWidget(BrowserTabContent* br QWidget* BrainBrowserWindowToolBar::createChartTwoAttributesWidget() { - this->m_chartTwoAttributesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAttributes(this); + this->m_chartTwoAttributesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAttributes(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart
Attributes", this->m_chartTwoAttributesToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3184,7 +3587,8 @@ BrainBrowserWindowToolBar::updateChartTwoAttributesWidget(BrowserTabContent* bro QWidget* BrainBrowserWindowToolBar::createChartTwoAxesWidget() { - this->m_chartTwoAxesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAxes(this); + this->m_chartTwoAxesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAxes(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Axes", this->m_chartTwoAxesToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3219,7 +3623,14 @@ BrainBrowserWindowToolBar::createSingleSurfaceOptionsWidget() { QLabel* structureSurfaceLabel = new QLabel("Brain Structure and Surface: "); - this->surfaceSurfaceSelectionControl = new StructureSurfaceSelectionControl(false); + /* + * Note: Macro support is in StructureSurfaceSelectionControl + */ + this->surfaceSurfaceSelectionControl = new StructureSurfaceSelectionControl(false, + m_objectNamePrefix + + ":Surface", + "surface view", + this); QObject::connect(this->surfaceSurfaceSelectionControl, SIGNAL(selectionChanged(const StructureEnum::Enum, ModelSurface*)), @@ -3274,7 +3685,8 @@ BrainBrowserWindowToolBar::updateSingleSurfaceOptionsWidget(BrowserTabContent* b QWidget* BrainBrowserWindowToolBar::createSurfaceMontageOptionsWidget() { - m_surfaceMontageToolBarComponent = new BrainBrowserWindowToolBarSurfaceMontage(this); + m_surfaceMontageToolBarComponent = new BrainBrowserWindowToolBarSurfaceMontage(this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Montage Selection", m_surfaceMontageToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3307,7 +3719,8 @@ QWidget* BrainBrowserWindowToolBar::createClippingOptionsWidget() { m_clippingToolBarComponent = new BrainBrowserWindowToolBarClipping(this->browserWindowIndex, - this); + this, + m_objectNamePrefix); QWidget* w = this->createToolWidget("Clipping", m_clippingToolBarComponent, WIDGET_PLACEMENT_LEFT, @@ -3341,7 +3754,8 @@ BrainBrowserWindowToolBar::updateClippingOptionsWidget(BrowserTabContent* browse QWidget* BrainBrowserWindowToolBar::createVolumeMontageWidget() { - m_volumeMontageComponent = new BrainBrowserWindowToolBarVolumeMontage(this); + m_volumeMontageComponent = new BrainBrowserWindowToolBarVolumeMontage(m_objectNamePrefix, + this); QWidget* w = this->createToolWidget("Montage", @@ -3377,7 +3791,8 @@ BrainBrowserWindowToolBar::updateVolumeMontageWidget(BrowserTabContent* browserT QWidget* BrainBrowserWindowToolBar::createVolumePlaneWidget() { - m_slicePlaneComponent = new BrainBrowserWindowToolBarSlicePlane(this); + m_slicePlaneComponent = new BrainBrowserWindowToolBarSlicePlane(m_objectNamePrefix, + this); QWidget* w = this->createToolWidget("Slice Plane", m_slicePlaneComponent, WIDGET_PLACEMENT_LEFT, @@ -3661,6 +4076,15 @@ BrainBrowserWindowToolBar::orientationAnteriorPosteriorToolButtonTriggered(bool this->updateGraphicsWindowAndYokedWindows(); } +/** + * Called when the scene tool button is clicked to show scene dialog + */ +void +BrainBrowserWindowToolBar::sceneToolButtonClicked() +{ + GuiManager::get()->getSceneDialogDisplayAction()->trigger(); +} + /** * Called when custom view is triggered and displays Custom View Menu. */ @@ -3727,6 +4151,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceTypeComboBoxIndexChanged(int /*indx* if (isValid) { wholeBrainModel->setSelectedSurfaceType(tabIndex, surfaceType); this->updateVolumeIndicesWidget(btc); /* slices may get deselected */ + this->updateAllWholeBrainSurfaceMenus(); this->updateGraphicsWindowAndYokedWindows(); } } @@ -3750,11 +4175,34 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftCheckBoxStateChanged(int /*state } /** - * Called when the left surface tool button is pressed. + * Update all whole brain surface selection menus */ -void -BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*checked*/) +void +BrainBrowserWindowToolBar::updateAllWholeBrainSurfaceMenus() { + updateWholeBrainSurfaceMenu(this->wholeBrainSurfaceLeftMenu, + StructureEnum::CORTEX_LEFT); + updateWholeBrainSurfaceMenu(this->wholeBrainSurfaceRightMenu, + StructureEnum::CORTEX_RIGHT); + updateWholeBrainSurfaceMenu(this->wholeBrainSurfaceCerebellumMenu, + StructureEnum::CEREBELLUM); +} + +/** + * Update the menu to contain surface for the given structure + * + * @param menu + * Menu that is updated + * @param structure + * Structure for surfaces + */ +void +BrainBrowserWindowToolBar::updateWholeBrainSurfaceMenu(QMenu* menu, + const StructureEnum::Enum structure) +{ + CaretAssert(menu); + menu->clear(); + BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { @@ -3763,7 +4211,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*check const int32_t tabIndex = btc->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); - BrainStructure* brainStructure = brain->getBrainStructure(StructureEnum::CORTEX_LEFT, false); + BrainStructure* brainStructure = brain->getBrainStructure(structure, false); if (brainStructure != NULL) { std::vector surfaces; brainStructure->getSurfacesOfType(wholeBrainModel->getSelectedSurfaceType(tabIndex), @@ -3771,143 +4219,138 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*check const int32_t numSurfaces = static_cast(surfaces.size()); if (numSurfaces > 0) { - Surface* selectedSurface = wholeBrainModel->getSelectedSurface(StructureEnum::CORTEX_LEFT, - tabIndex); - QMenu menu; - QActionGroup* actionGroup = new QActionGroup(&menu); - actionGroup->setExclusive(true); + Surface* selectedSurface = wholeBrainModel->getSelectedSurface(structure, + tabIndex); for (int32_t i = 0; i < numSurfaces; i++) { QString name = surfaces[i]->getFileNameNoPath(); - QAction* action = actionGroup->addAction(name); + QAction* action = new QAction(name); action->setCheckable(true); if (surfaces[i] == selectedSurface) { action->setChecked(true); } - menu.addAction(action); - } - QAction* result = menu.exec(QCursor::pos()); - if (result != NULL) { - QList actionList = actionGroup->actions(); - for (int32_t i = 0; i < numSurfaces; i++) { - if (result == actionList.at(i)) { - wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_LEFT, - tabIndex, - surfaces[i]); - this->updateGraphicsWindowAndYokedWindows(); - break; - } - } + action->setData(qVariantFromValue((void*)surfaces[i])); + menu->addAction(action); } } } } +/** + * Called when the left surface tool button is pressed. + */ +void +BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*checked*/) +{ + updateAllWholeBrainSurfaceMenus(); + if ( ! this->wholeBrainSurfaceLeftMenu->isEmpty()) { + this->wholeBrainSurfaceLeftMenu->exec(QCursor::pos()); + } +} + +/** + * Called when left surface is selected from menu + * + * @param action + * Action that was selected + */ +void +BrainBrowserWindowToolBar::wholeBrainSurfaceLeftMenuTriggered(QAction* action) +{ + BrowserTabContent* btc = this->getTabContentFromSelectedTab(); + ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); + if (wholeBrainModel == NULL) { + return; + } + + if (action != NULL) { + QVariant data = action->data(); + void* p = data.value(); + Surface* surface = (Surface*)p; + wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_LEFT, + btc->getTabNumber(), + surface); + this->updateGraphicsWindowAndYokedWindows(); + } +} + /** * Called when the right surface tool button is pressed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceRightToolButtonTriggered(bool /*checked*/) +{ + updateAllWholeBrainSurfaceMenus(); + if ( ! this->wholeBrainSurfaceRightMenu->isEmpty()) { + this->wholeBrainSurfaceRightMenu->exec(QCursor::pos()); + } +} + +/** + * Called when right surface is selected from menu + * + * @param action + * Action that was selected + */ +void +BrainBrowserWindowToolBar::wholeBrainSurfaceRightMenuTriggered(QAction* action) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } - const int32_t tabIndex = btc->getTabNumber(); - Brain* brain = GuiManager::get()->getBrain(); - BrainStructure* brainStructure = brain->getBrainStructure(StructureEnum::CORTEX_RIGHT, false); - if (brainStructure != NULL) { - std::vector surfaces; - brainStructure->getSurfacesOfType(wholeBrainModel->getSelectedSurfaceType(tabIndex), - surfaces); - - const int32_t numSurfaces = static_cast(surfaces.size()); - if (numSurfaces > 0) { - Surface* selectedSurface = wholeBrainModel->getSelectedSurface(StructureEnum::CORTEX_RIGHT, - tabIndex); - QMenu menu; - QActionGroup* actionGroup = new QActionGroup(&menu); - actionGroup->setExclusive(true); - for (int32_t i = 0; i < numSurfaces; i++) { - QString name = surfaces[i]->getFileNameNoPath(); - QAction* action = actionGroup->addAction(name); - action->setCheckable(true); - if (surfaces[i] == selectedSurface) { - action->setChecked(true); - } - menu.addAction(action); - } - QAction* result = menu.exec(QCursor::pos()); - if (result != NULL) { - QList actionList = actionGroup->actions(); - for (int32_t i = 0; i < numSurfaces; i++) { - if (result == actionList.at(i)) { - wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_RIGHT, - tabIndex, - surfaces[i]); - this->updateGraphicsWindowAndYokedWindows(); - break; - } - } - } - } + if (action != NULL) { + QVariant data = action->data(); + void* p = data.value(); + Surface* surface = (Surface*)p; + wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_RIGHT, + btc->getTabNumber(), + surface); + this->updateGraphicsWindowAndYokedWindows(); } } + /** * Called when the cerebellum surface tool button is pressed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumToolButtonTriggered(bool /*checked*/) +{ + updateAllWholeBrainSurfaceMenus(); + if ( ! this->wholeBrainSurfaceCerebellumMenu->isEmpty()) { + this->wholeBrainSurfaceCerebellumMenu->exec(QCursor::pos()); + } +} + +/** + * Called when cerebellum surface is selected from menu + * + * @param action + * Action that was selected + */ +void +BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumMenuTriggered(QAction* action) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } - const int32_t tabIndex = btc->getTabNumber(); - Brain* brain = GuiManager::get()->getBrain(); - BrainStructure* brainStructure = brain->getBrainStructure(StructureEnum::CEREBELLUM, false); - if (brainStructure != NULL) { - std::vector surfaces; - brainStructure->getSurfacesOfType(wholeBrainModel->getSelectedSurfaceType(tabIndex), - surfaces); - - const int32_t numSurfaces = static_cast(surfaces.size()); - if (numSurfaces > 0) { - Surface* selectedSurface = wholeBrainModel->getSelectedSurface(StructureEnum::CEREBELLUM, - tabIndex); - QMenu menu; - QActionGroup* actionGroup = new QActionGroup(&menu); - actionGroup->setExclusive(true); - for (int32_t i = 0; i < numSurfaces; i++) { - QString name = surfaces[i]->getFileNameNoPath(); - QAction* action = actionGroup->addAction(name); - action->setCheckable(true); - if (surfaces[i] == selectedSurface) { - action->setChecked(true); - } - menu.addAction(action); - } - QAction* result = menu.exec(QCursor::pos()); - if (result != NULL) { - QList actionList = actionGroup->actions(); - for (int32_t i = 0; i < numSurfaces; i++) { - if (result == actionList.at(i)) { - wholeBrainModel->setSelectedSurface(StructureEnum::CEREBELLUM, - tabIndex, - surfaces[i]); - this->updateGraphicsWindowAndYokedWindows(); - break; - } - } - } - } + if (action != NULL) { + QVariant data = action->data(); + void* p = data.value(); + Surface* surface = (Surface*)p; + wholeBrainModel->setSelectedSurface(StructureEnum::CEREBELLUM, + btc->getTabNumber(), + surface); + this->updateGraphicsWindowAndYokedWindows(); } } + /** * Called when whole brain surface right checkbox is toggled. */ @@ -3976,6 +4419,23 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationCerebellumSpinBoxSelected( this->updateGraphicsWindowAndYokedWindows(); } +/** + * Called when match check box is clicked + * + * @param checked + * New checked status. + */ +void +BrainBrowserWindowToolBar::wholeBrainSurfaceMatchCheckBoxClicked(bool checked) +{ + Brain* brain = GuiManager::get()->getBrain(); + CaretAssert(brain); + + brain->setSurfaceMatchingToAnatomical(checked); + this->updateGraphicsWindowAndYokedWindows(); + this->updateUserInterface(); +} + /** * Called when a single surface control is changed. * @param structure @@ -4092,21 +4552,28 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) if (tileTabsEvent->getWindowIndex() == this->browserWindowIndex) { const int32_t browserTabIndex = tileTabsEvent->getBrowserTabIndex(); int32_t tabBarIndex = getTabBarIndexWithBrowserTabIndex(browserTabIndex); - if (tabBarIndex >= 0) { - const EventBrowserWindowTileTabOperation::Operation operation = tileTabsEvent->getOperation(); - switch (operation) { - case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER: + const EventBrowserWindowTileTabOperation::Operation operation = tileTabsEvent->getOperation(); + switch (operation) { + case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER: + if (tabBarIndex >= 0) { insertNewTabAtTabBarIndex(tabBarIndex + 1); - break; - case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE: + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE: + if (tabBarIndex >= 0) { insertNewTabAtTabBarIndex(tabBarIndex); - break; - case EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB: + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB: + if (tabBarIndex >= 0) { m_tileTabsHighlightingTimerEnabledFlag = false; this->tabBar->setCurrentIndex(tabBarIndex); m_tileTabsHighlightingTimerEnabledFlag = true; - break; - } + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS: + replaceBrowserTabs(tileTabsEvent->getBrowserTabsForReplaceOperation()); + break; } tileTabsEvent->setEventProcessed(); @@ -4426,3 +4893,6 @@ BrainBrowserWindowToolBar::getNumberOfTabs() const return this->tabBar->count(); } + + + diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index d7bfe5410c8ef449c6344ef91f294127af2c9dcf..99d3516dfea1fca203b25d0152bfe5e45580a31e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -42,11 +42,12 @@ class QDoubleSpinBox; class QHBoxLayout; class QIcon; class QLabel; +class QMainWindow; class QMenu; class QRadioButton; class QSpinBox; -class QTabBar; class QToolButton; +class QVBoxLayout; namespace caret { @@ -74,6 +75,7 @@ namespace caret { class Surface; class SurfaceSelectionViewController; class StructureSurfaceSelectionControl; + class WuQTabBar; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBar : public QToolBar, public EventListenerInterface, public SceneableInterface { @@ -86,6 +88,7 @@ namespace caret { QAction* overlayToolBoxAction, QAction* layersToolBoxAction, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, + const QString& objectNamePrefix, BrainBrowserWindow* parentBrainBrowserWindow); ~BrainBrowserWindowToolBar(); @@ -102,11 +105,14 @@ namespace caret { int32_t getNumberOfTabs() const; + void insertDuplicateMenuBar(QMainWindow* mainWindow); + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); + signals: void viewedModelChanged(); @@ -211,12 +217,14 @@ namespace caret { WuQWidgetObjectGroup* modeWidgetGroup; WuQWidgetObjectGroup* singleSurfaceSelectionWidgetGroup; + QVBoxLayout* m_toolBarMainLayout; + QWidget* fullToolBarWidget; QWidget* m_toolbarWidget; QHBoxLayout* toolbarWidgetLayout; QWidget* tabBarWidget; - QTabBar* tabBar; + WuQTabBar* tabBar; /** Widget displayed at bottom of toolbar for mouse input controls */ QWidget* userInputControlsWidget; @@ -250,17 +258,20 @@ namespace caret { void showHideToolBar(bool showIt); + void showMacroDialog(); + private slots: void selectedTabChanged(int indx); void tabMoved(int, int); void tabCloseSelected(int); void showTabMenu(const QPoint& pos); + void tabBarMousePressedSlot(); + void tabBarMouseReleasedSlot(); private: enum class InsertTabMode { APPEND, - AT_TAB_BAR_INDEX, - AT_TAB_CONTENTS_INDEX + AT_TAB_BAR_INDEX }; bool allowAddingNewTab(); @@ -275,6 +286,7 @@ namespace caret { void insertNewTabAtTabBarIndex(int32_t tabBarIndex); void insertAndCloneTabContentAtTabBarIndex(const BrowserTabContent* tabContentToBeCloned, const int32_t tabBarIndex); + void replaceBrowserTabs(const std::vector& browserTabs); BrowserTabContent* createNewTab(AString& errorMessage); @@ -292,6 +304,8 @@ namespace caret { void customViewActionTriggered(); + void sceneToolButtonClicked(); + private: QAction* orientationLateralMedialToolButtonAction; QAction* orientationDorsalVentralToolButtonAction; @@ -328,6 +342,9 @@ namespace caret { QIcon* viewOrientationLeftMedialIcon; QIcon* viewOrientationRightLateralIcon; QIcon* viewOrientationRightMedialIcon; + + QToolButton* m_movieToolButton = NULL; + private slots: void orientationLeftOrLateralToolButtonTriggered(bool checked); void orientationRightOrMedialToolButtonTriggered(bool checked); @@ -347,8 +364,15 @@ namespace caret { QCheckBox* wholeBrainSurfaceLeftCheckBox; QCheckBox* wholeBrainSurfaceRightCheckBox; QCheckBox* wholeBrainSurfaceCerebellumCheckBox; + QMenu* wholeBrainSurfaceLeftMenu; + QMenu* wholeBrainSurfaceRightMenu; + QMenu* wholeBrainSurfaceCerebellumMenu; QDoubleSpinBox* wholeBrainSurfaceSeparationLeftRightSpinBox; QDoubleSpinBox* wholeBrainSurfaceSeparationCerebellumSpinBox; + QCheckBox* wholeBrainSurfaceMatchCheckBox; + void updateAllWholeBrainSurfaceMenus(); + void updateWholeBrainSurfaceMenu(QMenu* menu, + const StructureEnum::Enum structure); private slots: void wholeBrainSurfaceTypeComboBoxIndexChanged(int indx); @@ -360,7 +384,12 @@ namespace caret { void wholeBrainSurfaceLeftToolButtonTriggered(bool checked); void wholeBrainSurfaceRightToolButtonTriggered(bool checked); void wholeBrainSurfaceCerebellumToolButtonTriggered(bool checked); - + void wholeBrainSurfaceMatchCheckBoxClicked(bool checked); + + void wholeBrainSurfaceLeftMenuTriggered(QAction*); + void wholeBrainSurfaceRightMenuTriggered(QAction*); + void wholeBrainSurfaceCerebellumMenuTriggered(QAction*); + private: StructureSurfaceSelectionControl* surfaceSurfaceSelectionControl; @@ -435,6 +464,8 @@ namespace caret { QTimer* m_tileTabsHighlightingTimer = NULL; bool m_tileTabsHighlightingTimerEnabledFlag = true; + QString m_objectNamePrefix; + bool isContructorFinished; bool isDestructionInProgress; @@ -447,6 +478,9 @@ namespace caret { friend class BrainBrowserWindowToolBarTabPopUpMenu; }; + +#ifdef __BRAIN_BROWSER_WINDOW_TOOLBAR_DECLARE__ +#endif // __BRAIN_BROWSER_WINDOW_TOOLBAR_DECLARE__ } #endif // __BRAIN_BROWSER_WINDOW_TOOLBAR_H__ diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx index 425708ea2b27066c47d088bcdf583ff3ef4a059d..39d20a3304a7b216212f10f0e250d8477e499a2c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx @@ -47,6 +47,7 @@ #include "EventManager.h" #include "ModelChart.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -66,12 +67,18 @@ using namespace caret; * @param parentToolBar * The parent toolbar. */ -BrainBrowserWindowToolBarChartAttributes::BrainBrowserWindowToolBarChartAttributes(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartAttributes::BrainBrowserWindowToolBarChartAttributes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { - m_cartesianChartAttributesWidget = new CartesianChartAttributesWidget(this); + const QString objectNamePrefix(parentObjectName + + ":ChartOneAttributes"); - m_matrixChartAttributesWidget = new MatrixChartAttributesWidget(this); + m_cartesianChartAttributesWidget = new CartesianChartAttributesWidget(this, + objectNamePrefix); + + m_matrixChartAttributesWidget = new MatrixChartAttributesWidget(this, + objectNamePrefix); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_cartesianChartAttributesWidget); @@ -237,7 +244,8 @@ BrainBrowserWindowToolBarChartAttributes::updateGraphics() * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ -CartesianChartAttributesWidget::CartesianChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes) +CartesianChartAttributesWidget::CartesianChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes) { m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; @@ -250,6 +258,11 @@ CartesianChartAttributesWidget::CartesianChartAttributesWidget(BrainBrowserWindo this, SLOT(cartesianLineWidthValueChanged(double))); m_cartesianLineWidthDoubleSpinBox->setFixedWidth(65); + m_cartesianLineWidthDoubleSpinBox->setToolTip("Set line width"); + m_cartesianLineWidthDoubleSpinBox->setObjectName(parentObjectName + + ":LineWidth"); + WuQMacroManager::instance()->addMacroSupportToObject(m_cartesianLineWidthDoubleSpinBox, + "Set chart line width"); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); @@ -319,7 +332,8 @@ CartesianChartAttributesWidget::cartesianLineWidthValueChanged(double value) * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ -MatrixChartAttributesWidget::MatrixChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes) +MatrixChartAttributesWidget::MatrixChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes), EventListenerInterface() { @@ -333,6 +347,11 @@ EventListenerInterface() this, SLOT(cellWidthSpinBoxValueChanged(double))); m_cellWidthSpinBox->setKeyboardTracking(true); + m_cellWidthSpinBox->setToolTip("Set Cell Width"); + m_cellWidthSpinBox->setObjectName(parentObjectName + + ":Matrix:CellWidth"); + WuQMacroManager::instance()->addMacroSupportToObject(m_cellWidthSpinBox, + "Set matrix chart cell width"); QLabel* cellHeightLabel = new QLabel("Cell Height"); m_cellHeightSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(1.0, @@ -342,6 +361,11 @@ EventListenerInterface() this, SLOT(cellHeightSpinBoxValueChanged(double))); m_cellHeightSpinBox->setKeyboardTracking(true); + m_cellHeightSpinBox->setToolTip("Set Cell Height"); + m_cellHeightSpinBox->setObjectName(parentObjectName + + ":Matrix:CellHeight"); + WuQMacroManager::instance()->addMacroSupportToObject(m_cellHeightSpinBox, + "Set matrix chart cell height"); QAction* resetButtonAction = WuQtUtilities::createAction("Reset", "Reset panning (SHIFT-mouse),zooming (CTRL-mouse), and scale matrix to fit window", @@ -351,6 +375,10 @@ EventListenerInterface() QToolButton* resetToolButton = new QToolButton(); resetToolButton->setDefaultAction(resetButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(resetToolButton); + resetToolButton->setObjectName(parentObjectName + + ":Matrix:ResetButton"); + WuQMacroManager::instance()->addMacroSupportToObject(resetToolButton, + "Reset chart matrix scaling"); WuQtUtilities::matchWidgetWidths(m_cellHeightSpinBox, m_cellWidthSpinBox); @@ -358,10 +386,20 @@ EventListenerInterface() m_highlightSelectionCheckBox = new QCheckBox("Highlight Selection"); QObject::connect(m_highlightSelectionCheckBox, SIGNAL(clicked(bool)), this, SLOT(highlightSelectionCheckBoxClicked(bool))); + m_highlightSelectionCheckBox->setToolTip("Enable selected row/column highlight"); + m_highlightSelectionCheckBox->setObjectName(parentObjectName + + ":Matrix:EnableHighlight"); + WuQMacroManager::instance()->addMacroSupportToObject(m_highlightSelectionCheckBox, + "Enable chart matrix selected row height"); m_displayGridLinesCheckBox = new QCheckBox("Show Grid Outline"); QObject::connect(m_displayGridLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(displayGridLinesCheckBoxClicked(bool))); + m_displayGridLinesCheckBox->setToolTip("Show Grid Outline around matrix cells"); + m_displayGridLinesCheckBox->setObjectName(parentObjectName + + ":Matrix:EnableGridOutline"); + WuQMacroManager::instance()->addMacroSupportToObject(m_displayGridLinesCheckBox, + "Enable chart matrix grid outline"); m_manualWidgetsGroup = new WuQWidgetObjectGroup(this); m_manualWidgetsGroup->add(m_cellWidthSpinBox); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.h b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.h index 9dc7b666f99f4fc7f1589075c330c2d67b23ec51..df50cbe5200e7430f89e39a51ed8aa486d168e6e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.h @@ -42,7 +42,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartAttributes(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartAttributes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartAttributes(); @@ -81,7 +82,8 @@ namespace caret { Q_OBJECT public: - CartesianChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes); + CartesianChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName); ~CartesianChartAttributesWidget(); @@ -105,7 +107,8 @@ namespace caret { Q_OBJECT public: - MatrixChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes); + MatrixChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName); ~MatrixChartAttributesWidget(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx index f8ed112f2442a5d681d99e1e70417d08535b5dac..766b4ce907cbb77f6ee50654582ad1a370fc4845 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx @@ -39,6 +39,7 @@ #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ModelChart.h" +#include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -58,10 +59,15 @@ using namespace caret; * @param parentToolBar * parent toolbar. */ -BrainBrowserWindowToolBarChartAxes::BrainBrowserWindowToolBarChartAxes(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartAxes::BrainBrowserWindowToolBarChartAxes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { + const QString objectNamePrefix(parentObjectName + + ":ChartOneAxes:"); + WuQMacroManager* macroManager = WuQMacroManager::instance(); + QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->addWidget(new QLabel("Axis"), @@ -91,6 +97,19 @@ m_parentToolBar(parentToolBar) QObject::connect(m_bottomAxisMaximumValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(bottomAxisValueChanged(double))); + m_bottomAxisAutoRangeScaleCheckBox->setObjectName(objectNamePrefix + + "EnableBottomAxis"); + macroManager->addMacroSupportToObject(m_bottomAxisAutoRangeScaleCheckBox, + "Enable chart bottom axis auto scale"); + m_bottomAxisMinimumValueSpinBox->setObjectName(objectNamePrefix + + "BottomAxisMinimumValue"); + macroManager->addMacroSupportToObject(m_bottomAxisMinimumValueSpinBox, + "Set chart bottom axis minimum"); + m_bottomAxisMaximumValueSpinBox->setObjectName(objectNamePrefix + + "BottomAxisMaximumValue"); + macroManager->addMacroSupportToObject(m_bottomAxisMaximumValueSpinBox, + "Set chart bottom axis maximum"); + createAxisWidgets(gridLayout, m_leftAxisLabel, m_leftAxisAutoRangeScaleCheckBox, @@ -105,6 +124,19 @@ m_parentToolBar(parentToolBar) QObject::connect(m_leftAxisMaximumValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(leftAxisValueChanged(double))); + m_leftAxisAutoRangeScaleCheckBox->setObjectName(objectNamePrefix + + "EnableLeftAxis"); + macroManager->addMacroSupportToObject(m_leftAxisAutoRangeScaleCheckBox, + "Enable chart left axis auto scale"); + m_leftAxisMinimumValueSpinBox->setObjectName(objectNamePrefix + + "LeftAxisMinimumValue"); + macroManager->addMacroSupportToObject(m_leftAxisMinimumValueSpinBox, + "Set chart left axis minimum value"); + m_leftAxisMaximumValueSpinBox->setObjectName(objectNamePrefix + + "LeftAxisMaximumValue"); + macroManager->addMacroSupportToObject(m_leftAxisMaximumValueSpinBox, + "Set chart left axis maximum value"); + // createAxisWidgets(gridLayout, // m_topAxisLabel, // m_topAxisAutoRangeScaleCheckBox, diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.h index 1e4635a2d267a5e0861b15bc7cf0302631b5580a..600db73d95fee993f8867e53e77effba4595a9f5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.h @@ -42,7 +42,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartAxes(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartAxes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartAxes(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index 17054f71d269a6c51b15090832d2f65ac2fea626..b31006b28efac0ba8a8498ad0c7f84d036f1a5fb 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -44,6 +44,7 @@ #include "EventUserInterfaceUpdate.h" #include "ModelChartTwo.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -62,13 +63,21 @@ using namespace caret; * * @param parentToolBar * The parent toolbar. + * @param parentObjectName + * Name of parent for macros */ -BrainBrowserWindowToolBarChartTwoAttributes::BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartTwoAttributes::BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { - m_cartesianChartAttributesWidget = new CartesianChartTwoAttributesWidget(this); + const QString objectNamePrefix(parentObjectName + + ":ChartTwoAttributes"); - m_matrixChartTwoAttributesWidget = new MatrixChartTwoAttributesWidget(this); + m_cartesianChartAttributesWidget = new CartesianChartTwoAttributesWidget(this, + objectNamePrefix); + + m_matrixChartTwoAttributesWidget = new MatrixChartTwoAttributesWidget(this, + objectNamePrefix); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_cartesianChartAttributesWidget); @@ -162,7 +171,8 @@ BrainBrowserWindowToolBarChartTwoAttributes::updateGraphics() * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ -CartesianChartTwoAttributesWidget::CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes) +CartesianChartTwoAttributesWidget::CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes) { m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; @@ -175,6 +185,12 @@ CartesianChartTwoAttributesWidget::CartesianChartTwoAttributesWidget(BrainBrowse this, SLOT(cartesianLineWidthValueChanged(double))); m_cartesianLineWidthDoubleSpinBox->setFixedWidth(65); + m_cartesianLineWidthDoubleSpinBox->setToolTip("Width of line"); + m_cartesianLineWidthDoubleSpinBox->setObjectName(parentObjectName + + ":LineWidth"); + WuQMacroManager::instance()->addMacroSupportToObject(m_cartesianLineWidthDoubleSpinBox, + "Set cartesian chart line width"); + QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); @@ -232,7 +248,8 @@ CartesianChartTwoAttributesWidget::cartesianLineWidthValueChanged(double /*value * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ -MatrixChartTwoAttributesWidget::MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes) +MatrixChartTwoAttributesWidget::MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes), EventListenerInterface() { @@ -250,6 +267,10 @@ EventListenerInterface() m_cellWidthPercentageSpinBox->setToolTip("Percentage of tab width filled with matrix"); m_cellWidthPercentageSpinBox->setKeyboardTracking(false); m_cellWidthPercentageSpinBox->setSuffix("%"); + m_cellWidthPercentageSpinBox->setObjectName(parentObjectName + + ":CellWidth"); + WuQMacroManager::instance()->addMacroSupportToObject(m_cellWidthPercentageSpinBox, + "Set matrix chart cell width"); QLabel* cellHeightLabel = new QLabel("Cell Height"); m_cellHeightPercentageSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minPercent, @@ -261,6 +282,10 @@ EventListenerInterface() m_cellHeightPercentageSpinBox->setToolTip("Percentage of tab height filled with matrix"); m_cellHeightPercentageSpinBox->setKeyboardTracking(false); m_cellHeightPercentageSpinBox->setSuffix("%"); + m_cellHeightPercentageSpinBox->setObjectName(parentObjectName + + ":CellHeight"); + WuQMacroManager::instance()->addMacroSupportToObject(m_cellHeightPercentageSpinBox, + "Set matrix chart cell height"); WuQtUtilities::matchWidgetWidths(m_cellHeightPercentageSpinBox, m_cellWidthPercentageSpinBox); @@ -269,11 +294,19 @@ EventListenerInterface() m_highlightSelectionCheckBox->setToolTip("Highlight selected row/column in the matrix"); QObject::connect(m_highlightSelectionCheckBox, SIGNAL(clicked(bool)), this, SLOT(valueChanged())); + m_highlightSelectionCheckBox->setObjectName(parentObjectName + + ":HighlightSelection"); + WuQMacroManager::instance()->addMacroSupportToObject(m_highlightSelectionCheckBox, + "Enable outline of selected chart matrix row/column"); m_displayGridLinesCheckBox = new QCheckBox("Show Grid Outline"); QObject::connect(m_displayGridLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(valueChanged())); m_displayGridLinesCheckBox->setToolTip("Outline cells in the matrix"); + m_displayGridLinesCheckBox->setObjectName(parentObjectName + + ":EnableGridOutline"); + WuQMacroManager::instance()->addMacroSupportToObject(m_displayGridLinesCheckBox, + "Enable matrix chart grid outline"); m_manualWidgetsGroup = new WuQWidgetObjectGroup(this); m_manualWidgetsGroup->add(m_cellWidthPercentageSpinBox); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h index 3855496a6074d730de90b75121c54f6a0b2e80ba..f1f446f02760f920253e199fed07b00bb5062f4f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h @@ -41,7 +41,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoAttributes(); @@ -80,7 +81,8 @@ namespace caret { Q_OBJECT public: - CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes); + CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName); ~CartesianChartTwoAttributesWidget(); @@ -104,7 +106,8 @@ namespace caret { Q_OBJECT public: - MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes); + MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, + const QString& parentObjectName); ~MatrixChartTwoAttributesWidget(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 24e5e9d2a12b713632a478575e754223a815fba3..b7818b1080576a7c2ea224841e4635eb8dd1e686 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -55,6 +55,7 @@ #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQDoubleSpinBox.h" +#include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -73,13 +74,20 @@ using namespace caret; * * @param parentToolBar * The parent toolbar. + * @param parentObjectName + * Name of parent object for macros */ -BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { m_chartOverlaySet = NULL; m_chartAxis = NULL; + WuQMacroManager* macroManager = WuQMacroManager::instance(); + const QString objectNamePrefix(parentObjectName + + ":ChartAxes:"); + /* * 'Show' checkboxes */ @@ -87,26 +95,47 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_axisDisplayedByUserCheckBox->setToolTip("Show/hide the axis"); QObject::connect(m_axisDisplayedByUserCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); + m_axisDisplayedByUserCheckBox->setObjectName(objectNamePrefix + + "ShowAxis"); + macroManager->addMacroSupportToObject(m_axisDisplayedByUserCheckBox, + "Enable chart axis"); + m_showTickMarksCheckBox = new QCheckBox("Ticks"); QObject::connect(m_showTickMarksCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showTickMarksCheckBox->setToolTip("Show ticks along the axis"); + m_showTickMarksCheckBox->setObjectName(objectNamePrefix + + "ShowTicks"); + macroManager->addMacroSupportToObject(m_showTickMarksCheckBox, + "Enable chart axis ticks"); m_showLabelCheckBox = new QCheckBox("Label"); QObject::connect(m_showLabelCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showLabelCheckBox->setToolTip("Show label on axis"); + m_showLabelCheckBox->setObjectName(objectNamePrefix + + "ShowLabel"); + macroManager->addMacroSupportToObject(m_showLabelCheckBox, + "Enable chart axis label"); m_showNumericsCheckBox = new QCheckBox("Nums"); QObject::connect(m_showNumericsCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showNumericsCheckBox->setToolTip("Show numeric scale values on axis"); + m_showNumericsCheckBox->setObjectName(objectNamePrefix + + "ShowNumerics"); + macroManager->addMacroSupportToObject(m_showNumericsCheckBox, + "Enable chart axis numerics"); m_rotateNumericsCheckBox = new QCheckBox("Rotate"); QObject::connect(m_rotateNumericsCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_rotateNumericsCheckBox->setToolTip("Rotate numeric scale values on axis"); + m_rotateNumericsCheckBox->setObjectName(objectNamePrefix + + "EnableNumericsRotate"); + macroManager->addMacroSupportToObject(m_rotateNumericsCheckBox, + "Enable rotation of chart axis numerics"); /* * Axes selection @@ -116,6 +145,10 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QObject::connect(m_axisComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::axisChanged); m_axisComboBox->getWidget()->setToolTip("Choose axis for editing"); + m_axisComboBox->getWidget()->setObjectName(objectNamePrefix + + "ChooseAxis"); + macroManager->addMacroSupportToObject(m_axisComboBox->getComboBox(), + "Select chart axis"); /* * Controls for layer selection and label editing @@ -126,12 +159,20 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::axisLabelToolButtonClicked); WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisLabelToolButton); m_axisLabelToolButton->setToolTip("Edit the axis name for the file in the selected overlay"); + m_axisLabelToolButton->setObjectName(objectNamePrefix + + "EditAxis"); + macroManager->addMacroSupportToObject(m_axisLabelToolButton, + "Edit chart axis label"); QLabel* axisLabelFromOverlayLabel = new QLabel("Label From File In"); m_axisLabelFromOverlayComboBox = new QComboBox(); m_axisLabelFromOverlayComboBox->setToolTip("Label for axis is from file in selected layer"); QObject::connect(m_axisLabelFromOverlayComboBox, static_cast(&QComboBox::activated), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); + m_axisLabelFromOverlayComboBox->setObjectName(objectNamePrefix + + "LabelFromOverlay"); + macroManager->addMacroSupportToObject(m_axisLabelFromOverlayComboBox, + "Select chart axis overlay source"); /* * Range controls @@ -147,6 +188,10 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QObject::connect(m_autoUserRangeComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_autoUserRangeComboBox->getWidget()->setToolTip(rangeTooltip); + m_autoUserRangeComboBox->getWidget()->setObjectName(objectNamePrefix + + "RangeMode"); + macroManager->addMacroSupportToObject(m_autoUserRangeComboBox->getWidget(), + "Select chart axis range mode"); m_userMinimumValueSpinBox = new WuQDoubleSpinBox(this); m_userMinimumValueSpinBox->setDecimalsModeAuto(); @@ -154,6 +199,10 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QObject::connect(m_userMinimumValueSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged); m_userMinimumValueSpinBox->setToolTip("Set user scaling axis minimum value"); + m_userMinimumValueSpinBox->getWidget()->setObjectName(objectNamePrefix + + "ScaleMinimum"); + macroManager->addMacroSupportToObject(m_userMinimumValueSpinBox->getWidget(), + "Set chart axis minimum"); m_userMaximumValueSpinBox = new WuQDoubleSpinBox(this); m_userMaximumValueSpinBox->setDecimalsModeAuto(); @@ -161,6 +210,10 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QObject::connect(m_userMaximumValueSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged); m_userMaximumValueSpinBox->setToolTip("Set user scaling axis maximum value"); + m_userMaximumValueSpinBox->getWidget()->setObjectName(objectNamePrefix + + "ScaleMaximum"); + macroManager->addMacroSupportToObject(m_userMaximumValueSpinBox->getWidget(), + "See chart axis maximum"); /* * Format controls @@ -170,22 +223,38 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QObject::connect(m_userNumericFormatComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_userNumericFormatComboBox->getWidget()->setToolTip("Choose format of axis scale numeric values"); + m_userNumericFormatComboBox->getWidget()->setObjectName(objectNamePrefix + + "Format"); + macroManager->addMacroSupportToObject(m_userNumericFormatComboBox->getWidget(), + "Select chart axis numeric format"); m_userDigitsRightOfDecimalSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 10, 1); QObject::connect(m_userDigitsRightOfDecimalSpinBox, static_cast(&QSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userDigitsRightOfDecimalSpinBox->setToolTip("Set digits right of decimal for\ndecimal or scientific format"); + m_userDigitsRightOfDecimalSpinBox->setObjectName(objectNamePrefix + + "DigitsRightOfDecimal"); + macroManager->addMacroSupportToObject(m_userDigitsRightOfDecimalSpinBox, + "Set chart axis digits right of decimal"); m_numericSubdivisionsModeComboBox = new EnumComboBoxTemplate(this); m_numericSubdivisionsModeComboBox->setup(); QObject::connect(m_numericSubdivisionsModeComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_numericSubdivisionsModeComboBox->getWidget()->setToolTip("Numeric subdivisions mode"); + m_numericSubdivisionsModeComboBox->getWidget()->setObjectName(objectNamePrefix + + "NumericSubdivisionsMode"); + macroManager->addMacroSupportToObject(m_numericSubdivisionsModeComboBox->getWidget(), + "Set chart axis numeric subdivisions mode"); m_userSubdivisionsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 100, 1); QObject::connect(m_userSubdivisionsSpinBox, static_cast(&QSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userSubdivisionsSpinBox->setToolTip("Set subdivisions on the axis when Auto is not checked"); + m_userSubdivisionsSpinBox->setObjectName(objectNamePrefix + + "NumberOfSubdivisions"); + macroManager->addMacroSupportToObject(m_userSubdivisionsSpinBox, + "Set chart axis number of subivisions"); /* * Size spin boxes @@ -195,24 +264,40 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QObject::connect(m_labelSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height for selected axis"); + m_labelSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + + "LabelHeight"); + macroManager->addMacroSupportToObject(m_labelSizeSpinBox->getWidget(), + "Set chart axis label height"); m_numericsSizeSpinBox = new WuQDoubleSpinBox(this); m_numericsSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_numericsSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height for selected axis"); + m_numericsSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + + "NumericValueHeight"); + macroManager->addMacroSupportToObject(m_numericsSizeSpinBox->getWidget(), + "Set chart axis numerics height"); m_linesTicksSizeSpinBox = new WuQDoubleSpinBox(this); m_linesTicksSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_linesTicksSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisLineThicknessChanged); m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines as percentage of tab height for ALL axes"); + m_linesTicksSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + + "TicksSize"); + macroManager->addMacroSupportToObject(m_linesTicksSizeSpinBox->getWidget(), + "Set chart axis ticks height"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); m_paddingSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height for selected axis"); + m_paddingSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + + "PaddingSize"); + macroManager->addMacroSupportToObject(m_paddingSizeSpinBox->getWidget(), + "Set chart axis padding height"); /* * Group widgets for blocking signals diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index df8db9b20ebc24f9d1adedb25eb8185c3c1570e5..544348b0c2bea5cf5481352c51bc08a382163e96 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -46,7 +46,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoAxes(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx index ea4313238c88edccb2b250b8b077f985b66dbcc5..319936bfc429036e342279e1a6e038e94b8dbebe 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx @@ -33,6 +33,7 @@ #include "EventManager.h" #include "ModelChartTwo.h" #include "SessionManager.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -48,30 +49,42 @@ using namespace caret; /** * Constructor. */ -BrainBrowserWindowToolBarChartTwoOrientation::BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartTwoOrientation::BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { + const QString objectNamePrefix(parentObjectName + + ":ChartOrientation"); + + QToolButton* orientationResetToolButton = new QToolButton(); m_orientationResetToolButtonAction = WuQtUtilities::createAction("Reset", "Reset the view to remove any panning or zooming", - this, + orientationResetToolButton, this, SLOT(orientationResetToolButtonTriggered(bool))); + m_orientationResetToolButtonAction->setObjectName(objectNamePrefix + + ":ResetButton"); + WuQMacroManager::instance()->addMacroSupportToObject(m_orientationResetToolButtonAction, + "Reset chart panning and zooming"); const QString customToolTip = ("Pressing the \"Custom\" button displays a dialog for creating and editing orientations.\n" "Note that custom orientations are stored in your Workbench's preferences and thus\n" "will be availble in any concurrent or future instances of Workbench."); + m_orientationCustomViewSelectToolButton = new QToolButton(); m_customViewAction = WuQtUtilities::createAction("Custom", customToolTip, - this, + m_orientationCustomViewSelectToolButton, this, SLOT(customViewActionTriggered())); + m_customViewAction->setObjectName(objectNamePrefix + + ":ShowCustomViewDialog"); + WuQMacroManager::instance()->addMacroSupportToObject(m_customViewAction, + "Display chart custom view dialog"); - QToolButton* orientationResetToolButton = new QToolButton(); orientationResetToolButton->setDefaultAction(m_orientationResetToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(orientationResetToolButton); - m_orientationCustomViewSelectToolButton = new QToolButton(); m_orientationCustomViewSelectToolButton->setDefaultAction(m_customViewAction); m_orientationCustomViewSelectToolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h index 6890f270082690b7e1d2e91bcdd6c6704e25e1f0..34aa3877ff5bce1a6b8e7eede3ad53e03ec7ed3a 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h @@ -32,7 +32,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoOrientation(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index 21d62455edab09514a0902a4f83b119c2c088c21..88e04dba1a5aaa9cde431cf76633f1c64867f9e6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -42,6 +42,7 @@ #include "ModelChartTwo.h" #include "WuQDataEntryDialog.h" #include "WuQDoubleSpinBox.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -56,21 +57,38 @@ using namespace caret; /** * Constructor. + * + * @param parentToolBar + * The parent toolbar + * @param parentObjectName + * Name of parent object for macros */ -BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + const QString objectNamePrefix(parentObjectName + + ":ChartTitle:"); + m_showTitleCheckBox = new QCheckBox("Show Title"); m_showTitleCheckBox->setToolTip("Show the title at the top of the chart"); QObject::connect(m_showTitleCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxClicked); + m_showTitleCheckBox->setObjectName(objectNamePrefix + + "Show"); + macroManager->addMacroSupportToObject(m_showTitleCheckBox, + "Show chart title"); - QAction* editTitleAction = new QAction("Edit Title...", this); + QToolButton* editTitleToolButton = new QToolButton; + QAction* editTitleAction = new QAction("Edit Title...", editTitleToolButton); editTitleAction->setToolTip("Edit the chart title in a dialog"); QObject::connect(editTitleAction, &QAction::triggered, this, &BrainBrowserWindowToolBarChartTwoTitle::editTitleActionTriggered); - - QToolButton* editTitleToolButton = new QToolButton; + editTitleAction->setObjectName(objectNamePrefix + + "Edit"); + macroManager->addMacroSupportToObject(editTitleAction, + "Display dialog to edit chart title"); WuQtUtilities::setToolButtonStyleForQt5Mac(editTitleToolButton); editTitleToolButton->setDefaultAction(editTitleAction); @@ -79,11 +97,19 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B QObject::connect(m_titleSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); m_titleSizeSpinBox->setToolTip("Set height of title as percentage of tab height"); + m_titleSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + + "Height"); + macroManager->addMacroSupportToObject(m_titleSizeSpinBox->getWidget(), + "Set chart title height"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); m_paddingSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); + m_paddingSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + + "Padding"); + macroManager->addMacroSupportToObject(m_paddingSizeSpinBox->getWidget(), + "Set chart padding"); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height"); QGridLayout* layout = new QGridLayout(this); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h index cf803400fc22a11c01d4bfd1bada9e638a2129ec..aa27d189529a9125b9ac03ae7ac18004602b85ef 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h @@ -35,7 +35,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoTitle(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx index a1cdab23ee8c43c7a589c398b7478bc8a6502b48..a19c7b36861ca0ae5f80a19df6c05dae51787df8 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx @@ -32,6 +32,7 @@ #include "CaretAssert.h" #include "EnumComboBoxTemplate.h" #include "ModelChartTwo.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -49,8 +50,11 @@ using namespace caret; * * @param parentToolBar * parent toolbar. + * @param parentObjectName + * Name of parent object for macros */ -BrainBrowserWindowToolBarChartTwoType::BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartTwoType::BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { @@ -69,6 +73,16 @@ m_parentToolBar(parentToolBar) QRadioButton* rb = new QRadioButton(ChartTwoDataTypeEnum::toGuiName(ct)); m_chartTypeButtonGroup->addButton(rb, m_chartTypeRadioButtons.size()); + rb->setToolTip("Set chart to " + + rb->text()); + + QString chartTypeName = rb->text(); + chartTypeName = chartTypeName.replace(" ", ""); + rb->setObjectName(parentObjectName + + ":ChartType:" + + chartTypeName); + WuQMacroManager::instance()->addMacroSupportToObject(rb, + "Select " + chartTypeName + " chart"); radioButtonLayout->addWidget(rb); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h index b784137f66ec1417fada78d89aa2ed118c818bf9..c7c7e9a89a1fe88f90f250d418dc0f2eadf9b780 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h @@ -36,7 +36,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoType(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx index b45ecc59be06b4ffae2f8dfa666e3ed598bedf96..f2ba10012934f69019655c21e18699b2490dcc7c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx @@ -33,6 +33,7 @@ #include "ChartModel.h" #include "EnumComboBoxTemplate.h" #include "ModelChart.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -51,10 +52,12 @@ using namespace caret; * @param parentToolBar * parent toolbar. */ -BrainBrowserWindowToolBarChartType::BrainBrowserWindowToolBarChartType(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartType::BrainBrowserWindowToolBarChartType(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { + m_chartTypeButtonGroup = new QButtonGroup(this); QVBoxLayout* radioButtonLayout = new QVBoxLayout(this); @@ -74,6 +77,17 @@ m_parentToolBar(parentToolBar) m_chartTypeButtonGroup->addButton(rb, m_chartTypeRadioButtons.size()); + rb->setToolTip("Set chart to " + + rb->text()); + + QString chartTypeName = rb->text(); + chartTypeName = chartTypeName.replace(" ", ""); + rb->setObjectName(parentObjectName + + ":ChartOneType:" + + chartTypeName); + WuQMacroManager::instance()->addMacroSupportToObject(rb, + "Select " + chartTypeName + " chart"); + radioButtonLayout->addWidget(rb); m_chartTypeRadioButtons.push_back(std::make_pair(ct, rb)); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.h b/src/GuiQt/BrainBrowserWindowToolBarChartType.h index f468511becd38766c906978ace807b51bc20a819..47f0d93e51d3655219460ed58afeb63aa9672167 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.h @@ -36,7 +36,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarChartType(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartType(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartType(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx b/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx index 9c3beeb22c6fc40f9dcc6f4e709ae0bfa21335c1..fa3535807318f828b22f0fac185a57996c6ba0ed 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx @@ -33,6 +33,7 @@ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "GuiManager.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -47,45 +48,93 @@ using namespace caret; /** * Constructor. + * + * @param browserWindowIndex + * Index of window + * @param parentToolBar + * The parent toolbar + * @param parentObjectNamePrefix + * Name of parent object */ BrainBrowserWindowToolBarClipping::BrainBrowserWindowToolBarClipping(const int32_t browserWindowIndex, - BrainBrowserWindowToolBar* parentToolBar) + BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectNamePrefix) : BrainBrowserWindowToolBarComponent(parentToolBar), m_browserWindowIndex(browserWindowIndex), m_parentToolBar(parentToolBar) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + + const QString objectNamePrefix(parentObjectNamePrefix + + ":Clipping"); + m_xClippingEnabledCheckBox = new QCheckBox("X"); QObject::connect(m_xClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); + m_xClippingEnabledCheckBox->setToolTip("Enable X clipping plane"); + m_xClippingEnabledCheckBox->setObjectName(objectNamePrefix + + ":EnableX"); + macroManager->addMacroSupportToObject(m_xClippingEnabledCheckBox, + "Enable X clipping plane"); m_yClippingEnabledCheckBox = new QCheckBox("Y"); QObject::connect(m_yClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); + m_yClippingEnabledCheckBox->setToolTip("Enable Y clipping plane"); + m_yClippingEnabledCheckBox->setObjectName(objectNamePrefix + + ":EnableY"); + macroManager->addMacroSupportToObject(m_yClippingEnabledCheckBox, + "Enable Y clipping plane"); m_zClippingEnabledCheckBox = new QCheckBox("Z"); QObject::connect(m_zClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); + m_zClippingEnabledCheckBox->setToolTip("Enable Z clipping plane"); + m_zClippingEnabledCheckBox->setObjectName(objectNamePrefix + + ":EnableZ"); + macroManager->addMacroSupportToObject(m_zClippingEnabledCheckBox, + "Enable Z clipping"); m_surfaceClippingEnabledCheckBox = new QCheckBox("Surface"); QObject::connect(m_surfaceClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); + m_surfaceClippingEnabledCheckBox->setToolTip("Enable Clipping of Surface"); + m_surfaceClippingEnabledCheckBox->setObjectName(objectNamePrefix + + ":EnableSurface"); + macroManager->addMacroSupportToObject(m_surfaceClippingEnabledCheckBox, + "Enable surface clipping"); m_volumeClippingEnabledCheckBox = new QCheckBox("Volume"); QObject::connect(m_volumeClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); + m_volumeClippingEnabledCheckBox->setToolTip("Enable Clipping of Volume Slices"); + m_volumeClippingEnabledCheckBox->setObjectName(objectNamePrefix + + ":EnableVolume"); + macroManager->addMacroSupportToObject(m_volumeClippingEnabledCheckBox, + "Enable volume clipping"); m_featuresClippingEnabledCheckBox = new QCheckBox("Features"); QObject::connect(m_featuresClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); + m_featuresClippingEnabledCheckBox->setToolTip("Enable Clipping of Features"); + m_featuresClippingEnabledCheckBox->setObjectName(objectNamePrefix + + ":EnableFeatures"); + macroManager->addMacroSupportToObject(m_featuresClippingEnabledCheckBox, + "Enable features clipping"); QToolButton* setupToolButton = new QToolButton(); setupToolButton->setText("Setup"); QObject::connect(setupToolButton, SIGNAL(clicked()), this, SLOT(setupClippingPushButtonClicked())); WuQtUtilities::setToolButtonStyleForQt5Mac(setupToolButton); + setupToolButton->setToolTip("Display Clipping Planes Setup Dialog"); + setupToolButton->setObjectName(objectNamePrefix + + ":ShowSetupDialog"); + macroManager->addMacroSupportToObject(setupToolButton, + "Display clipping planes dialog"); QGridLayout* gridLayout = new QGridLayout(this); -// WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); gridLayout->setHorizontalSpacing(6); gridLayout->setVerticalSpacing(4); gridLayout->setContentsMargins(1, 1, 1, 1); @@ -101,31 +150,6 @@ m_parentToolBar(parentToolBar) gridLayout->addWidget(m_volumeClippingEnabledCheckBox, rowIndex, 0, 1, 3); rowIndex++; gridLayout->addWidget(setupToolButton, rowIndex, 0, 1, 3, Qt::AlignHCenter); - -// /* -// * Layout: -// * Column 1: Clipping X, Y, Z -// * Column 2: Nothing but used as space -// * Column 3: Type of data clipped. -// */ -// QGridLayout* checkboxGridLayout = new QGridLayout(); -// WuQtUtilities::setLayoutSpacingAndMargins(checkboxGridLayout, 4, 0); -// checkboxGridLayout->setColumnMinimumWidth(1, 15); -// checkboxGridLayout->setColumnStretch(0, 0); -// checkboxGridLayout->setColumnStretch(0, 1); -// checkboxGridLayout->setColumnStretch(0, 2); -// checkboxGridLayout->addWidget(m_xClippingEnabledCheckBox, 0, 0); -// checkboxGridLayout->addWidget(m_yClippingEnabledCheckBox, 1, 0); -// checkboxGridLayout->addWidget(m_zClippingEnabledCheckBox, 2, 0); -// checkboxGridLayout->addWidget(m_surfaceClippingEnabledCheckBox, 0, 2); -// checkboxGridLayout->addWidget(m_volumeClippingEnabledCheckBox, 1, 2); -// checkboxGridLayout->addWidget(m_featuresClippingEnabledCheckBox, 2, 2); -// -// QVBoxLayout* layout = new QVBoxLayout(this); -// WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); -// layout->addLayout(checkboxGridLayout); -// layout->addWidget(setupToolButton, 0, Qt::AlignHCenter); -// layout->addStretch(); } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBarClipping.h b/src/GuiQt/BrainBrowserWindowToolBarClipping.h index 23b631c56361168deab1011f88cf582d0e776fc8..a76376fca5c7107b4ab218bae7b65f8259191397 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarClipping.h +++ b/src/GuiQt/BrainBrowserWindowToolBarClipping.h @@ -35,7 +35,8 @@ namespace caret { public: BrainBrowserWindowToolBarClipping(const int32_t browserWindowIndex, - BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBar* parentToolBar, + const QString& objectNamePrefix); virtual ~BrainBrowserWindowToolBarClipping(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx index f18e1332adb3637be1d08d3e70a58423cb698f39..762693d18d9731b27d3c28cb81c75ab9ed2785e2 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx @@ -25,15 +25,23 @@ #include #include +#include #include +#include #include #include #include +#include #include "BrainBrowserWindowToolBar.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" +#include "CaretPreferenceDataValue.h" +#include "CaretPreferences.h" +#include "GuiManager.h" +#include "SessionManager.h" +#include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -49,11 +57,20 @@ using namespace caret; /** * Constructor. + * + * @param parentToolBar + * The parent toolbar */ -BrainBrowserWindowToolBarSlicePlane::BrainBrowserWindowToolBarSlicePlane(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarSlicePlane::BrainBrowserWindowToolBarSlicePlane(const QString& parentObjectName, + BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + const QString objectNamePrefix(parentObjectName + + ":SlicePlane:"); + QIcon parasagittalIcon; const bool parasagittalIconValid = WuQtUtilities::loadIcon(":/ToolBar/view-plane-parasagittal.png", @@ -77,6 +94,10 @@ m_parentToolBar(parentToolBar) if (parasagittalIconValid) { m_volumePlaneParasagittalToolButtonAction->setIcon(parasagittalIcon); } + m_volumePlaneParasagittalToolButtonAction->setObjectName(objectNamePrefix + + "ParasagittalSliceView"); + macroManager->addMacroSupportToObject(m_volumePlaneParasagittalToolButtonAction, + "Select parasagittal slice view"); m_volumePlaneCoronalToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::CORONAL), "View the CORONAL slice", @@ -85,6 +106,10 @@ m_parentToolBar(parentToolBar) if (coronalIconValid) { m_volumePlaneCoronalToolButtonAction->setIcon(coronalIcon); } + m_volumePlaneCoronalToolButtonAction->setObjectName(objectNamePrefix + + "CoronalSliceView"); + macroManager->addMacroSupportToObject(m_volumePlaneCoronalToolButtonAction, + "Select coronal slice view"); m_volumePlaneAxialToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::AXIAL), "View the AXIAL slice", @@ -93,13 +118,21 @@ m_parentToolBar(parentToolBar) if (axialIconValid) { m_volumePlaneAxialToolButtonAction->setIcon(axialIcon); } + m_volumePlaneAxialToolButtonAction->setObjectName(objectNamePrefix + + "AxialSliceView"); + macroManager->addMacroSupportToObject(m_volumePlaneAxialToolButtonAction, + "Select axial slice view"); m_volumePlaneAllToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::ALL), "View the PARASAGITTAL, CORONAL, and AXIAL slices\n" "Press arrow to display menu for layout selection", this); m_volumePlaneAllToolButtonAction->setCheckable(true); - m_volumePlaneAllToolButtonAction->setMenu(createViewAllSlicesLayoutMenu()); + m_volumePlaneAllToolButtonAction->setMenu(createViewAllSlicesLayoutMenu(objectNamePrefix)); + m_volumePlaneAllToolButtonAction->setObjectName(objectNamePrefix + + "AllSlicesView"); + macroManager->addMacroSupportToObject(m_volumePlaneAllToolButtonAction, + "Select all planes view"); m_volumePlaneActionGroup = new QActionGroup(this); @@ -117,23 +150,31 @@ m_parentToolBar(parentToolBar) this, this, SLOT(volumePlaneResetToolButtonTriggered(bool))); + m_volumePlaneResetToolButtonAction->setObjectName(objectNamePrefix + + "ResetView"); + macroManager->addMacroSupportToObject(m_volumePlaneResetToolButtonAction, + "Reset slice view pan/rotate/zoom"); QToolButton* volumePlaneParasagittalToolButton = new QToolButton(); volumePlaneParasagittalToolButton->setDefaultAction(m_volumePlaneParasagittalToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneParasagittalToolButton); + m_volumePlaneParasagittalToolButtonAction->setParent(volumePlaneParasagittalToolButton); QToolButton* volumePlaneCoronalToolButton = new QToolButton(); volumePlaneCoronalToolButton->setDefaultAction(m_volumePlaneCoronalToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneCoronalToolButton); + m_volumePlaneCoronalToolButtonAction->setParent(volumePlaneCoronalToolButton); QToolButton* volumePlaneAxialToolButton = new QToolButton(); volumePlaneAxialToolButton->setDefaultAction(m_volumePlaneAxialToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneAxialToolButton); + m_volumePlaneAxialToolButtonAction->setParent(volumePlaneAxialToolButton); QToolButton* volumePlaneAllToolButton = new QToolButton(); volumePlaneAllToolButton->setDefaultAction(m_volumePlaneAllToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneAllToolButton); + m_volumePlaneAllToolButtonAction->setParent(volumePlaneAllToolButton); QToolButton* volumePlaneResetToolButton = new QToolButton(); volumePlaneResetToolButton->setDefaultAction(m_volumePlaneResetToolButtonAction); @@ -156,9 +197,18 @@ m_parentToolBar(parentToolBar) m_volumeAxisCrosshairsToolButtonAction = new QAction("", this); m_volumeAxisCrosshairsToolButtonAction->setCheckable(true); - m_volumeAxisCrosshairsToolButtonAction->setToolTip("Show crosshairs on slice planes"); + m_volumeAxisCrosshairsToolButtonAction->setToolTip("" + "Show crosshairs on slice planes.
" + "Press arrow to adjust gap" + ""); + m_volumeAxisCrosshairsToolButtonAction->setMenu(createCrosshairMenu(objectNamePrefix)); QObject::connect(m_volumeAxisCrosshairsToolButtonAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSlicePlane::volumeAxisCrosshairsTriggered); + m_volumeAxisCrosshairsToolButtonAction->setObjectName(objectNamePrefix + + "ShowVolumeSliceCrosshairs"); + macroManager->addMacroSupportToObject(m_volumeAxisCrosshairsToolButtonAction, + "Show slice axis crosshairs"); + QToolButton* volumeCrosshairsToolButton = new QToolButton(); QPixmap xhairPixmap = createCrosshairsIcon(volumeCrosshairsToolButton); volumeCrosshairsToolButton->setDefaultAction(m_volumeAxisCrosshairsToolButtonAction); @@ -171,6 +221,11 @@ m_parentToolBar(parentToolBar) m_volumeAxisCrosshairLabelsToolButtonAction->setToolTip("Show crosshair slice plane labels"); QObject::connect(m_volumeAxisCrosshairLabelsToolButtonAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSlicePlane::volumeAxisCrosshairLabelsTriggered); + m_volumeAxisCrosshairLabelsToolButtonAction->setObjectName(objectNamePrefix + + "ShowVolumeSliceLabels"); + macroManager->addMacroSupportToObject(m_volumeAxisCrosshairLabelsToolButtonAction, + "Show slice axis labels"); + QToolButton* volumeCrosshairLabelsToolButton = new QToolButton(); volumeCrosshairLabelsToolButton->setDefaultAction(m_volumeAxisCrosshairLabelsToolButtonAction); QPixmap labelsPixmap = createCrosshairLabelsIcon(volumeCrosshairLabelsToolButton); @@ -243,23 +298,35 @@ BrainBrowserWindowToolBarSlicePlane::updateContent(BrowserTabContent* browserTab /** * @return A new instance of the view all slices layout menu. + * @param objectNamePrefix + * Prefix for object names in macro system */ QMenu* -BrainBrowserWindowToolBarSlicePlane::createViewAllSlicesLayoutMenu() +BrainBrowserWindowToolBarSlicePlane::createViewAllSlicesLayoutMenu(const QString& objectNamePrefix) { std::vector allLayouts; VolumeSliceViewAllPlanesLayoutEnum::getAllEnums(allLayouts); - QMenu* menu = new QMenu(); + QMenu* menu = new QMenu(this); + menu->setObjectName(objectNamePrefix + + "LayoutMenu"); + menu->setToolTip("Selects layout of volume slices (column, grid, row)"); QActionGroup* actionGroup = new QActionGroup(this); for (auto layout : allLayouts) { QAction* action = menu->addAction(VolumeSliceViewAllPlanesLayoutEnum::toGuiName(layout)); action->setData((int)VolumeSliceViewAllPlanesLayoutEnum::toIntegerCode(layout)); action->setCheckable(true); + action->setObjectName(objectNamePrefix + + ":Layout:" + + VolumeSliceViewAllPlanesLayoutEnum::toName(layout)); m_viewAllSliceLayoutMenuActions.push_back(action); - actionGroup->addAction(action); + + WuQMacroManager::instance()->addMacroSupportToObject(action, + "Select " + + VolumeSliceViewAllPlanesLayoutEnum::toGuiName(layout) + + " volume slice layout"); } QObject::connect(menu, &QMenu::triggered, @@ -267,6 +334,73 @@ BrainBrowserWindowToolBarSlicePlane::createViewAllSlicesLayoutMenu() return menu; } +/** + * @return A new instance of the crosshair menu + * @param objectNamePrefix + * Prefix for object names in macro system + * @return + * Menu for crosshair button + */ +QMenu* +BrainBrowserWindowToolBarSlicePlane::createCrosshairMenu(const QString& objectNamePrefix) +{ + m_crosshairGapSpinBox = new QDoubleSpinBox(); + m_crosshairGapSpinBox->setMinimum(0.0); + m_crosshairGapSpinBox->setMaximum(100); + m_crosshairGapSpinBox->setSingleStep(0.1); + m_crosshairGapSpinBox->setDecimals(1); + m_crosshairGapSpinBox->setSuffix("%"); + m_crosshairGapSpinBox->setObjectName(objectNamePrefix + + "CrossHairGapSinBox"); + m_crosshairGapSpinBox->setToolTip("Gap for cross hairs as percentage of window height"); + + QObject::connect(m_crosshairGapSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarSlicePlane::crosshairGapSpinBoxValueChanged); + + QLabel* crosshairLabel = new QLabel("Gap "); + + QWidget* crosshairWidget = new QWidget(); + QHBoxLayout* crosshairLayout = new QHBoxLayout(crosshairWidget); + crosshairLayout->setContentsMargins(0, 0, 0, 0); + crosshairLayout->addWidget(crosshairLabel); + crosshairLayout->addWidget(m_crosshairGapSpinBox); + crosshairWidget->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + + QWidgetAction* crossHairGapWidgetAction = new QWidgetAction(this); + crossHairGapWidgetAction->setDefaultWidget(crosshairWidget); + + QMenu* menu = new QMenu(this); + QObject::connect(menu, &QMenu::aboutToShow, + this, &BrainBrowserWindowToolBarSlicePlane::crosshairMenuAboutToShow); + menu->addAction(crossHairGapWidgetAction); + + return menu; +} + +/** + * Called when crosshair menu is about to show + */ +void +BrainBrowserWindowToolBarSlicePlane::crosshairMenuAboutToShow() +{ + const float gapValue = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); + QSignalBlocker blocker(m_crosshairGapSpinBox); + m_crosshairGapSpinBox->setValue(gapValue); +} + +/** + * Called when crosshair gap spin box value changed + * + * @param value + * New value for crosshair gap. + */ +void +BrainBrowserWindowToolBarSlicePlane::crosshairGapSpinBoxValueChanged(double value) +{ + SessionManager::get()->getCaretPreferences()->setVolumeCrosshairGap(value); + GuiManager::updateGraphicsAllWindows(); +} + /** * Gets called when the user selects an item on the view all slices layout menu. * @@ -403,7 +537,8 @@ BrainBrowserWindowToolBarSlicePlane::createCrosshairsIcon(const QWidget* widget) QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, - pixmap); + pixmap, + static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); const int startXY = 4; const int endXY = 10; QPen pen(painter->pen()); @@ -441,7 +576,8 @@ BrainBrowserWindowToolBarSlicePlane::createCrosshairLabelsIcon(const QWidget* wi QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, - pixmap); + pixmap, + static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); QFont font = painter->font(); font.setPixelSize(10); painter->setFont(font); diff --git a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h index f22ed5f140536323eadbc1c5bbeb85726ec39d25..4259b9755d013bbaaaaab35118f06ced23e79272 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h +++ b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h @@ -25,6 +25,7 @@ #include "BrainBrowserWindowToolBarComponent.h" class QActionGroup; +class QDoubleSpinBox; class QMenu; class QPixmap; @@ -36,7 +37,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarSlicePlane(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarSlicePlane(const QString& parentObjectName, + BrainBrowserWindowToolBar* parentToolBar); virtual ~BrainBrowserWindowToolBarSlicePlane(); @@ -53,12 +55,14 @@ namespace caret { void volumeAxisCrosshairsTriggered(bool checked); void volumeAxisCrosshairLabelsTriggered(bool checked); + void crosshairMenuAboutToShow(); + private: BrainBrowserWindowToolBarSlicePlane(const BrainBrowserWindowToolBarSlicePlane&); BrainBrowserWindowToolBarSlicePlane& operator=(const BrainBrowserWindowToolBarSlicePlane&); - QMenu* createViewAllSlicesLayoutMenu(); + QMenu* createViewAllSlicesLayoutMenu(const QString& objectNamePrefix); void updateViewAllSlicesLayoutMenu(BrowserTabContent* browserTabContent); @@ -66,6 +70,10 @@ namespace caret { QPixmap createCrosshairLabelsIcon(const QWidget* widget); + QMenu* createCrosshairMenu(const QString& objectNamePrefix); + + void crosshairGapSpinBoxValueChanged(double value); + BrainBrowserWindowToolBar* m_parentToolBar; std::vector m_viewAllSliceLayoutMenuActions; @@ -82,6 +90,8 @@ namespace caret { QActionGroup* m_volumePlaneActionGroup; + QDoubleSpinBox* m_crosshairGapSpinBox; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index b9737c4a1c32252338d3eec75c81e70269aee8e6..cf9eb4754c9e68be77adb4c15f069fd4c1ee4e34 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -47,6 +49,7 @@ #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -62,11 +65,22 @@ using namespace caret; /** * Constructor. + * + * @param parentToolBar + * The parent toolbar. + * @param parentObjectName + * Name of parent object. */ -BrainBrowserWindowToolBarSliceSelection::BrainBrowserWindowToolBarSliceSelection(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarSliceSelection::BrainBrowserWindowToolBarSliceSelection(BrainBrowserWindowToolBar* parentToolBar, + const QString parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + const QString objectNamePrefix(parentObjectName + + ":ToolBar:SliceSelection:"); + QAction* volumeIndicesOriginToolButtonAction = WuQtUtilities::createAction("O\nR\nI\nG\nI\nN", "Set the slice indices to the origin, \n" "stereotaxic coordinate (0, 0, 0)", @@ -76,6 +90,11 @@ m_parentToolBar(parentToolBar) QToolButton* volumeIndicesOriginToolButton = new QToolButton; volumeIndicesOriginToolButton->setDefaultAction(volumeIndicesOriginToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumeIndicesOriginToolButton); + volumeIndicesOriginToolButtonAction->setObjectName(objectNamePrefix + + "MoveVolumeSlicesToOrigin"); + volumeIndicesOriginToolButtonAction->setParent(volumeIndicesOriginToolButton); + macroManager->addMacroSupportToObject(volumeIndicesOriginToolButtonAction, + "Set volume slices to origin"); QLabel* parasagittalLabel = new QLabel("P:"); QLabel* coronalLabel = new QLabel("C:"); @@ -84,21 +103,33 @@ m_parentToolBar(parentToolBar) m_volumeIndicesParasagittalCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesParasagittalCheckBox, "Enable/Disable display of PARASAGITTAL slice"); + m_volumeIndicesParasagittalCheckBox->setObjectName(objectNamePrefix + + "EnableParasagittalSlice"); QObject::connect(m_volumeIndicesParasagittalCheckBox, SIGNAL(stateChanged(int)), this, SLOT(volumeIndicesParasagittalCheckBoxStateChanged(int))); + macroManager->addMacroSupportToObject(m_volumeIndicesParasagittalCheckBox, + "Enable parasagittal volume slice"); m_volumeIndicesCoronalCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesCoronalCheckBox, "Enable/Disable display of CORONAL slice"); + m_volumeIndicesCoronalCheckBox->setObjectName(objectNamePrefix + + "EnableCoronalSlice"); QObject::connect(m_volumeIndicesCoronalCheckBox, SIGNAL(stateChanged(int)), this, SLOT(volumeIndicesCoronalCheckBoxStateChanged(int))); + macroManager->addMacroSupportToObject(m_volumeIndicesCoronalCheckBox, + "Enable coronal volume slice"); m_volumeIndicesAxialCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesAxialCheckBox, "Enable/Disable display of AXIAL slice"); + m_volumeIndicesAxialCheckBox->setObjectName(objectNamePrefix + + "EnableAxialSlice"); QObject::connect(m_volumeIndicesAxialCheckBox, SIGNAL(stateChanged(int)), this, SLOT(volumeIndicesAxialCheckBoxStateChanged(int))); + macroManager->addMacroSupportToObject(m_volumeIndicesAxialCheckBox, + "Enable axial volume slice"); const int sliceIndexSpinBoxWidth = 55; const int sliceCoordinateSpinBoxWidth = 60; @@ -109,6 +140,10 @@ m_parentToolBar(parentToolBar) "Change the selected PARASAGITTAL slice"); QObject::connect(m_volumeIndicesParasagittalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(volumeIndicesParasagittalSpinBoxValueChanged(int))); + m_volumeIndicesParasagittalSpinBox->setObjectName(objectNamePrefix + + "VolumeParasagittalSliceIndex"); + macroManager->addMacroSupportToObject(m_volumeIndicesParasagittalSpinBox, + "Set parasagittal volume slice index"); m_volumeIndicesCoronalSpinBox = WuQFactory::newSpinBox(); m_volumeIndicesCoronalSpinBox->setFixedWidth(sliceIndexSpinBoxWidth); @@ -116,6 +151,10 @@ m_parentToolBar(parentToolBar) "Change the selected CORONAL slice"); QObject::connect(m_volumeIndicesCoronalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(volumeIndicesCoronalSpinBoxValueChanged(int))); + m_volumeIndicesCoronalSpinBox->setObjectName(objectNamePrefix + + "VolumeCoronalSliceIndex"); + macroManager->addMacroSupportToObject(m_volumeIndicesCoronalSpinBox, + "Set coronal volume slice index"); m_volumeIndicesAxialSpinBox = WuQFactory::newSpinBox(); m_volumeIndicesAxialSpinBox->setFixedWidth(sliceIndexSpinBoxWidth); @@ -123,6 +162,10 @@ m_parentToolBar(parentToolBar) "Change the selected AXIAL slice"); QObject::connect(m_volumeIndicesAxialSpinBox, SIGNAL(valueChanged(int)), this, SLOT(volumeIndicesAxialSpinBoxValueChanged(int))); + m_volumeIndicesAxialSpinBox->setObjectName(objectNamePrefix + + "VolumeAxialSliceIndex"); + macroManager->addMacroSupportToObject(m_volumeIndicesAxialSpinBox, + "Set axial volume slice index"); m_volumeIndicesXcoordSpinBox = WuQFactory::newDoubleSpinBox(); m_volumeIndicesXcoordSpinBox->setDecimals(1); @@ -131,6 +174,10 @@ m_parentToolBar(parentToolBar) "Adjust coordinate to select PARASAGITTAL slice"); QObject::connect(m_volumeIndicesXcoordSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeIndicesXcoordSpinBoxValueChanged(double))); + m_volumeIndicesXcoordSpinBox->setObjectName(objectNamePrefix + + "VolumeParasagittalCoordinate"); + macroManager->addMacroSupportToObject(m_volumeIndicesXcoordSpinBox, + "Set parasagittal volume slice coordinate"); m_volumeIndicesYcoordSpinBox = WuQFactory::newDoubleSpinBox(); m_volumeIndicesYcoordSpinBox->setDecimals(1); @@ -139,6 +186,10 @@ m_parentToolBar(parentToolBar) "Adjust coordinate to select CORONAL slice"); QObject::connect(m_volumeIndicesYcoordSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeIndicesYcoordSpinBoxValueChanged(double))); + m_volumeIndicesYcoordSpinBox->setObjectName(objectNamePrefix + + "VolumeCoronalCoordinate"); + macroManager->addMacroSupportToObject(m_volumeIndicesYcoordSpinBox, + "Set coronal volume slice coordinate"); m_volumeIndicesZcoordSpinBox = WuQFactory::newDoubleSpinBox(); m_volumeIndicesZcoordSpinBox->setDecimals(1); @@ -147,6 +198,10 @@ m_parentToolBar(parentToolBar) "Adjust coordinate to select AXIAL slice"); QObject::connect(m_volumeIndicesZcoordSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeIndicesZcoordSpinBoxValueChanged(double))); + m_volumeIndicesZcoordSpinBox->setObjectName(objectNamePrefix + + "VolumeAxialCoordinate"); + macroManager->addMacroSupportToObject(m_volumeIndicesZcoordSpinBox, + "Set axial volume slice coordinate"); const AString idToolTipText = ("When selected: If there is an identification operation " "in ths tab or any other tab with the same yoking status " @@ -162,15 +217,20 @@ m_parentToolBar(parentToolBar) const bool volumeCrossHairIconValid = WuQtUtilities::loadIcon(":/ToolBar/volume-crosshair-pointer.png", volumeCrossHairIcon); + QToolButton* volumeIDToolButton = new QToolButton; if (volumeCrossHairIconValid) { m_volumeIdentificationUpdatesSlicesAction->setIcon(volumeCrossHairIcon); + m_volumeIdentificationUpdatesSlicesAction->setIcon(createVolumeIdentificationUpdatesSlicesIcon(volumeIDToolButton)); } else { m_volumeIdentificationUpdatesSlicesAction->setText("ID"); } - QToolButton* volumeIDToolButton = new QToolButton; volumeIDToolButton->setDefaultAction(m_volumeIdentificationUpdatesSlicesAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumeIDToolButton); + m_volumeIdentificationUpdatesSlicesAction->setObjectName(objectNamePrefix + + "MoveSliceToID"); + macroManager->addMacroSupportToObject(m_volumeIdentificationUpdatesSlicesAction, + "Enable move volume slice to ID location"); m_volumeSliceProjectionTypeEnumComboBox = new EnumComboBoxTemplate(this); m_volumeSliceProjectionTypeEnumComboBox->setup(); @@ -179,16 +239,24 @@ m_parentToolBar(parentToolBar) this, SLOT(volumeSliceProjectionTypeEnumComboBoxItemActivated())); WuQtUtilities::setToolTipAndStatusTip(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), "Chooses viewing orientation (oblique or orthogonal)"); + m_volumeSliceProjectionTypeEnumComboBox->getComboBox()->setObjectName(objectNamePrefix + + "Orthogonal/Oblique"); + macroManager->addMacroSupportToObject(m_volumeSliceProjectionTypeEnumComboBox->getComboBox(), + "Select volume slice projection type"); m_obliqueMaskingAction = new QAction("M", this); m_obliqueMaskingAction->setToolTip(VolumeSliceInterpolationEdgeEffectsMaskingEnum::getToolTip()); m_obliqueMaskingAction->setCheckable(true); QObject::connect(m_obliqueMaskingAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered); + m_obliqueMaskingAction->setObjectName(objectNamePrefix + + "ObliqueMasking"); + QToolButton* obliqueMaskingToolButton = new QToolButton(); obliqueMaskingToolButton->setDefaultAction(m_obliqueMaskingAction); WuQtUtilities::setToolButtonStyleForQt5Mac(obliqueMaskingToolButton); + QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->addWidget(m_volumeIndicesParasagittalCheckBox, 0, 0); @@ -225,6 +293,8 @@ m_parentToolBar(parentToolBar) m_volumeIndicesWidgetGroup->add(m_volumeIndicesZcoordSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeSliceProjectionTypeEnumComboBox->getWidget()); m_volumeIndicesWidgetGroup->add(m_volumeIdentificationUpdatesSlicesAction); + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR); } /** @@ -232,6 +302,27 @@ m_parentToolBar(parentToolBar) */ BrainBrowserWindowToolBarSliceSelection::~BrainBrowserWindowToolBarSliceSelection() { + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +BrainBrowserWindowToolBarSliceSelection::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR) { + m_volumeIndicesWidgetGroup->blockAllSignals(true); + this->updateSliceIndicesAndCoordinatesRanges(); + m_volumeIndicesWidgetGroup->blockAllSignals(false); + event->setEventProcessed(); + } + else { + BrainBrowserWindowToolBarSliceSelection::receiveEvent(event); + } } /** @@ -752,6 +843,8 @@ BrainBrowserWindowToolBarSliceSelection::volumeIdentificationToggled(bool value) void BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) { + static bool addMacroSupportStaticFlag(true); + BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); if (browserTabContent == NULL) { return; @@ -765,11 +858,21 @@ BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) QAction* selectedAction = NULL; for (auto maskEnum : allMaskEnums) { QAction* action = maskActionGroup->addAction(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toGuiName(maskEnum)); + action->setObjectName(m_obliqueMaskingAction->objectName() + + ":" + + VolumeSliceInterpolationEdgeEffectsMaskingEnum::toName(maskEnum)); action->setCheckable(true); action->setData(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toIntegerCode(maskEnum)); if (maskEnum == browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType()) { selectedAction = action; } + + if (addMacroSupportStaticFlag) { + addMacroSupportStaticFlag = false; + WuQMacroManager::instance()->addMacroSupportToObject(action, + "Select " + action->text() + " oblique sampling"); + } + obliqueMaskingMenu.addAction(action); } if (selectedAction != NULL) { @@ -826,4 +929,51 @@ BrainBrowserWindowToolBarSliceSelection::updateObliqueMaskingButton() } } +/** + * Create a pixmap for the volume identification updates slice selection button. + * + * @param widget + * To color the pixmap with backround and foreground, + * the palette from the given widget is used. + * @return + * The pixmap. + */ +QPixmap +BrainBrowserWindowToolBarSliceSelection::createVolumeIdentificationUpdatesSlicesIcon(const QWidget* widget) +{ + CaretAssert(widget); + const int pixmapSize = 24; + const int halfSize = pixmapSize / 2; + + QPixmap pixmap(pixmapSize, + pixmapSize); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, + pixmap, + static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); + const int startXY = 3; + const int endXY = 8; + QPen pen(painter->pen()); + pen.setWidth(2); + painter->setPen(pen); + const int tx(-3); + const int ty(3); + painter->translate(tx, ty); + painter->drawLine(-startXY, 0, -endXY, 0); + painter->drawLine( startXY, 0, endXY, 0); + painter->drawLine(0, -startXY, 0, -endXY); + painter->drawLine(0, startXY, 0, endXY); + painter->translate(-tx, -ty); + + const int tipX(3); + const int tipY(-3); + const int tailX(halfSize); + const int tailY(-halfSize); + painter->drawLine(tipX, tipY, tailX, tailY); + + const int headLength(3); + painter->drawLine(tipX, tipY, tipX + headLength, tipY); + painter->drawLine(tipX, tipY, tipX, tipY - headLength); + + return pixmap; +} diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h index a1c7b966fb0920f4eccfc7efc5d1a815d1d08cb6..cf38a2439240e54ae9a5f18a78860fb5d874965e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h @@ -39,12 +39,14 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarSliceSelection(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarSliceSelection(BrainBrowserWindowToolBar* parentToolBar, + const QString parentObjectName); virtual ~BrainBrowserWindowToolBarSliceSelection(); virtual void updateContent(BrowserTabContent* browserTabContent); - + + virtual void receiveEvent(Event* event) override; // ADD_NEW_METHODS_HERE @@ -75,6 +77,9 @@ namespace caret { void updateObliqueMaskingButton(); + QPixmap createVolumeIdentificationUpdatesSlicesIcon(const QWidget* widget); + + BrainBrowserWindowToolBar* m_parentToolBar; WuQWidgetObjectGroup* m_volumeIndicesWidgetGroup; diff --git a/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.cxx b/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.cxx index 032d72f1d313406857fbd19273fb47e07723e21e..c04f57c2dbdcae1539b1d794bc775cd329a04808 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.cxx @@ -41,6 +41,7 @@ #include "SurfaceMontageLayoutOrientationEnum.h" #include "SurfaceSelectionModel.h" #include "SurfaceSelectionViewController.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" @@ -59,8 +60,11 @@ using namespace caret; * * @param parentToolBar * parent toolbar. + * @param objectNamePrefix + * Prefix name for naming objects */ -BrainBrowserWindowToolBarSurfaceMontage::BrainBrowserWindowToolBarSurfaceMontage(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarSurfaceMontage::BrainBrowserWindowToolBarSurfaceMontage(BrainBrowserWindowToolBar* parentToolBar, + const QString& objectNamePrefix) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { @@ -74,6 +78,10 @@ m_parentToolBar(parentToolBar) " Cerebellar Cortex\n" " Cerebral Cortex\n" " Flat Maps")); + m_surfaceMontageConfigurationTypeEnumComboBox->getComboBox()->setObjectName(objectNamePrefix + + ":SurfaceMontageConfiguration"); + WuQMacroManager::instance()->addMacroSupportToObject(m_surfaceMontageConfigurationTypeEnumComboBox->getComboBox(), + "Select surface montage configuration"); m_surfaceMontageLayoutOrientationEnumComboBox = new EnumComboBoxTemplate(this); m_surfaceMontageLayoutOrientationEnumComboBox->setup(); @@ -84,12 +92,19 @@ m_parentToolBar(parentToolBar) ("Selects Surface Layout:\n" " Landscape (Layout left-to-right)\n" " Portrait (Layout top-to-bottom)")); + m_surfaceMontageLayoutOrientationEnumComboBox->getComboBox()->setObjectName(objectNamePrefix + + ":SurfaceMontageOrientation"); + WuQMacroManager::instance()->addMacroSupportToObject(m_surfaceMontageLayoutOrientationEnumComboBox->getComboBox(), + "Select surface montage layout"); - m_cerebellarComponent = new SurfaceMontageCerebellarComponent(this); + m_cerebellarComponent = new SurfaceMontageCerebellarComponent(this, + objectNamePrefix); - m_cerebralComponent = new SurfaceMontageCerebralComponent(this); + m_cerebralComponent = new SurfaceMontageCerebralComponent(this, + objectNamePrefix); - m_flatMapsComponent = new SurfaceMontageFlatMapsComponent(this); + m_flatMapsComponent = new SurfaceMontageFlatMapsComponent(this, + objectNamePrefix); QHBoxLayout* configOrientationLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(configOrientationLayout, 2, 0); @@ -221,49 +236,99 @@ BrainBrowserWindowToolBarSurfaceMontage::updateContent(BrowserTabContent* browse * * @param parentToolBar * parent toolbar. + * @param objectNamePrefix + * Prefix name for naming objects */ -SurfaceMontageCerebralComponent::SurfaceMontageCerebralComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage) +SurfaceMontageCerebralComponent::SurfaceMontageCerebralComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, + const QString& parentObjectNamePrefix) : QWidget(parentToolBarMontage) { + const QString objectNamePrefix(parentObjectNamePrefix + + ":SurfaceMontage"); + m_parentToolBarMontage = parentToolBarMontage; + WuQMacroManager* macroManager = WuQMacroManager::instance(); + m_leftCheckBox = new QCheckBox("Left"); QObject::connect(m_leftCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_leftCheckBox->setObjectName(objectNamePrefix + + ":EnableLeft"); + m_leftCheckBox->setToolTip("Enable Left Surfaces"); + macroManager->addMacroSupportToObject(m_leftCheckBox, + "Enable left surface in cerebral montage"); m_rightCheckBox = new QCheckBox("Right"); QObject::connect(m_rightCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_rightCheckBox->setObjectName(objectNamePrefix + + ":EnableRight"); + m_rightCheckBox->setToolTip("Enable Right Surface"); + macroManager->addMacroSupportToObject(m_rightCheckBox, + "Enable right surface in cerebral montage"); m_lateralCheckBox = new QCheckBox("Lateral"); QObject::connect(m_lateralCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_lateralCheckBox->setObjectName(objectNamePrefix + + ":EnableLateralView"); + m_lateralCheckBox->setToolTip("Enable Lateral View"); + macroManager->addMacroSupportToObject(m_lateralCheckBox, + "Enable lateral view in cerebral montage"); m_medialCheckBox = new QCheckBox("Medial"); QObject::connect(m_medialCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_medialCheckBox->setObjectName(objectNamePrefix + + ":EnableMedialView"); + m_medialCheckBox->setToolTip("Enable Medial View"); + macroManager->addMacroSupportToObject(m_medialCheckBox, + "Enable medial view in cerebral montage"); m_surfaceMontageFirstSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_surfaceMontageFirstSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_surfaceMontageFirstSurfaceCheckBox->setObjectName(objectNamePrefix + + ":EnableFirstRowSurfaces"); + m_surfaceMontageFirstSurfaceCheckBox->setToolTip("Enable First Surfaces"); + macroManager->addMacroSupportToObject(m_surfaceMontageFirstSurfaceCheckBox, + "Enable first surface row in cerebral montage"); m_surfaceMontageSecondSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_surfaceMontageSecondSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); - - m_leftSurfaceViewController = new SurfaceSelectionViewController(this); + m_surfaceMontageSecondSurfaceCheckBox->setObjectName(objectNamePrefix + + ":EnableSecondRowSurfaces"); + m_surfaceMontageSecondSurfaceCheckBox->setToolTip("Enable Second Surfaces"); + macroManager->addMacroSupportToObject(m_surfaceMontageSecondSurfaceCheckBox, + "Enable second row in cerebral montage"); + + m_leftSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":SurfaceLeftTop", + "cerebral montage left top"); QObject::connect(m_leftSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(leftSurfaceSelected(Surface*))); - m_leftSecondSurfaceViewController = new SurfaceSelectionViewController(this); + m_leftSecondSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":SurfaceLeftBottom", + "cerebral montage left bottom"); QObject::connect(m_leftSecondSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(leftSecondSurfaceSelected(Surface*))); - m_rightSurfaceViewController = new SurfaceSelectionViewController(this); + m_rightSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":SurfaceRightTop", + "cerebral montage right top"); QObject::connect(m_rightSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(rightSurfaceSelected(Surface*))); - m_rightSecondSurfaceViewController = new SurfaceSelectionViewController(this); + m_rightSecondSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":SurfaceRightBottom", + "cerebral montage right bottom"); QObject::connect(m_rightSecondSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(rightSecondSurfaceSelected(Surface*))); @@ -468,41 +533,85 @@ SurfaceMontageCerebralComponent::checkBoxSelected(bool /*status*/) * * @param parentToolBar * parent toolbar. + * @param objectNamePrefix + * Prefix name for naming objects */ -SurfaceMontageCerebellarComponent::SurfaceMontageCerebellarComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage) +SurfaceMontageCerebellarComponent::SurfaceMontageCerebellarComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, + const QString& parentObjectNamePrefix) : QWidget(parentToolBarMontage) { + const QString objectNamePrefix(parentObjectNamePrefix + + ":SurfaceMontageCerebellum"); + m_parentToolBarMontage = parentToolBarMontage; + WuQMacroManager* macroManager = WuQMacroManager::instance(); m_dorsalCheckBox = new QCheckBox("Dorsal"); QObject::connect(m_dorsalCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_dorsalCheckBox->setObjectName(objectNamePrefix + + ":EnableDorsalView"); + m_dorsalCheckBox->setToolTip("Enable Dorsal View"); + macroManager->addMacroSupportToObject(m_dorsalCheckBox, + "Enable dorsal view in cerebellar montage"); m_ventralCheckBox = new QCheckBox("Ventral"); QObject::connect(m_ventralCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_ventralCheckBox->setObjectName(objectNamePrefix + + ":EnableVentralView"); + m_ventralCheckBox->setToolTip("Enable Ventral View"); + macroManager->addMacroSupportToObject(m_ventralCheckBox, + "Enable ventral view in cerebellar montage"); m_anteriorCheckBox = new QCheckBox("Anterior"); QObject::connect(m_anteriorCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_anteriorCheckBox->setObjectName(objectNamePrefix + + ":EnableAnteriorView"); + m_anteriorCheckBox->setToolTip("Enable Anterior View"); + macroManager->addMacroSupportToObject(m_anteriorCheckBox, + "Enable anterior view in cerebellar montage"); m_posteriorCheckBox = new QCheckBox("Posterior"); QObject::connect(m_posteriorCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_posteriorCheckBox->setObjectName(objectNamePrefix + + ":EnablePosteriorView"); + m_posteriorCheckBox->setToolTip("Enable Posterior View"); + macroManager->addMacroSupportToObject(m_posteriorCheckBox, + "Enable posterior view in cerebellar montage"); m_firstSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_firstSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_firstSurfaceCheckBox->setObjectName(objectNamePrefix + + ":EnableFirstSurface"); + m_firstSurfaceCheckBox->setToolTip("Enable First Cerebellar Surface"); + macroManager->addMacroSupportToObject(m_firstSurfaceCheckBox, + "Enable first in cerebellar montage"); m_secondSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_secondSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); - - m_firstSurfaceViewController = new SurfaceSelectionViewController(this); + m_secondSurfaceCheckBox->setObjectName(objectNamePrefix + + ":EnableSecondSurface"); + m_secondSurfaceCheckBox->setToolTip("Enable Second Cerebellar Surface"); + macroManager->addMacroSupportToObject(m_secondSurfaceCheckBox, + "Enable second surface in cerebellar montage"); + + m_firstSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":SurfaceFirst", + "cerebellar monage first"); QObject::connect(m_firstSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(firstSurfaceSelected(Surface*))); - m_secondSurfaceViewController = new SurfaceSelectionViewController(this); + m_secondSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":SecondSurface", + "cerebellar montage second"); + QObject::connect(m_secondSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(secondSurfaceSelected(Surface*))); @@ -669,48 +778,68 @@ SurfaceMontageCerebellarComponent::checkBoxSelected(bool /*status*/) * * @param parentToolBar * parent toolbar. + * @param objectNamePrefix + * Prefix name for naming objects */ -SurfaceMontageFlatMapsComponent::SurfaceMontageFlatMapsComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage) +SurfaceMontageFlatMapsComponent::SurfaceMontageFlatMapsComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, + const QString& parentObjectNamePrefix) : QWidget(parentToolBarMontage) { + const QString objectNamePrefix(parentObjectNamePrefix + + ":SurfaceMontageFlat"); + m_parentToolBarMontage = parentToolBarMontage; + WuQMacroManager* macroManager = WuQMacroManager::instance(); + m_leftSurfaceCheckBox = new QCheckBox("Left"); QObject::connect(m_leftSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_leftSurfaceCheckBox->setObjectName(objectNamePrefix + + ":EnableLeft"); + m_leftSurfaceCheckBox->setToolTip("Enable Left Flat Surface"); + macroManager->addMacroSupportToObject(m_leftSurfaceCheckBox, + "Enable left surface in flat montage"); m_rightSurfaceCheckBox = new QCheckBox("Right"); QObject::connect(m_rightSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); + m_rightSurfaceCheckBox->setObjectName(objectNamePrefix + + ":EnableRight"); + m_rightSurfaceCheckBox->setToolTip("Enable Right Flat Surface"); + macroManager->addMacroSupportToObject(m_rightSurfaceCheckBox, + "Enable right surface in flat montage"); m_cerebellumSurfaceCheckBox = new QCheckBox("Cerebellum "); QObject::connect(m_cerebellumSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); - - m_leftSurfaceViewController = new SurfaceSelectionViewController(this); + m_cerebellumSurfaceCheckBox->setObjectName(objectNamePrefix + + ":EnableCerebellum"); + m_cerebellumSurfaceCheckBox->setToolTip("Enable Cerebellum Flat Surface"); + macroManager->addMacroSupportToObject(m_cerebellumSurfaceCheckBox, + "Enable cerebellar surface in flat montage"); + + m_leftSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":LeftFlatSurface", + "montage flat left"); QObject::connect(m_leftSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(leftSurfaceSelected(Surface*))); - m_rightSurfaceViewController = new SurfaceSelectionViewController(this); + m_rightSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":RightFlatSurface", + "montage flat right"); QObject::connect(m_rightSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(rightSurfaceSelected(Surface*))); - m_cerebellumSurfaceViewController = new SurfaceSelectionViewController(this); + m_cerebellumSurfaceViewController = new SurfaceSelectionViewController(this, + objectNamePrefix + + ":CerebellumSurface", + "montage flat cerebellum"); QObject::connect(m_cerebellumSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(cerebellumSurfaceSelected(Surface*))); -// QHBoxLayout* checkBoxLayout = new QHBoxLayout(); -// WuQtUtilities::setLayoutSpacingAndMargins(checkBoxLayout, 2, 0); -// checkBoxLayout->addStretch(); -// checkBoxLayout->addWidget(m_leftSurfaceCheckBox); -// checkBoxLayout->addSpacing(5); -// checkBoxLayout->addStretch(); -// checkBoxLayout->addWidget(m_rightSurfaceCheckBox); -// checkBoxLayout->addSpacing(5); -// checkBoxLayout->addStretch(); -// checkBoxLayout->addWidget(m_cerebellumSurfaceCheckBox); -// checkBoxLayout->addStretch(); - int32_t columnIndex = 0; const int32_t COLUMN_CHECKBOX = columnIndex++; const int32_t COLUMN_SELECTION = columnIndex++; @@ -729,10 +858,6 @@ SurfaceMontageFlatMapsComponent::SurfaceMontageFlatMapsComponent(BrainBrowserWin layout->addWidget(m_cerebellumSurfaceCheckBox, row, COLUMN_CHECKBOX); layout->addWidget(m_cerebellumSurfaceViewController->getWidget(), row, COLUMN_SELECTION); row = layout->rowCount(); -// layout->addLayout(checkBoxLayout, -// row, COLUMN_CHECKBOX, -// 1, 2); -// row = layout->rowCount(); m_widgetGroup = new WuQWidgetObjectGroup(this); m_widgetGroup->add(m_leftSurfaceViewController->getWidget()); diff --git a/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.h b/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.h index 04f92d97bc88ac1dad257a81be90051c0368960e..59e28f2eb9051e1dbfa228642a989cfa422af5a5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.h +++ b/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.h @@ -41,7 +41,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarSurfaceMontage(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarSurfaceMontage(BrainBrowserWindowToolBar* parentToolBar, + const QString& parentObjectNamePrefix); virtual ~BrainBrowserWindowToolBarSurfaceMontage(); @@ -84,7 +85,8 @@ namespace caret { Q_OBJECT public: - SurfaceMontageCerebralComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage); + SurfaceMontageCerebralComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, + const QString& parentObjectNamePrefix); ~SurfaceMontageCerebralComponent(); @@ -121,7 +123,8 @@ namespace caret { Q_OBJECT public: - SurfaceMontageCerebellarComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage); + SurfaceMontageCerebellarComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, + const QString& parentObjectNamePrefix); ~SurfaceMontageCerebellarComponent(); @@ -154,7 +157,8 @@ namespace caret { Q_OBJECT public: - SurfaceMontageFlatMapsComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage); + SurfaceMontageFlatMapsComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, + const QString& parentObjectNamePrefix); ~SurfaceMontageFlatMapsComponent(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx index d632cf1474e8dbe3ec71d9d257ca2bed22972221..9f31eec1b7796a3805b4c32c7a563da8a5857fc7 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx @@ -41,6 +41,7 @@ #include "WuQWidgetObjectGroup.h" #include "YokingGroupEnum.h" #include "WuQDataEntryDialog.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -60,10 +61,13 @@ using namespace caret; * Button for locking window and all tab aspect ratio. * @param parentToolBar * Parent toolbar. + * @param objectNamePrefix + Prefix for naming objects */ BrainBrowserWindowToolBarTab::BrainBrowserWindowToolBarTab(const int32_t browserWindowIndex, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, - BrainBrowserWindowToolBar* parentToolBar) + BrainBrowserWindowToolBar* parentToolBar, + const QString& objectNamePrefix) : BrainBrowserWindowToolBarComponent(parentToolBar), m_browserWindowIndex(browserWindowIndex), m_parentToolBar(parentToolBar), @@ -76,6 +80,11 @@ m_lockWindowAndAllTabAspectButton(toolBarLockWindowAndAllTabAspectRatioButton) "Models yoked to a group are displayed in the same view.\n" "Surface Yoking is applied to Surface, Surface Montage\n" "and Whole Brain. Volume Yoking is applied to Volumes.")); + QComboBox* encapComboBox = m_yokingGroupComboBox->getComboBox(); + encapComboBox->setObjectName(objectNamePrefix + + ":Tab:YokingGroup"); + WuQMacroManager::instance()->addMacroSupportToObject(encapComboBox, + "Select yoking group"); m_yokeToLabel = new QLabel("Yoking:"); QObject::connect(m_yokingGroupComboBox, SIGNAL(itemActivated()), @@ -86,8 +95,14 @@ m_lockWindowAndAllTabAspectButton(toolBarLockWindowAndAllTabAspectRatioButton) "may be helpful to turn shading off."); m_lightingEnabledCheckBox = new QCheckBox("Shading"); m_lightingEnabledCheckBox->setToolTip(lightToolTip); - QObject::connect(m_lightingEnabledCheckBox, &QCheckBox::toggled, - this, &BrainBrowserWindowToolBarTab::lightingEnabledCheckBoxToggled); + QObject::connect(m_lightingEnabledCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarTab::lightingEnabledCheckBoxChecked); + m_lightingEnabledCheckBox->setObjectName(objectNamePrefix + + ":Tab:EnableShading"); + WuQMacroManager::instance()->addMacroSupportToObject(m_lightingEnabledCheckBox, + "Enable shading"); + + m_macroRecordingLabel = new QLabel(""); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); @@ -95,10 +110,12 @@ m_lockWindowAndAllTabAspectButton(toolBarLockWindowAndAllTabAspectRatioButton) layout->addWidget(m_yokingGroupComboBox->getWidget()); layout->addWidget(m_lockWindowAndAllTabAspectButton); layout->addWidget(m_lightingEnabledCheckBox); + layout->addWidget(m_macroRecordingLabel); addToWidgetGroup(m_yokeToLabel); addToWidgetGroup(m_yokingGroupComboBox->getWidget()); addToWidgetGroup(m_lightingEnabledCheckBox); + addToWidgetGroup(m_macroRecordingLabel); } /** @@ -154,17 +171,29 @@ BrainBrowserWindowToolBarTab::updateContent(BrowserTabContent* browserTabContent m_lightingEnabledCheckBox->setChecked(browserTabContent->isLightingEnabled()); + m_macroRecordingLabel->setText(""); + switch (WuQMacroManager::instance()->getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + m_macroRecordingLabel->setText("Macro"); + break; + case WuQMacroModeEnum::RUNNING: + break; + } + blockAllSignals(false); } /** - * Called when lighting checkbox is toggled by user + * Called when lighting checkbox is checked by user * * @param checked * New status of lighting. */ void -BrainBrowserWindowToolBarTab::lightingEnabledCheckBoxToggled(bool checked) +BrainBrowserWindowToolBarTab::lightingEnabledCheckBoxChecked(bool checked) { BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); if (browserTabContent == NULL) { diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.h b/src/GuiQt/BrainBrowserWindowToolBarTab.h index 4b959553721b9551b425a37313995372fe198f6d..9d5c2f37c7e8b124b5e86fc587437ba7ae26fa5a 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.h +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.h @@ -39,7 +39,8 @@ namespace caret { public: BrainBrowserWindowToolBarTab(const int32_t browserWindowIndex, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, - BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBar* parentToolBar, + const QString& objectNamePrefix); virtual ~BrainBrowserWindowToolBarTab(); @@ -51,7 +52,7 @@ namespace caret { private slots: void yokeToGroupComboBoxIndexChanged(); - void lightingEnabledCheckBoxToggled(bool checked); + void lightingEnabledCheckBoxChecked(bool checked); private: BrainBrowserWindowToolBarTab(const BrainBrowserWindowToolBarTab&); @@ -70,6 +71,8 @@ namespace caret { QCheckBox* m_lightingEnabledCheckBox; + QLabel* m_macroRecordingLabel; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx index 5433697d3f34e8e81ce9ea338c1e7030a3c06e4c..f2df57ec92072e6774a2d5c9d7d6904b61ed69ea 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx @@ -25,6 +25,7 @@ #include "BrainBrowserWindowToolBar.h" #include "CaretAssert.h" +#include "WuQTabBar.h" using namespace caret; diff --git a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx index 23cd40bb16bb834c452e546e02d293c50e7b14d2..b291d05069f4fa9d23bb349babb0e0b0cf387965 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx @@ -33,6 +33,7 @@ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -48,11 +49,19 @@ using namespace caret; /** * Constructor. + * + * @param parentObjectName + * Name of parent for macros + * @param parentToolBar + * The parent toolbar */ -BrainBrowserWindowToolBarVolumeMontage::BrainBrowserWindowToolBarVolumeMontage(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarVolumeMontage::BrainBrowserWindowToolBarVolumeMontage(const QString& parentObjectName, + BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { + const QString objectNamePrefix(parentObjectName + + ":VolumeSliceMontage:"); const int spinBoxWidth = 48; @@ -64,6 +73,11 @@ m_parentToolBar(parentToolBar) m_montageRowsSpinBox->setToolTip(rowsLabel->toolTip()); QObject::connect(m_montageRowsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(montageRowsSpinBoxValueChanged(int))); + m_montageRowsSpinBox->setObjectName(objectNamePrefix + + "Rows"); + WuQMacroManager::instance()->addMacroSupportToObject(m_montageRowsSpinBox, + "Set volume montage rows"); + QLabel* columnsLabel = new QLabel("Cols:"); columnsLabel->setToolTip("Select the number of columns in montage of volume slices"); @@ -73,6 +87,10 @@ m_parentToolBar(parentToolBar) m_montageColumnsSpinBox->setToolTip(columnsLabel->toolTip()); QObject::connect(m_montageColumnsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(montageColumnsSpinBoxValueChanged(int))); + m_montageColumnsSpinBox->setObjectName(objectNamePrefix + + "Columns"); + WuQMacroManager::instance()->addMacroSupportToObject(m_montageColumnsSpinBox, + "Set volume montage columns"); QLabel* spacingLabel = new QLabel("Step:"); spacingLabel->setToolTip("Select the number of slices stepped (incremented) between displayed montage slices"); @@ -82,6 +100,10 @@ m_parentToolBar(parentToolBar) m_montageSpacingSpinBox->setToolTip(spacingLabel->toolTip()); QObject::connect(m_montageSpacingSpinBox, SIGNAL(valueChanged(int)), this, SLOT(montageSpacingSpinBoxValueChanged(int))); + m_montageSpacingSpinBox->setObjectName(objectNamePrefix + + "Step"); + WuQMacroManager::instance()->addMacroSupportToObject(m_montageSpacingSpinBox, + "Set volume montage spacing"); m_showSliceCoordinateAction = new QAction("XYZ", this); m_showSliceCoordinateAction->setText("XYZ"); @@ -89,6 +111,10 @@ m_parentToolBar(parentToolBar) m_showSliceCoordinateAction->setToolTip("Show coordinates on slices"); QObject::connect(m_showSliceCoordinateAction, &QAction::triggered, this, &BrainBrowserWindowToolBarVolumeMontage::showSliceCoordinateToolButtonClicked); + m_showSliceCoordinateAction->setObjectName(objectNamePrefix + + "ShowCoordinateOnSlice"); + WuQMacroManager::instance()->addMacroSupportToObject(m_showSliceCoordinateAction, + "Enable coordinates in volume montage"); QToolButton* showSliceCoordToolButton = new QToolButton; showSliceCoordToolButton->setDefaultAction(m_showSliceCoordinateAction); @@ -102,17 +128,25 @@ m_parentToolBar(parentToolBar) m_sliceCoordinatePrecisionSpinBox->setToolTip(decimalsLabel->toolTip()); QObject::connect(m_sliceCoordinatePrecisionSpinBox, static_cast(&QSpinBox::valueChanged), this, &BrainBrowserWindowToolBarVolumeMontage::slicePrecisionSpinBoxValueChanged); + m_sliceCoordinatePrecisionSpinBox->setObjectName(objectNamePrefix + + "Precision"); + WuQMacroManager::instance()->addMacroSupportToObject(m_sliceCoordinatePrecisionSpinBox, + "Set volume montage coordinate precision"); + QToolButton* montageEnabledToolButton = new QToolButton(); m_montageEnabledAction = WuQtUtilities::createAction("On", "View a montage of parallel slices", - this, + montageEnabledToolButton, this, SLOT(montageEnabledActionToggled(bool))); m_montageEnabledAction->setCheckable(true); - QToolButton* montageEnabledToolButton = new QToolButton(); montageEnabledToolButton->setDefaultAction(m_montageEnabledAction); WuQtUtilities::setToolButtonStyleForQt5Mac(montageEnabledToolButton); + m_montageEnabledAction->setObjectName(objectNamePrefix + + "Enable"); + WuQMacroManager::instance()->addMacroSupportToObject(m_montageEnabledAction, + "Enable volume slice montage"); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); @@ -127,7 +161,6 @@ m_parentToolBar(parentToolBar) gridLayout->addWidget(m_sliceCoordinatePrecisionSpinBox, 3, 1); gridLayout->addWidget(showSliceCoordToolButton, 4, 0); gridLayout->addWidget(montageEnabledToolButton, 4, 1); -// gridLayout->addWidget(montageEnabledToolButton, 4, 0, 1, 2, Qt::AlignHCenter); m_volumeMontageWidgetGroup = new WuQWidgetObjectGroup(this); m_volumeMontageWidgetGroup->add(m_montageRowsSpinBox); diff --git a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.h b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.h index d0ce2fcc1ec8a29d3ef51aa584c87e217117b06d..985e261385673aed69a907d56c4755ca4c9e4a95 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.h +++ b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.h @@ -35,7 +35,8 @@ namespace caret { Q_OBJECT public: - BrainBrowserWindowToolBarVolumeMontage(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarVolumeMontage(const QString& parentObjectName, + BrainBrowserWindowToolBar* parentToolBar); virtual ~BrainBrowserWindowToolBarVolumeMontage(); diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index e2a9b86c4113262d0ac9bc0a8d18e43aed3226f4..71c19edcea107062c63b51db507fd3e70c96b3d4 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -25,7 +25,9 @@ #include #include +#include #include +#include #include #include #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET @@ -34,6 +36,7 @@ #include #include +#include "AnnotationManager.h" #include "Border.h" #include "Brain.h" #include "BrainBrowserWindow.h" @@ -47,25 +50,32 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "CursorManager.h" +#include "DataToolTipsManager.h" +#include "DeveloperFlagsEnum.h" #include "DummyFontTextRenderer.h" +#include "ElapsedTimer.h" #include "EventBrainReset.h" #include "EventImageCapture.h" #include "EventModelGetAll.h" #include "EventManager.h" #include "EventBrowserWindowDrawingContent.h" #include "EventBrowserWindowGraphicsRedrawn.h" +#include "EventGraphicsTimingOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventIdentificationRequest.h" +#include "EventMovieManualModeRecording.h" #include "EventUserInterfaceUpdate.h" #include "FtglFontTextRenderer.h" #include "GuiManager.h" +#include "ImageFile.h" #include "KeyEvent.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "Model.h" #include "MouseEvent.h" +#include "MovieRecorder.h" #include "OffScreenOpenGLRenderer.h" #include "SelectionManager.h" #include "SelectionItemAnnotation.h" @@ -80,6 +90,7 @@ #include "UserInputModeImage.h" #include "UserInputModeView.h" #include "UserInputModeVolumeEdit.h" +#include "WuQMacroManager.h" #include "WuQMessageBox.h" using namespace caret; @@ -94,9 +105,20 @@ using namespace caret; * * @param * The parent widget. + * @param shareWidget + * Widget used for sharing OpenGL contexts when the deprecated + * QGLWidget is used. Note that with QOpenGLWidget, + * sharing is enabled by calling QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts) + * in desktop.cxx + * @param windowIndex + * Index of this window */ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + const BrainOpenGLWidget* /*shareWidget*/, +#else const BrainOpenGLWidget* shareWidget, +#endif const int32_t windowIndex) #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET : QOpenGLWidget(parent), @@ -106,6 +128,10 @@ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, #endif windowIndex(windowIndex) { + setObjectName("Window_" + + AString::number(windowIndex + 1) + + ":OpenGLWidget"); + this->borderBeingDrawn = new Border(); m_mousePositionValid = false; @@ -144,11 +170,13 @@ windowIndex(windowIndex) setMouseTracking(true); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BRAIN_RESET); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_REQUEST); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IMAGE_CAPTURE); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); m_openGLContextSharingValid = true; @@ -242,13 +270,19 @@ BrainOpenGLWidget::initializeGL() * OpenGL drawing will take ownership of the text renderer * and handle deletion of the text renderer. */ - BrainOpenGLTextRenderInterface* textRenderer = new FtglFontTextRenderer(); + BrainOpenGLTextRenderInterface* textRenderer = NULL; +#ifdef HAVE_FREETYPE + textRenderer = new FtglFontTextRenderer(); if (! textRenderer->isValid()) { delete textRenderer; textRenderer = NULL; CaretLogWarning("Unable to create FTGL Font Renderer.\n" "No text will be available in graphics window."); } +#else + CaretLogWarning("Unable to create FTGL Font Renderer due to FreeType not found during configuration.\n" + "No text will be available in graphics window."); +#endif if (textRenderer == NULL) { textRenderer = new DummyFontTextRenderer(); } @@ -376,7 +410,7 @@ BrainOpenGLWidget::getOpenGLInformation() #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS info += "\n"; - return info; + return std::move(info); } /** @@ -450,6 +484,7 @@ BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, windowContent); s_singletonOpenGL->drawModels(this->windowIndex, + this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, windowContent.getAllTabViewports()); @@ -568,6 +603,7 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], browserWindowContent, gapsAndMargins, windowViewport, + this->windowIndex, getModelEvent.getTabIndexForTileTabsHighlighting()); for (auto tabvp : tabViewportContent) { windowContent.addTabViewport(tabvp); @@ -595,7 +631,6 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], windowContent.setWindowViewport(windowViewportContent); } - /** * Paints the graphics. */ @@ -630,6 +665,7 @@ BrainOpenGLWidget::paintGL() s_singletonOpenGL->setBorderBeingDrawn(NULL); } s_singletonOpenGL->drawModels(this->windowIndex, + this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, m_windowContent.getAllTabViewports()); @@ -649,33 +685,46 @@ BrainOpenGLWidget::paintGL() bool BrainOpenGLWidget::event(QEvent* event) { - const bool toolTipsEnabled = false; - if (toolTipsEnabled) { + if (SessionManager::get()->getDataToolTipsManager()->isEnabled()) { if (event->type() == QEvent::ToolTip) { QHelpEvent* helpEvent = static_cast(event); CaretAssert(helpEvent); QPoint globalXY = helpEvent->globalPos(); - QPoint xy = helpEvent->pos(); + QPoint xyPoint = helpEvent->pos(); + const int32_t x = xyPoint.x(); + const int32_t y = this->height() - xyPoint.y(); - static int counter = 0; + DataToolTipsManager* dttm = SessionManager::get()->getDataToolTipsManager(); + CaretAssert(dttm); - std::cout - << "Displaying tooltip " - << counter++ - << " at global (" - << globalXY.x() - << ", " - << globalXY.y() - << ") at pos (" - << xy.x() - << ", " - << xy.y() - << ")" - << std::endl; + AString toolTipText; + + const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); + if (idViewport != NULL) { + BrowserTabContent* browserTabContent = idViewport->getBrowserTabContent(); + if (browserTabContent != NULL) { + SelectionManager* selectionManager = performIdentification(x, + y, + false); // include items in background + toolTipText = dttm->getToolTip(GuiManager::get()->getBrain(), + browserTabContent, + selectionManager); + } + } - QToolTip::showText(globalXY, - "This is the tooltip " + AString::number(counter)); + if (toolTipText.isEmpty()) { + QToolTip::hideText(); + event->ignore(); + } + else { + const int millisecondsDisplayTime = (3 * 1000); + QToolTip::showText(globalXY, + toolTipText, + nullptr, + QRect(), + millisecondsDisplayTime); + } return true; } @@ -731,10 +780,71 @@ BrainOpenGLWidget::contextMenuEvent(QContextMenuEvent* contextMenuEvent) void BrainOpenGLWidget::wheelEvent(QWheelEvent* we) { - const int wheelX = we->x(); - const int wheelY = this->windowHeight[this->windowIndex] - we->y(); - int delta = we->delta(); - delta = MathFunctions::limitRange(delta, -2, 2); + /* + * Notes 24 Sep 2019 + * + * QWheelEvent::pixelDelta() is not used since it is only set on Mac. + * + * Trackpad usage is when QWheelEvent::source()==Qt::MouseEventSynthesizedBySystem + * Mouse usage is when QWheelEvent::source()==Qt::MouseEventNotSynthesized + * + * Inverted flag is only used by Mouse on MacOS. It is true when + * Preferences->Trackpad->Scroll & Zoom is ON. The Wheel's inverted + * flag is ignored since Mac alters the sign of the mouse Y-value. + * It appears that "Scroll Direction:Natural is defaulted ON" on Macs + * + * Forward Wheel or Trackpad (moving away from user) + * ** Negative when MacOS->Preferences->Trackpad->Scroll&Zoom->Scroll Direction:Natural is ON + * ** Positive when MacOS->Preferences->Trackpad->Scroll&Zoom->Scroll Direction:Natural is OFF + * ** Negative when MacOS->Preferences->Mouse->Scroll Direction:Natural is ON + * ** Positive when MacOS->Preferences->Mouse->Scroll Direction:Natural is OFF + * + * ** Positive on Linux + */ + const QPoint angleDelta = we->angleDelta(); + if (angleDelta.isNull()) { + return; + } + + int32_t deltaDegrees = angleDelta.y(); + if (deltaDegrees == 0) { + return; + } + + /* + * While the mouse/trackpad flags are not used at this time, + * we also do not have access to a Linux or Windows system + * with a trackpad. + */ + bool mouseFlag(false); + bool trackpadFlag(false); + switch (we->source()) { + case Qt::MouseEventNotSynthesized: + mouseFlag = true; + break; + case Qt::MouseEventSynthesizedByApplication: + break; + case Qt::MouseEventSynthesizedByQt: + break; + case Qt::MouseEventSynthesizedBySystem: + trackpadFlag = true; + break; + } + + const bool debugFlag(false); + if (debugFlag) { + std::cout << "Angle Delta: " << we->angleDelta().y() << std::endl; + std::cout << "Inverted: " << AString::fromBool(we->inverted()) << std::endl; + std::cout << "Source: " << (int32_t)we->source() << std::endl; + std::cout << "Mouse Flag: " << AString::fromBool(mouseFlag) << std::endl; + std::cout << "Trackpad Flag: " << AString::fromBool(trackpadFlag) << std::endl; + } + + /* + * If not limited, it is way too fast + */ + const int limitValue(8); + deltaDegrees = MathFunctions::limitRange(deltaDegrees, -limitValue, limitValue); /* * Use location of mouse press so that the model @@ -742,8 +852,10 @@ BrainOpenGLWidget::wheelEvent(QWheelEvent* we) * out of its viewport without releasing the mouse * button. */ + const int wheelX = we->x(); + const int wheelY = this->windowHeight[this->windowIndex] - we->y(); const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(wheelX, - wheelY); + wheelY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, @@ -751,13 +863,13 @@ BrainOpenGLWidget::wheelEvent(QWheelEvent* we) wheelX, wheelY, 0, - delta, + deltaDegrees, 0, 0, this->mouseNewDraggingStartedFlag); this->selectedUserInputProcessor->mouseLeftDragWithCtrl(mouseEvent); } - + we->accept(); } @@ -818,11 +930,19 @@ BrainOpenGLWidget::keyPressEvent(QKeyEvent* e) m_newKeyPressStartedFlag, shiftKeyDownFlag); - this->selectedUserInputProcessor->keyPressEvent(keyEvent); + const bool keyWasProcessedFlag = this->selectedUserInputProcessor->keyPressEvent(keyEvent); e->accept(); m_newKeyPressStartedFlag = false; + + if ( ! keyWasProcessedFlag) { +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + QOpenGLWidget::keyPressEvent(e); +#else + QGLWidget::keyPressEvent(e); +#endif + } } /** @@ -846,6 +966,10 @@ BrainOpenGLWidget::keyReleaseEvent(QKeyEvent* e) void BrainOpenGLWidget::mousePressEvent(QMouseEvent* me) { + WuQMacroManager::instance()->addMouseEventToRecording(this, + "Mouse Press in Window" + AString::number(this->windowIndex + 1), + me); + Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); @@ -931,6 +1055,10 @@ BrainOpenGLWidget::mousePressEvent(QMouseEvent* me) void BrainOpenGLWidget::mouseReleaseEvent(QMouseEvent* me) { + WuQMacroManager::instance()->addMouseEventToRecording(this, + "Mouse Release in Window" + AString::number(this->windowIndex + 1), + me); + Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); @@ -1026,6 +1154,10 @@ BrainOpenGLWidget::mouseReleaseEvent(QMouseEvent* me) void BrainOpenGLWidget::mouseDoubleClickEvent(QMouseEvent* me) { + WuQMacroManager::instance()->addMouseEventToRecording(this, + "Mouse Double Click in Window" + AString::number(this->windowIndex + 1), + me); + Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); @@ -1158,6 +1290,7 @@ BrainOpenGLWidget::performIdentification(const int x, if (idViewport != NULL) { s_singletonOpenGL->selectModel(this->windowIndex, + this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, idViewport, @@ -1176,10 +1309,10 @@ BrainOpenGLWidget::performIdentification(const int x, * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ - this->repaint(); + this->repaintGraphics(); this->doneCurrent(); #else - this->repaint(); + this->repaintGraphics(); #endif return idManager; @@ -1222,6 +1355,7 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, const int idY = y - vp[1]; */ s_singletonOpenGL->selectModel(this->windowIndex, + this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, idViewport, @@ -1240,10 +1374,10 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ - this->repaint(); + this->repaintGraphics(); this->doneCurrent(); #else - this->repaint(); + this->repaintGraphics(); #endif return annotationID; @@ -1288,6 +1422,7 @@ BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFi const int idY = y - vp[1]; */ s_singletonOpenGL->selectModel(this->windowIndex, + this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, idViewport, @@ -1306,10 +1441,10 @@ BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFi * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ - this->repaint(); + this->repaintGraphics(); this->doneCurrent(); #else - this->repaint(); + this->repaintGraphics(); #endif return idManager; @@ -1337,6 +1472,7 @@ BrainOpenGLWidget::performProjection(const int x, if (projectionViewport != NULL) { s_singletonOpenGL->projectToModel(this->windowIndex, + this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, projectionViewport, @@ -1355,7 +1491,7 @@ BrainOpenGLWidget::performProjection(const int x, * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ - this->repaint(); + this->repaintGraphics(); this->doneCurrent(); #endif } @@ -1367,11 +1503,21 @@ BrainOpenGLWidget::performProjection(const int x, */ void BrainOpenGLWidget::mouseMoveEvent(QMouseEvent* me) -{ +{ + WuQMacroManager::instance()->addMouseEventToRecording(this, + "Mouse Move in Window" + AString::number(this->windowIndex + 1), + me); + + /* + * Tooltip will remain displayed for several seconds. + * So if the user moves the mouse, remove the tooltip. + */ + QToolTip::hideText(); + Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); - + checkForMiddleMouseButton(mouseButtons, button, keyModifiers, @@ -1380,92 +1526,87 @@ BrainOpenGLWidget::mouseMoveEvent(QMouseEvent* me) const int mouseX = me->x(); const int mouseY = this->windowHeight[this->windowIndex] - me->y(); - if (button == Qt::NoButton) { + if (mouseButtons == Qt::LeftButton) { + this->mouseMovementMinimumX = std::min(this->mouseMovementMinimumX, mouseX); + this->mouseMovementMaximumX = std::max(this->mouseMovementMaximumX, mouseX); + this->mouseMovementMinimumY = std::min(this->mouseMovementMinimumY, mouseY); + this->mouseMovementMaximumY = std::max(this->mouseMovementMaximumY, mouseY); - if (mouseButtons == Qt::LeftButton) { - - this->mouseMovementMinimumX = std::min(this->mouseMovementMinimumX, mouseX); - this->mouseMovementMaximumX = std::max(this->mouseMovementMaximumX, mouseX); - this->mouseMovementMinimumY = std::min(this->mouseMovementMinimumY, mouseY); - this->mouseMovementMaximumY = std::max(this->mouseMovementMaximumY, mouseY); - - const int dx = mouseX - this->lastMouseX; - const int dy = mouseY - this->lastMouseY; - const int absDX = (dx >= 0) ? dx : -dx; - const int absDY = (dy >= 0) ? dy : -dy; - - if ((absDX > 0) - || (absDY > 0)) { - /* - * Use location of mouse press so that the model - * being manipulated does not change if mouse moves - * out of its viewport without releasing the mouse - * button. - */ - const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, - this->mousePressY); - if (viewportContent != NULL) { - MouseEvent mouseEvent(viewportContent, - this, - this->windowIndex, - mouseX, - mouseY, - dx, - dy, - this->mousePressX, - this->mousePressY, - this->mouseNewDraggingStartedFlag); - - if (keyModifiers == Qt::NoModifier) { - this->selectedUserInputProcessor->mouseLeftDrag(mouseEvent); - } - else if (keyModifiers == Qt::ControlModifier) { - this->selectedUserInputProcessor->mouseLeftDragWithCtrl(mouseEvent); - } - else if (keyModifiers == Qt::ShiftModifier) { - this->selectedUserInputProcessor->mouseLeftDragWithShift(mouseEvent); - } - else if (keyModifiers == Qt::AltModifier) { - this->selectedUserInputProcessor->mouseLeftDragWithAlt(mouseEvent); - } - else if (keyModifiers == (Qt::ShiftModifier - | Qt::ControlModifier)) { - this->selectedUserInputProcessor->mouseLeftDragWithCtrlShift(mouseEvent); - } - - this->mouseNewDraggingStartedFlag = false; - } - } - - this->lastMouseX = mouseX; - this->lastMouseY = mouseY; - } - else if (mouseButtons == Qt::NoButton) { - const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, - mouseY); + const int dx = mouseX - this->lastMouseX; + const int dy = mouseY - this->lastMouseY; + const int absDX = (dx >= 0) ? dx : -dx; + const int absDY = (dy >= 0) ? dy : -dy; + + if ((absDX > 0) + || (absDY > 0)) { + /* + * Use location of mouse press so that the model + * being manipulated does not change if mouse moves + * out of its viewport without releasing the mouse + * button. + */ + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, + this->mousePressY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, - 0, - 0, + dx, + dy, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag); if (keyModifiers == Qt::NoModifier) { - this->selectedUserInputProcessor->mouseMove(mouseEvent); + this->selectedUserInputProcessor->mouseLeftDrag(mouseEvent); + } + else if (keyModifiers == Qt::ControlModifier) { + this->selectedUserInputProcessor->mouseLeftDragWithCtrl(mouseEvent); } else if (keyModifiers == Qt::ShiftModifier) { - this->selectedUserInputProcessor->mouseMoveWithShift(mouseEvent); + this->selectedUserInputProcessor->mouseLeftDragWithShift(mouseEvent); + } + else if (keyModifiers == Qt::AltModifier) { + this->selectedUserInputProcessor->mouseLeftDragWithAlt(mouseEvent); + } + else if (keyModifiers == (Qt::ShiftModifier + | Qt::ControlModifier)) { + this->selectedUserInputProcessor->mouseLeftDragWithCtrlShift(mouseEvent); } + + this->mouseNewDraggingStartedFlag = false; } + } + + this->lastMouseX = mouseX; + this->lastMouseY = mouseY; + } + else if (mouseButtons == Qt::NoButton) { + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, + mouseY); + if (viewportContent != NULL) { + MouseEvent mouseEvent(viewportContent, + this, + this->windowIndex, + mouseX, + mouseY, + 0, + 0, + this->mousePressX, + this->mousePressY, + this->mouseNewDraggingStartedFlag); + if (keyModifiers == Qt::NoModifier) { + this->selectedUserInputProcessor->mouseMove(mouseEvent); + } + else if (keyModifiers == Qt::ShiftModifier) { + this->selectedUserInputProcessor->mouseMoveWithShift(mouseEvent); + } } } - + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { @@ -1499,6 +1640,13 @@ BrainOpenGLWidget::mouseMoveEvent(QMouseEvent* me) void BrainOpenGLWidget::receiveEvent(Event* event) { + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + MovieRecorderModeEnum::Enum movieRecordingMode = movieRecorder->getRecordingMode(); + + bool doRepaintGraphicsFlag(false); + bool doUpdateGraphicsFlag(false); + int32_t captureManualMovieModeImageRepeatCount(-1); + if (event->getEventType() == EventTypeEnum::EVENT_BRAIN_RESET) { EventBrainReset* brainResetEvent = dynamic_cast(event); CaretAssert(brainResetEvent); @@ -1507,6 +1655,15 @@ BrainOpenGLWidget::receiveEvent(Event* event) brainResetEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW) { + EventGraphicsTimingOneWindow* timingEvent = dynamic_cast(event); + CaretAssert(timingEvent); + + if (timingEvent->getWindowIndex() == this->windowIndex) { + doRepaintGraphicsFlag = true; + timingEvent->setEventProcessed(); + } + } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS) { EventGraphicsUpdateAllWindows* updateAllEvent = dynamic_cast(event); @@ -1515,14 +1672,10 @@ BrainOpenGLWidget::receiveEvent(Event* event) updateAllEvent->setEventProcessed(); if (updateAllEvent->isRepaint()) { - this->repaint(); + doRepaintGraphicsFlag = true; } else { -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - this->update(); -#else - this->updateGL(); -#endif + doUpdateGraphicsFlag = true; } } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) { @@ -1532,12 +1685,7 @@ BrainOpenGLWidget::receiveEvent(Event* event) if (updateOneEvent->getWindowIndex() == this->windowIndex) { updateOneEvent->setEventProcessed(); - -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - this->update(); -#else - this->updateGL(); -#endif + doUpdateGraphicsFlag = true; } else { /* @@ -1552,11 +1700,7 @@ BrainOpenGLWidget::receiveEvent(Event* event) bool needUpdate = false; if (needUpdate) { -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - this->update(); -#else - this->updateGL(); -#endif + doUpdateGraphicsFlag = true; } } } @@ -1572,29 +1716,35 @@ BrainOpenGLWidget::receiveEvent(Event* event) else if (inputModeEvent->isSetUserInputMode()) { UserInputModeAbstract* newUserInputProcessor = NULL; switch (inputModeEvent->getUserInputMode()) { - case UserInputModeAbstract::INVALID: + case UserInputModeEnum::INVALID: CaretAssertMessage(0, "INVALID is NOT allowed for user input mode"); break; - case UserInputModeAbstract::ANNOTATIONS: + case UserInputModeEnum::ANNOTATIONS: newUserInputProcessor = this->userInputAnnotationsModeProcessor; break; - case UserInputModeAbstract::BORDERS: + case UserInputModeEnum::BORDERS: newUserInputProcessor = this->userInputBordersModeProcessor; break; - case UserInputModeAbstract::FOCI: + case UserInputModeEnum::FOCI: newUserInputProcessor = this->userInputFociModeProcessor; break; - case UserInputModeAbstract::IMAGE: + case UserInputModeEnum::IMAGE: newUserInputProcessor = this->userInputImageModeProcessor; break; - case UserInputModeAbstract::VOLUME_EDIT: + case UserInputModeEnum::VOLUME_EDIT: newUserInputProcessor = this->userInputVolumeEditModeProcessor; break; - case UserInputModeAbstract::VIEW: + case UserInputModeEnum::VIEW: newUserInputProcessor = this->userInputViewModeProcessor; break; } + if ((newUserInputProcessor == this->userInputAnnotationsModeProcessor) + || (this->selectedUserInputProcessor == this->userInputAnnotationsModeProcessor)) { + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + CaretAssert(annMan); + annMan->deselectAllAnnotationsForEditing(this->windowIndex); + } if (newUserInputProcessor != NULL) { if (newUserInputProcessor != this->selectedUserInputProcessor) { this->selectedUserInputProcessor->finish(); @@ -1627,6 +1777,31 @@ BrainOpenGLWidget::receiveEvent(Event* event) idRequestEvent->setEventProcessed(); } } + else if (event->getEventType() == EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE) { + EventMovieManualModeRecording* movieEvent = dynamic_cast(event); + CaretAssert(movieEvent); + + const int32_t windowIndex = movieEvent->getBrowserWindowIndex(); + if ((windowIndex < 0) + || (windowIndex == this->windowIndex)) { + /* + * Movie mode may be automatic but override with manual + * so that images are captured + */ + movieRecordingMode = MovieRecorderModeEnum::MANUAL; + + const float durationSeconds = movieEvent->getDurationSeconds(); + const float frameRate = movieRecorder->getFramesRate(); + captureManualMovieModeImageRepeatCount = static_cast(frameRate + * durationSeconds); + if (captureManualMovieModeImageRepeatCount < 1) { + captureManualMovieModeImageRepeatCount = 1; + } + doRepaintGraphicsFlag = true; + + movieEvent->setEventProcessed(); + } + } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* guiUpdateEvent = dynamic_cast(event); CaretAssert(guiUpdateEvent); @@ -1637,6 +1812,221 @@ BrainOpenGLWidget::receiveEvent(Event* event) else { } + + if (doRepaintGraphicsFlag + || doUpdateGraphicsFlag) { + + bool captureAutomaticImageForMovieFlag(false); + if (movieRecorder->getRecordingWindowIndex() == this->windowIndex) { + switch (movieRecordingMode) { + case MovieRecorderModeEnum::MANUAL: + break; + case MovieRecorderModeEnum::AUTOMATIC: + captureAutomaticImageForMovieFlag = true; + doRepaintGraphicsFlag = true; + break; + } + } + + if (doRepaintGraphicsFlag) { + repaintGraphics(); + if (captureAutomaticImageForMovieFlag + || (captureManualMovieModeImageRepeatCount > 0)) { + const bool showTimingResultFlag(false); + + int captureRegionOffsetX(0); + int captureRegionOffsetY(0); + int captureRegionWidth(0); + int captureRegionHeight(0); + int widgetWidth(0); + int widgetHeight(0); + BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); + + if (browserWindow != NULL) { + browserWindow->getGraphicsWidgetSize(captureRegionOffsetX, + captureRegionOffsetY, + captureRegionWidth, + captureRegionHeight, + widgetWidth, + widgetHeight, + true); + int outputImageWidth(0); + int outputImageHeight(0); + movieRecorder->getVideoWidthAndHeight(outputImageWidth, + outputImageHeight); + + AString msg; + if ((outputImageWidth <= 0) + || (outputImageHeight <= 0)) { + msg.appendWithNewLine("Movie width=" + + AString::number(outputImageWidth) + + ", height=" + + AString::number(outputImageHeight) + + " is invalid."); + } + if ((captureRegionWidth <= 0) + || (captureRegionHeight <= 0)) { + msg.appendWithNewLine("Movie capture region width=" + + AString::number(captureRegionWidth) + + ", height=" + + AString::number(captureRegionHeight) + + " is invalid."); + } + if ( ! msg.isEmpty()) { + CaretLogSevere(msg); + } + else { + QImage image; + bool imageValid(false); + + switch (movieRecorder->getCaptureRegionType()) { + case MovieRecorderCaptureRegionTypeEnum::GRAPHICS: + { + bool adjustImageSizeFlag(false); + int captureWidth = outputImageWidth; + int captureHeight = outputImageHeight; + if ((captureWidth != captureRegionWidth) + || (captureHeight != captureRegionHeight)) { + const float outputAspectRatio = (outputImageHeight / outputImageWidth); + const float captureRegionAspectRatio = (captureRegionHeight / captureRegionWidth); + if (captureRegionAspectRatio > outputAspectRatio) { + const float ratio = outputImageHeight / captureRegionHeight; + captureWidth = outputImageWidth * ratio; + captureHeight = outputImageHeight; + } + else { + const float ratio = outputImageWidth / captureRegionWidth; + captureHeight = outputImageHeight * ratio; + captureWidth = outputImageWidth; + + } + adjustImageSizeFlag = true; + } + + ElapsedTimer timer; + timer.start(); + EventImageCapture captureEvent(this->windowIndex, + captureRegionOffsetX, + captureRegionOffsetY, + captureRegionWidth, + captureRegionHeight, + captureWidth, + captureHeight); + captureImage(&captureEvent); + if (showTimingResultFlag) { + std::cout << "Capture time: " << timer.getElapsedTimeSeconds() << std::endl; + } + + if (captureEvent.isError()) { + CaretLogSevere("Failed to capture image of graphics for movie recording"); + } + else { + image = captureEvent.getImage(); + imageValid = true; + if (adjustImageSizeFlag) { + QImage scaledImage = ImageFile::scaleToSizeWithPadding(image, + outputImageWidth, + outputImageHeight); + if (scaledImage.isNull()) { + CaretLogSevere("Failed to scale image for movie recording"); + } + else { + image = scaledImage; + } + } + } + } + break; + case MovieRecorderCaptureRegionTypeEnum::WINDOW: + { + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); + QRect rect(0, 0, + bbw->width(), bbw->height()); + QPixmap pm = bbw->grab(rect); + if ((pm.width() > 0) + && (pm.height() > 0)) { + image = pm.toImage(); + imageValid = true; + + QImage scaledImage = ImageFile::scaleToSizeWithPadding(image, + outputImageWidth, + outputImageHeight); + if (scaledImage.isNull()) { + CaretLogSevere("Failed to scale image for movie recording"); + } + else { + image = scaledImage; + } + } + else { + CaretLogSevere("Failed to capture image of window"); + } + } + break; + } + + if (imageValid) { + ElapsedTimer imageTimer; + imageTimer.start(); + if (captureAutomaticImageForMovieFlag) { + movieRecorder->addImageToMovie(&image); + } + else if (captureManualMovieModeImageRepeatCount > 0) { + movieRecorder->addImageToMovieWithCopies(&image, + captureManualMovieModeImageRepeatCount); + } + if (showTimingResultFlag) { + std::cout << " Image write time: " << imageTimer.getElapsedTimeSeconds() << std::endl; + } + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); + } + } + } + } + } + else if (doUpdateGraphicsFlag) { +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + this->update(); +#else + this->updateGL(); +#endif + } + } +} + +/** + * Perform an immediate repaint of the graphics + */ +void +BrainOpenGLWidget::repaintGraphics() +{ + repaint(); + +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* + * As of QT 5.12.0. + * + * When using QOpenGLWidget, calling repaint() returns before + * it calls paintGL() so graphics are not updated even though + * the documentation states that drawing will complete during + * the call to repaint(). Essentially, repaint() functions + * the same as update(). + * + * Two Qt bug reports have been submitted by others: + * QTBUG-74404, QTBUG-53107. + * + * A previous kludge to fix this problem made a call to + * QApplication::processEvents(). However, it was found + * to cause a problem with annotation dragging as multiple + * mouse events were getting issued. + * Commit: 666b0e7c3d8d443aa9668a5cff986f7b83158488 + * + * Now, the kludge is to call grabFramebuffer() which I + * assume has to complete drawing before capturing an + * image. This fixes the problem with dragging annotations. + */ + (void)grabFramebuffer(); +#endif } /** @@ -1705,7 +2095,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) * buffer is updated. (repaint() updates immediately, * update() is a scheduled update). */ - repaint(); + repaintGraphics(); #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET image = grabFramebuffer(); #else @@ -1795,7 +2185,12 @@ BrainOpenGLWidget::initializeDefaultGLFormat() glfmt.setProfile(QSurfaceFormat::CompatibilityProfile); glfmt.setRedBufferSize(8); glfmt.setRenderableType(QSurfaceFormat::OpenGL); - glfmt.setSamples(6); + /* + * Values greater than zero for setSamples() cause an OpenGL error in + * glReadPixels(). + * QtBug-43127 + */ + glfmt.setSamples(0); //6); glfmt.setStereo(false); glfmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); @@ -1827,3 +2222,35 @@ BrainOpenGLWidget::initializeDefaultGLFormat() s_defaultGLFormatInitialized = true; } + +/** + * Process a mouse event from the macro system. + * + * @param me + * The mouse event + */ +void +BrainOpenGLWidget::processMouseEventFromMacro(QMouseEvent* me) +{ + m_mousePositionValid = true; + switch (me->type()) { + case QEvent::MouseButtonDblClick: + mouseDoubleClickEvent(me); + break; + case QEvent::MouseButtonPress: + mousePressEvent(me); + break; + case QEvent::MouseButtonRelease: + mouseReleaseEvent(me); + break; + case QEvent::MouseMove: + mouseMoveEvent(me); + break; + default: + CaretAssert(0); + break; + } + m_mousePositionValid = false; +} + + diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index ef7f45817a3b2648427d72f7e722da8e8e5c89d6..5f5942eee25ec9f4a9ac9bc9e53673df319f380e 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -45,6 +45,7 @@ #include "BrainOpenGLWindowContent.h" #include "CaretPointer.h" #include "EventListenerInterface.h" +#include "WuQMacroMouseEventWidgetInterface.h" class QMouseEvent; class QWidget; @@ -71,9 +72,9 @@ namespace caret { class VolumeFile; #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - class BrainOpenGLWidget : public QOpenGLWidget, public EventListenerInterface { + class BrainOpenGLWidget : public QOpenGLWidget, public EventListenerInterface, public WuQMacroMouseEventWidgetInterface { #else - class BrainOpenGLWidget : public QGLWidget, public EventListenerInterface { + class BrainOpenGLWidget : public QGLWidget, public EventListenerInterface, public WuQMacroMouseEventWidgetInterface { #endif Q_OBJECT @@ -116,6 +117,8 @@ namespace caret { QImage performOffScreenImageCapture(const int32_t imageWidth, const int32_t imageHeight); + virtual void processMouseEventFromMacro(QMouseEvent* me) override; + protected: virtual void initializeGL(); @@ -164,6 +167,8 @@ namespace caret { void captureImage(EventImageCapture* imageCaptureEvent); + void repaintGraphics(); + const int32_t windowIndex; BrainOpenGLWindowContent m_windowContent; @@ -212,8 +217,6 @@ namespace caret { static std::set s_brainOpenGLWidgets; static BrainOpenGL* s_singletonOpenGL; - - }; #ifdef __BRAIN_OPENGL_WIDGET_DEFINE__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index d1fb497fc017af2958410ba345d66c4dd5e1831b..a1fbd80338119540d6d3854538e5ecf082e7b1ac 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -12,6 +12,12 @@ if(Qt5_FOUND) include_directories(${Qt5OpenGL_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Widgets_INCLUDE_DIRS}) + if(HAVE_QT_WEBKIT) + include_directories(${Qt5WebEngine_INCLUDE_DIRS}) + include_directories(${Qt5WebEngineCore_INCLUDE_DIRS}) + include_directories(${Qt5WebEngineWidgets_INCLUDE_DIRS}) + include_directories(${Qt5WebView_INCLUDE_DIRS}) + endif(HAVE_QT_WEBKIT) endif() IF (QT4_FOUND) SET(QT_USE_QTNETWORK TRUE) @@ -110,7 +116,7 @@ ELSE() CiftiParcelSelectionComboBox.h ClippingPlanesDialog.h ColorEditorWidget.h - CopyPaletteColorMappingToFilesDialog.h + CopyPaletteColorMappingToFilesDialog.h CustomViewDialog.h DataFileContentCopyMoveDialog.h DisplayGroupAndTabItemViewController.h @@ -135,11 +141,12 @@ ELSE() InformationDisplayDialog.h InformationDisplayPropertiesDialog.h LabelSelectionViewController.h - LockAspectWarningDialog.h + LockAspectWarningDialog.h MacApplication.h MacDockMenu.h + MacDuplicateMenuBar.h MapSettingsChartTwoLineHistoryWidget.h - MapSettingsColorBarPaletteOptionsWidget.h + MapSettingsColorBarPaletteOptionsWidget.h MapSettingsColorBarWidget.h MapSettingsFiberTrajectoryWidget.h MapSettingsLabelsWidget.h @@ -150,7 +157,8 @@ ELSE() MetaDataEditorDialog.h MetaDataEditorWidget.h MovieDialog.h - OffScreenOpenGLRenderer.h + MovieRecordingDialog.h + OffScreenOpenGLRenderer.h OverlaySetViewController.h OverlaySettingsEditorDialog.h OverlayViewController.h @@ -165,7 +173,10 @@ ELSE() SceneBasePathWidget.h SceneCreateReplaceDialog.h SceneDialog.h + SceneFileInformationDialog.h + SceneDataFileTreeItemModel.h ScenePreviewDialog.h + SceneReplaceAllDialog.h SceneShowOptionsDialog.h SpecFileManagementDialog.h SplashScreen.h @@ -173,7 +184,7 @@ ELSE() StructureSurfaceSelectionControl.h SurfacePropertiesEditorDialog.h SurfaceSelectionViewController.h - ThresholdingSetMapsDialog.h + ThresholdingSetMapsDialog.h TileTabsConfigurationDialog.h UserInputModeAnnotationsContextMenu.h UserInputModeAnnotationsWidget.h @@ -185,9 +196,12 @@ ELSE() UserInputTileTabsContextMenu.h UsernamePasswordWidget.h VolumeFileCreateDialog.h + VolumePropertiesEditorDialog.h VolumeSurfaceOutlineColorOrTabViewController.h VolumeSurfaceOutlineSetViewController.h VolumeSurfaceOutlineViewController.h + WbMacroHelper.h + WbMacroWidgetActionsManager.h WuQCollapsibleWidget.h WuQDataEntryDialog.h WuQDialog.h @@ -200,14 +214,30 @@ ELSE() WuQGroupBoxExclusiveWidget.h WuQImageLabel.h WuQListWidget.h + WuQMacroCommandParameterWidget.h + WuQMacroCopyDialog.h + WuQMacroCreateDialog.h + WuQMacroDialog.h + WuQMacroExecutor.h + WuQMacroExecutorMonitor.h + WuQMacroHelperInterface.h + WuQMacroManager.h + WuQMacroMenu.h + WuQMacroNewCommandSelectionDialog.h + WuQMacroShortCutKeyComboBox.h + WuQMacroSignalEmitter.h + WuQMacroSignalWatcher.h + WuQMacroWidgetAction.h WuQMessageBox.h WuQwtPlot.h WuQSpecialIncrementDoubleSpinBox.h + WuQSpinBox.h WuQSpinBoxGroup.h WuQSpinBoxOddValue.h + WuQTabBar.h WuQTabWidget.h - WuQTabWidgetWithSizeHint.h - WuQTextEditorDialog.h + WuQTabWidgetWithSizeHint.h + WuQTextEditorDialog.h WuQTimedMessageDisplay.h WuQTreeWidget.h WuQTrueFalseComboBox.h @@ -329,12 +359,14 @@ EventBrowserWindowGraphicsRedrawn.h EventBrowserWindowNew.h EventBrowserWindowTileTabOperation.h EventGetOrSetUserInputModeProcessor.h +EventGraphicsTimingOneWindow.h EventGraphicsUpdateAllWindows.h EventGraphicsUpdateOneWindow.h EventHelpViewerDisplay.h EventIdentificationRequest.h EventImageCapture.h EventMacDockMenuUpdate.h +EventMovieManualModeRecording.h EventOperatingSystemRequestOpenDataFile.h EventOverlaySettingsEditorDialogRequest.h EventPaletteColorMappingEditorDialogRequest.h @@ -367,6 +399,7 @@ LabelSelectionViewController.h LockAspectWarningDialog.h MacApplication.h MacDockMenu.h +MacDuplicateMenuBar.h MapSettingsChartTwoLineHistoryWidget.h MapSettingsColorBarPaletteOptionsWidget.h MapSettingsColorBarWidget.h @@ -380,6 +413,7 @@ MetaDataEditorDialog.h MetaDataEditorWidget.h MouseEvent.h MovieDialog.h +MovieRecordingDialog.h OffScreenOpenGLRenderer.h OverlaySetViewController.h OverlaySettingsEditorDialog.h @@ -396,7 +430,11 @@ RegionOfInterestCreateFromBorderDialog.h SceneBasePathWidget.h SceneCreateReplaceDialog.h SceneDialog.h +SceneFileInformationDialog.h +SceneDataFileTreeItem.h +SceneDataFileTreeItemModel.h ScenePreviewDialog.h +SceneReplaceAllDialog.h SceneShowOptionsDialog.h SceneWindowGeometry.h SpecFileManagementDialog.h @@ -407,6 +445,7 @@ SurfacePropertiesEditorDialog.h SurfaceSelectionViewController.h ThresholdingSetMapsDialog.h TileTabsConfigurationDialog.h +TileTabsConfigurationModifier.h UserInputModeAbstract.h UserInputModeAnnotations.h UserInputModeAnnotationsContextMenu.h @@ -425,9 +464,26 @@ UserInputTileTabsContextMenu.h UsernamePasswordWidget.h ViewModeEnum.h VolumeFileCreateDialog.h +VolumePropertiesEditorDialog.h VolumeSurfaceOutlineColorOrTabViewController.h VolumeSurfaceOutlineSetViewController.h VolumeSurfaceOutlineViewController.h +WbMacroCustomDataInfo.h +WbMacroCustomDataTypeEnum.h +WbMacroCustomOperationAnimateOverlayCrossFade.h +WbMacroCustomOperationAnimateRotation.h +WbMacroCustomOperationAnimateSurfaceInterpolation.h +WbMacroCustomOperationAnimateVolumeSliceSequence.h +WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h +WbMacroCustomOperationBase.h +WbMacroCustomOperationDelay.h +WbMacroCustomOperationIncrementRotation.h +WbMacroCustomOperationIncrementVolumeSlice.h +WbMacroCustomOperationManager.h +WbMacroCustomOperationTypeEnum.h +WbMacroHelper.h +WbMacroWidgetActionNames.h +WbMacroWidgetActionsManager.h WuQCollapsibleWidget.h WuQDataEntryDialog.h WuQDialog.h @@ -441,11 +497,30 @@ WuQGridLayoutGroup.h WuQGroupBoxExclusiveWidget.h WuQImageLabel.h WuQListWidget.h +WuQMacroCommandParameterWidget.h +WuQMacroCopyDialog.h +WuQMacroCreateDialog.h +WuQMacroCustomOperationManagerInterface.h +WuQMacroDialog.h +WuQMacroExecutor.h +WuQMacroExecutorMonitor.h +WuQMacroExecutorOptions.h +WuQMacroHelperInterface.h +WuQMacroManager.h +WuQMacroMenu.h +WuQMacroMouseEventWidgetInterface.h +WuQMacroNewCommandSelectionDialog.h +WuQMacroShortCutKeyComboBox.h +WuQMacroSignalEmitter.h +WuQMacroSignalWatcher.h +WuQMacroWidgetAction.h WuQMessageBox.h WuQwtPlot.h WuQSpecialIncrementDoubleSpinBox.h +WuQSpinBox.h WuQSpinBoxGroup.h WuQSpinBoxOddValue.h +WuQTabBar.h WuQTabWidget.h WuQTabWidgetWithSizeHint.h WuQTextEditorDialog.h @@ -556,12 +631,14 @@ EventBrowserWindowGraphicsRedrawn.cxx EventBrowserWindowNew.cxx EventBrowserWindowTileTabOperation.cxx EventGetOrSetUserInputModeProcessor.cxx +EventGraphicsTimingOneWindow.cxx EventGraphicsUpdateAllWindows.cxx EventGraphicsUpdateOneWindow.cxx EventHelpViewerDisplay.cxx EventIdentificationRequest.cxx EventImageCapture.cxx EventMacDockMenuUpdate.cxx +EventMovieManualModeRecording.cxx EventOperatingSystemRequestOpenDataFile.cxx EventOverlaySettingsEditorDialogRequest.cxx EventPaletteColorMappingEditorDialogRequest.cxx @@ -594,6 +671,7 @@ LabelSelectionViewController.cxx LockAspectWarningDialog.cxx MacApplication.cxx MacDockMenu.cxx +MacDuplicateMenuBar.cxx MapSettingsChartTwoLineHistoryWidget.cxx MapSettingsColorBarPaletteOptionsWidget.cxx MapSettingsColorBarWidget.cxx @@ -607,6 +685,7 @@ MetaDataEditorDialog.cxx MetaDataEditorWidget.cxx MouseEvent.cxx MovieDialog.cxx +MovieRecordingDialog.cxx OffScreenOpenGLRenderer.cxx OverlaySetViewController.cxx OverlayViewController.cxx @@ -623,7 +702,11 @@ RegionOfInterestCreateFromBorderDialog.cxx SceneBasePathWidget.cxx SceneCreateReplaceDialog.cxx SceneDialog.cxx +SceneFileInformationDialog.cxx +SceneDataFileTreeItem.cxx +SceneDataFileTreeItemModel.cxx ScenePreviewDialog.cxx +SceneReplaceAllDialog.cxx SceneShowOptionsDialog.cxx SceneWindowGeometry.cxx SpecFileManagementDialog.cxx @@ -634,6 +717,7 @@ SurfacePropertiesEditorDialog.cxx SurfaceSelectionViewController.cxx ThresholdingSetMapsDialog.cxx TileTabsConfigurationDialog.cxx +TileTabsConfigurationModifier.cxx UserInputModeAbstract.cxx UserInputModeAnnotations.cxx UserInputModeAnnotationsContextMenu.cxx @@ -652,9 +736,25 @@ UserInputTileTabsContextMenu.cxx UsernamePasswordWidget.cxx ViewModeEnum.cxx VolumeFileCreateDialog.cxx +VolumePropertiesEditorDialog.cxx VolumeSurfaceOutlineColorOrTabViewController.cxx VolumeSurfaceOutlineSetViewController.cxx VolumeSurfaceOutlineViewController.cxx +WbMacroCustomDataInfo.cxx +WbMacroCustomDataTypeEnum.cxx +WbMacroCustomOperationAnimateOverlayCrossFade.cxx +WbMacroCustomOperationAnimateRotation.cxx +WbMacroCustomOperationAnimateSurfaceInterpolation.cxx +WbMacroCustomOperationAnimateVolumeSliceSequence.cxx +WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.cxx +WbMacroCustomOperationBase.cxx +WbMacroCustomOperationDelay.cxx +WbMacroCustomOperationIncrementRotation.cxx +WbMacroCustomOperationIncrementVolumeSlice.cxx +WbMacroCustomOperationManager.cxx +WbMacroCustomOperationTypeEnum.cxx +WbMacroHelper.cxx +WbMacroWidgetActionsManager.cxx WuQCollapsibleWidget.cxx WuQDataEntryDialog.cxx WuQDialog.cxx @@ -668,11 +768,27 @@ WuQGridLayoutGroup.cxx WuQGroupBoxExclusiveWidget.cxx WuQImageLabel.cxx WuQListWidget.cxx +WuQMacroCommandParameterWidget.cxx +WuQMacroCopyDialog.cxx +WuQMacroCreateDialog.cxx +WuQMacroDialog.cxx +WuQMacroExecutor.cxx +WuQMacroExecutorMonitor.cxx +WuQMacroExecutorOptions.cxx +WuQMacroManager.cxx +WuQMacroMenu.cxx +WuQMacroNewCommandSelectionDialog.cxx +WuQMacroShortCutKeyComboBox.cxx +WuQMacroSignalEmitter.cxx +WuQMacroSignalWatcher.cxx +WuQMacroWidgetAction.cxx WuQMessageBox.cxx WuQwtPlot.cxx WuQSpecialIncrementDoubleSpinBox.cxx +WuQSpinBox.cxx WuQSpinBoxGroup.cxx WuQSpinBoxOddValue.cxx +WuQTabBar.cxx WuQTabWidget.cxx WuQTabWidgetWithSizeHint.cxx WuQTextEditorDialog.cxx diff --git a/src/GuiQt/CaretColorEnumComboBox.cxx b/src/GuiQt/CaretColorEnumComboBox.cxx index e59e78dc25abdf2c62c466fd911076d7fd64d6e0..0a0559949ecad4f3817889b1d23f69924de305ef 100644 --- a/src/GuiQt/CaretColorEnumComboBox.cxx +++ b/src/GuiQt/CaretColorEnumComboBox.cxx @@ -26,6 +26,7 @@ #include #include "CaretAssert.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -91,6 +92,38 @@ CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelecti &customColorSelectionIcon); } +/** + * Constructor. + * + * @param customColorSelectionName + * If not empty, CaretColorEnum::CUSTOM is added to the combo with this name as the text. + * @param customColorSelectionIcon + * Icon for custom color. + * @param objectNameForMacros + * If not empty, name is used to set this combo box for macro support + * @param objectDescriptiveNameForMacros + * Descriptive name for macros + * @param parent + * Parent object. + */ +CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelectionName, + const QIcon& customColorSelectionIcon, + const QString& objectNameForMacros, + const QString& objectDescriptiveNameForMacros, + QObject* parent) +: WuQWidget(parent) +{ + initializeCaretColorComboBox(customColorSelectionName, + &customColorSelectionIcon); + + if ( ! objectNameForMacros.isEmpty()) { + this->colorComboBox->setObjectName(objectNameForMacros); + this->colorComboBox->setToolTip("Select Color"); + WuQMacroManager::instance()->addMacroSupportToObject(this->colorComboBox, + objectDescriptiveNameForMacros); + } +} + /** * Destructor. */ diff --git a/src/GuiQt/CaretColorEnumComboBox.h b/src/GuiQt/CaretColorEnumComboBox.h index 4e991eeee6a22ad415c4b66eb119d520f246e887..5882fab420294d9efaf8a0c228d28f2e92926edc 100644 --- a/src/GuiQt/CaretColorEnumComboBox.h +++ b/src/GuiQt/CaretColorEnumComboBox.h @@ -43,6 +43,12 @@ namespace caret { const QIcon& customColorSelectionIcon, QObject* parent); + CaretColorEnumComboBox(const AString& customColorSelectionName, + const QIcon& customColorSelectionIcon, + const QString& objectNameForMacros, + const QString& objectDescriptiveNameForMacros, + QObject* parent); + virtual ~CaretColorEnumComboBox(); CaretColorEnum::Enum getSelectedColor(); diff --git a/src/GuiQt/CaretFileDialog.cxx b/src/GuiQt/CaretFileDialog.cxx index fb51fee688cc37e5300baa4fc0c5318a2cd9cb17..68709f39f1ff5a516c993085cbf6d223a7ff5e8b 100644 --- a/src/GuiQt/CaretFileDialog.cxx +++ b/src/GuiQt/CaretFileDialog.cxx @@ -403,7 +403,7 @@ CaretFileDialog::getSaveFileNameDialog(const DataFileTypeEnum::Enum dataFileType if (selectedFiles.size() > 0) { AString filename = DataFileTypeEnum::addFileExtensionIfMissing(selectedFiles[0], dataFileType); - return filename; + return std::move(filename); } } @@ -470,7 +470,7 @@ CaretFileDialog::getChooseFileNameDialog(const DataFileTypeEnum::Enum dataFileTy if (selectedFiles.size() > 0) { AString filename = DataFileTypeEnum::addFileExtensionIfMissing(selectedFiles[0], dataFileType); - return filename; + return std::move(filename); } } return QString(); diff --git a/src/GuiQt/ChartHistoryViewController.cxx b/src/GuiQt/ChartHistoryViewController.cxx index 89d42473b2657f4a131789f2a3afec9f5ad43d28..997293d8e46b06e53a436ee996b7e7e2702b6999 100644 --- a/src/GuiQt/ChartHistoryViewController.cxx +++ b/src/GuiQt/ChartHistoryViewController.cxx @@ -48,6 +48,7 @@ #include "EventGraphicsUpdateOneWindow.h" #include "GuiManager.h" #include "ModelChart.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -65,11 +66,15 @@ using namespace caret; */ ChartHistoryViewController::ChartHistoryViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_orientation(orientation), -m_browserWindowIndex(browserWindowIndex) +m_browserWindowIndex(browserWindowIndex), +m_objectNamePrefix(parentObjectName + + ":History") { + WuQMacroManager* macroManager = WuQMacroManager::instance(); m_averageCheckBox = new QCheckBox("Show Average"); WuQtUtilities::setWordWrappedToolTip(m_averageCheckBox, "Display an average of the displayed chart data. " @@ -79,6 +84,10 @@ m_browserWindowIndex(browserWindowIndex) "chart."); QObject::connect(m_averageCheckBox, SIGNAL(clicked(bool)), this, SLOT(averageCheckBoxClicked(bool))); + m_averageCheckBox->setObjectName(m_objectNamePrefix + + ":ShowAverage"); + macroManager->addMacroSupportToObject(m_averageCheckBox, + "Enable linew chart history average"); QPushButton* clearPushButton = new QPushButton("Clear"); clearPushButton->setFixedWidth(clearPushButton->sizeHint().width() + 20); @@ -86,6 +95,11 @@ m_browserWindowIndex(browserWindowIndex) this, SLOT(clearPushButtonClicked())); WuQtUtilities::setWordWrappedToolTip(clearPushButton, "Remove all charts of the selected type in this tab"); + clearPushButton->setObjectName(m_objectNamePrefix + + ":ClearButton"); + macroManager->addMacroSupportToObject(clearPushButton, + "Remove line charts in tab"); + QLabel* maximumDisplayedLabel = new QLabel("Show last "); m_maximumDisplayedSpinBox = new QSpinBox(); @@ -93,6 +107,12 @@ m_browserWindowIndex(browserWindowIndex) m_maximumDisplayedSpinBox->setMaximum(1000); QObject::connect(m_maximumDisplayedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(maximumDisplayedSpinBoxValueChanged(int))); + m_maximumDisplayedSpinBox->setToolTip("Show Last Lines"); + m_maximumDisplayedSpinBox->setObjectName(m_objectNamePrefix + + ":ShowLastCount"); + macroManager->addMacroSupportToObject(m_maximumDisplayedSpinBox, + "Set maximum line charts"); + QHBoxLayout* maxDisplayedLayout = new QHBoxLayout(); maxDisplayedLayout->addWidget(maximumDisplayedLabel); maxDisplayedLayout->addWidget(m_maximumDisplayedSpinBox); @@ -283,6 +303,7 @@ ChartHistoryViewController::updateHistoryViewController() break; } + WuQMacroManager* macroManager = WuQMacroManager::instance(); const std::vector chartDataVector = chartModel->getAllChartDatas(); const int32_t numData = static_cast(chartDataVector.size()); @@ -291,6 +312,8 @@ ChartHistoryViewController::updateHistoryViewController() numWidgetRows); for (int32_t i = 0; i < maxItems; i++) { if (i >= static_cast(m_chartDataCheckBoxes.size())) { + const QString numberString(QString("%1").arg((int)i+1, 2, 10, QLatin1Char('0'))); + /* * Checkbox */ @@ -299,6 +322,13 @@ ChartHistoryViewController::updateHistoryViewController() m_chartDataCheckBoxesSignalMapper, SLOT(map())); m_chartDataCheckBoxesSignalMapper->setMapping(checkBox, i); m_chartDataCheckBoxes.push_back(checkBox); + checkBox->setToolTip("Show Chart Line"); + checkBox->setObjectName(m_objectNamePrefix + + ":ShowChartLine" + + numberString); + macroManager->addMacroSupportToObject(checkBox, + "Show line chart " + numberString); + /* * Construction Tool Button @@ -326,6 +356,12 @@ ChartHistoryViewController::updateHistoryViewController() m_chartDataColorComboBoxesSignalMapper, SLOT(map())); m_chartDataColorComboBoxesSignalMapper->setMapping(colorComboBox, i); m_chartDataColorComboBoxes.push_back(colorComboBox); + colorComboBox->getWidget()->setToolTip("Select Color"); + colorComboBox->getWidget()->setObjectName(m_objectNamePrefix + + ":Color" + + numberString); + macroManager->addMacroSupportToObject(colorComboBox->getWidget(), + "Set line chart " + numberString + " color"); /* * Label diff --git a/src/GuiQt/ChartHistoryViewController.h b/src/GuiQt/ChartHistoryViewController.h index 75fbc9570c248d632298ab299ccf0fd2adadc50f..e4d81f4ab22d8119445e329989128fccfddef169 100644 --- a/src/GuiQt/ChartHistoryViewController.h +++ b/src/GuiQt/ChartHistoryViewController.h @@ -48,6 +48,7 @@ namespace caret { public: ChartHistoryViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent); virtual ~ChartHistoryViewController(); @@ -90,6 +91,8 @@ namespace caret { const int32_t m_browserWindowIndex; + const QString m_objectNamePrefix; + QCheckBox* m_averageCheckBox; QSpinBox* m_maximumDisplayedSpinBox; diff --git a/src/GuiQt/ChartLinesSelectionViewController.cxx b/src/GuiQt/ChartLinesSelectionViewController.cxx index 76c21e2b1dfc3918d51c6634ad42534e6d9bf808..748fc6545ba8fa910efe2a4b7816f2c9c388733c 100644 --- a/src/GuiQt/ChartLinesSelectionViewController.cxx +++ b/src/GuiQt/ChartLinesSelectionViewController.cxx @@ -189,9 +189,6 @@ ChartLinesSelectionViewController::updateSelectionViewController() yokeComboBox = new MapYokingGroupComboBox(this); yokeComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); yokeComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); -#ifdef CARET_OS_MACOSX - yokeComboBox->getWidget()->setFixedWidth(yokeComboBox->getWidget()->sizeHint().width() - 20); -#endif // CARET_OS_MACOSX QObject::connect(yokeComboBox, SIGNAL(itemActivated()), m_signalMapperBrainordinateYokingComboBox, SLOT(map())); m_signalMapperBrainordinateYokingComboBox->setMapping(yokeComboBox, i); diff --git a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx index 37e68c1d1ea299169f617368efc3d11d14595a6b..a67c888f04e8d8b093866d92a214a5da47c7e786 100644 --- a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx +++ b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx @@ -136,9 +136,6 @@ m_browserWindowIndex(browserWindowIndex) m_matrixSeriesYokingComboBox = new MapYokingGroupComboBox(this); m_matrixSeriesYokingComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); m_matrixSeriesYokingComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); -#ifdef CARET_OS_MACOSX - m_matrixSeriesYokingComboBox->getWidget()->setFixedWidth(m_matrixSeriesYokingComboBox->getWidget()->sizeHint().width() - 20); -#endif // CARET_OS_MACOSX QObject::connect(m_matrixSeriesYokingComboBox, SIGNAL(itemActivated()), this, SLOT(matrixSeriesYokingGroupActivated())); diff --git a/src/GuiQt/ChartSelectionViewController.cxx b/src/GuiQt/ChartSelectionViewController.cxx index c606229863c9ff3c208b6d06d2e011fe8db1eea4..4a6fc2789a697a216a432d876d5b3884291c84bc 100644 --- a/src/GuiQt/ChartSelectionViewController.cxx +++ b/src/GuiQt/ChartSelectionViewController.cxx @@ -37,6 +37,7 @@ #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ModelChart.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -52,10 +53,15 @@ using namespace caret; */ ChartSelectionViewController::ChartSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) + { + const QString objectNamePrefix(parentObjectName + + ":History"); + m_mode = MODE_INVALID; m_brainordinateChartWidget = new ChartLinesSelectionViewController(orientation, diff --git a/src/GuiQt/ChartSelectionViewController.h b/src/GuiQt/ChartSelectionViewController.h index fb2fe096ab7758b434a5cb88b79cf96981d5100e..437c6beb8585f0d8668e3ab4a91de17a4f5db4f3 100644 --- a/src/GuiQt/ChartSelectionViewController.h +++ b/src/GuiQt/ChartSelectionViewController.h @@ -41,6 +41,7 @@ namespace caret { public: ChartSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent); virtual ~ChartSelectionViewController(); diff --git a/src/GuiQt/ChartToolBoxViewController.cxx b/src/GuiQt/ChartToolBoxViewController.cxx index f345685bb6b021f92eb552733f8d9baead70f577..3f844dae1913d961433ca134f1e93ce9ccec44ee 100644 --- a/src/GuiQt/ChartToolBoxViewController.cxx +++ b/src/GuiQt/ChartToolBoxViewController.cxx @@ -42,6 +42,7 @@ #include "ModelChart.h" #include "SceneClass.h" #include "SceneClassAssistant.h" +#include "WuQMacroManager.h" using namespace caret; @@ -56,28 +57,49 @@ using namespace caret; /** * Constructor. + * + * @param orientation + * Orientation of toolbox + * @param browserWindowIndex + * Index of browser window + * @param parentObjectName + * Name of parent object for macros + * @param parent + * Parent widget */ ChartToolBoxViewController::ChartToolBoxViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent) : QWidget(parent), EventListenerInterface(), m_browserWindowIndex(browserWindowIndex) { + const QString objectNamePrefix(parentObjectName + + ":Chart"); + /* * Data series widgets */ m_chartSelectionViewController = new ChartSelectionViewController(orientation, - browserWindowIndex, - NULL); + browserWindowIndex, + objectNamePrefix, + NULL); m_chartHistoryViewController = new ChartHistoryViewController(orientation, - browserWindowIndex, - NULL); + browserWindowIndex, + objectNamePrefix, + NULL); m_tabWidget = new QTabWidget(); m_tabWidget->addTab(m_chartSelectionViewController, "Loading"); m_tabWidget->addTab(m_chartHistoryViewController, "History"); + m_tabWidget->setObjectName(objectNamePrefix + + ":Tab"); + WuQMacroManager::instance()->addMacroSupportToObjectWithToolTip(m_tabWidget, + "Overlay ToolBox Chart Tab", + ""); + QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_tabWidget); diff --git a/src/GuiQt/ChartToolBoxViewController.h b/src/GuiQt/ChartToolBoxViewController.h index debc5c366d8c9ee9d3589ececfd6f9628c2345e8..adb0613442f900732ce275125bbc6764d272c297 100644 --- a/src/GuiQt/ChartToolBoxViewController.h +++ b/src/GuiQt/ChartToolBoxViewController.h @@ -43,6 +43,7 @@ namespace caret { public: ChartToolBoxViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent); virtual ~ChartToolBoxViewController(); diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.cxx b/src/GuiQt/ChartTwoOverlaySetViewController.cxx index 687430db776be54731e742e7a53336e90d494c6f..5db1dbc90fc469c50fc2a4a0dd25029b3cff8bf1 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.cxx +++ b/src/GuiQt/ChartTwoOverlaySetViewController.cxx @@ -63,12 +63,15 @@ using namespace caret; * Orientation for layout * @param browserWindowIndex * Index of browser window that contains this view controller. + * @param parentObjectName + * Name of parent object for macros * @param parent * Parent widget. */ ChartTwoOverlaySetViewController::ChartTwoOverlaySetViewController(const Qt::Orientation orientation, - const int32_t browserWindowIndex, - QWidget* parent) + const int32_t browserWindowIndex, + const QString& parentObjectName, + QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { @@ -77,10 +80,11 @@ m_browserWindowIndex(browserWindowIndex) WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 2); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - ChartTwoOverlayViewController* ovc = new ChartTwoOverlayViewController(orientation, - m_browserWindowIndex, - i, - this); + ChartTwoOverlayViewController* ovc = new ChartTwoOverlayViewController(orientation, + m_browserWindowIndex, + i, + parentObjectName, + this); m_chartOverlayViewControllers.push_back(ovc); m_chartOverlayGridLayoutGroups.push_back(new WuQGridLayoutGroup(gridLayout, this)); diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.h b/src/GuiQt/ChartTwoOverlaySetViewController.h index f637eae69838b5c779943675016e76ce340de6aa..de18b713f5196719f36a6214e7312128b0a4bafa 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.h +++ b/src/GuiQt/ChartTwoOverlaySetViewController.h @@ -40,8 +40,9 @@ namespace caret { public: ChartTwoOverlaySetViewController(const Qt::Orientation orientation, - const int32_t browserWindowIndex, - QWidget* parent = 0); + const int32_t browserWindowIndex, + const QString& parentObjectName, + QWidget* parent = 0); virtual ~ChartTwoOverlaySetViewController(); diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index db16ad6dd20b462d30467ba62c1527506eb90752..f75c243be4319209854535f226410866f2894cb6 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -59,6 +59,7 @@ using namespace caret; #include "MapYokingGroupComboBox.h" #include "UsernamePasswordWidget.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -77,13 +78,16 @@ using namespace caret; * Index of browser window in which this view controller resides. * @param chartOverlayIndex * Index of this overlay view controller. + * @param parentObjectName + * Name of parent object for macros * @param parent * The parent widget. */ ChartTwoOverlayViewController::ChartTwoOverlayViewController(const Qt::Orientation orientation, - const int32_t browserWindowIndex, - const int32_t chartOverlayIndex, - QObject* parent) + const int32_t browserWindowIndex, + const int32_t chartOverlayIndex, + const QString& parentObjectName, + QObject* parent) : QObject(parent), m_browserWindowIndex(browserWindowIndex), m_chartOverlayIndex(chartOverlayIndex), @@ -97,14 +101,26 @@ m_chartOverlay(NULL) } const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContentsOnFirstShow; //QComboBox::AdjustToContents; + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + QString objectNamePrefix = QString(parentObjectName + + ":ChartOverlay%1" + + ":").arg((int)(chartOverlayIndex + 1), 2, 10, QLatin1Char('0')); + QString descriptivePrefix = QString("chart overlay " + + QString::number(chartOverlayIndex + 1)); + /* * Enabled Check Box */ const QString enabledCheckboxText = ((orientation == Qt::Horizontal) ? " " : "On"); m_enabledCheckBox = new QCheckBox(enabledCheckboxText); + m_enabledCheckBox->setObjectName(objectNamePrefix + + "OnOff"); QObject::connect(m_enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(enabledCheckBoxClicked(bool))); m_enabledCheckBox->setToolTip("Display line charts from the selected file"); + macroManager->addMacroSupportToObject(m_enabledCheckBox, + "Enable line chart display for " + descriptivePrefix); /* * Line Series Enabled Check Box @@ -114,6 +130,10 @@ m_chartOverlay(NULL) QObject::connect(m_lineSeriesLoadingEnabledCheckBox, &QCheckBox::clicked, this, &ChartTwoOverlayViewController::lineSeriesLoadingEnabledCheckBoxClicked); m_lineSeriesLoadingEnabledCheckBox->setToolTip("Enable loading of line charts for the selected file"); + m_lineSeriesLoadingEnabledCheckBox->setObjectName(objectNamePrefix + + "EnableLoading"); + macroManager->addMacroSupportToObject(m_lineSeriesLoadingEnabledCheckBox, + "Enable line chart loading for " + descriptivePrefix); /* * Settings Tool Button @@ -122,15 +142,19 @@ m_chartOverlay(NULL) const bool settingsIconValid = WuQtUtilities::loadIcon(":/LayersPanel/wrench.png", settingsIcon); + m_settingsToolButton = new QToolButton(); m_settingsAction = WuQtUtilities::createAction("S", "Edit settings for this chart", - this, + m_settingsToolButton, this, SLOT(settingsActionTriggered())); if (settingsIconValid) { m_settingsAction->setIcon(settingsIcon); } - m_settingsToolButton = new QToolButton(); + m_settingsAction->setObjectName(objectNamePrefix + + "ShowSettingsDialog"); + macroManager->addMacroSupportToObject(m_settingsAction, + "Show settings dialog for " + descriptivePrefix); m_settingsToolButton->setDefaultAction(m_settingsAction); /* @@ -139,20 +163,25 @@ m_chartOverlay(NULL) QIcon colorBarIcon; const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", colorBarIcon); + m_colorBarToolButton = new QToolButton(); m_colorBarAction = WuQtUtilities::createAction("CB", "Display color bar for this overlay", - this, + m_colorBarToolButton, this, SLOT(colorBarActionTriggered(bool))); m_colorBarAction->setCheckable(true); if (colorBarIconValid) { m_colorBarAction->setIcon(colorBarIcon); } - m_colorBarToolButton = new QToolButton(); + m_colorBarAction->setObjectName(objectNamePrefix + + "ShowColorBar"); + macroManager->addMacroSupportToObject(m_colorBarAction, + "Enable color bar for " + descriptivePrefix); m_colorBarToolButton->setDefaultAction(m_colorBarAction); /* * Construction Tool Button + * Note: macro support is on each action in menu in 'createConstructionMenu' */ QIcon constructionIcon; const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", @@ -164,19 +193,26 @@ m_chartOverlay(NULL) m_constructionAction->setIcon(constructionIcon); } m_constructionToolButton = new QToolButton(); - QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton); + QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton, + (objectNamePrefix + + "ConstructionMenu:"), + descriptivePrefix); m_constructionAction->setMenu(constructionMenu); m_constructionToolButton->setDefaultAction(m_constructionAction); m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); /* * Matrix triangular view mode button + * Note: macro support is on each action in menu in createMatrixTriangularViewModeMenu */ + m_matrixTriangularViewModeToolButton = new QToolButton(); m_matrixTriangularViewModeAction = WuQtUtilities::createAction("M", "Select a triangular view of the matrix", - this); - m_matrixTriangularViewModeToolButton = new QToolButton(); - QMenu* matrixTriangularViewModeMenu = createMatrixTriangularViewModeMenu(m_matrixTriangularViewModeToolButton); + m_matrixTriangularViewModeToolButton); + QMenu* matrixTriangularViewModeMenu = createMatrixTriangularViewModeMenu(m_matrixTriangularViewModeToolButton, + (objectNamePrefix + + "TriangularViewMenu:"), + descriptivePrefix); m_matrixTriangularViewModeAction->setMenu(matrixTriangularViewModeMenu); m_matrixTriangularViewModeToolButton->setDefaultAction(m_matrixTriangularViewModeAction); m_matrixTriangularViewModeToolButton->setPopupMode(QToolButton::InstantPopup); @@ -184,12 +220,16 @@ m_chartOverlay(NULL) /* * Axis location button + * Note: macro support is on each action in menu in createMatrixTriangularViewModeMenu */ + m_axisLocationToolButton = new QToolButton(); m_axisLocationAction = WuQtUtilities::createAction("A", "Select location of vertical axis for the selected file", - this); - m_axisLocationToolButton = new QToolButton(); - QMenu* axisLocationMenu = createAxisLocationMenu(m_axisLocationToolButton); + m_axisLocationToolButton); + QMenu* axisLocationMenu = createAxisLocationMenu(m_axisLocationToolButton, + (objectNamePrefix + + "VerticalAxisLocationMenu:"), + descriptivePrefix); m_axisLocationAction->setMenu(axisLocationMenu); m_axisLocationToolButton->setDefaultAction(m_axisLocationAction); m_axisLocationToolButton->setPopupMode(QToolButton::InstantPopup); @@ -204,6 +244,10 @@ m_chartOverlay(NULL) this, SLOT(fileComboBoxSelected(int))); m_mapFileComboBox->setToolTip("Selects file for this overlay"); m_mapFileComboBox->setSizeAdjustPolicy(comboSizePolicy); + m_mapFileComboBox->setObjectName(objectNamePrefix + + "FileSelection"); + macroManager->addMacroSupportToObject(m_mapFileComboBox, + "Select file in " + descriptivePrefix); /* * Yoking Group @@ -218,9 +262,6 @@ m_chartOverlay(NULL) m_mapRowOrColumnYokingGroupComboBox = new MapYokingGroupComboBox(this); m_mapRowOrColumnYokingGroupComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); m_mapRowOrColumnYokingGroupComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); -#ifdef CARET_OS_MACOSX - m_mapRowOrColumnYokingGroupComboBox->getWidget()->setFixedWidth(m_mapRowOrColumnYokingGroupComboBox->getWidget()->sizeHint().width() - 20); -#endif // CARET_OS_MACOSX QObject::connect(m_mapRowOrColumnYokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokingGroupActivated())); @@ -234,6 +275,10 @@ m_chartOverlay(NULL) } QObject::connect(m_allMapsCheckBox, SIGNAL(clicked(bool)), this, SLOT(allMapsCheckBoxClicked(bool))); + m_allMapsCheckBox->setObjectName(objectNamePrefix + + "AllMaps"); + macroManager->addMacroSupportToObject(m_allMapsCheckBox, + "Enable all maps in " + descriptivePrefix); /* * Map/Row/Column Index Spin Box @@ -246,6 +291,11 @@ m_chartOverlay(NULL) m_mapRowOrColumnIndexSpinBox->setFixedSize(m_mapRowOrColumnIndexSpinBox->sizeHint()); m_mapRowOrColumnIndexSpinBox->setRange(1, 1); m_mapRowOrColumnIndexSpinBox->setValue(1); + m_mapRowOrColumnIndexSpinBox->setObjectName(objectNamePrefix + + "MapIndex"); + macroManager->addMacroSupportToObject(m_mapRowOrColumnIndexSpinBox, + "Select map by index in " + descriptivePrefix); + /* * Map/Row/Column Name Combo Box @@ -257,6 +307,10 @@ m_chartOverlay(NULL) this, SLOT(mapRowOrColumnNameComboBoxSelected(int))); m_mapRowOrColumnNameComboBox->setToolTip("Select map/row/column by its name"); m_mapRowOrColumnNameComboBox->setSizeAdjustPolicy(comboSizePolicy); + m_mapRowOrColumnNameComboBox->setObjectName(objectNamePrefix + + "MapSelection"); + macroManager->addMacroSupportToObject(m_mapRowOrColumnNameComboBox, + "Select map name in " + descriptivePrefix); } /** @@ -932,9 +986,15 @@ ChartTwoOverlayViewController::updateGraphicsWindow() * Create the matrix triangular view mode menu. * @param parent * Parent widget. + * @param parentObjectName + * Name of parent object for macros + * @param descriptivePrefix + * Descriptive prefix for macros */ QMenu* -ChartTwoOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* parent) +ChartTwoOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* parent, + const QString& parentObjectName, + const QString& descriptivePrefix) { std::vector allViewModes; ChartTwoMatrixTriangularViewingModeEnum::getAllEnums(allViewModes); @@ -954,6 +1014,13 @@ ChartTwoOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* paren action->setIcon(pixmap); actionGroup->addAction(action); + QString objName = (parentObjectName + + ChartTwoMatrixTriangularViewingModeEnum::toGuiName(viewMode)); + objName = objName.replace(" ", ""); + action->setObjectName(objName); + WuQMacroManager::instance()->addMacroSupportToObject(action, + "Set triangular view in " + descriptivePrefix); + m_matrixViewMenuData.push_back(std::make_tuple(viewMode, action, pixmap)); } @@ -994,9 +1061,13 @@ ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* ac * Create the axis location menu. * @param parent * Parent widget. + * @param parentObjectName + * Name of parent object for macros */ QMenu* -ChartTwoOverlayViewController::createAxisLocationMenu(QWidget* widget) +ChartTwoOverlayViewController::createAxisLocationMenu(QWidget* widget, + const QString& parentObjectName, + const QString& descriptivePrefix) { std::vector axisLocations; axisLocations.push_back(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); @@ -1017,6 +1088,13 @@ ChartTwoOverlayViewController::createAxisLocationMenu(QWidget* widget) action->setIcon(pixmap); actionGroup->addAction(action); + QString objName = (parentObjectName + + ChartAxisLocationEnum::toGuiName(axis)); + objName = objName.replace(" ", ""); + action->setObjectName(objName); + WuQMacroManager::instance()->addMacroSupportToObject(action, + "Select chart axis location for " + descriptivePrefix); + m_axisLocationMenuData.push_back(std::make_tuple(axis, action, pixmap)); } @@ -1048,53 +1126,102 @@ ChartTwoOverlayViewController::menuAxisLocationTriggered(QAction* action) * Create the construction menu. * @param parent * Parent widget. + * @param parentObjectName + * Name of parent object for macros + * @param descriptivePrefix + * Descriptive name for macros */ QMenu* -ChartTwoOverlayViewController::createConstructionMenu(QWidget* parent) +ChartTwoOverlayViewController::createConstructionMenu(QWidget* parent, + const QString& menuActionNamePrefix, + const QString& descriptivePrefix) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + QMenu* menu = new QMenu(parent); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(menuConstructionAboutToShow())); - menu->addAction("Add Overlay Above", + QAction* addAboveAction = menu->addAction("Add Overlay Above", this, SLOT(menuAddOverlayAboveTriggered())); + addAboveAction->setObjectName(menuActionNamePrefix + + "AddOverlayAbove"); + addAboveAction->setToolTip("Add an overlay above this overlay"); + macroManager->addMacroSupportToObject(addAboveAction, + "Add overlay above " + descriptivePrefix); - menu->addAction("Add Overlay Below", + QAction* addBelowAction = menu->addAction("Add Overlay Below", this, SLOT(menuAddOverlayBelowTriggered())); + addBelowAction->setObjectName(menuActionNamePrefix + + "AddOverlayBelow"); + addBelowAction->setToolTip("Add an overlay below this overlay"); + macroManager->addMacroSupportToObject(addBelowAction, + "Add overlay below " + descriptivePrefix); menu->addSeparator(); - menu->addAction("Move Overlay Up", + QAction* moveUpAction = menu->addAction("Move Overlay Up", this, SLOT(menuMoveOverlayUpTriggered())); + moveUpAction->setObjectName(menuActionNamePrefix + + "MoveOverlayUp"); + moveUpAction->setToolTip("Move this overlay up"); + macroManager->addMacroSupportToObject(moveUpAction, + "Move " + descriptivePrefix + " up"); - menu->addAction("Move Overlay Down", + QAction* moveDownAction = menu->addAction("Move Overlay Down", this, SLOT(menuMoveOverlayDownTriggered())); + moveDownAction->setObjectName(menuActionNamePrefix + + "MoveOverlayDown"); + moveDownAction->setToolTip("Move this overlay down"); + macroManager->addMacroSupportToObject(moveDownAction, + "Move " + descriptivePrefix + " down"); menu->addSeparator(); - menu->addAction("Remove This Overlay", + QAction* removeAction = menu->addAction("Remove This Overlay", this, SLOT(menuRemoveOverlayTriggered())); + removeAction->setObjectName(menuActionNamePrefix + + "RemoveOverlay"); + removeAction->setToolTip("Remove this overlay"); + macroManager->addMacroSupportToObject(removeAction, + "Remove " + descriptivePrefix + " overlay"); menu->addSeparator(); m_constructionReloadFileAction = menu->addAction("Reload Selected File", this, SLOT(menuReloadFileTriggered())); + m_constructionReloadFileAction->setObjectName(menuActionNamePrefix + + "ReloadSelectedFile"); + m_constructionReloadFileAction->setToolTip("Reload file in this overlay"); + macroManager->addMacroSupportToObject(m_constructionReloadFileAction, + "Reload file in " + descriptivePrefix); menu->addSeparator(); - menu->addAction("Copy Path and File Name to Clipboard", + QAction* copyPathFileNameAction = menu->addAction("Copy Path and File Name to Clipboard", this, SLOT(menuCopyFileNameToClipBoard())); + copyPathFileNameAction->setObjectName(menuActionNamePrefix + + "CopyPathAndFileNameToClipboard"); + copyPathFileNameAction->setToolTip("Copy path and file name of file in this overlay to clipboard"); + macroManager->addMacroSupportToObject(copyPathFileNameAction, + "Copy path and name to clipboard from " + descriptivePrefix); - menu->addAction("Copy Map Name to Clipboard", + QAction* copyMapNameAction = menu->addAction("Copy Map Name to Clipboard", this, SLOT(menuCopyMapNameToClipBoard())); + copyMapNameAction->setObjectName(menuActionNamePrefix + + "CopyMapNameToClipboard"); + copyMapNameAction->setToolTip("Copy name of selected map to the clipboard"); + macroManager->addMacroSupportToObject(copyMapNameAction, + "Copy map name to clipboard from " + descriptivePrefix); return menu; diff --git a/src/GuiQt/ChartTwoOverlayViewController.h b/src/GuiQt/ChartTwoOverlayViewController.h index 0be90da0681e20c13824a653fd5a7ce5ab41c5f9..039273bd2ebcf0f02cefca4c777815b3a51730fb 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.h +++ b/src/GuiQt/ChartTwoOverlayViewController.h @@ -47,9 +47,10 @@ namespace caret { public: ChartTwoOverlayViewController(const Qt::Orientation orientation, - const int32_t browserWindowIndex, - const int32_t chartOverlayIndex, - QObject* parent); + const int32_t browserWindowIndex, + const int32_t chartOverlayIndex, + const QString& parentObjectName, + QObject* parent); virtual ~ChartTwoOverlayViewController(); @@ -119,11 +120,17 @@ namespace caret { void updateGraphicsWindow(); - QMenu* createConstructionMenu(QWidget* parent); + QMenu* createConstructionMenu(QWidget* parent, + const QString& parentObjectName, + const QString& descriptivePrefix); - QMenu* createMatrixTriangularViewModeMenu(QWidget* widget); + QMenu* createMatrixTriangularViewModeMenu(QWidget* widget, + const QString& parentObjectName, + const QString& descriptivePrefix); - QMenu* createAxisLocationMenu(QWidget* widget); + QMenu* createAxisLocationMenu(QWidget* widget, + const QString& parentObjectName, + const QString& descriptivePrefix); void validateYokingSelection(); diff --git a/src/GuiQt/CiftiConnectivityMatrixViewController.cxx b/src/GuiQt/CiftiConnectivityMatrixViewController.cxx index 1780d2ad4ca5e1c8779b137b39898a5f21b66fd6..4ef6a8ec32fb43d37a12c8174f00ace34a138e76 100644 --- a/src/GuiQt/CiftiConnectivityMatrixViewController.cxx +++ b/src/GuiQt/CiftiConnectivityMatrixViewController.cxx @@ -49,6 +49,9 @@ #include "FiberTrajectoryMapProperties.h" #include "FilePathNamePrefixCompactor.h" #include "GuiManager.h" +#include "MetricDynamicConnectivityFile.h" +#include "VolumeDynamicConnectivityFile.h" +#include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -63,10 +66,17 @@ static const char* FILE_POINTER_PROPERTY_NAME = "filePointer"; */ /** * Constructor. + * + * @param parentObjectName + * Name of parent object for macros + * @param parent + * The parent widget */ -CiftiConnectivityMatrixViewController::CiftiConnectivityMatrixViewController(const Qt::Orientation /*orientation*/, +CiftiConnectivityMatrixViewController::CiftiConnectivityMatrixViewController(const QString& parentObjectName, QWidget* parent) -: QWidget(parent) +: QWidget(parent), +m_objectNamePrefix(parentObjectName + + ":Connectivity") { m_gridLayout = new QGridLayout(); WuQtUtilities::setLayoutSpacingAndMargins(m_gridLayout, 2, 2); @@ -147,16 +157,21 @@ CiftiConnectivityMatrixViewController::updateViewController() matrixIter++) { files.push_back(*matrixIter); } + + std::vector metricDynConnFiles; + brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); + files.insert(files.end(), + metricDynConnFiles.begin(), metricDynConnFiles.end()); + std::vector volumeDynConnFiles; + brain->getVolumeDynamicConnectivityFiles(volumeDynConnFiles); + files.insert(files.end(), + volumeDynConnFiles.begin(), volumeDynConnFiles.end()); + + WuQMacroManager* macroManager = WuQMacroManager::instance(); const int32_t numFiles = static_cast(files.size()); -// std::vector displayNames; -// FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(files, -// displayNames); -// -// CaretAssert(files.size() == displayNames.size()); - for (int32_t i = 0; i < numFiles; i++) { QCheckBox* checkBox = NULL; QCheckBox* layerCheckBox = NULL; @@ -172,21 +187,33 @@ CiftiConnectivityMatrixViewController::updateViewController() comboBox = m_fiberOrientationFileComboBoxes[i]; } else { + + const QString objectNamePrefix(m_objectNamePrefix + + QString("%1").arg((int)i+1, 2, 10, QLatin1Char('0')) + + ":"); + const QString descriptivePrefix("connectivity file " + QString::number(i+1)); + checkBox = new QCheckBox(""); checkBox->setToolTip("When selected, load data during\n" "an identification operation"); m_fileEnableCheckBoxes.push_back(checkBox); + checkBox->setObjectName(objectNamePrefix + + "Enable"); + macroManager->addMacroSupportToObject(checkBox, + "Enable " + descriptivePrefix); - const AString dynToolTip("This option is enabled only for .dynconn.nii (dynamic connectivity) files. " + const AString dynToolTip("This option is enabled only for dynamic connectivity files. " "When checked, this dynamic connectivity file will appear in the Overlay Layers' File selection combo box. " "Dynamic connectivity files do not explicitly exist but allow dynamic " - "computation of connectivity from a dense data series (.dtseries) file. " - "Dynamic connectivity allows one to view connectivity for a brainordinate without creation of an " - "extremely large dense connectivity (.dconn.nii) file. " - "In Preferences, one may set the default to show/hide .dynconn.nii files."); + "computation of connectivity from a CIFTI data-series, metric, or volume file. " + "In Preferences, one may set the default to show/hide dynamic connectivity files."); layerCheckBox = new QCheckBox(""); WuQtUtilities::setWordWrappedToolTip(layerCheckBox, dynToolTip); m_layerCheckBoxes.push_back(layerCheckBox); + layerCheckBox->setObjectName(objectNamePrefix + + "EnableLayer"); + macroManager->addMacroSupportToObject(layerCheckBox, + "Enable dynamic connectivity for " + descriptivePrefix); lineEdit = new QLineEdit(); lineEdit->setReadOnly(true); @@ -194,11 +221,20 @@ CiftiConnectivityMatrixViewController::updateViewController() copyToolButton = new QToolButton(); copyToolButton->setText("Copy"); - copyToolButton->setToolTip("Copy loaded row data to a new CIFTI Scalar File"); + copyToolButton->setToolTip("Copy loaded connectivity data into a writable file that is added to layers"); m_fileCopyToolButtons.push_back(copyToolButton); + copyToolButton->setObjectName(objectNamePrefix + + "CopyButton"); + macroManager->addMacroSupportToObject(copyToolButton, + "Copy load row to new CIFTI scalar or Volume file for " + descriptivePrefix); comboBox = new QComboBox(); m_fiberOrientationFileComboBoxes.push_back(comboBox); + comboBox->setToolTip("Select Fiber Orientation File"); + comboBox->setObjectName(objectNamePrefix + + "FiberOrientationFile"); + macroManager->addMacroSupportToObject(comboBox, + "Select fiber orientation for " + descriptivePrefix); QObject::connect(copyToolButton, SIGNAL(clicked()), m_signalMapperFileCopyToolButton, SLOT(map())); @@ -231,6 +267,8 @@ CiftiConnectivityMatrixViewController::updateViewController() const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(files[i]); const CiftiFiberTrajectoryFile* trajFile = dynamic_cast(files[i]); + const VolumeDynamicConnectivityFile* volDynConnFile = dynamic_cast(files[i]); + const MetricDynamicConnectivityFile* metricDynConnFile = dynamic_cast(files[i]); bool checkStatus = false; if (matrixFile != NULL) { @@ -239,6 +277,12 @@ CiftiConnectivityMatrixViewController::updateViewController() else if (trajFile != NULL) { checkStatus = trajFile->isDataLoadingEnabled(); } + else if (volDynConnFile != NULL) { + checkStatus = volDynConnFile->isDataLoadingEnabled(); + } + else if (metricDynConnFile != NULL) { + checkStatus = metricDynConnFile->isDataLoadingEnabled(); + } else { CaretAssertMessage(0, "Has a new file type been added?"); } @@ -251,6 +295,12 @@ CiftiConnectivityMatrixViewController::updateViewController() if (dynConnFile != NULL) { layerCheckBox->setChecked(dynConnFile->isEnabledAsLayer()); } + else if (volDynConnFile != NULL) { + layerCheckBox->setChecked(volDynConnFile->isEnabledAsLayer()); + } + else if (metricDynConnFile != NULL) { + layerCheckBox->setChecked(metricDynConnFile->isEnabledAsLayer()); + } else { layerCheckBox->setChecked(false); } @@ -269,10 +319,15 @@ CiftiConnectivityMatrixViewController::updateViewController() if (dynamic_cast(files[i]) != NULL) { showOrientationComboBox = true; } - if (dynamic_cast(files[i]) != NULL) { layerCheckBoxValid = true; } + else if (dynamic_cast(files[i]) != NULL) { + layerCheckBoxValid = true; + } + else if (dynamic_cast(files[i]) != NULL) { + layerCheckBoxValid = true; + } } m_fileEnableCheckBoxes[i]->setVisible(showRow); @@ -302,11 +357,15 @@ CiftiConnectivityMatrixViewController::updateFiberOrientationComboBoxes() QComboBox* comboBox = m_fiberOrientationFileComboBoxes[i]; CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; + MetricDynamicConnectivityFile* metricDynConnFile(NULL); + VolumeDynamicConnectivityFile* volDynConnFile = NULL; if (comboBox->isEnabled()) { getFileAtIndex(i, matrixFile, - trajFile); + trajFile, + metricDynConnFile, + volDynConnFile); } if (trajFile != NULL) { @@ -361,18 +420,28 @@ CiftiConnectivityMatrixViewController::enabledCheckBoxClicked(int indx) CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; - + VolumeDynamicConnectivityFile* volDynConnFile(NULL); + MetricDynamicConnectivityFile* metricDynConnFile(NULL); + getFileAtIndex(indx, matrixFile, - trajFile); + trajFile, + metricDynConnFile, + volDynConnFile); if (matrixFile != NULL) { matrixFile->setMapDataLoadingEnabled(0, newStatus); } + else if (metricDynConnFile != NULL) { + metricDynConnFile->setDataLoadingEnabled(newStatus); + } else if (trajFile != NULL) { trajFile->setDataLoadingEnabled(newStatus); } + else if (volDynConnFile != NULL) { + volDynConnFile->setDataLoadingEnabled(newStatus); + } else { CaretAssertMessage(0, "Has a new file type been added?"); } @@ -394,10 +463,14 @@ CiftiConnectivityMatrixViewController::layerCheckBoxClicked(int indx) CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; - + MetricDynamicConnectivityFile* metricDynConnFile(NULL); + VolumeDynamicConnectivityFile* volDynConnFile(NULL); + getFileAtIndex(indx, matrixFile, - trajFile); + trajFile, + metricDynConnFile, + volDynConnFile); if (matrixFile != NULL) { CiftiConnectivityMatrixDenseDynamicFile* dynConnFile = dynamic_cast(matrixFile); @@ -405,6 +478,12 @@ CiftiConnectivityMatrixViewController::layerCheckBoxClicked(int indx) dynConnFile->setEnabledAsLayer(newStatus); } } + else if (metricDynConnFile != NULL) { + metricDynConnFile->setEnabledAsLayer(newStatus); + } + else if (volDynConnFile != NULL) { + volDynConnFile->setEnabledAsLayer(newStatus); + } else if (trajFile != NULL) { CaretAssertMessage(0, "Should never get caled for fiber trajectory file"); } @@ -428,18 +507,26 @@ CiftiConnectivityMatrixViewController::layerCheckBoxClicked(int indx) * If there is a CIFTI matrix file at the given index, this will be non-NULL. * @param ciftiTrajFileOut * If there is a CIFTI trajectory file at the given index, this will be non-NULL. + * @param metricDynConnFileOut + * If there is a Metric Dynamic file at the given index, this will be non-NULL + * @param volDynConnFileOut + * If there is a volume dynamnic connectivity files at the given index, this will be non-NULL */ void CiftiConnectivityMatrixViewController::getFileAtIndex(const int32_t indx, CiftiMappableConnectivityMatrixDataFile* &ciftiMatrixFileOut, - CiftiFiberTrajectoryFile* &ciftiTrajFileOut) + CiftiFiberTrajectoryFile* &ciftiTrajFileOut, + MetricDynamicConnectivityFile* &metricDynConnFileOut, + VolumeDynamicConnectivityFile* &volDynConnFileOut) { CaretAssertVectorIndex(m_fileEnableCheckBoxes, indx); void* ptr = m_fileEnableCheckBoxes[indx]->property(FILE_POINTER_PROPERTY_NAME).value(); CaretMappableDataFile* mapFilePointer = (CaretMappableDataFile*)ptr; - ciftiMatrixFileOut = dynamic_cast(mapFilePointer); - ciftiTrajFileOut = dynamic_cast(mapFilePointer); + ciftiMatrixFileOut = dynamic_cast(mapFilePointer); + ciftiTrajFileOut = dynamic_cast(mapFilePointer); + metricDynConnFileOut = dynamic_cast(mapFilePointer); + volDynConnFileOut = dynamic_cast(mapFilePointer); AString name = ""; if (mapFilePointer != NULL) { @@ -462,6 +549,12 @@ CiftiConnectivityMatrixViewController::getFileAtIndex(const int32_t indx, else if (ciftiTrajFileOut != NULL) { /* OK */ } + else if (metricDynConnFileOut != NULL) { + /* OK */ + } + else if (volDynConnFileOut != NULL) { + /* OK */ + } else { CaretAssertMessage(0, "Has a new file type been added?"); @@ -481,10 +574,14 @@ CiftiConnectivityMatrixViewController::fiberOrientationFileComboBoxActivated(int CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; + MetricDynamicConnectivityFile* metricDynConnFile(NULL); + VolumeDynamicConnectivityFile* volDynConnFile(NULL); getFileAtIndex(indx, matrixFile, - trajFile); + trajFile, + metricDynConnFile, + volDynConnFile); CaretAssertMessage(trajFile, "Selected orientation file but trajectory file is invalid."); @@ -526,10 +623,14 @@ CiftiConnectivityMatrixViewController::copyToolButtonClicked(int indx) CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; - + MetricDynamicConnectivityFile* metricDynConnFile(NULL); + VolumeDynamicConnectivityFile* volDynConnFile(NULL); + getFileAtIndex(indx, matrixFile, - trajFile); + trajFile, + metricDynConnFile, + volDynConnFile); bool errorFlag = false; @@ -554,6 +655,38 @@ CiftiConnectivityMatrixViewController::copyToolButtonClicked(int indx) errorFlag = true; } } + else if (volDynConnFile != NULL) { + VolumeFile* newVolumeFile = volDynConnFile->newVolumeFileFromLoadedData(directoryName, + errorMessage); + if (newVolumeFile != NULL) { + EventDataFileAdd dataFileAdd(newVolumeFile); + EventManager::get()->sendEvent(dataFileAdd.getPointer()); + + if (dataFileAdd.isError()) { + errorMessage = dataFileAdd.getErrorMessage(); + errorFlag = true; + } + } + else { + errorFlag = true; + } + } + else if (metricDynConnFile != NULL) { + MetricFile* newMetricFile = metricDynConnFile->newMetricFileFromLoadedData(directoryName, + errorMessage); + if (newMetricFile != NULL) { + EventDataFileAdd dataFileAdd(newMetricFile); + EventManager::get()->sendEvent(dataFileAdd.getPointer()); + + if (dataFileAdd.isError()) { + errorMessage = dataFileAdd.getErrorMessage(); + errorFlag = true; + } + } + else { + errorFlag = true; + } + } else if (trajFile != NULL) { CiftiFiberTrajectoryFile* newTrajFile = trajFile->newFiberTrajectoryFileFromLoadedRowData(directoryName, errorMessage); diff --git a/src/GuiQt/CiftiConnectivityMatrixViewController.h b/src/GuiQt/CiftiConnectivityMatrixViewController.h index 89f53378f1c9144f30d4aaca72951f9221f43244..d0bdd3da15a1f723efac72c382766bdb1527c288 100644 --- a/src/GuiQt/CiftiConnectivityMatrixViewController.h +++ b/src/GuiQt/CiftiConnectivityMatrixViewController.h @@ -38,13 +38,15 @@ namespace caret { class CiftiMappableConnectivityMatrixDataFile; class CiftiFiberTrajectoryFile; + class MetricDynamicConnectivityFile; + class VolumeDynamicConnectivityFile; class CiftiConnectivityMatrixViewController : public QWidget, EventListenerInterface { Q_OBJECT public: - CiftiConnectivityMatrixViewController(const Qt::Orientation orientation, + CiftiConnectivityMatrixViewController(const QString& parentObjectName, QWidget* parent); virtual ~CiftiConnectivityMatrixViewController(); @@ -75,7 +77,11 @@ namespace caret { void getFileAtIndex(const int32_t indx, CiftiMappableConnectivityMatrixDataFile* &ciftiMatrixFileOut, - CiftiFiberTrajectoryFile* &ciftiTrajFileOut); + CiftiFiberTrajectoryFile* &ciftiTrajFileOut, + MetricDynamicConnectivityFile* &metricDynConnFileOut, + VolumeDynamicConnectivityFile* &volDynConnFileOut); + + const QString m_objectNamePrefix; std::vector m_fileEnableCheckBoxes; diff --git a/src/GuiQt/CopyPaletteColorMappingToFilesDialog.cxx b/src/GuiQt/CopyPaletteColorMappingToFilesDialog.cxx index 627b16b6f3e344336e3a79708adf0d80ee3f9bc9..546b5ca7497f38334f67d2a1b75c0f030e0b399c 100644 --- a/src/GuiQt/CopyPaletteColorMappingToFilesDialog.cxx +++ b/src/GuiQt/CopyPaletteColorMappingToFilesDialog.cxx @@ -165,6 +165,7 @@ CopyPaletteColorMappingToFilesDialog::okButtonClicked() if (checkBox->isChecked()) { if (mapFile != m_selectedMapFile) { + ++checkedCount; mapFile->setPaletteNormalizationMode(m_selectedMapFile->getPaletteNormalizationMode()); const int32_t numMaps = mapFile->getNumberOfMaps(); @@ -172,9 +173,8 @@ CopyPaletteColorMappingToFilesDialog::okButtonClicked() PaletteColorMapping* pcm = mapFile->getMapPaletteColorMapping(iMap); pcm->copy(*m_selectedPaletteColorMapping, false); - mapFile->updateScalarColoringForAllMaps(); - ++checkedCount; } + mapFile->updateScalarColoringForAllMaps(); } else { sourceFileFlag = true; diff --git a/src/GuiQt/DisplayGroupAndTabItemViewController.cxx b/src/GuiQt/DisplayGroupAndTabItemViewController.cxx index 0fe90256ae45071c8774cb7030dd5b3f2dc518ac..8ac882c00d4193996db90ec76c21188cdd3fa2bb 100644 --- a/src/GuiQt/DisplayGroupAndTabItemViewController.cxx +++ b/src/GuiQt/DisplayGroupAndTabItemViewController.cxx @@ -23,7 +23,10 @@ #include "DisplayGroupAndTabItemViewController.h" #undef __DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_DECLARE__ +#include +#include #include +#include #include #include "Annotation.h" @@ -66,9 +69,32 @@ DisplayGroupAndTabItemViewController::DisplayGroupAndTabItemViewController(const m_dataFileType(dataFileType), m_browserWindowIndex(browserWindowIndex) { + const QString onOffToolTip("" + "To select more than one item:
" + "* For a contiguous selection, click an item " + "and then click another item while holding down " + "the SHIFT key.
" + "* For non-contiguous selection, select items while " + "holding down the CTRL key (Command key on Apple)" + ""); + m_turnOnSelectedItemsAction = new QAction("On"); + m_turnOnSelectedItemsAction->setToolTip(onOffToolTip); + m_turnOnSelectedItemsAction->setCheckable(false); + QObject::connect(m_turnOnSelectedItemsAction, &QAction::triggered, + this, &DisplayGroupAndTabItemViewController::turnOnSelectedItemsTriggered); + QToolButton* turnOnToolButton = new QToolButton(); + turnOnToolButton->setDefaultAction(m_turnOnSelectedItemsAction); + + m_turnOffSelectedItemsAction = new QAction("Off"); + m_turnOffSelectedItemsAction->setToolTip(onOffToolTip); + m_turnOffSelectedItemsAction->setCheckable(false); + QObject::connect(m_turnOffSelectedItemsAction, &QAction::triggered, + this, &DisplayGroupAndTabItemViewController::turnOffSelectedItemsTriggered); + QToolButton* turnOffToolButton = new QToolButton(); + turnOffToolButton->setDefaultAction(m_turnOffSelectedItemsAction); + m_treeWidget = new QTreeWidget(); m_treeWidget->setHeaderHidden(true); - //m_treeWidget->setSelectionMode(QTreeWidget::ExtendedSelection); m_treeWidget->setSelectionMode(QTreeWidget::NoSelection); QObject::connect(m_treeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem*)), @@ -79,8 +105,20 @@ m_browserWindowIndex(browserWindowIndex) this, SLOT(itemWasChanged(QTreeWidgetItem*, int))); QObject::connect(m_treeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemsWereSelected())); + m_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); + QObject::connect(m_treeWidget, &QTreeWidget::customContextMenuRequested, + this, &DisplayGroupAndTabItemViewController::displayContextMenu); + + QHBoxLayout* buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->addWidget(new QLabel("Selected Items: ")); + buttonLayout->addWidget(turnOnToolButton); + buttonLayout->addSpacing(5); + buttonLayout->addWidget(turnOffToolButton); + buttonLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(this); + layout->addLayout(buttonLayout); layout->addWidget(m_treeWidget, 100); s_allViewControllers.insert(this); @@ -102,6 +140,7 @@ DisplayGroupAndTabItemViewController::itemsWereSelected() { QList itemsSelected = m_treeWidget->selectedItems(); + if ( ! itemsSelected.empty()) { std::vector itemInterfacesVector; @@ -129,11 +168,39 @@ DisplayGroupAndTabItemViewController::itemsWereSelected() getDisplayGroupAndTabIndex(displayGroup, tabIndex); updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); - //updateSelectedAndExpandedCheckboxesInOtherViewControllers(); updateGraphics(); } +/** + * Display a context sensitive (right-click) menu. + * + * @param pos + * Position for context menu + */ +void +DisplayGroupAndTabItemViewController::displayContextMenu(const QPoint& pos) +{ + QList itemsSelected = m_treeWidget->selectedItems(); + + if (itemsSelected.isEmpty()) { + return; + } + + QMenu menu(this); + QAction* onAction = menu.addAction("Turn all selected items ON"); + menu.addAction("Turn all selected items OFF"); + + QSignalBlocker blocker(m_treeWidget); + QAction* selectedAction = menu.exec(m_treeWidget->mapToGlobal(pos)); + if (selectedAction == NULL) { + return; + } + + const bool newStatus = (selectedAction == onAction); + setCheckedStatusOfSelectedItems(newStatus); +} + /** * Process the selection of annotations. * @@ -414,6 +481,10 @@ DisplayGroupAndTabItemViewController::updateSelectedAndExpandedCheckboxes(const } } + const bool itemsSelectedFlag = ( ! m_treeWidget->selectedItems().isEmpty()); + m_turnOnSelectedItemsAction->setEnabled(itemsSelectedFlag); + m_turnOffSelectedItemsAction->setEnabled(itemsSelectedFlag); + m_treeWidget->blockSignals(false); } @@ -442,3 +513,61 @@ DisplayGroupAndTabItemViewController::updateSelectedAndExpandedCheckboxesInOther } } +/** + * Turn on all selected items + */ +void +DisplayGroupAndTabItemViewController::turnOnSelectedItemsTriggered() +{ + setCheckedStatusOfSelectedItems(true); +} + +/** + * Turn off all selected items + */ +void +DisplayGroupAndTabItemViewController::turnOffSelectedItemsTriggered() +{ + setCheckedStatusOfSelectedItems(false); +} + +/** + * Set the checked status of all selected itemsj + * + * @param checkedStatus + * Checked status + */ +void +DisplayGroupAndTabItemViewController::setCheckedStatusOfSelectedItems(const bool checkedStatus) +{ + QList itemsSelected = m_treeWidget->selectedItems(); + + if (itemsSelected.isEmpty()) { + return; + } + + DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::DISPLAY_GROUP_TAB; + int32_t tabIndex = -1; + getDisplayGroupAndTabIndex(displayGroup, tabIndex); + + + const Qt::CheckState newCheckState = (checkedStatus + ? Qt::Checked + : Qt::Unchecked); + QListIterator iter(itemsSelected); + while (iter.hasNext()) { + QTreeWidgetItem* item = iter.next(); + DisplayGroupAndTabItemInterface* dataItem = getDataItem(item); + + const TriStateSelectionStatusEnum::Enum itemCheckState = DisplayGroupAndTabItemTreeWidgetItem::fromQCheckState(newCheckState); + dataItem->setItemDisplaySelected(displayGroup, + tabIndex, + itemCheckState); + } + + updateSelectedAndExpandedCheckboxes(displayGroup, + tabIndex); + updateSelectedAndExpandedCheckboxesInOtherViewControllers(); + + updateGraphics();} + diff --git a/src/GuiQt/DisplayGroupAndTabItemViewController.h b/src/GuiQt/DisplayGroupAndTabItemViewController.h index 48ddc927cfa4aca242ca89899cb3b5903adfcd73..54658c8b8a50c07179fd09b66ccef3ff6e391d51 100644 --- a/src/GuiQt/DisplayGroupAndTabItemViewController.h +++ b/src/GuiQt/DisplayGroupAndTabItemViewController.h @@ -28,6 +28,7 @@ #include "DataFileTypeEnum.h" #include "DisplayGroupEnum.h" +class QAction; class QTreeWidget; class QTreeWidgetItem; namespace caret { @@ -63,6 +64,12 @@ namespace caret { void itemsWereSelected(); + void displayContextMenu(const QPoint& pos); + + void turnOnSelectedItemsTriggered(); + + void turnOffSelectedItemsTriggered(); + private: DisplayGroupAndTabItemViewController(const DisplayGroupAndTabItemViewController&); @@ -87,12 +94,18 @@ namespace caret { void updateSelectedAndExpandedCheckboxesInOtherViewControllers(); + void setCheckedStatusOfSelectedItems(const bool checkedFlag); + const DataFileTypeEnum::Enum m_dataFileType; const int32_t m_browserWindowIndex; QTreeWidget* m_treeWidget; + QAction* m_turnOnSelectedItemsAction; + + QAction* m_turnOffSelectedItemsAction; + static std::set s_allViewControllers; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/DisplayGroupEnumComboBox.cxx b/src/GuiQt/DisplayGroupEnumComboBox.cxx index 4d12ab471be0657066a9f2ff6d83385437c7f3ad..07ea86299072009d6a3bd2aa87d40e14eac986b4 100644 --- a/src/GuiQt/DisplayGroupEnumComboBox.cxx +++ b/src/GuiQt/DisplayGroupEnumComboBox.cxx @@ -25,6 +25,8 @@ #include "DisplayGroupEnumComboBox.h" #undef __DISPLAY_GROUP_ENUM_COMBO_BOX_DECLARE__ +#include "WuQMacroManager.h" + using namespace caret; @@ -46,6 +48,40 @@ using namespace caret; * Parent object. */ DisplayGroupEnumComboBox::DisplayGroupEnumComboBox(QObject* parent) +: DisplayGroupEnumComboBox(parent, + "", + "") +{ + +} +//: WuQWidget(parent) +//{ +// std::vector allDisplayGroups; +// DisplayGroupEnum::getAllEnums(allDisplayGroups); +// const int32_t numStructures = static_cast(allDisplayGroups.size()); +// +// this->displayGroupComboBox = new QComboBox(); +// for (int32_t i = 0; i < numStructures; i++) { +// this->displayGroupComboBox->addItem(DisplayGroupEnum::toGuiName(allDisplayGroups[i])); +// this->displayGroupComboBox->setItemData(i, DisplayGroupEnum::toIntegerCode(allDisplayGroups[i])); +// } +// +// QObject::connect(this->displayGroupComboBox, SIGNAL(activated(int)), +// this, SLOT(displayGroupComboBoxSelection(int))); +//} + +/** + * Constructor. + * @param Parent + * Parent object. + * @param objectNameForMacros + * Name of object for macros + * @param descriptiveNameForMacros + * Descriptive name for macros + */ +DisplayGroupEnumComboBox::DisplayGroupEnumComboBox(QObject* parent, + const QString& objectNameForMacros, + const QString& descriptiveNameForMacros) : WuQWidget(parent) { std::vector allDisplayGroups; @@ -60,6 +96,13 @@ DisplayGroupEnumComboBox::DisplayGroupEnumComboBox(QObject* parent) QObject::connect(this->displayGroupComboBox, SIGNAL(activated(int)), this, SLOT(displayGroupComboBoxSelection(int))); + + if ( ! objectNameForMacros.isEmpty()) { + this->displayGroupComboBox->setToolTip("Select Display Group"); + this->displayGroupComboBox->setObjectName(objectNameForMacros); + WuQMacroManager::instance()->addMacroSupportToObject(this->displayGroupComboBox, + "Select display group for " + descriptiveNameForMacros); + } } /** diff --git a/src/GuiQt/DisplayGroupEnumComboBox.h b/src/GuiQt/DisplayGroupEnumComboBox.h index d779b9a5145a7175b4c22c3786e8c13795b3f636..6141fb56a81d871a64bcf1f9fc8c7e7e74811155 100644 --- a/src/GuiQt/DisplayGroupEnumComboBox.h +++ b/src/GuiQt/DisplayGroupEnumComboBox.h @@ -34,6 +34,10 @@ namespace caret { public: DisplayGroupEnumComboBox(QObject* parent); + DisplayGroupEnumComboBox(QObject* parent, + const QString& objectNameForMacros, + const QString& descriptiveNameForMacros); + virtual ~DisplayGroupEnumComboBox(); DisplayGroupEnum::Enum getSelectedDisplayGroup() const; diff --git a/src/GuiQt/EventBrowserWindowTileTabOperation.cxx b/src/GuiQt/EventBrowserWindowTileTabOperation.cxx index 52a52281a163968093b0f98d04fa6ff4ef4246e6..9cd4f3788f39b03557d9e7670dfea823ac6f4c19 100644 --- a/src/GuiQt/EventBrowserWindowTileTabOperation.cxx +++ b/src/GuiQt/EventBrowserWindowTileTabOperation.cxx @@ -54,16 +54,30 @@ using namespace caret; EventBrowserWindowTileTabOperation::EventBrowserWindowTileTabOperation(const Operation operation, QWidget* parentWidget, const int32_t windowIndex, - const int32_t browserTabIndex) + const int32_t browserTabIndex, + const std::vector& browserTabsForReplaceOperation) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION), m_operation(operation), m_parentWidget(parentWidget), m_windowIndex(windowIndex), -m_browserTabIndex(browserTabIndex) +m_browserTabIndex(browserTabIndex), +m_browserTabsForReplaceOperation(browserTabsForReplaceOperation) { CaretAssert(m_parentWidget); CaretAssert(m_windowIndex >= 0); - CaretAssert(m_browserTabIndex >= 0); + switch (m_operation) { + case OPERATION_NEW_TAB_AFTER: + CaretAssert(m_browserTabIndex >= 0); + break; + case OPERATION_NEW_TAB_BEFORE: + CaretAssert(m_browserTabIndex >= 0); + break; + case OPERATION_REPLACE_TABS: + break; + case OPERATION_SELECT_TAB: + CaretAssert(m_browserTabIndex >= 0); + break; + } } /** @@ -88,10 +102,12 @@ EventBrowserWindowTileTabOperation::selectTabInWindow(QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex) { + std::vector emptyBrowserTabs; EventBrowserWindowTileTabOperation tabOperation(Operation::OPERATION_SELECT_TAB, parentWidget, windowIndex, - browserTabIndex); + browserTabIndex, + emptyBrowserTabs); EventManager::get()->sendEvent(tabOperation.getPointer()); @@ -128,4 +144,13 @@ EventBrowserWindowTileTabOperation::getBrowserTabIndex() const return m_browserTabIndex; } +/** + * @return Get the browser tabs for a replace tabs operation. + */ +const std::vector +EventBrowserWindowTileTabOperation::getBrowserTabsForReplaceOperation() const +{ + return m_browserTabsForReplaceOperation; +} + diff --git a/src/GuiQt/EventBrowserWindowTileTabOperation.h b/src/GuiQt/EventBrowserWindowTileTabOperation.h index 39540e96e610c51e6dd3ac45df914812c2607560..87a6aa0de847057a93ff47514d1ff15d2a7e25af 100644 --- a/src/GuiQt/EventBrowserWindowTileTabOperation.h +++ b/src/GuiQt/EventBrowserWindowTileTabOperation.h @@ -24,6 +24,7 @@ #include +#include #include "Event.h" @@ -31,6 +32,8 @@ class QWidget; namespace caret { + class BrowserTabContent; + class EventBrowserWindowTileTabOperation : public Event { public: @@ -40,13 +43,15 @@ namespace caret { enum Operation { OPERATION_NEW_TAB_AFTER, OPERATION_NEW_TAB_BEFORE, + OPERATION_REPLACE_TABS, OPERATION_SELECT_TAB }; EventBrowserWindowTileTabOperation(const Operation operation, QWidget* parentWidget, const int32_t windowIndex, - const int32_t browserTabIndex); + const int32_t browserTabIndex, + const std::vector& browserTabsForReplaceOperation); virtual ~EventBrowserWindowTileTabOperation(); @@ -56,6 +61,8 @@ namespace caret { int32_t getBrowserTabIndex() const; + const std::vector getBrowserTabsForReplaceOperation() const; + // ADD_NEW_METHODS_HERE private: @@ -71,6 +78,8 @@ namespace caret { const int32_t m_browserTabIndex; + const std::vector m_browserTabsForReplaceOperation; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/EventGetOrSetUserInputModeProcessor.cxx b/src/GuiQt/EventGetOrSetUserInputModeProcessor.cxx index aa8a9edb61e022d9eab5a25efd63405bb9e17095..3ca428eccf4c8a6173488ed1648d09354300670b 100644 --- a/src/GuiQt/EventGetOrSetUserInputModeProcessor.cxx +++ b/src/GuiQt/EventGetOrSetUserInputModeProcessor.cxx @@ -36,7 +36,7 @@ using namespace caret; * The requested input mode. */ EventGetOrSetUserInputModeProcessor::EventGetOrSetUserInputModeProcessor(const int32_t windowIndex, - const UserInputModeAbstract::UserInputMode userInputMode) + const UserInputModeEnum::Enum userInputMode) : Event(EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE) { this->userInputProcessor = NULL; @@ -55,7 +55,7 @@ EventGetOrSetUserInputModeProcessor::EventGetOrSetUserInputModeProcessor(const i : Event(EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE) { this->userInputProcessor = NULL; - this->userInputMode = UserInputModeAbstract::INVALID; + this->userInputMode = UserInputModeEnum::INVALID; this->windowIndex = windowIndex; this->modeGetOrSet = GET; } @@ -79,7 +79,7 @@ EventGetOrSetUserInputModeProcessor::getWindowIndex() const /** * @return The requested input mode. */ -UserInputModeAbstract::UserInputMode +UserInputModeEnum::Enum EventGetOrSetUserInputModeProcessor::getUserInputMode() const { return this->userInputMode; diff --git a/src/GuiQt/EventGetOrSetUserInputModeProcessor.h b/src/GuiQt/EventGetOrSetUserInputModeProcessor.h index e2437105d4e2e9bb295de04f990a35a1952f7454..b12f7a1973d44eca9598b69456bf06233243e24e 100644 --- a/src/GuiQt/EventGetOrSetUserInputModeProcessor.h +++ b/src/GuiQt/EventGetOrSetUserInputModeProcessor.h @@ -32,7 +32,7 @@ namespace caret { public: EventGetOrSetUserInputModeProcessor(const int32_t windowIndex, - const UserInputModeAbstract::UserInputMode userInputMode); + const UserInputModeEnum::Enum userInputMode); EventGetOrSetUserInputModeProcessor(const int32_t windowIndex); @@ -44,7 +44,7 @@ namespace caret { int32_t getWindowIndex() const; - UserInputModeAbstract::UserInputMode getUserInputMode() const; + UserInputModeEnum::Enum getUserInputMode() const; void setUserInputProcessor(UserInputModeAbstract* userInputProcessor); @@ -64,7 +64,7 @@ namespace caret { UserInputModeAbstract* userInputProcessor; /** Requested input mode for SETTING and set when GETTING*/ - UserInputModeAbstract::UserInputMode userInputMode; + UserInputModeEnum::Enum userInputMode; /** index of window for update */ int32_t windowIndex; diff --git a/src/GuiQt/EventGraphicsTimingOneWindow.cxx b/src/GuiQt/EventGraphicsTimingOneWindow.cxx new file mode 100644 index 0000000000000000000000000000000000000000..31db78d7b25e3cb6ffc01401f12f0c6d27646ee8 --- /dev/null +++ b/src/GuiQt/EventGraphicsTimingOneWindow.cxx @@ -0,0 +1,67 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ +#include "EventGraphicsTimingOneWindow.h" +#undef __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventGraphicsTimingOneWindow + * \brief Event for timing graphics + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param windowIndex + * Index of window for timing + */ +EventGraphicsTimingOneWindow::EventGraphicsTimingOneWindow(const int32_t windowIndex) +: Event(EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW), +m_windowIndex(windowIndex) +{ + +} + +/** + * Destructor. + */ +EventGraphicsTimingOneWindow::~EventGraphicsTimingOneWindow() +{ +} + +/** + * @return Index of window for timinig test + */ +int32_t +EventGraphicsTimingOneWindow::getWindowIndex() const +{ + return m_windowIndex; +} + diff --git a/src/GuiQt/EventGraphicsTimingOneWindow.h b/src/GuiQt/EventGraphicsTimingOneWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..2ad53dd4027b18a333aad0990414614df7dc40d2 --- /dev/null +++ b/src/GuiQt/EventGraphicsTimingOneWindow.h @@ -0,0 +1,61 @@ +#ifndef __EVENT_GRAPHICS_TIMING_ONE_WINDOW_H__ +#define __EVENT_GRAPHICS_TIMING_ONE_WINDOW_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class EventGraphicsTimingOneWindow : public Event { + + public: + EventGraphicsTimingOneWindow(const int32_t windowIndex); + + virtual ~EventGraphicsTimingOneWindow(); + + EventGraphicsTimingOneWindow(const EventGraphicsTimingOneWindow&) = delete; + + EventGraphicsTimingOneWindow& operator=(const EventGraphicsTimingOneWindow&) = delete; + + int32_t getWindowIndex() const; + + // ADD_NEW_METHODS_HERE + + private: + int32_t m_windowIndex; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ + // +#endif // __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ + +} // namespace +#endif //__EVENT_GRAPHICS_TIMING_ONE_WINDOW_H__ diff --git a/src/GuiQt/EventMovieManualModeRecording.cxx b/src/GuiQt/EventMovieManualModeRecording.cxx new file mode 100644 index 0000000000000000000000000000000000000000..480e297704295b488b005173350ce23666f23721 --- /dev/null +++ b/src/GuiQt/EventMovieManualModeRecording.cxx @@ -0,0 +1,80 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ +#include "EventMovieManualModeRecording.h" +#undef __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventMovieManualModeRecording + * \brief Manual mode recording image capture + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param browserWindowIndex + * Index of the browser window + * @param durationSeconds + * Time in seconds for manual recording (used with movie recording frame + * rate to determine number of images captured) + */ +EventMovieManualModeRecording::EventMovieManualModeRecording(const int32_t browserWindowIndex, + const float durationSeconds) +: Event(EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE), +m_browserWindowIndex(browserWindowIndex), +m_durationSeconds(durationSeconds) +{ + +} + +/** + * Destructor. + */ +EventMovieManualModeRecording::~EventMovieManualModeRecording() +{ +} + +/** + * @return Index of browser window or negative for all windows + */ +int32_t +EventMovieManualModeRecording::getBrowserWindowIndex() const +{ + return m_browserWindowIndex; +} + +/** + * @return Duration in seconds + */ +float +EventMovieManualModeRecording::getDurationSeconds() const +{ + return m_durationSeconds; +} diff --git a/src/GuiQt/EventMovieManualModeRecording.h b/src/GuiQt/EventMovieManualModeRecording.h new file mode 100644 index 0000000000000000000000000000000000000000..4631ac7a3e82e6b87678783e73ed3cfbd972d0da --- /dev/null +++ b/src/GuiQt/EventMovieManualModeRecording.h @@ -0,0 +1,66 @@ +#ifndef __EVENT_MOVIE_MANUAL_MODE_RECORDING_H__ +#define __EVENT_MOVIE_MANUAL_MODE_RECORDING_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class EventMovieManualModeRecording : public Event { + + public: + EventMovieManualModeRecording(const int32_t browserWindowIndex, + const float durationSeconds); + + virtual ~EventMovieManualModeRecording(); + + EventMovieManualModeRecording(const EventMovieManualModeRecording&) = delete; + + EventMovieManualModeRecording& operator=(const EventMovieManualModeRecording&) = delete; + + int32_t getBrowserWindowIndex() const; + + float getDurationSeconds() const; + + // ADD_NEW_METHODS_HERE + + private: + const int32_t m_browserWindowIndex; + + const float m_durationSeconds; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ + // +#endif // __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ + +} // namespace +#endif //__EVENT_MOVIE_MANUAL_MODE_RECORDING_H__ diff --git a/src/GuiQt/FociProjectionDialog.cxx b/src/GuiQt/FociProjectionDialog.cxx index dde8958a35dcfe2e9f19be2f064a38de2b85fc6c..ac79f9081d7e6970b1f2d2b09c736c099efe6409 100644 --- a/src/GuiQt/FociProjectionDialog.cxx +++ b/src/GuiQt/FociProjectionDialog.cxx @@ -61,6 +61,8 @@ FociProjectionDialog::FociProjectionDialog(QWidget* parent) : WuQDialogModal("Project Foci", parent) { + m_objectNamePrefix = "FociProjectDialog"; + QWidget* surfaceWidget = NULL; //createSurfaceSelectionWidget(); QWidget* fociFileWidget = createFociFileSelectionWidget(); @@ -205,7 +207,9 @@ FociProjectionDialog::createSurfaceSelectionWidget() if (leftBrainStructure != NULL) { m_leftSurfaceCheckBox = new QCheckBox("Left: "); m_leftSurfaceCheckBox->setChecked(true); - m_leftSurfaceViewController = new SurfaceSelectionViewController(this, leftBrainStructure); + m_leftSurfaceViewController = new SurfaceSelectionViewController(this, leftBrainStructure, + (m_objectNamePrefix + ":LeftSurface"), + "foci projection left"); m_leftSurfaceViewController->updateControl(); } @@ -214,7 +218,9 @@ FociProjectionDialog::createSurfaceSelectionWidget() if (rightBrainStructure != NULL) { m_rightSurfaceCheckBox = new QCheckBox("Right: "); m_rightSurfaceCheckBox->setChecked(true); - m_rightSurfaceViewController = new SurfaceSelectionViewController(this, rightBrainStructure); + m_rightSurfaceViewController = new SurfaceSelectionViewController(this, rightBrainStructure, + (m_objectNamePrefix + ":RightSurface"), + "foci projection right"); m_rightSurfaceViewController->updateControl(); } @@ -224,7 +230,9 @@ FociProjectionDialog::createSurfaceSelectionWidget() m_cerebellumSurfaceCheckBox = new QCheckBox("Cerebellum: "); m_cerebellumSurfaceCheckBox->setChecked(true); m_cerebellumSurfaceViewController = new SurfaceSelectionViewController(this, - cerebellumBrainStructure); + cerebellumBrainStructure, + (m_objectNamePrefix + ":CerebellumSurface"), + "foci projection cerebellum"); m_cerebellumSurfaceViewController->updateControl(); } diff --git a/src/GuiQt/FociProjectionDialog.h b/src/GuiQt/FociProjectionDialog.h index 1b9564933cbf52209ba8d80b1de88c74f35945a7..e4f36308d9a9180ee5e2e56d69377389ffbc4d8b 100644 --- a/src/GuiQt/FociProjectionDialog.h +++ b/src/GuiQt/FociProjectionDialog.h @@ -57,6 +57,8 @@ namespace caret { QWidget* createOptionsWidget(); + QString m_objectNamePrefix; + QCheckBox* m_leftSurfaceCheckBox; SurfaceSelectionViewController* m_leftSurfaceViewController; diff --git a/src/GuiQt/FociSelectionViewController.cxx b/src/GuiQt/FociSelectionViewController.cxx index 2667e418e119618d3ff8837efed97cf8828ae700..e5888c340c241003b1f626e16c727ef077f2a7c8 100644 --- a/src/GuiQt/FociSelectionViewController.cxx +++ b/src/GuiQt/FociSelectionViewController.cxx @@ -50,6 +50,7 @@ #include "SceneClass.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQTabWidget.h" #include "WuQTrueFalseComboBox.h" #include "WuQtUtilities.h" @@ -69,10 +70,20 @@ using namespace caret; /** * Constructor. + * + * @param browserWindowIndex + * Index of browser window + * @param parentObjectName + * Name of parent object + * @param parent + * The parent object */ FociSelectionViewController::FociSelectionViewController(const int32_t browserWindowIndex, - QWidget* parent) -: QWidget(parent) + const QString& parentObjectName, + QWidget* parent) +: QWidget(parent), +m_objectNamePrefix(parentObjectName + + ":Foci") { m_browserWindowIndex = browserWindowIndex; @@ -90,6 +101,10 @@ FociSelectionViewController::FociSelectionViewController(const int32_t browserWi m_fociDisplayCheckBox->setToolTip("Enable the display of foci"); QObject::connect(m_fociDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_fociDisplayCheckBox->setObjectName(m_objectNamePrefix + + ":DisplayFoci"); + WuQMacroManager::instance()->addMacroSupportToObject(m_fociDisplayCheckBox, + "Enable foci display"); QWidget* attributesWidget = this->createAttributesWidget(); QWidget* selectionWidget = this->createSelectionWidget(); @@ -101,6 +116,11 @@ FociSelectionViewController::FociSelectionViewController(const int32_t browserWi m_tabWidget->addTab(selectionWidget, "Selection"); m_tabWidget->setCurrentWidget(attributesWidget); + m_tabWidget->getTabBar()->setToolTip("Select foci tab"); + m_tabWidget->getTabBar()->setObjectName(m_objectNamePrefix + + ":Tab"); + WuQMacroManager::instance()->addMacroSupportToObject(m_tabWidget->getTabBar(), + "Select features toolbox foci tab"); QVBoxLayout* layout = new QVBoxLayout(this); //WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); @@ -125,11 +145,17 @@ FociSelectionViewController::~FociSelectionViewController() FociSelectionViewController::allFociSelectionViewControllers.erase(this); } - +/** + * @return New instance of foci selection widget + */ QWidget* FociSelectionViewController::createSelectionWidget() { - m_fociClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex); + m_fociClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex, + (m_objectNamePrefix + + ":Selection"), + "foci", + this); return m_fociClassNameHierarchyViewController; } @@ -140,15 +166,25 @@ FociSelectionViewController::createSelectionWidget() QWidget* FociSelectionViewController::createAttributesWidget() { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + m_fociContralateralCheckBox = new QCheckBox("Contralateral"); m_fociContralateralCheckBox->setToolTip("Enable display of foci from contralateral brain structure"); QObject::connect(m_fociContralateralCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_fociContralateralCheckBox->setObjectName(m_objectNamePrefix + + ":Contralateral"); + macroManager->addMacroSupportToObject(m_fociContralateralCheckBox, + "Enable contralateral foci"); m_pasteOntoSurfaceCheckBox = new QCheckBox("Paste Onto Surface"); m_pasteOntoSurfaceCheckBox->setToolTip("Place the foci onto the surface"); QObject::connect(m_pasteOntoSurfaceCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_pasteOntoSurfaceCheckBox->setObjectName(m_objectNamePrefix + + ":PasteOntoSurface"); + macroManager->addMacroSupportToObject(m_pasteOntoSurfaceCheckBox, + "Enable paste foci onto surface"); QLabel* coloringLabel = new QLabel("Coloring"); m_coloringTypeComboBox = new EnumComboBoxTemplate(this); @@ -157,9 +193,18 @@ FociSelectionViewController::createAttributesWidget() m_coloringTypeComboBox->getWidget()->setToolTip("Select the coloring assignment for foci"); QObject::connect(m_coloringTypeComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); + m_coloringTypeComboBox->getComboBox()->setObjectName(m_objectNamePrefix + + ":ColorType"); + macroManager->addMacroSupportToObject(m_coloringTypeComboBox->getComboBox(), + "Select foci color type"); QLabel* standardColorLabel = new QLabel("Standard Color"); - m_standardColorComboBox = new CaretColorEnumComboBox(this); + m_standardColorComboBox = new CaretColorEnumComboBox("", + QIcon(), + (m_objectNamePrefix + + ":Color"), + "Select foci standard color", + this); m_standardColorComboBox->getWidget()->setToolTip("Select the standard color"); QObject::connect(m_standardColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(processAttributesChanges())); @@ -178,6 +223,10 @@ FociSelectionViewController::createAttributesWidget() m_drawTypeComboBox->setToolTip("Select the drawing style of foci"); QObject::connect(m_drawTypeComboBox, SIGNAL(activated(int)), this, SLOT(processAttributesChanges())); + m_drawTypeComboBox->setObjectName(m_objectNamePrefix + + ":DrawingStyle"); + macroManager->addMacroSupportToObject(m_drawTypeComboBox, + "Select foci drawing style"); float minLineWidth = 0; float maxLineWidth = 1000; @@ -195,6 +244,10 @@ FociSelectionViewController::createAttributesWidget() m_sizeSpinBox->setSuffix("mm"); QObject::connect(m_sizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_sizeSpinBox->setObjectName(m_objectNamePrefix + + ":Diameter"); + macroManager->addMacroSupportToObject(m_sizeSpinBox, + "Set foci size"); QWidget* gridWidget = new QWidget(); diff --git a/src/GuiQt/FociSelectionViewController.h b/src/GuiQt/FociSelectionViewController.h index d6700292bc172d2484d77ac70eb5d7ef2a120144..974be517767943200b81086d063625ec1742fcd8 100644 --- a/src/GuiQt/FociSelectionViewController.h +++ b/src/GuiQt/FociSelectionViewController.h @@ -48,7 +48,8 @@ namespace caret { public: FociSelectionViewController(const int32_t browserWindowIndex, - QWidget* parent = 0); + const QString& parentObjectName, + QWidget* parent = 0); virtual ~FociSelectionViewController(); @@ -82,6 +83,8 @@ namespace caret { QWidget* createAttributesWidget(); + const QString m_objectNamePrefix; + int32_t m_browserWindowIndex; GroupAndNameHierarchyViewController* m_fociClassNameHierarchyViewController; diff --git a/src/GuiQt/GroupAndNameHierarchyViewController.cxx b/src/GuiQt/GroupAndNameHierarchyViewController.cxx index 0239246aa28dba7048bbdab4145639387ea5cc78..d84daa230754977f179da045229febc96e2a584c 100644 --- a/src/GuiQt/GroupAndNameHierarchyViewController.cxx +++ b/src/GuiQt/GroupAndNameHierarchyViewController.cxx @@ -49,6 +49,7 @@ #include "GiftiLabelTable.h" #include "LabelFile.h" #include "VolumeFile.h" +#include "WuQMacroManager.h" #include "WuQTreeWidget.h" #include "WuQtUtilities.h" @@ -65,10 +66,19 @@ using namespace caret; /** * Constructor. + * + * @param browserWindowIndex + * Index of browser window + * @param objectNameForMacros + * Name of this object for macros + * @param descriptiveNameForMacros + * Descriptive name for macros * @param parent * Parent widget. */ GroupAndNameHierarchyViewController::GroupAndNameHierarchyViewController(const int32_t browserWindowIndex, + const QString& objectNameForMacros, + const QString& descriptiveNameForMacros, QWidget* parent) : QWidget(parent) { @@ -78,7 +88,8 @@ GroupAndNameHierarchyViewController::GroupAndNameHierarchyViewController(const i m_previousBrowserTabIndex = -1; m_browserWindowIndex = browserWindowIndex; - QWidget* allOnOffWidget = createAllOnOffControls(); + QWidget* allOnOffWidget = createAllOnOffControls(objectNameForMacros, + descriptiveNameForMacros); m_modelTreeWidgetLayout = new QVBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(m_modelTreeWidgetLayout, 0, 0); @@ -176,19 +187,37 @@ GroupAndNameHierarchyViewController::updateGraphics() /** * Create buttons for all on and off + * + * @param objectNameForMacros + * Name of this object for macros + * @param descriptiveNameForMacros + * Descriptive name for macros */ QWidget* -GroupAndNameHierarchyViewController::createAllOnOffControls() +GroupAndNameHierarchyViewController::createAllOnOffControls(const QString& objectNameForMacros, + const QString& descriptiveNameForMacros) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + QLabel* allLabel = new QLabel("All: "); QPushButton* onPushButton = new QPushButton("On"); + onPushButton->setToolTip("Turn all on"); + onPushButton->setObjectName(objectNameForMacros + + ":AllOn"); QObject::connect(onPushButton, SIGNAL(clicked()), this, SLOT(allOnPushButtonClicked())); + macroManager->addMacroSupportToObject(onPushButton, + "Turn on all in " + descriptiveNameForMacros + " selection"); QPushButton* offPushButton = new QPushButton("Off"); + offPushButton->setToolTip("Turn all of"); + offPushButton->setObjectName(objectNameForMacros + + ":AllOff"); QObject::connect(offPushButton, SIGNAL(clicked()), this, SLOT(allOffPushButtonClicked())); + macroManager->addMacroSupportToObject(offPushButton, + "Turn off all in " + descriptiveNameForMacros + " selection"); QWidget* w = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(w); diff --git a/src/GuiQt/GroupAndNameHierarchyViewController.h b/src/GuiQt/GroupAndNameHierarchyViewController.h index 9e0b7466f3ca080656e152b3ddd5175820b4d136..6e5cb85289563841191f96334712bb8a95883856 100644 --- a/src/GuiQt/GroupAndNameHierarchyViewController.h +++ b/src/GuiQt/GroupAndNameHierarchyViewController.h @@ -49,7 +49,9 @@ namespace caret { public: GroupAndNameHierarchyViewController(const int32_t browserWindowIndex, - QWidget* parent = 0); + const QString& objectNameForMacros, + const QString& descriptiveNameForMacros, + QWidget* parent); virtual ~GroupAndNameHierarchyViewController(); @@ -95,7 +97,8 @@ namespace caret { void createTreeWidget(); - QWidget* createAllOnOffControls(); + QWidget* createAllOnOffControls(const QString& objectNameForMacros, + const QString& descriptiveNameForMacros); void setAllSelected(bool selected); diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 37ca652874bb8a03d2452adaf14e2e6aa5683bd2..03c4444019ebfa03b0968e514ff0112f19322821 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #define __GUI_MANAGER_DEFINE__ @@ -59,6 +61,7 @@ #include "CursorManager.h" #include "CustomViewDialog.h" #include "DataFileException.h" +#include "DataToolTipsManager.h" #include "ElapsedTimer.h" #include "EventAlertUser.h" #include "EventAnnotationGetDrawnInWindow.h" @@ -92,16 +95,20 @@ #include "ImageFile.h" #include "ImageCaptureDialog.h" #include "InformationDisplayDialog.h" +#include "MetricDynamicConnectivityFile.h" #include "ModelChartTwo.h" #include "OverlaySettingsEditorDialog.h" #include "MacDockMenu.h" #include "MovieDialog.h" +#include "MovieRecordingDialog.h" #include "PaletteColorMappingEditorDialog.h" #include "PreferencesDialog.h" +#include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneDialog.h" +#include "SceneFile.h" #include "SceneWindowGeometry.h" #include "SelectionManager.h" #include "SelectionItemChartMatrix.h" @@ -117,7 +124,14 @@ #include "SurfacePropertiesEditorDialog.h" #include "Surface.h" #include "TileTabsConfigurationDialog.h" +#include "VolumeDynamicConnectivityFile.h" #include "VolumeMappableInterface.h" +#include "VolumePropertiesEditorDialog.h" +#include "WbMacroCustomOperationManager.h" +#include "WbMacroHelper.h" +#include "WuQMessageBox.h" +#include "WuQMacroManager.h" +#include "WuQMacroWidgetTypeEnum.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -169,6 +183,7 @@ GuiManager::initializeGuiManager() m_gapsAndMarginsDialog = NULL; this->imageCaptureDialog = NULL; this->movieDialog = NULL; + m_movieRecordingDialog = NULL; m_informationDisplayDialog = NULL; m_identifyBrainordinateDialog = NULL; this->preferencesDialog = NULL; @@ -178,10 +193,24 @@ GuiManager::initializeGuiManager() m_chartTwoLineSeriesHistoryDialog = NULL; this->sceneDialog = NULL; m_surfacePropertiesEditorDialog = NULL; + m_volumePropertiesEditorDialog = NULL; m_tileTabsConfigurationDialog = NULL; this->cursorManager = new CursorManager(); + /* + * When running macro commands, some object may be child + * of GuiManager and not found when searching a window + * for children objects + */ + WuQMacroWidgetTypeEnum::addWidgetClassNameAlias("QTabWidget", + "caret::WuQTabWidgetWithSizeHint"); + WuQMacroWidgetTypeEnum::addWidgetClassNameAlias("QTabBar", + "caret::WuQTabBar"); + WuQMacroManager::instance()->addParentObject(this); + WuQMacroManager::instance()->setMacroHelper(new WbMacroHelper(this)); + WuQMacroManager::instance()->setCustomCommandManager(new WbMacroCustomOperationManager()); + /* * Windows vector never changes size */ @@ -217,6 +246,9 @@ GuiManager::initializeGuiManager() this->showHideInfoWindowSelected(m_informationDisplayDialogEnabledAction->isChecked()); m_informationDisplayDialogEnabledAction->setIconText("Info"); m_informationDisplayDialogEnabledAction->blockSignals(false); + m_informationDisplayDialogEnabledAction->setObjectName("ToolBar:ShowInformationWindow"); + WuQMacroManager::instance()->addMacroSupportToObject(m_informationDisplayDialogEnabledAction, + "Display information window"); /* * Identify brainordinate window @@ -243,15 +275,17 @@ GuiManager::initializeGuiManager() m_identifyBrainordinateDialogEnabledAction->setCheckable(true); m_identifyBrainordinateDialogEnabledAction->setChecked(false); m_identifyBrainordinateDialogEnabledAction->blockSignals(false); + m_identifyBrainordinateDialogEnabledAction->setObjectName("ToolBar:ShowIdentifyBrainordinateWindow"); + WuQMacroManager::instance()->addMacroSupportToObject(m_identifyBrainordinateDialogEnabledAction, + "Display Identify Brainordinate Window"); /* * Scene dialog action */ - m_sceneDialogDisplayAction = WuQtUtilities::createAction("Scenes...", - "Show/Hide the Scenes Window", - this, - this, - SLOT(sceneDialogDisplayActionToggled(bool))); + m_sceneDialogDisplayAction = new QAction("Scenes...", + this); + QObject::connect(m_sceneDialogDisplayAction, &QAction::triggered, + this, &GuiManager::sceneDialogDisplayActionTriggered); QIcon clapBoardIcon; const bool clapBoardIconValid = WuQtUtilities::loadIcon(":/ToolBar/clapboard.png", clapBoardIcon); @@ -263,9 +297,12 @@ GuiManager::initializeGuiManager() m_sceneDialogDisplayAction->setIconText("Scenes"); } m_sceneDialogDisplayAction->blockSignals(true); - m_sceneDialogDisplayAction->setCheckable(true); - m_sceneDialogDisplayAction->setChecked(false); + m_sceneDialogDisplayAction->setCheckable(false); m_sceneDialogDisplayAction->blockSignals(false); + m_sceneDialogDisplayAction->setObjectName("ToolBar:ShowScenesWindow"); + m_sceneDialogDisplayAction->setToolTip("Show the scenes window"); + WuQMacroManager::instance()->addMacroSupportToObject(m_sceneDialogDisplayAction, + "Display Scene Dialog"); /* * Help dialog action @@ -290,6 +327,14 @@ GuiManager::initializeGuiManager() m_helpViewerDialogDisplayAction->setCheckable(true); m_helpViewerDialogDisplayAction->setChecked(false); m_helpViewerDialogDisplayAction->blockSignals(false); + m_helpViewerDialogDisplayAction->setObjectName("ToolBar:ShowHelpWindow"); + WuQMacroManager::instance()->addMacroSupportToObject(m_helpViewerDialogDisplayAction, + "Display Help Dialog"); + + /* + * Data tooltip action is created when requested by a toolbar + */ + m_dataToolTipsEnabledAction = NULL; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ALERT_USER); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW); @@ -379,6 +424,42 @@ GuiManager::beep() QApplication::beep(); } +/** + * Send an event to update the user interface + */ +void +GuiManager::updateUserInterface() +{ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} + +/** + * Send an event to update all graphics windows + */ +void +GuiManager::updateGraphicsAllWindows() +{ + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + +/** + * Send an event to update one graphics window + */ +void +GuiManager::updateGraphicsOneWindow(const int32_t windowIndex) +{ + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex).getPointer()); +} + +/** + * Send an event to update surface coloring + */ +void +GuiManager::updateSurfaceColoring() +{ + EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); +} + /** * @return The brain. */ @@ -706,6 +787,8 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, dataFileTypesToExclude.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC); dataFileTypesToExclude.push_back(DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY); dataFileTypesToExclude.push_back(DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY); + dataFileTypesToExclude.push_back(DataFileTypeEnum::METRIC_DYNAMIC); + dataFileTypesToExclude.push_back(DataFileTypeEnum::VOLUME_DYNAMIC); switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: @@ -1143,6 +1226,13 @@ GuiManager::processBringAllWindowsToFront() w->raise(); } } + + std::vector macroDialogs = WuQMacroManager::instance()->getNonModalDialogs(); + for (auto md : macroDialogs) { + if (md->isVisible()) { + md->raise(); + } + } } /** @@ -1528,6 +1618,11 @@ GuiManager::receiveEvent(Event* event) warningEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { + if (m_movieRecordingDialog != NULL) { + m_movieRecordingDialog->updateDialog(); + } + } } /** @@ -1631,8 +1726,15 @@ GuiManager::reparentNonModalDialogs(BrainBrowserWindow* closingBrainBrowserWindo ? NULL : *(validWindows.begin())); + std::vector allNonModalDialogs(this->nonModalDialogs.begin(), + this->nonModalDialogs.end()); + std::vector macroDialogs = WuQMacroManager::instance()->getNonModalDialogs(); + allNonModalDialogs.insert(allNonModalDialogs.end(), + macroDialogs.begin(), + macroDialogs.end()); + if (firstBrainBrowserWindow != NULL) { - for (auto dialog : this->nonModalDialogs) { + for (auto dialog : allNonModalDialogs) { QWidget* dialogParent = dialog->parentWidget(); if (validWindows.find(dialogParent) == validWindows.end()) { const bool wasVisible = dialog->isVisible(); @@ -1646,16 +1748,10 @@ GuiManager::reparentNonModalDialogs(BrainBrowserWindow* closingBrainBrowserWindo dialog->hide(); } } - - /* - * Update any dialogs that are WuQ non modal dialogs. - */ - WuQDialogNonModal* wuqNonModalDialog = dynamic_cast(dialog); - if (wuqNonModalDialog != NULL) { - wuqNonModalDialog->updateDialog(); - } } } + + updateNonModalDialogs(); } /** @@ -1664,7 +1760,13 @@ GuiManager::reparentNonModalDialogs(BrainBrowserWindow* closingBrainBrowserWindo void GuiManager::updateNonModalDialogs() { - reparentNonModalDialogs(NULL); + for (auto dialog : this->nonModalDialogs) { + WuQDialogNonModal* wuqNonModalDialog = dynamic_cast(dialog); + if (wuqNonModalDialog != NULL) { + wuqNonModalDialog->updateDialog(); + } + } + WuQMacroManager::instance()->updateNonModalDialogs(); } /** @@ -1691,6 +1793,30 @@ GuiManager::processShowSurfacePropertiesEditorDialog(BrainBrowserWindow* browser } } +/** + * Show the volume properties editor dialog. + * @param browserWindow + * Browser window on which dialog is displayed. + */ +void +GuiManager::processShowVolumePropertiesEditorDialog(BrainBrowserWindow* browserWindow) +{ + bool wasCreatedFlag = false; + + if (this->m_volumePropertiesEditorDialog == NULL) { + m_volumePropertiesEditorDialog = new VolumePropertiesEditorDialog(browserWindow); + this->addNonModalDialog(m_volumePropertiesEditorDialog); + m_volumePropertiesEditorDialog->setSaveWindowPositionForNextTime(true); + wasCreatedFlag = true; + } + m_volumePropertiesEditorDialog->showDialog(); + + if (wasCreatedFlag) { + WuQtUtilities::moveWindowToSideOfParent(browserWindow, + m_volumePropertiesEditorDialog); + } +} + /** * @return The action for showing/hiding the scene dialog. */ @@ -1707,9 +1833,9 @@ GuiManager::getSceneDialogDisplayAction() * New status (true display dialog, false hide it). */ void -GuiManager::sceneDialogDisplayActionToggled(bool status) +GuiManager::sceneDialogDisplayActionTriggered(bool /*status*/) { - showHideSceneDialog(status, + showHideSceneDialog(true, NULL); } @@ -1722,7 +1848,6 @@ void GuiManager::sceneDialogWasClosed() { m_sceneDialogDisplayAction->blockSignals(true); - m_sceneDialogDisplayAction->setChecked(false); m_sceneDialogDisplayAction->blockSignals(false); } @@ -1786,7 +1911,6 @@ GuiManager::showHideSceneDialog(const bool status, } m_sceneDialogDisplayAction->blockSignals(true); - m_sceneDialogDisplayAction->setChecked(status); m_sceneDialogDisplayAction->blockSignals(false); } @@ -1811,25 +1935,76 @@ GuiManager::processShowSceneDialog(BrainBrowserWindow* browserWindowIn) * * @param browserWindow * Parent of scene dialog if it needs to be created. - * @param sceneFile - * Scene File that contains the scene. + * @param sceneFileIn + * Scene File that contains the scene. If NULL, the scene file + * containing the scene will be located and used * @param scene * Scene that is displayed. + * @param showSceneDialogFlag + * If true, update the scene dialog. Otherwise, load the scene + * without showing the scene dialog */ void GuiManager::processShowSceneDialogAndScene(BrainBrowserWindow* browserWindow, - SceneFile* sceneFile, - Scene* scene) + SceneFile* sceneFileIn, + Scene* scene, + const bool showSceneDialogFlag) { - showHideSceneDialog(true, - browserWindow); + CaretAssert(browserWindow); + CaretAssert(scene); + + SceneFile* sceneFile(sceneFileIn); + if (sceneFile == NULL) { + /* + * If scene file is not valid, find scene file containing the scene + */ + Brain* brain = getBrain(); + CaretAssert(brain); + const int32_t numSceneFiles = brain->getNumberOfSceneFiles(); + for (int32_t i = 0; i < numSceneFiles; i++) { + SceneFile* sf = brain->getSceneFile(i); + CaretAssert(sf); + const int32_t numScenes = sf->getNumberOfScenes(); + for (int32_t j = 0; j < numScenes; j++) { + if (sf->getSceneAtIndex(j) == scene) { + sceneFile = sf; + break; + } + } + if (sceneFile != NULL) { + break; + } + } + + if (sceneFile == NULL) { + const QString msg("Cannot load scene. Unable to find scene file containing scene named \"" + + scene->getName() + + "\""); + WuQMessageBox::errorOk(browserWindow, + msg); + return; + } + } - const bool sceneWasDisplayed = this->sceneDialog->displayScene(sceneFile, - scene); - if (sceneWasDisplayed) { - showHideSceneDialog(false, - NULL); + /* + * Update scene dialog if it is open or if it should be displayed + */ + const bool updateSceneDialogFlag(showSceneDialogFlag + || (this->sceneDialog != NULL)); + if (updateSceneDialogFlag) { + this->sceneDialog->displayScene(sceneFile, + scene); + if (showSceneDialogFlag) { + showHideSceneDialog(true, + NULL); + } + } + else { + SceneDialog::displaySceneWithErrorMessageDialog(browserWindow, + sceneFile, + scene); } + } /** @@ -1862,6 +2037,100 @@ GuiManager::getHelpViewerDialogDisplayAction() return m_helpViewerDialogDisplayAction; } +/** + * Get the action for the data tooltips. The action + * is lazily initialized since a widget is needed to + * create the tooltip's icon. The background and foreground + * colors are copied from the widget and nothing is dependent + * upon the widget after this method returns. + * + * @param buttonWidget + * Widget that is used the first time this method is called + * to provide foreground/background colors for the pixmap. + * + * @return Action for display of data tool tips. + */ +QAction* +GuiManager::getDataToolTipsAction(QWidget* buttonWidget) +{ + if (m_dataToolTipsEnabledAction == NULL) { + m_dataToolTipsEnabledAction = WuQtUtilities::createAction("Data ToolTips", + "Enable/Disable Data Tool Tips", + this, + this, + SLOT(dataToolTipsActionTriggered(bool))); + m_dataToolTipsEnabledAction->setIcon(createDataToolTipsIcon(buttonWidget)); + m_dataToolTipsEnabledAction->setIconVisibleInMenu(false); + m_dataToolTipsEnabledAction->setCheckable(true); + m_dataToolTipsEnabledAction->setChecked(SessionManager::get()->getDataToolTipsManager()->isEnabled()); + + m_dataToolTipsEnabledAction->setObjectName("ToolBar:DataToolTipsEnabled"); + WuQMacroManager::instance()->addMacroSupportToObject(m_dataToolTipsEnabledAction, + "Enable data tool tips"); + } + + return m_dataToolTipsEnabledAction; +} + +/** + * Create a pixmap for the data tool tips button. + * + * @param widget + * To color the pixmap with backround and foreground, + * the palette from the given widget is used. + * @return + * The pixmap. + */ +QPixmap +GuiManager::createDataToolTipsIcon(const QWidget* widget) +{ + CaretAssert(widget); + const float pixmapSize = 32.0; + + QPixmap pixmap(static_cast(pixmapSize), + static_cast(pixmapSize)); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, + pixmap, + WuQtUtilities::PixMapCreationOptions::TransparentBackground); + const int leftX(-14); + const int rightX(14); + const int bottomY(-8); + const int topY(14); + const int tipLeftX(-6); + const int tipRightX(6); + const int tipY(-14); + const int tipX(0); + + QPen pen(painter->pen()); + pen.setWidth(2); + painter->setPen(pen); + + /* + * Outline of icon + */ + QPolygon polygon; + polygon.push_back(QPoint(leftX, topY)); + polygon.push_back(QPoint(leftX, bottomY)); + polygon.push_back(QPoint(tipLeftX, bottomY)); + polygon.push_back(QPoint(tipX, tipY)); + polygon.push_back(QPoint(tipRightX, bottomY)); + polygon.push_back(QPoint(rightX, bottomY)); + polygon.push_back(QPoint(rightX, topY)); + painter->drawPolygon(polygon); + + /* + * Horizontal lines inside outline + */ + const int lineLeftX(-8); + const int lineRightX(8); + const int lineOneY(6); + const int lineTwoY(0); + painter->drawLine(lineLeftX, lineOneY, lineRightX, lineOneY); + painter->drawLine(lineLeftX, lineTwoY, lineRightX, lineTwoY); + + return pixmap; +} + /** * Show or hide the help dialog. * @@ -1925,6 +2194,9 @@ GuiManager::helpDialogWasClosed() /** * Called when show help action is triggered + * + * @param status + * New status. */ void GuiManager::showHelpDialogActionToggled(bool status) @@ -1932,6 +2204,18 @@ GuiManager::showHelpDialogActionToggled(bool status) showHideHelpDialog(status, NULL); } +/** + * Called when data tooltips action is triggered + * + * @param status + * New status. + */ +void +GuiManager::dataToolTipsActionTriggered(bool status) +{ + SessionManager::get()->getDataToolTipsManager()->setEnabled(status); +} + /** * @return The action that indicates the enabled status * for display of the information window. @@ -2204,6 +2488,24 @@ GuiManager::processShowImageCaptureDialog(BrainBrowserWindow* browserWindow) this->imageCaptureDialog->showDialog(); } +/** + * Show the image capture window. + * @param browserWindow + * Window on which dialog was requested. + */ +void +GuiManager::processShowMovieRecordingDialog(BrainBrowserWindow* browserWindow) +{ + if (m_movieRecordingDialog == NULL) { + m_movieRecordingDialog = new MovieRecordingDialog(browserWindow); + this->addNonModalDialog(m_movieRecordingDialog); + } + m_movieRecordingDialog->updateDialog(); + m_movieRecordingDialog->setBrowserWindowIndex(browserWindow->getBrowserWindowIndex()); + m_movieRecordingDialog->showDialog(); + m_movieRecordingDialog->restorePositionAndSize(); +} + /** * Show the gaps and margins window. * @param browserWindow @@ -2375,6 +2677,10 @@ GuiManager::saveToScene(const SceneAttributes* sceneAttributes, sceneClass->addClass(m_surfacePropertiesEditorDialog->saveToScene(sceneAttributes, "m_surfacePropertiesEditorDialog")); } + if (m_volumePropertiesEditorDialog != NULL) { + sceneClass->addClass(m_volumePropertiesEditorDialog->saveToScene(sceneAttributes, + "m_volumePropertiesEditorDialog")); + } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: @@ -2608,6 +2914,18 @@ GuiManager::restoreFromScene(const SceneAttributes* sceneAttributes, surfPropClass); } + const SceneClass* volPropClass = sceneClass->getClass("m_volumePropertiesEditorDialog"); + if (volPropClass != NULL) { + if (m_volumePropertiesEditorDialog == NULL) { + processShowVolumePropertiesEditorDialog(firstBrowserWindow); + } + else if ( ! m_volumePropertiesEditorDialog->isVisible()) { + processShowVolumePropertiesEditorDialog(firstBrowserWindow); + } + m_volumePropertiesEditorDialog->restoreFromScene(sceneAttributes, + volPropClass); + } + CaretLogFine("Time to restore information/property windows was " + QString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds"); @@ -2619,6 +2937,9 @@ GuiManager::restoreFromScene(const SceneAttributes* sceneAttributes, if (imageCaptureDialog != NULL) { imageCaptureDialog->updateDialog(); } + if (m_movieRecordingDialog != NULL) { + m_movieRecordingDialog->updateDialog(); + } progressEvent.setProgressMessage("Invalidating coloring and updating user interface"); EventManager::get()->sendEvent(progressEvent.getPointer()); @@ -2784,6 +3105,18 @@ GuiManager::processIdentification(const int32_t tabIndex, ciftiLoadingInfo); chartingDataManager->loadChartForSurfaceNode(surface, nodeIndex); + + std::vector metricDynConnFiles; + brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); + + for (auto mdc : metricDynConnFiles) { + if (mdc->isEnabledAsLayer()) { + mdc->loadDataForSurfaceNode(surface->getNumberOfNodes(), + surface->getStructure(), + nodeIndex); + } + } + updateGraphicsFlag = true; } catch (const DataFileException& e) { @@ -2840,6 +3173,20 @@ GuiManager::processIdentification(const int32_t tabIndex, } } + if (idVoxel->isValid()) { + std::vector volumeDynConnFiles; + brain->getVolumeDynamicConnectivityFiles(volumeDynConnFiles); + + for (auto vdc : volumeDynConnFiles) { + if (vdc->isEnabledAsLayer()) { + double xyzDouble[3]; + idVoxel->getModelXYZ(xyzDouble); + float xyz[3] { static_cast(xyzDouble[0]), static_cast(xyzDouble[1]), static_cast(xyzDouble[2]) }; + vdc->loadConnectivityForVoxelXYZ(xyz); + } + } + } + SelectionItemChartMatrix* idChartOneMatrix = selectionManager->getChartMatrixIdentification(); if (idChartOneMatrix->isValid()) { ChartableMatrixInterface* chartMatrixInterface = idChartOneMatrix->getChartableMatrixInterface(); @@ -3204,4 +3551,3 @@ GuiManager::processIdentification(const int32_t tabIndex, } - diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index 3caec26127cb4e71a32c5e88e67070c2e0fb0879..080280235b09133e280e696409ac0694b30bfbdb 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -55,6 +55,7 @@ namespace caret { class ImageFile; class ImageCaptureDialog; class InformationDisplayDialog; + class MovieRecordingDialog; class OverlaySettingsEditorDialog; class Model; class PaletteColorMappingEditorDialog; @@ -65,6 +66,7 @@ namespace caret { class SelectionManager; class SpecFile; class SurfacePropertiesEditorDialog; + class VolumePropertiesEditorDialog; class TileTabsConfigurationDialog; /** @@ -83,6 +85,14 @@ namespace caret { static void beep(); + static void updateUserInterface(); + + static void updateGraphicsAllWindows(); + + static void updateGraphicsOneWindow(const int32_t windowIndex); + + static void updateSurfaceColoring(); + Brain* getBrain() const; int32_t getNumberOfOpenBrainBrowserWindows() const; @@ -123,6 +133,8 @@ namespace caret { QAction* getHelpViewerDialogDisplayAction(); + QAction* getDataToolTipsAction(QWidget* buttonWidget); + void closeAllOtherWindows(BrainBrowserWindow* browserWindow); void closeOtherWindowsAndReturnTheirTabContent(BrainBrowserWindow* browserWindow, @@ -134,6 +146,7 @@ namespace caret { void processShowCustomViewDialog(BrainBrowserWindow* browserWindow); void processShowGapsAndMarginsDialog(BrainBrowserWindow* browserWindow); void processShowImageCaptureDialog(BrainBrowserWindow* browserWindow); + void processShowMovieRecordingDialog(BrainBrowserWindow* browserWindow); void processShowMovieDialog(BrainBrowserWindow* browserWindow); void processShowPreferencesDialog(BrainBrowserWindow* browserWindow); void processShowInformationDisplayDialog(const bool forceDisplayOfDialog); @@ -145,9 +158,12 @@ namespace caret { void processShowSurfacePropertiesEditorDialog(BrainBrowserWindow* browserWindow); + void processShowVolumePropertiesEditorDialog(BrainBrowserWindow* browserWindow); + void processShowSceneDialogAndScene(BrainBrowserWindow* browserWindow, SceneFile* sceneFile, - Scene* scene); + Scene* scene, + const bool showSceneDialogFlag); void processShowAllenDataBaseWebView(BrainBrowserWindow* browserWindow); void processShowConnectomeDataBaseWebView(BrainBrowserWindow* browserWindow); @@ -193,7 +209,7 @@ namespace caret { void showIdentifyBrainordinateDialogActionToggled(bool); - void sceneDialogDisplayActionToggled(bool); + void sceneDialogDisplayActionTriggered(bool); void showHelpDialogActionToggled(bool); @@ -201,6 +217,7 @@ namespace caret { void helpDialogWasClosed(); void sceneDialogWasClosed(); void identifyBrainordinateDialogWasClosed(); + void dataToolTipsActionTriggered(bool); private: GuiManager(QObject* parent = 0); @@ -233,6 +250,8 @@ namespace caret { void addParentLessNonModalDialog(QWidget* dialog); + QPixmap createDataToolTipsIcon(const QWidget* widget); + /** One instance of the GuiManager */ static GuiManager* singletonGuiManager; @@ -258,6 +277,8 @@ namespace caret { ImageCaptureDialog* imageCaptureDialog; + MovieRecordingDialog* m_movieRecordingDialog; + GapsAndMarginsDialog* m_gapsAndMarginsDialog; MovieDialog* movieDialog; @@ -274,6 +295,8 @@ namespace caret { SurfacePropertiesEditorDialog* m_surfacePropertiesEditorDialog; + VolumePropertiesEditorDialog* m_volumePropertiesEditorDialog; + WuQWebView* connectomeDatabaseWebView; CursorManager* cursorManager; @@ -282,6 +305,8 @@ namespace caret { QAction* m_identifyBrainordinateDialogEnabledAction; + QAction* m_dataToolTipsEnabledAction; + BugReportDialog* m_bugReportDialog; QAction* m_helpViewerDialogDisplayAction; diff --git a/src/GuiQt/IdentifyBrainordinateDialog.cxx b/src/GuiQt/IdentifyBrainordinateDialog.cxx index fccfdfec5251a349dc71b2b63a0582005e2c9edf..a5975c4b898e94effac3568e73748af0506b2a8a 100644 --- a/src/GuiQt/IdentifyBrainordinateDialog.cxx +++ b/src/GuiQt/IdentifyBrainordinateDialog.cxx @@ -41,12 +41,16 @@ using namespace caret; #include "CaretLogger.h" #include "CiftiFiberTrajectoryFile.h" #include "CaretMappableDataFile.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartableTwoFileMatrixChart.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryManager.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "CaretMappableDataFileAndMapSelectorObject.h" #include "CiftiParcelSelectionComboBox.h" +#include "CiftiScalarDataSeriesFile.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventIdentificationHighlightLocation.h" #include "EventManager.h" @@ -68,6 +72,7 @@ using namespace caret; #include "WuQFactory.h" #include "WuQGroupBoxExclusiveWidget.h" #include "WuQMessageBox.h" +#include "WuQSpinBox.h" #include "WuQtUtilities.h" #include @@ -93,7 +98,9 @@ IdentifyBrainordinateDialog::IdentifyBrainordinateDialog(QWidget* parent) */ std::vector allDataFileTypes; DataFileTypeEnum::getAllEnums(allDataFileTypes, - DataFileTypeEnum::OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC); + (DataFileTypeEnum::OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC + | DataFileTypeEnum::OPTIONS_INCLUDE_METRIC_DENSE_DYNAMIC + | DataFileTypeEnum::OPTIONS_INCLUDE_VOLUME_DENSE_DYNAMIC)); std::vector supportedCiftiRowFileTypes; std::vector supportedLabelFileTypes; @@ -153,6 +160,7 @@ IdentifyBrainordinateDialog::IdentifyBrainordinateDialog(QWidget* parent) ciftiRowFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + ciftiRowFlag = true; break; case DataFileTypeEnum::FOCI: break; @@ -163,6 +171,8 @@ IdentifyBrainordinateDialog::IdentifyBrainordinateDialog(QWidget* parent) break; case DataFileTypeEnum::METRIC: break; + case DataFileTypeEnum::METRIC_DYNAMIC: + break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: @@ -177,6 +187,8 @@ IdentifyBrainordinateDialog::IdentifyBrainordinateDialog(QWidget* parent) break; case DataFileTypeEnum::VOLUME: break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + break; } if (parcelSourceDimension != PARCEL_SOURCE_INVALID_DIMENSION) { @@ -208,7 +220,7 @@ IdentifyBrainordinateDialog::IdentifyBrainordinateDialog(QWidget* parent) m_ciftiParcelWidget = createCiftiParcelWidget(); m_widgetBox = new WuQGroupBoxExclusiveWidget(); - m_widgetBox->addWidget(m_ciftiRowWidget, "Identify Brainordinate from CIFTI File Row"); + m_widgetBox->addWidget(m_ciftiRowWidget, "Identify from CIFTI File Row"); m_widgetBox->addWidget(m_ciftiParcelWidget, "Identify CIFTI File Parcel"); m_widgetBox->addWidget(m_labelFileWidgets.m_widget, "Identify Label"); m_widgetBox->addWidget(m_surfaceVertexWidget, "Identify Surface Vertex"); @@ -333,11 +345,12 @@ IdentifyBrainordinateDialog::createCiftiRowWidget(const std::vector::max(), - 1); - QObject::connect(m_ciftiRowFileIndexSpinBox, SIGNAL(valueChanged(int)), + m_ciftiRowFileIndexSpinBox = new WuQSpinBox(); + m_ciftiRowFileIndexSpinBox->setMinimum(1); + m_ciftiRowFileIndexSpinBox->setMaximum(std::numeric_limits::max()); + QObject::connect(m_ciftiRowFileIndexSpinBox, SIGNAL(signalReturnPressed()), this, SLOT(apply())); + m_ciftiRowFileIndexSpinBox->setFixedWidth(INDEX_SPIN_BOX_WIDTH); switch (CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI()) { case 0: @@ -760,6 +773,7 @@ IdentifyBrainordinateDialog::processCiftiRowWidget(AString& errorMessageOut) if (dataFile != NULL) { CiftiMappableDataFile* ciftiMapFile = dynamic_cast(dataFile); CiftiFiberTrajectoryFile* ciftiTrajFile = dynamic_cast(dataFile); + CiftiScalarDataSeriesFile* ciftiSdsFile = dynamic_cast(dataFile); const int32_t selectedCiftiRowIndex = m_ciftiRowFileIndexSpinBox->value() - m_ciftiRowFileIndexSpinBox->minimum(); @@ -771,75 +785,101 @@ IdentifyBrainordinateDialog::processCiftiRowWidget(AString& errorMessageOut) int64_t voxelIJK[3]; float voxelXYZ[3]; bool voxelValid = false; - if (ciftiMapFile != NULL) { - ciftiMapFile->getBrainordinateFromRowIndex(selectedCiftiRowIndex, - surfaceStructure, - surfaceNodeIndex, - surfaceNumberOfNodes, - surfaceNodeValid, - voxelIJK, - voxelXYZ, - voxelValid); - } - else if (ciftiTrajFile != NULL) { - ciftiTrajFile->getBrainordinateFromRowIndex(selectedCiftiRowIndex, - surfaceStructure, - surfaceNodeIndex, - surfaceNumberOfNodes, - surfaceNodeValid, - voxelIJK, - voxelXYZ, - voxelValid); - } - else { - errorMessageOut = "Neither CIFTI Mappable nor CIFTI Trajectory file. Has new file type been added?"; - } - - if (surfaceNodeValid) { - SelectionItemSurfaceNode* surfaceID = selectionManager->getSurfaceNodeIdentification(); - const Surface* surface = brain->getPrimaryAnatomicalSurfaceForStructure(surfaceStructure); - if (surface != NULL) { - if ((surfaceNodeIndex >= 0) - && (surfaceNodeIndex < surface->getNumberOfNodes())) { - surfaceID->setSurface(const_cast(surface)); - surfaceID->setBrain(brain); - const float* xyz = surface->getCoordinate(surfaceNodeIndex); - const double doubleXYZ[3] = { xyz[0], xyz[1], xyz[2] }; - surfaceID->setModelXYZ(doubleXYZ); - surfaceID->setNodeNumber(surfaceNodeIndex); + if (ciftiSdsFile != NULL) { + ChartableTwoFileDelegate* chartDelegate = ciftiSdsFile->getChartingDelegate(); + CaretAssert(chartDelegate); + ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); + ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); + if (matrixChart != NULL) { + int32_t rowCount(0), columnCount(0); + matrixChart->getMatrixDimensions(rowCount, + columnCount); + if (selectedCiftiRowIndex < rowCount) { + const int32_t tabIndex = 0; // selections are same in all tabs + matrixChart->setSelectedRowColumnIndex(tabIndex, + selectedCiftiRowIndex); + if (lineSeriesChart) { + lineSeriesChart->loadDataForRowOrColumn(tabIndex, + selectedCiftiRowIndex); + } - GuiManager::get()->processIdentification(-1, // invalid tab index - selectionManager, - this); - } - else { - errorMessageOut = ("Surface vertex index " - + AString::number(surfaceNodeIndex) - + " is not valid for surface " - + surface->getFileNameNoPath()); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } - else{ - errorMessageOut = ("No surfaces are loaded for structure " - + StructureEnum::toGuiName(surfaceStructure)); + } + else { + if (ciftiMapFile != NULL) { + ciftiMapFile->getBrainordinateFromRowIndex(selectedCiftiRowIndex, + surfaceStructure, + surfaceNodeIndex, + surfaceNumberOfNodes, + surfaceNodeValid, + voxelIJK, + voxelXYZ, + voxelValid); + } + else if (ciftiTrajFile != NULL) { + ciftiTrajFile->getBrainordinateFromRowIndex(selectedCiftiRowIndex, + surfaceStructure, + surfaceNodeIndex, + surfaceNumberOfNodes, + surfaceNodeValid, + voxelIJK, + voxelXYZ, + voxelValid); + } + else { + errorMessageOut = "Neither CIFTI Mappable nor CIFTI Trajectory file. Has new file type been added?"; } - } - else if (voxelValid) { - SelectionItemVoxel* voxelID = selectionManager->getVoxelIdentification(); - voxelID->setBrain(brain); - voxelID->setEnabledForSelection(true); - voxelID->setVoxelIdentification(brain, - ciftiMapFile, - voxelIJK, - 0.0); - const double doubleXYZ[3] = { voxelXYZ[0], voxelXYZ[1], voxelXYZ[2] }; - voxelID->setModelXYZ(doubleXYZ); - GuiManager::get()->processIdentification(-1, // invalid tab index - selectionManager, - this); + if (surfaceNodeValid) { + SelectionItemSurfaceNode* surfaceID = selectionManager->getSurfaceNodeIdentification(); + const Surface* surface = brain->getPrimaryAnatomicalSurfaceForStructure(surfaceStructure); + if (surface != NULL) { + if ((surfaceNodeIndex >= 0) + && (surfaceNodeIndex < surface->getNumberOfNodes())) { + surfaceID->setSurface(const_cast(surface)); + surfaceID->setBrain(brain); + const float* xyz = surface->getCoordinate(surfaceNodeIndex); + const double doubleXYZ[3] = { xyz[0], xyz[1], xyz[2] }; + surfaceID->setModelXYZ(doubleXYZ); + surfaceID->setNodeNumber(surfaceNodeIndex); + + GuiManager::get()->processIdentification(-1, // invalid tab index + selectionManager, + this); + } + else { + errorMessageOut = ("Surface vertex index " + + AString::number(surfaceNodeIndex) + + " is not valid for surface " + + surface->getFileNameNoPath()); + } + } + else{ + errorMessageOut = ("No surfaces are loaded for structure " + + StructureEnum::toGuiName(surfaceStructure)); + } + + } + else if (voxelValid) { + SelectionItemVoxel* voxelID = selectionManager->getVoxelIdentification(); + voxelID->setBrain(brain); + voxelID->setEnabledForSelection(true); + voxelID->setVoxelIdentification(brain, + ciftiMapFile, + voxelIJK, + 0.0); + const double doubleXYZ[3] = { voxelXYZ[0], voxelXYZ[1], voxelXYZ[2] }; + voxelID->setModelXYZ(doubleXYZ); + + GuiManager::get()->processIdentification(-1, // invalid tab index + selectionManager, + this); + } } } catch (const DataFileException& dfe) { diff --git a/src/GuiQt/ImageCaptureDialog.cxx b/src/GuiQt/ImageCaptureDialog.cxx index ac3a43aaf78a3f01b4d55c84f43c5ee72962311e..c1460f2d865b7c3eef35d8813a69a2138f6e827f 100644 --- a/src/GuiQt/ImageCaptureDialog.cxx +++ b/src/GuiQt/ImageCaptureDialog.cxx @@ -1037,6 +1037,14 @@ ImageCaptureDialog::applyButtonClicked() return; } + AString imageFileName = m_imageFileNameLineEdit->text().trimmed(); + if (m_saveImageToFileCheckBox->isChecked()) { + if (imageFileName.isEmpty()) { + WuQMessageBox::errorOk(this, "Save to File name is empty. Choose an Image File."); + return; + } + } + /* * Default to width of window that may exclude empty regions * caused by locking of aspect ratio. @@ -1102,35 +1110,35 @@ ImageCaptureDialog::applyButtonClicked() QApplication::clipboard()->setImage(*imageFile.getAsQImage(), QClipboard::Clipboard); } - + if (m_saveImageToFileCheckBox->isChecked()) { std::vector imageFileExtensions; AString defaultFileExtension; ImageFile::getImageFileExtensions(imageFileExtensions, defaultFileExtension); - AString filename = m_imageFileNameLineEdit->text().trimmed(); + CaretAssert( ! imageFileName.isEmpty()); bool validExtension = false; for (std::vector::iterator extensionIterator = imageFileExtensions.begin(); extensionIterator != imageFileExtensions.end(); extensionIterator++) { - if (filename.endsWith(*extensionIterator)) { + if (imageFileName.endsWith(*extensionIterator)) { validExtension = true; } } - if (validExtension == false) { + if ( ! validExtension) { if (defaultFileExtension.isEmpty() == false) { - filename += ("." + defaultFileExtension); + imageFileName += ("." + defaultFileExtension); } } try { - imageFile.writeFile(filename); + imageFile.writeFile(imageFileName); } catch (const DataFileException& /*e*/) { - QString msg("Unable to save: " + filename); + QString msg("Unable to save: " + imageFileName); WuQMessageBox::errorOk(this, msg); errorFlag = true; } @@ -1139,7 +1147,7 @@ ImageCaptureDialog::applyButtonClicked() ChartMatrixDisplayProperties::setManualScaleModeWindowWidthHeightScaling(1.0, 1.0); - if (errorFlag == false) { + if ( ! errorFlag) { /* * Display over "Capture" (the renamed Apply) button. */ diff --git a/src/GuiQt/ImageSelectionViewController.cxx b/src/GuiQt/ImageSelectionViewController.cxx index 4d7a20d26d0600c96cd365f94dbeece135ef5f4f..53661617cda2beab26652a1262ca1b4cc9ccc528 100644 --- a/src/GuiQt/ImageSelectionViewController.cxx +++ b/src/GuiQt/ImageSelectionViewController.cxx @@ -46,6 +46,7 @@ #include "ImageFile.h" #include "SceneClass.h" #include "SceneClassAssistant.h" +#include "WuQMacroManager.h" #include "WuQSpinBoxGroup.h" #include "WuQtUtilities.h" #include "WuQTabWidget.h" @@ -64,16 +65,24 @@ static const int COLUMN_RADIO_BUTTON = 0; * Constructor. */ ImageSelectionViewController::ImageSelectionViewController(const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent) : QWidget(parent), -m_browserWindowIndex(browserWindowIndex) +m_browserWindowIndex(browserWindowIndex), +m_objectNamePrefix(parentObjectName + + ":Image") { setWindowTitle("Images"); + WuQMacroManager* macroManager = WuQMacroManager::instance(); + m_sceneAssistant = new SceneClassAssistant(); QLabel* groupLabel = new QLabel("Group"); - m_imagesDisplayGroupComboBox = new DisplayGroupEnumComboBox(this); + m_imagesDisplayGroupComboBox = new DisplayGroupEnumComboBox(this, + (m_objectNamePrefix + + ":DisplayGroup"), + "images"); QObject::connect(m_imagesDisplayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(imageDisplayGroupSelected(const DisplayGroupEnum::Enum))); @@ -85,10 +94,20 @@ m_browserWindowIndex(browserWindowIndex) m_imageDisplayCheckBox = new QCheckBox("Display Image"); QObject::connect(m_imageDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_imageDisplayCheckBox->setToolTip("Display Image"); + m_imageDisplayCheckBox->setObjectName(m_objectNamePrefix + + ":Display"); + macroManager->addMacroSupportToObject(m_imageDisplayCheckBox, + "Enable display of image"); m_controlPointsDisplayCheckBox = new QCheckBox("Display Control Points"); QObject::connect(m_controlPointsDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); + m_controlPointsDisplayCheckBox->setToolTip("Display Control Points"); + m_controlPointsDisplayCheckBox->setObjectName(m_objectNamePrefix + + ":DisplayControlPoints"); + macroManager->addMacroSupportToObject(m_controlPointsDisplayCheckBox, + "Display image control points"); QWidget* attributesWidget = this->createAttributesWidget(); QWidget* selectionWidget = this->createSelectionWidget(); @@ -100,6 +119,11 @@ m_browserWindowIndex(browserWindowIndex) m_tabWidget->addTab(selectionWidget, "Selection"); m_tabWidget->setCurrentWidget(attributesWidget); + m_tabWidget->getTabBar()->setObjectName(m_objectNamePrefix + + ":Tab"); + macroManager->addMacroSupportToObjectWithToolTip(m_tabWidget->getTabBar(), + "Select features toolbox image tab", + "Features ToolBox Image Tab"); QVBoxLayout* layout = new QVBoxLayout(this); // WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); @@ -189,12 +213,20 @@ ImageSelectionViewController::createSelectionWidget() QWidget* ImageSelectionViewController::createAttributesWidget() { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + const QString objectNamePrefix(m_objectNamePrefix + + ":Attributes"); + QLabel* depthLabel = new QLabel("Depth"); m_depthComboBox = new EnumComboBoxTemplate(this); m_depthComboBox->setup(); m_depthComboBox->getWidget()->setToolTip("Set the depth position of the image3"); QObject::connect(m_depthComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); + m_depthComboBox->getComboBox()->setObjectName(objectNamePrefix + + ":DepthPosition"); + macroManager->addMacroSupportToObject(m_depthComboBox->getComboBox(), + "Set image depth"); const float threshMin = -1.0; const float threshMax = 100000.0; @@ -209,6 +241,10 @@ ImageSelectionViewController::createAttributesWidget() m_thresholdMinimumSpinBox->setToolTip("Do not display image pixels containing a color component less than this value"); QObject::connect(m_thresholdMinimumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_thresholdMinimumSpinBox->setObjectName(objectNamePrefix + + "MinimumThreshold"); + macroManager->addMacroSupportToObject(m_thresholdMinimumSpinBox, + "Set image threshold minimum"); QLabel* thresholdMaximumLabel = new QLabel("Maximum Threshold"); m_thresholdMaximumSpinBox = WuQFactory::newDoubleSpinBox(); @@ -220,6 +256,10 @@ ImageSelectionViewController::createAttributesWidget() m_thresholdMaximumSpinBox->setToolTip("Do not display image pixels containing a color component greater than this value"); QObject::connect(m_thresholdMaximumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_thresholdMaximumSpinBox->setObjectName(objectNamePrefix + + "MaximumThreshold"); + macroManager->addMacroSupportToObject(m_thresholdMaximumSpinBox, + "Set image threshold maximum"); const float minOpacity = 0.0; const float maxOpacity = 1.0; @@ -233,6 +273,10 @@ ImageSelectionViewController::createAttributesWidget() m_opacitySpinBox->setToolTip("Opacity for image"); QObject::connect(m_opacitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); + m_opacitySpinBox->setObjectName(objectNamePrefix + + ":Opacity"); + macroManager->addMacroSupportToObject(m_opacitySpinBox, + "Set image opacity"); QWidget* gridWidget = new QWidget(); @@ -251,17 +295,6 @@ ImageSelectionViewController::createAttributesWidget() gridLayout->addWidget(opacityLabel, row, 0); gridLayout->addWidget(m_opacitySpinBox, row, 1); row++; -// gridLayout->addWidget(pointSizeLabel, row, 0); -// gridLayout->addWidget(m_pointSizeSpinBox, row, 1); -// row++; -// gridLayout->addWidget(m_enableUnstretchedLinesCheckBox, row, 0); -// gridLayout->addWidget(m_unstretchedLinesLengthSpinBox, row, 1); -// row++; -// gridLayout->addWidget(aboveSurfaceLabel, row, 0); -// gridLayout->addWidget(m_aboveSurfaceOffsetSpinBox, row, 1); -// -// gridWidget->setSizePolicy(QSizePolicy::Fixed, -// QSizePolicy::Fixed); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); @@ -417,6 +450,16 @@ ImageSelectionViewController::updateImageViewController() m_imageRadioButtonGroup->addButton(rb, buttonID); + + const QString buttonName(m_objectNamePrefix + + ":Selection:Image" + + QString("%1").arg((int)i+1, 2, 10, QLatin1Char('0'))); + rb->setObjectName(buttonName); + const QString descriptiveName("Select Image" + + QString("%1").arg(i + 1)); + WuQMacroManager::instance()->addMacroSupportToObjectWithToolTip(rb, + descriptiveName, + ""); } numRadioButtons = static_cast(m_imageRadioButtons.size()); diff --git a/src/GuiQt/ImageSelectionViewController.h b/src/GuiQt/ImageSelectionViewController.h index fcf9a97472d3baab6598ea27713131b72e754c72..ac31e19da510e2c8fd1b12224288199e2e444019 100644 --- a/src/GuiQt/ImageSelectionViewController.h +++ b/src/GuiQt/ImageSelectionViewController.h @@ -49,6 +49,7 @@ namespace caret { public: ImageSelectionViewController(const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent = 0); virtual ~ImageSelectionViewController(); @@ -97,6 +98,8 @@ namespace caret { const int32_t m_browserWindowIndex; + const QString m_objectNamePrefix; + WuQTabWidget* m_tabWidget; SceneClassAssistant* m_sceneAssistant; diff --git a/src/GuiQt/LabelSelectionViewController.cxx b/src/GuiQt/LabelSelectionViewController.cxx index b294bba3bb5906d9c8ac6ca09d7a4eb36b4285f0..02cd98890096cce59d4560b0e4954a07969d89d9 100644 --- a/src/GuiQt/LabelSelectionViewController.cxx +++ b/src/GuiQt/LabelSelectionViewController.cxx @@ -49,6 +49,7 @@ #include "SceneClass.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" +#include "WuQMacroManager.h" #include "WuQTabWidget.h" #include "WuQtUtilities.h" @@ -67,15 +68,28 @@ using namespace caret; /** * Constructor. + * + * @param browserWindowIndex + * Index of browser window + * @param parentObjectName + * Name of parent object + * @param parent + * The parent object */ LabelSelectionViewController::LabelSelectionViewController(const int32_t browserWindowIndex, - QWidget* parent) -: QWidget(parent) + const QString& parentObjectName, + QWidget* parent) +: QWidget(parent), +m_objectNamePrefix(parentObjectName + + ":Label") { m_browserWindowIndex = browserWindowIndex; QLabel* groupLabel = new QLabel("Group"); - m_labelsDisplayGroupComboBox = new DisplayGroupEnumComboBox(this); + m_labelsDisplayGroupComboBox = new DisplayGroupEnumComboBox(this, + (m_objectNamePrefix + + ":DisplayGroup"), + "labels"); QObject::connect(m_labelsDisplayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(labelDisplayGroupSelected(const DisplayGroupEnum::Enum))); @@ -110,7 +124,11 @@ LabelSelectionViewController::~LabelSelectionViewController() QWidget* LabelSelectionViewController::createSelectionWidget() { - m_labelClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex); + m_labelClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex, + (m_objectNamePrefix + + ":Selection"), + "labels", + this); return m_labelClassNameHierarchyViewController; } diff --git a/src/GuiQt/LabelSelectionViewController.h b/src/GuiQt/LabelSelectionViewController.h index e15632ba9bf984d06d7803e79c0eabac3a805446..59141d8b381830bfb3c1df0bb6a77fcf990a60f2 100644 --- a/src/GuiQt/LabelSelectionViewController.h +++ b/src/GuiQt/LabelSelectionViewController.h @@ -43,7 +43,8 @@ namespace caret { public: LabelSelectionViewController(const int32_t browserWindowIndex, - QWidget* parent = 0); + const QString& parentObjectName, + QWidget* parent = 0); virtual ~LabelSelectionViewController(); @@ -73,6 +74,8 @@ namespace caret { QWidget* createSelectionWidget(); + const QString m_objectNamePrefix; + int32_t m_browserWindowIndex; GroupAndNameHierarchyViewController* m_labelClassNameHierarchyViewController; diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx index e3fbb1a152a29479db789e18cdf05f1b73a815af..aa71e5556328410ba69927f0589813dad7a6316d 100644 --- a/src/GuiQt/LockAspectWarningDialog.cxx +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -53,7 +53,50 @@ using namespace caret; */ /** - * Run the lock aspect warning dialog and return the result. + * Run the dialog for when the user turns on the Lock Aspect button in the toolbar + * + * @param bbw + * Parent brain browser window + * @param numberOfTabsInWindow + * Number of tabs in the window + */ +bool +LockAspectWarningDialog::runDialogToolBarLockAspect(BrainBrowserWindow* bbw, + const int32_t numberOfTabsInWindow) +{ + CaretAssert(bbw); + + /* + * Show warning if all of these conditions are met: + * + * (1) User has NOT set do not show again + * (2) Tile tabs is NOT selected + * (3) There is more than one tab in the window + */ + if (s_doNotShowAgainLockAspectModeStatusFlag) { + return true; + } + if (bbw->isTileTabsSelected()) { + return true; + } + if (numberOfTabsInWindow <= 1) { + return true; + } + + LockAspectWarningDialog dialog(bbw, + Mode::TOOLBAR_LOCK_ASPECT); + + + const bool acceptedFlag = (dialog.exec() == LockAspectWarningDialog::Accepted); + s_doNotShowAgainLockAspectModeStatusFlag = dialog.isDoNotShowAgainChecked(); + + return acceptedFlag; +} + + +/** + * Run the lock aspect warning dialog when the user presses the + * Annotation mode button and return the result. * * @param browserWindowIndex * Index of the browser window. @@ -61,7 +104,7 @@ using namespace caret; * Result of user interaction with dialog. */ LockAspectWarningDialog::Result -LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex) +LockAspectWarningDialog::runDialogEnterAnnotationsMode(const int32_t browserWindowIndex) { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); CaretAssert(bbw); @@ -79,120 +122,170 @@ LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex) return Result::NO_CHANGES; } - if (s_doNotShowAgainStatusFlag) { + if (s_doNotShowAgainEnterAnnotationsModeStatusFlag) { return Result::NO_CHANGES; } - LockAspectWarningDialog dialog(bbw); + LockAspectWarningDialog dialog(bbw, + Mode::ENTER_ANNOTATIONS_MODE); if (dialog.exec() == LockAspectWarningDialog::Accepted) { - s_doNotShowAgainStatusFlag = dialog.isDoNotShowAgainChecked(); + s_doNotShowAgainEnterAnnotationsModeStatusFlag = dialog.isDoNotShowAgainChecked(); return dialog.getOkResult(); } return Result::CANCEL; } +/** + * @return Locking aspect instruction containing importance of window sizing + * and locking tabs. + * + * @parm buttonText + * Text of button that user has clicked + * @param showBestPracticesLink + If true, include a link to the best practices guide. + */ +QString +LockAspectWarningDialog::getLockingInstructionsText(const QString& buttonText, + const bool showBestPracticesLink) +{ + QString text("" + "Prior to locking the aspect ratio, the user should: " + "
    " + "
  • Adjust the size of the window;" + "
  • Optionally enable Tile Tabs for a multi-tab view; " + "If annotating a Tile Tabs view, Tile Tabs " + "(View Menu -> Enter Tile Tabs) should ALWAYS be enabled prior to " + "locking the aspect ratio. Failure to do so may cause excess, " + "undesirable space around and between the drawing of tab rows." + "
" + "If this has not been done, click the Cancel button, make those " + "adjustments, and then click the " + buttonText + " button."); + if (showBestPracticesLink) { + text.append("

" + "View the Best Practices Guide (this dialog " + "will close). This guide explains the importance of aspect " + "locking and documents procedures for successful creation of annotations " + "and scenes."); + } + text.append(""); + + return text; +} + + /** * Constructor. * - * @param tabMode - * The mode for tabs (selected or all) - * @param tileTabsEnabled - * True if tile tabs is enabled. - * @param browserWindowAspectLocked - * True if window aspect is locked. - * @param tabAspectLockedCount - * Count of tabs with aspect locked. - * @param tabCount - * Count of tabs. + * @param mode + * The mode for the dialog + * @param brainBrowserWindow + * Parent window for help dialog that is linked from this dialog * @param parent * The parent widget. */ -LockAspectWarningDialog::LockAspectWarningDialog(BrainBrowserWindow* brainBrowserWindow) +LockAspectWarningDialog::LockAspectWarningDialog(BrainBrowserWindow* brainBrowserWindow, + const Mode mode) : WuQDialogModal("Enter Annotations Mode", brainBrowserWindow), -m_brainBrowserWindow(brainBrowserWindow) +m_brainBrowserWindow(brainBrowserWindow), +m_mode(mode) { - const QString mainInstructions("Do you want to lock the aspect ratio while entering annotations mode?"); - - const QString supplementalInstructions("" - "Prior to locking the aspect ratio, the user should adjust the size " - "of the window and optionally enable Tile Tabs for a multi-tab view. " - "If this has not been done, click the Cancel button, make those " - "adjustments, and then click the Toolbar's Annotate Mode button." - "

" - "View the Best Practices Guide (this dialog " - "will close). This guide explains the importance of aspect " - "locking and documents procedures for successful creation of annotations " - "and scenes." - ""); - - const QString lockAspectInstructions("Locking the aspect ratio, and never unlocking the aspect " - "ratio, ensures annotations stay in the correct location."); - const QString leaveUnlockedInstructions("Advanced users may choose to lock and unlock the aspect ratio"); + QString buttonName; + switch (m_mode) { + case Mode::ENTER_ANNOTATIONS_MODE: + setWindowTitle("Enter Annotations Mode"); + buttonName = "Toolbar's Annotate Mode"; + break; + case Mode::TOOLBAR_LOCK_ASPECT: + setWindowTitle("Lock Aspect Ratio"); + buttonName = "Lock Aspect"; + break; + } - QLabel* mainInstructionsLabel = new QLabel(mainInstructions); - QFont font = mainInstructionsLabel->font(); - font.setPointSize(font.pointSize() * 1.4); - font.setBold(true); - mainInstructionsLabel->setFont(font); + const QString supplementalInstructions(getLockingInstructionsText(buttonName, + true)); QLabel* supplementalInstructionLabel = new QLabel(supplementalInstructions); supplementalInstructionLabel->setWordWrap(true); QObject::connect(supplementalInstructionLabel, &QLabel::linkActivated, this, &LockAspectWarningDialog::detailsLabelLinkActivated); - QLabel* lockAspectLabel = new QLabel(lockAspectInstructions); - lockAspectLabel->setWordWrap(true); - QLabel* lockAspectRadioButtonLabel = new QLabel("Lock Aspect Ratio (Recommended)"); - m_lockAspectRadioButton = new QRadioButton(); - - QLabel* leaveUnlockedAspectRadioButtonLabel = new QLabel("Leave Aspect Ratio Unlocked"); - m_leaveUnlockedAspectRadioButton = new QRadioButton(); - QLabel* leaveUnlockedLabel = new QLabel(leaveUnlockedInstructions); - - QButtonGroup* buttGroup = new QButtonGroup(this); - buttGroup->addButton(m_lockAspectRadioButton); - buttGroup->addButton(m_leaveUnlockedAspectRadioButton); - m_lockAspectRadioButton->setChecked(true); - - m_doNotShowAgainCheckBox = new QCheckBox("Do not show again. User will not be warned about " + m_doNotShowAgainCheckBox = new QCheckBox("Do not show this dialog again. User will not be warned about " "aspect locking and unlocking."); - - /* - * No text is added to readio buttons since - * radio buttons and labels seem to get a different - * height in a grid layout. - */ - const int COL_RADIO_EMPTY = 0; - const int COL_RADIO_BUTTON = 1; - const int COL_RADIO_LABEL = 2; - const int COL_RADIO_INFO = 3; - const int COL_RADIO_STRETCH = 4; - QGridLayout* buttonGridLayout = new QGridLayout(); - buttonGridLayout->setVerticalSpacing(4); - buttonGridLayout->setColumnMinimumWidth(COL_RADIO_EMPTY, 20); - buttonGridLayout->setColumnMinimumWidth(COL_RADIO_LABEL, 20); - buttonGridLayout->setColumnStretch(COL_RADIO_EMPTY, 0); - buttonGridLayout->setColumnStretch(COL_RADIO_BUTTON, 0); - buttonGridLayout->setColumnStretch(COL_RADIO_STRETCH, 100); - int row = 0; - buttonGridLayout->addWidget(m_lockAspectRadioButton, row, COL_RADIO_BUTTON); - buttonGridLayout->addWidget(lockAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); - row++; - buttonGridLayout->addWidget(lockAspectLabel, row, COL_RADIO_INFO); - row++; - buttonGridLayout->addWidget(m_leaveUnlockedAspectRadioButton, row, COL_RADIO_BUTTON); - buttonGridLayout->addWidget(leaveUnlockedAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); - row++; - buttonGridLayout->addWidget(leaveUnlockedLabel, row, COL_RADIO_INFO); + QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); - dialogLayout->addWidget(mainInstructionsLabel); - dialogLayout->addLayout(buttonGridLayout); - dialogLayout->addSpacing(10); + switch (m_mode) { + case Mode::ENTER_ANNOTATIONS_MODE: + { + const QString mainInstructions("Do you want to lock the aspect ratio while entering annotations mode?"); + + + const QString lockAspectInstructions("Locking the aspect ratio, and never unlocking the aspect " + "ratio, ensures annotations stay in the correct location."); + const QString leaveUnlockedInstructions("Advanced users may choose to lock and unlock the aspect ratio"); + + QLabel* mainInstructionsLabel = new QLabel(mainInstructions); + QFont font = mainInstructionsLabel->font(); + font.setPointSize(font.pointSize() * 1.4); + font.setBold(true); + mainInstructionsLabel->setFont(font); + + QLabel* lockAspectLabel = new QLabel(lockAspectInstructions); + lockAspectLabel->setWordWrap(true); + QLabel* lockAspectRadioButtonLabel = new QLabel("Lock Aspect Ratio (Recommended)"); + m_lockAspectRadioButton = new QRadioButton(); + + QLabel* leaveUnlockedAspectRadioButtonLabel = new QLabel("Leave Aspect Ratio Unlocked"); + m_leaveUnlockedAspectRadioButton = new QRadioButton(); + QLabel* leaveUnlockedLabel = new QLabel(leaveUnlockedInstructions); + + QButtonGroup* buttGroup = new QButtonGroup(this); + buttGroup->addButton(m_lockAspectRadioButton); + buttGroup->addButton(m_leaveUnlockedAspectRadioButton); + m_lockAspectRadioButton->setChecked(true); + + + /* + * No text is added to readio buttons since + * radio buttons and labels seem to get a different + * height in a grid layout. + */ + const int COL_RADIO_EMPTY = 0; + const int COL_RADIO_BUTTON = 1; + const int COL_RADIO_LABEL = 2; + const int COL_RADIO_INFO = 3; + const int COL_RADIO_STRETCH = 4; + QGridLayout* buttonGridLayout = new QGridLayout(); + buttonGridLayout->setVerticalSpacing(4); + buttonGridLayout->setColumnMinimumWidth(COL_RADIO_EMPTY, 20); + buttonGridLayout->setColumnMinimumWidth(COL_RADIO_LABEL, 20); + buttonGridLayout->setColumnStretch(COL_RADIO_EMPTY, 0); + buttonGridLayout->setColumnStretch(COL_RADIO_BUTTON, 0); + buttonGridLayout->setColumnStretch(COL_RADIO_STRETCH, 100); + int row = 0; + buttonGridLayout->addWidget(m_lockAspectRadioButton, row, COL_RADIO_BUTTON); + buttonGridLayout->addWidget(lockAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); + row++; + buttonGridLayout->addWidget(lockAspectLabel, row, COL_RADIO_INFO); + row++; + buttonGridLayout->addWidget(m_leaveUnlockedAspectRadioButton, row, COL_RADIO_BUTTON); + buttonGridLayout->addWidget(leaveUnlockedAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); + row++; + buttonGridLayout->addWidget(leaveUnlockedLabel, row, COL_RADIO_INFO); + + dialogLayout->addWidget(mainInstructionsLabel); + dialogLayout->addLayout(buttonGridLayout); + dialogLayout->addSpacing(10); + } + break; + case Mode::TOOLBAR_LOCK_ASPECT: + break; + } + dialogLayout->addWidget(supplementalInstructionLabel); dialogLayout->addSpacing(10); dialogLayout->addWidget(m_doNotShowAgainCheckBox); @@ -201,7 +294,6 @@ m_brainBrowserWindow(brainBrowserWindow) WuQDialogModal::SCROLL_AREA_NEVER); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - } /** diff --git a/src/GuiQt/LockAspectWarningDialog.h b/src/GuiQt/LockAspectWarningDialog.h index 85f8c398c31cff6259ecc0ae853be8938184c971..6acd1af84117b53590e976bb1894bce611bf87e8 100644 --- a/src/GuiQt/LockAspectWarningDialog.h +++ b/src/GuiQt/LockAspectWarningDialog.h @@ -45,9 +45,18 @@ namespace caret { CANCEL }; - static Result runDialog(const int32_t browserWindowIndex); + enum class Mode { + ENTER_ANNOTATIONS_MODE, + TOOLBAR_LOCK_ASPECT + }; + + static bool runDialogToolBarLockAspect(BrainBrowserWindow* bbw, + const int32_t numberOfTabsInWindow); + + static Result runDialogEnterAnnotationsMode(const int32_t browserWindowIndex); - LockAspectWarningDialog(BrainBrowserWindow* brainBrowserWindow); + LockAspectWarningDialog(BrainBrowserWindow* brainBrowserWindow, + const Mode mode); virtual ~LockAspectWarningDialog(); @@ -57,6 +66,14 @@ namespace caret { // ADD_NEW_METHODS_HERE + enum class LockingMode { + ENTER_ANNOTATIONS_MODE, + LOCK_ASPECT + }; + + static QString getLockingInstructionsText(const QString& buttonText, + const bool showBestPracticesLink); + private slots: void detailsLabelLinkActivated(const QString& link); @@ -67,22 +84,27 @@ namespace caret { BrainBrowserWindow* m_brainBrowserWindow; + const Mode m_mode; + Result m_result = Result::CANCEL; QCheckBox* m_doNotShowAgainCheckBox; - QRadioButton* m_lockAspectRadioButton; + QRadioButton* m_lockAspectRadioButton = NULL; + + QRadioButton* m_leaveUnlockedAspectRadioButton = NULL; - QRadioButton* m_leaveUnlockedAspectRadioButton; + static bool s_doNotShowAgainEnterAnnotationsModeStatusFlag; - static bool s_doNotShowAgainStatusFlag; + static bool s_doNotShowAgainLockAspectModeStatusFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ - bool LockAspectWarningDialog::s_doNotShowAgainStatusFlag = false; + bool LockAspectWarningDialog::s_doNotShowAgainEnterAnnotationsModeStatusFlag = false; + bool LockAspectWarningDialog::s_doNotShowAgainLockAspectModeStatusFlag = false; #endif // __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ } // namespace diff --git a/src/GuiQt/MacDuplicateMenuBar.cxx b/src/GuiQt/MacDuplicateMenuBar.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d0f0b832a4123d87694555f7cedff3c50a2fc613 --- /dev/null +++ b/src/GuiQt/MacDuplicateMenuBar.cxx @@ -0,0 +1,156 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __MAC_DUPLICATE_MENU_BAR_DECLARE__ +#include "MacDuplicateMenuBar.h" +#undef __MAC_DUPLICATE_MENU_BAR_DECLARE__ + +#include + +#include +#include +#include +#include +#include + + +#include "AString.h" +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::MacDuplicateMenuBar + * \brief A duplicate of the mac menu bar placed in the main window + * \ingroup GuiQt + * + * The menu on macs is separate from the main window and placed at the + * top of the display. When creating screen images, such as for tutorials, + * it makes it difficult to include the menu bar in the image. This class + * creates a copy of the menu bar in a widget that can be added to + * the main window. + */ + +/** + * Constructor. + * + * @param mainWindow + * Main window whose menu bar is copied. + * @param parent + * Optional parent widget. + */ +MacDuplicateMenuBar::MacDuplicateMenuBar(QMainWindow* mainWindow, + QWidget* parent) +: QWidget(parent) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + QMargins margins = layout->contentsMargins(); + margins.setTop(0); + margins.setBottom(0); + layout->setContentsMargins(margins); + + CaretAssert(mainWindow); + + /* + * Examine contents of menu bar and duplicate all items in it + */ + QList menuList = mainWindow->menuBar()->actions(); + QListIterator iter(menuList); + while (iter.hasNext()) { + QAction* action = iter.next(); + QMenu* menu = action->menu(); + if (menu != NULL) { + QMenu* dupMenu = duplicateMenu(menu); + if (dupMenu != NULL) { + /* + * Cannot add a menu bar to the window so each menu + * is attached to a new QToolButton + */ + QToolButton* tb = new QToolButton(); + tb->setPopupMode(QToolButton::InstantPopup); + tb->setText(menu->title()); + tb->setMenu(dupMenu); + layout->addWidget(tb); + } + } + } + layout->addStretch(); +} + +/** + * Destructor. + */ +MacDuplicateMenuBar::~MacDuplicateMenuBar() +{ +} + +/** + * Recursively duplicate the given menu. + * + * @param copyFromMenu + * Menu that is examined and copied + * @return + * Pointer to duplicated menu or NULL if failed to duplicate. + */ +QMenu* +MacDuplicateMenuBar::duplicateMenu(QMenu* copyFromMenu) +{ + const bool printFlag(false); + + if (printFlag) { + std::cout << std::endl; + std::cout << m_indentText << "Menu: " << copyFromMenu->title() << std::endl; + } + m_indentText.append(" "); + + QMenu* newMenu = new QMenu(copyFromMenu->title()); + QList actionList = copyFromMenu->actions(); + QListIterator iter(actionList); + while (iter.hasNext()) { + QAction* action = iter.next(); + QMenu* subMenu = action->menu(); + if (subMenu != NULL) { + QMenu* dupMenu = duplicateMenu(subMenu); + if (dupMenu != NULL) { + newMenu->addMenu(dupMenu); + } + } + else if (action->isSeparator()) { + if (printFlag) { + std::cout << m_indentText << "Separator" << std::endl; + } + newMenu->addSeparator(); + } + else { + if (printFlag) { + std::cout << m_indentText << "Item: " << action->text() << std::endl; + } + newMenu->addAction(action); + } + } + + m_indentText.resize(m_indentText.length() - 3); + + return newMenu; +} + + diff --git a/src/GuiQt/MacDuplicateMenuBar.h b/src/GuiQt/MacDuplicateMenuBar.h new file mode 100644 index 0000000000000000000000000000000000000000..6ca9bb0e95cddb835804ceb8ad6e72cac1e4d697 --- /dev/null +++ b/src/GuiQt/MacDuplicateMenuBar.h @@ -0,0 +1,65 @@ +#ifndef __MAC_DUPLICATE_MENU_BAR_H__ +#define __MAC_DUPLICATE_MENU_BAR_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QMainWindow; +class QMenu; +namespace caret { + + class MacDuplicateMenuBar : public QWidget { + + Q_OBJECT + + public: + MacDuplicateMenuBar(QMainWindow* mainWindow, + QWidget* parent = 0); + + virtual ~MacDuplicateMenuBar(); + + MacDuplicateMenuBar(const MacDuplicateMenuBar&) = delete; + + MacDuplicateMenuBar& operator=(const MacDuplicateMenuBar&) = delete; + + + // ADD_NEW_METHODS_HERE + + private: + QMenu* duplicateMenu(QMenu* menu); + + QString m_indentText; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __MAC_DUPLICATE_MENU_BAR_DECLARE__ + // +#endif // __MAC_DUPLICATE_MENU_BAR_DECLARE__ + +} // namespace +#endif //__MAC_DUPLICATE_MENU_BAR_H__ diff --git a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx index a416b961d4d4c61839e9e8f6c015eeec78c1b96c..02fff7927a3c82021767ce187ce51c3b43bccecb 100644 --- a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx +++ b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -74,8 +75,6 @@ MapSettingsChartTwoLineHistoryWidget::MapSettingsChartTwoLineHistoryWidget(QWidg m_removeAllHistoryIcon = WuQtUtilities::loadIcon(":/SpecFileDialog/delete_icon.png"); - m_filenameLabel = new QLabel(""); - QLabel* defaultColorLabel = new QLabel("Default Color: "); defaultColorLabel->setToolTip(defaultColorToolTip); m_defaultColorComboBox = new CaretColorEnumComboBox(this); @@ -130,8 +129,6 @@ MapSettingsChartTwoLineHistoryWidget::MapSettingsChartTwoLineHistoryWidget(QWidg topLayout->setColumnStretch(3, 0); topLayout->setColumnStretch(4, 100); int gridRow = 0; - topLayout->addWidget(m_filenameLabel, gridRow, 0, 1, 5, Qt::AlignLeft); - gridRow++; topLayout->addWidget(defaultLineWidthLabel, gridRow, 0); topLayout->addWidget(m_defaultLineWidthSpinBox->getWidget(), gridRow, 1); topLayout->addWidget(defaultColorLabel, gridRow, 2); @@ -218,11 +215,6 @@ MapSettingsChartTwoLineHistoryWidget::updateDialogContentPrivate() ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { - const CaretMappableDataFile* mapFile = getMapFile(); - if (mapFile != NULL) { - m_filenameLabel->setText("Filename: " + mapFile->getFileNameNoPath()); - m_filenameLabel->setToolTip(mapFile->getFileName()); - } m_defaultColorComboBox->setSelectedColor(lineSeriesHistory->getDefaultColor()); m_defaultLineWidthSpinBox->blockSignals(true); m_defaultLineWidthSpinBox->setValue(lineSeriesHistory->getDefaultLineWidth()); @@ -329,6 +321,33 @@ MapSettingsChartTwoLineHistoryWidget::loadHistoryIntoTableWidget(ChartTwoLineSer COLUMN_REMOVE, removeHistoryLabel); } + else if (j == COLUMN_MOVE) { + QLabel dummyLabel(""); + QPixmap moveDownPixmap = createIcon(&dummyLabel, IconType::ARROW_DOWN); + WuQImageLabel* moveDownLabel = new WuQImageLabel(moveDownPixmap, + "Move Down"); + QObject::connect(moveDownLabel, &WuQImageLabel::clicked, + this, [=] { moveDownHistoryItemSelected(iRow); }); + + QPixmap moveUpPixmap = createIcon(&dummyLabel, IconType::ARROW_UP); + WuQImageLabel* moveUpLabel = new WuQImageLabel(moveUpPixmap, + "Move Up"); + QObject::connect(moveUpLabel, &WuQImageLabel::clicked, + this, [=] { moveUpHistoryItemSelected(iRow); }); + + QWidget* moveWidget = new QWidget; + QHBoxLayout* moveLayout = new QHBoxLayout(moveWidget); + moveLayout->setContentsMargins(4, 0, 4, 0); + moveLayout->setSpacing(6); + moveLayout->addWidget(moveDownLabel); + moveLayout->addWidget(moveUpLabel); + moveWidget->setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); + + m_tableWidget->setCellWidget(iRow, + COLUMN_MOVE, + moveWidget); + } else if (j == COLUMN_COLOR) { CaretColorEnumComboBox* caretColorComboBox = new CaretColorEnumComboBox(this); QObject::connect(caretColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), @@ -405,6 +424,8 @@ MapSettingsChartTwoLineHistoryWidget::loadHistoryIntoTableWidget(ChartTwoLineSer new QTableWidgetItem("View")); m_tableWidget->setHorizontalHeaderItem(COLUMN_REMOVE, new QTableWidgetItem("Remove")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_MOVE, + new QTableWidgetItem("Move")); m_tableWidget->setHorizontalHeaderItem(COLUMN_COLOR, new QTableWidgetItem("Color")); m_tableWidget->setHorizontalHeaderItem(COLUMN_LINE_WIDTH, @@ -414,6 +435,7 @@ MapSettingsChartTwoLineHistoryWidget::loadHistoryIntoTableWidget(ChartTwoLineSer m_tableWidget->resizeColumnToContents(COLUMN_VIEW); m_tableWidget->resizeColumnToContents(COLUMN_REMOVE); + m_tableWidget->resizeColumnToContents(COLUMN_MOVE); m_tableWidget->resizeColumnToContents(COLUMN_COLOR); m_tableWidget->resizeColumnToContents(COLUMN_LINE_WIDTH); m_tableWidget->setColumnWidth(COLUMN_DESCRIPTION, @@ -475,6 +497,36 @@ MapSettingsChartTwoLineHistoryWidget::removeHistoryItemSelected(int rowIndex) EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } +/** + * Move a history item up + * + * @param rowIndex + * Row index of item. + */ +void +MapSettingsChartTwoLineHistoryWidget::moveUpHistoryItemSelected(int rowIndex) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + lineSeriesHistory->moveUpHistoryItem(rowIndex); + updateDialogContentPrivate(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + +/** + * Move a history item down + * + * @param rowIndex + * Row index of item. + */ +void +MapSettingsChartTwoLineHistoryWidget::moveDownHistoryItemSelected(int rowIndex) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + lineSeriesHistory->moveDownHistoryItem(rowIndex); + updateDialogContentPrivate(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + /** * Color item selected * @@ -580,4 +632,55 @@ MapSettingsChartTwoLineHistoryWidget::viewedMaximumSpinBoxValueChanged(int num) updateDialogContentPrivate(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } -} \ No newline at end of file +} + +/** + * Create a pixmap for the given widget + * + * @param editButton + * The edit button identifier + * @return + * Pixmap for the given button + */ +QPixmap +MapSettingsChartTwoLineHistoryWidget::createIcon(const QWidget* widget, + const IconType iconType) const +{ + CaretAssert(widget); + const qreal pixmapSize = 22.0; + const qreal maxValue = pixmapSize / 2.0 - 1.0; + const qreal arrowTip = maxValue * (2.0 / 3.0); + + uint32_t pixmapOptions(static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); + + QPixmap pixmap(static_cast(pixmapSize), + static_cast(pixmapSize)); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, + pixmap, + pixmapOptions); + QPen pen(painter->pen()); + pen.setWidth(3); + painter->setPen(pen); + + switch (iconType) { + case IconType::ARROW_DOWN: + /* + * Down arrow + */ + painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); + painter->drawLine(QPointF(0, -maxValue), QPointF(arrowTip, -maxValue + arrowTip)); + painter->drawLine(QPointF(0, -maxValue), QPointF(-arrowTip, -maxValue + arrowTip)); + break; + case IconType::ARROW_UP: + /* + * Up arrow + */ + painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); + painter->drawLine(QPointF(0, maxValue), QPointF(arrowTip, maxValue - arrowTip)); + painter->drawLine(QPointF(0, maxValue), QPointF(-arrowTip, maxValue - arrowTip)); + break; + } + + return pixmap; +} + diff --git a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h index 2594fa802caccdff55d8346cd66e667d632f9bc5..87d09e3906ff604efa4d3b4c526bcaac80926c65 100644 --- a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h +++ b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h @@ -63,6 +63,10 @@ namespace caret { void removeHistoryItemSelected(int rowIndex); + void moveUpHistoryItemSelected(int rowIndex); + + void moveDownHistoryItemSelected(int rowIndex); + void colorItemSelected(int rowIndex); void lineWidthItemSelected(int rowIndex); @@ -76,6 +80,10 @@ namespace caret { void viewedMaximumSpinBoxValueChanged(int); private: + enum class IconType { + ARROW_DOWN, + ARROW_UP + }; MapSettingsChartTwoLineHistoryWidget(const MapSettingsChartTwoLineHistoryWidget&); @@ -91,12 +99,19 @@ namespace caret { CaretMappableDataFile* getMapFile(); + QPixmap createIcon(const QWidget* widget, + const IconType iconType) const; + std::weak_ptr m_chartOverlayWeakPointer; QTableWidget* m_tableWidget; QIcon* m_removeAllHistoryIcon; + QIcon* m_downArrowIcon; + + QIcon* m_upArrowIcon; + QSignalMapper* m_removeHistoryItemSignalMapper; QSignalMapper* m_colorItemSignalMapper; @@ -107,8 +122,6 @@ namespace caret { std::vector m_lineWidthSpinBoxes; - QLabel* m_filenameLabel; - CaretColorEnumComboBox* m_defaultColorComboBox; WuQDoubleSpinBox* m_defaultLineWidthSpinBox; @@ -117,10 +130,11 @@ namespace caret { static const int32_t COLUMN_VIEW = 0; static const int32_t COLUMN_REMOVE = 1; - static const int32_t COLUMN_COLOR = 2; - static const int32_t COLUMN_LINE_WIDTH = 3; - static const int32_t COLUMN_DESCRIPTION = 4; - static const int32_t COLUMN_COUNT = 5; + static const int32_t COLUMN_MOVE = 2; + static const int32_t COLUMN_COLOR = 3; + static const int32_t COLUMN_LINE_WIDTH = 4; + static const int32_t COLUMN_DESCRIPTION = 5; + static const int32_t COLUMN_COUNT = 6; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/MapYokingGroupComboBox.cxx b/src/GuiQt/MapYokingGroupComboBox.cxx index 7806926aa9173e23f806a6e867f7fa289f0d01bc..75eac115808794c1d41caa341468c3e20d70eb30 100644 --- a/src/GuiQt/MapYokingGroupComboBox.cxx +++ b/src/GuiQt/MapYokingGroupComboBox.cxx @@ -33,6 +33,7 @@ #include "EventManager.h" #include "EventMapYokingValidation.h" #include "Overlay.h" +#include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -48,17 +49,56 @@ using namespace caret; * Constructor. */ MapYokingGroupComboBox::MapYokingGroupComboBox(QObject* parent) +: MapYokingGroupComboBox(parent, + "", + "") +{ +} +//: WuQWidget(parent) +//{ +// m_comboBox = new EnumComboBoxTemplate(this); +// m_comboBox->setup(); +// m_comboBox->getWidget()->setStatusTip("Synchronize selected map indices (and selection status for overlays)"); +// m_comboBox->getWidget()->setToolTip("Synchronize selected map indices (and selection status for overlays)"); +//#ifdef CARET_OS_MACOSX +// m_comboBox->getComboBox()->setFixedWidth(m_comboBox->getComboBox()->sizeHint().width() - 20); +//#endif // CARET_OS_MACOSX +// QObject::connect(m_comboBox, SIGNAL(itemActivated()), +// this, SLOT(comboBoxActivated())); +// WuQObject::watchObjectForMacroRecording(m_comboBox); +//} + +/** + * Constructor. + * + * @param parent + * Parent of this combo box + * @param objectName + * Object name for macros + * @param descriptiveName + Descriptive name for macros + */ +MapYokingGroupComboBox::MapYokingGroupComboBox(QObject* parent, + const QString& objectName, + const QString& descriptiveName) : WuQWidget(parent) { m_comboBox = new EnumComboBoxTemplate(this); m_comboBox->setup(); m_comboBox->getWidget()->setStatusTip("Synchronize selected map indices (and selection status for overlays)"); m_comboBox->getWidget()->setToolTip("Synchronize selected map indices (and selection status for overlays)"); + m_comboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContents); #ifdef CARET_OS_MACOSX - m_comboBox->getComboBox()->setFixedWidth(m_comboBox->getComboBox()->sizeHint().width() - 20); +// m_comboBox->getComboBox()->setFixedWidth(m_comboBox->getComboBox()->sizeHint().width() - 20); #endif // CARET_OS_MACOSX QObject::connect(m_comboBox, SIGNAL(itemActivated()), this, SLOT(comboBoxActivated())); + if ( ! objectName.isEmpty()) { + QWidget* encapsulatedComboBox = m_comboBox->getWidget(); + encapsulatedComboBox->setObjectName(objectName); + WuQMacroManager::instance()->addMacroSupportToObject(encapsulatedComboBox, + "Select map yoking for " + descriptiveName); + } } /** diff --git a/src/GuiQt/MapYokingGroupComboBox.h b/src/GuiQt/MapYokingGroupComboBox.h index 532fb9a24fea8aae95678fa6b500fa5b390e46e0..787a9584832a5c49cea943863bfec48bc36b7819 100644 --- a/src/GuiQt/MapYokingGroupComboBox.h +++ b/src/GuiQt/MapYokingGroupComboBox.h @@ -39,6 +39,10 @@ namespace caret { public: MapYokingGroupComboBox(QObject* parent); + MapYokingGroupComboBox(QObject* parent, + const QString& objectName, + const QString& descriptiveName); + virtual ~MapYokingGroupComboBox(); virtual QWidget* getWidget(); diff --git a/src/GuiQt/MovieRecordingDialog.cxx b/src/GuiQt/MovieRecordingDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..192405dc7839188136f9a7a7d060a4f13d664109 --- /dev/null +++ b/src/GuiQt/MovieRecordingDialog.cxx @@ -0,0 +1,723 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __MOVIE_RECORDING_DIALOG_DECLARE__ +#include "MovieRecordingDialog.h" +#undef __MOVIE_RECORDING_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Brain.h" +#include "BrainBrowserWindowComboBox.h" +#include "CaretAssert.h" +#include "CaretFileDialog.h" +#include "CursorDisplayScoped.h" +#include "Event.h" +#include "EventManager.h" +#include "EventGraphicsUpdateOneWindow.h" +#include "EventMovieManualModeRecording.h" +#include "EventUserInterfaceUpdate.h" +#include "EnumComboBoxTemplate.h" +#include "FileInformation.h" +#include "GuiManager.h" +#include "MovieRecorder.h" +#include "MovieRecorderVideoFormatTypeEnum.h" +#include "SessionManager.h" +#include "WuQMessageBox.h" + +using namespace caret; + + + +/** + * \class caret::MovieRecordingDialog + * \brief Dialog for control of movie recording and creation + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +MovieRecordingDialog::MovieRecordingDialog(QWidget* parent) +: WuQDialogNonModal("Movie Recording", + parent) +{ + QTabWidget* tabWidget = new QTabWidget(); + tabWidget->addTab(createMainWidget(), "Main"); + tabWidget->addTab(createSettingsWidget(), "Settings"); + + setCentralWidget(tabWidget, + SCROLL_AREA_NEVER); + + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); + + setApplyButtonText(""); + disableAutoDefaultForAllPushButtons(); + + CaretAssert(SessionManager::get()->getMovieRecorder()); +} + +/** + * Destructor. + */ +MovieRecordingDialog::~MovieRecordingDialog() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Called when close event is issuedf + * + * @param event + * The close event + */ +void +MovieRecordingDialog::closeEvent(QCloseEvent* event) +{ + s_previousDialogGeometry = saveGeometry(); + + WuQDialogNonModal::closeEvent(event); +} + +void +MovieRecordingDialog::restorePositionAndSize() +{ + if ( ! s_previousDialogGeometry.isEmpty()) { + restoreGeometry(s_previousDialogGeometry); + } +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +MovieRecordingDialog::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE) { + updateDialog(); + event->setEventProcessed(); + } +} + +/** + * May be called to update the dialog's content. + */ +void +MovieRecordingDialog::updateDialog() +{ + const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + CaretAssert(movieRecorder); + + m_windowComboBox->updateComboBox(); + m_windowComboBox->setBrowserWindowByIndex(movieRecorder->getRecordingWindowIndex()); + + switch (movieRecorder->getRecordingMode()) { + case MovieRecorderModeEnum::MANUAL: + m_recordingManualRadioButton->setChecked(true); + break; + case MovieRecorderModeEnum::AUTOMATIC: + m_recordingAutomaticRadioButton->setChecked(true); + break; + } + + const MovieRecorderVideoResolutionTypeEnum::Enum resType = movieRecorder->getVideoResolutionType(); + m_movieRecorderVideoResolutionTypeEnumComboBox->setSelectedItem(resType); + + const MovieRecorderCaptureRegionTypeEnum::Enum captureType = movieRecorder->getCaptureRegionType(); + m_movieRecorderCaptureRegionTypeComboBox->setSelectedItem(captureType); + + updateManualRecordingOptions(); + updateCustomWidthHeightSpinBoxes(); + updateFrameCountLabel(); +} + +/** + * Update the manual recording options + */ +void +MovieRecordingDialog::updateManualRecordingOptions() +{ + const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + CaretAssert(movieRecorder); + + bool manualRecordingEnabledFlag(false); + switch (movieRecorder->getRecordingMode()) { + case MovieRecorderModeEnum::MANUAL: + manualRecordingEnabledFlag = true; + break; + case MovieRecorderModeEnum::AUTOMATIC: + break; + } + + m_manualCaptureToolButton->setEnabled(manualRecordingEnabledFlag); +} + +/** + * Update the custom width/height spin boxes + */ +void +MovieRecordingDialog::updateCustomWidthHeightSpinBoxes() +{ + const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + CaretAssert(movieRecorder); + + int32_t customWidth(0); + int32_t customHeight(0); + movieRecorder->getCustomWidthAndHeight(customWidth, + customHeight); + QSignalBlocker widthBlocker(m_customWidthSpinBox); + m_customWidthSpinBox->setValue(customWidth); + QSignalBlocker heightBlocker(m_customHeightSpinBox); + m_customHeightSpinBox->setValue(customHeight); + QSignalBlocker frameRateBlocker(m_frameRateSpinBox); + m_frameRateSpinBox->setValue(movieRecorder->getFramesRate()); + m_removeTemporaryImagesAfterMovieCreationCheckBox->setChecked(movieRecorder->isRemoveTemporaryImagesAfterMovieCreation()); + + const bool customSpinBoxesEnabled(movieRecorder->getVideoResolutionType() == MovieRecorderVideoResolutionTypeEnum::CUSTOM); + m_customWidthSpinBox->setEnabled(customSpinBoxesEnabled); + m_customHeightSpinBox->setEnabled(customSpinBoxesEnabled); +} + +/** + * Update the frame count label + */ +void +MovieRecordingDialog::updateFrameCountLabel() +{ + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + const int32_t numberOfFrames = movieRecorder->getNumberOfFrames(); + m_frameCountNumberLabel->setNum(numberOfFrames); + + const int32_t timeSeconds = (movieRecorder->getNumberOfFrames() + / movieRecorder->getFramesRate()); + QTime qtime(0, 0, 0, 0); + QTime timeForString = qtime.addSecs(timeSeconds); + m_lengthLabel->setText(timeForString.toString("h:mm:ss")); + + /* + * Do not allow user to change image size once an image has been captured + */ + m_movieRecorderVideoResolutionTypeEnumComboBox->getWidget()->setEnabled(numberOfFrames <= 0); +} + +/** + * Called when window index is changed + * + * @param windowIndex + * Index of window for recording + */ +void +MovieRecordingDialog::windowIndexSelected(const int32_t windowIndex) +{ + SessionManager::get()->getMovieRecorder()->setRecordingWindowIndex(windowIndex); +} + +/** + * Called when video resolution type is changed + */ +void +MovieRecordingDialog::movieRecorderVideoResolutionTypeEnumComboBoxItemActivated() +{ + const MovieRecorderVideoResolutionTypeEnum::Enum dimType = m_movieRecorderVideoResolutionTypeEnumComboBox->getSelectedItem(); + SessionManager::get()->getMovieRecorder()->setVideoResolutionType(dimType); + updateCustomWidthHeightSpinBoxes(); +} + +/** + * Called when capture region type is changed + */ +void +MovieRecordingDialog::movieRecorderCaptureRegionTypeComboBoxActivated() +{ + const MovieRecorderCaptureRegionTypeEnum::Enum regionType = m_movieRecorderCaptureRegionTypeComboBox->getSelectedItem(); + SessionManager::get()->getMovieRecorder()->setCaptureRegionType(regionType); +} + +/** +* Set the selected browser window to the browser window with the +* given index. +* @param browserWindowIndex +* Index of browser window. +*/ +void +MovieRecordingDialog::setBrowserWindowIndex(const int32_t browserWindowIndex) +{ + m_windowComboBox->setBrowserWindowByIndex(browserWindowIndex); + windowIndexSelected(browserWindowIndex); +} + +/** + * @param Called when custom width spin box value changed + * + * @param width + * New custom width + */ +void +MovieRecordingDialog::customWidthSpinBoxValueChanged(int width) +{ + SessionManager::get()->getMovieRecorder()->setCustomWidthAndHeight(width, + m_customHeightSpinBox->value()); +} + +/** + * @param Called when custom height spin box value changed + * + * @param height + * New custom height + */ +void +MovieRecordingDialog::customHeightSpinBoxValueChanged(int height) +{ + SessionManager::get()->getMovieRecorder()->setCustomWidthAndHeight(m_customWidthSpinBox->value(), + height); +} + +/** + * @param Called when frame rate spin box value changed + * + * @param frameRate + * New frame rate + */ +void +MovieRecordingDialog::frameRateSpinBoxValueChanged(int frameRate) +{ + SessionManager::get()->getMovieRecorder()->setFramesRate(frameRate); +} + +/** + * @param Called when remove temporary images checkbox is clicked + * + * @param checked + * New checked status + */ +void +MovieRecordingDialog::removeTemporaryImagesCheckBoxClicked(bool checked) +{ + if ( ! checked) { + const QString text("If this is deselected, additional movies may contain images from previous movies."); + if ( ! WuQMessageBox::warningOkCancel(m_removeTemporaryImagesAfterMovieCreationCheckBox, + text)) { + checked = true; + } + } + + SessionManager::get()->getMovieRecorder()->setRemoveTemporaryImagesAfterMovieCreation(checked); + m_removeTemporaryImagesAfterMovieCreationCheckBox->setChecked(checked); +} + +/** + * Called when recording mode button is clicked + * + * @param button + * Button that was clicked + */ +void +MovieRecordingDialog::recordingModeRadioButtonClicked(QAbstractButton* button) +{ + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + CaretAssert(movieRecorder); + + if (button == m_recordingAutomaticRadioButton) { + movieRecorder->setRecordingMode(MovieRecorderModeEnum::AUTOMATIC); + } + else if (button == m_recordingManualRadioButton) { + movieRecorder->setRecordingMode(MovieRecorderModeEnum::MANUAL); + } + else { + CaretAssert(0); + } + + updateManualRecordingOptions(); +} + +/** + * Called when manual capture tool button is clicked + */ +void +MovieRecordingDialog::manualCaptureToolButtonClicked() +{ + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + + EventMovieManualModeRecording movieEvent(m_windowComboBox->getSelectedBrowserWindowIndex(), + m_manualCaptureSecondsSpinBox->value()); + EventManager::get()->sendEvent(movieEvent.getPointer()); + updateFrameCountLabel(); +} + +/** + * Called when manual capture seconds spin box value changed + */ +void +MovieRecordingDialog::manualCaptureSecondsSpinBoxValueChanged(int /*seconds*/) +{ +} + +/** + * Called when create movie push button is clicked + */ +void +MovieRecordingDialog::createMoviePushButtonClicked() +{ + createMoviePrivate(m_createMoviePushButton, + true); + QApplication::beep(); +} + +/** + * Get the movie file name + * + * @param parent + * Widget as parent for file selection dialog + * @return + * Name for movie file or empty string if canceled. + */ +QString +MovieRecordingDialog::getMovieFileNameFromFileDialog(QWidget* parent) +{ + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + QString currentFileName = movieRecorder->getMovieFileName(); + MovieRecorderVideoFormatTypeEnum::Enum formatType = MovieRecorderVideoFormatTypeEnum::MPEG; + + QString filters; + QString selectedFilter = MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(formatType); + std::vector formatEnums; + MovieRecorderVideoFormatTypeEnum::getAllEnums(formatEnums); + for (auto fe : formatEnums) { + if ( ! filters.isEmpty()) { + filters.append(";;"); + } + filters.append(MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(fe)); + + if (currentFileName.endsWith(MovieRecorderVideoFormatTypeEnum::toFileNameExtensionNoDot(fe))) { + formatType = fe; + selectedFilter = MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(fe); + } + } + + QString filename = CaretFileDialog::getSaveFileNameDialog(parent, + "Choose Movie File", + currentFileName, + filters, + &selectedFilter, + CaretFileDialog::DontConfirmOverwrite); + + if (filename.isEmpty()) { + return ""; + } + + for (auto fe : formatEnums) { + if (selectedFilter == MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(fe)) { + const QString ext = ("." + MovieRecorderVideoFormatTypeEnum::toFileNameExtensionNoDot(fe)); + if ( ! filename.endsWith(ext)) { + filename.append(ext); + break; + } + } + } + + return filename; +} + +/** + * Create a movie from captured images and if current + * filename is empty, ask for name in file dialog + * + * @param parent + * Parent widget for error message dialog. + */ +void +MovieRecordingDialog::createMovie(QWidget* parent) +{ + createMoviePrivate(parent, + false); +} +/** + * Create a movie from captured images. + * + * @param parent + * Parent widget for error message dialog. + * @param askForFileNameFlag + * If true always query for filename, even if filename is valid + */ +void +MovieRecordingDialog::createMoviePrivate(QWidget* parent, + const bool askForFileNameFlag) +{ + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + QString filename(movieRecorder->getMovieFileName()); + if (filename.isEmpty() + || askForFileNameFlag) { + filename = getMovieFileNameFromFileDialog(parent); + } + + if (filename.isEmpty()) { + return; + } + + FileInformation fileInfo(filename); + const QString name(fileInfo.getCanonicalFilePath()); + if (fileInfo.exists()) { + if ( ! fileInfo.remove()) { + AString msg("Unable to remove movie file \"" + + name + + "\""); + WuQMessageBox::errorOk(parent, + msg); + } + } + + AString errorMessage; + const bool successFlag = movieRecorder->createMovie(filename, + errorMessage); + if ( ! successFlag) { + WuQMessageBox::errorOk(parent, + errorMessage); + } + + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} + +/** + * Called when reset push button is clicked + */ +void +MovieRecordingDialog::resetPushButtonClicked() +{ + if (WuQMessageBox::warningOkCancel(m_resetPushButton, + "Reset (delete) recorded images for new movie")) { + SessionManager::get()->getMovieRecorder()->removeTemporaryImages(); + updateDialog(); + } +} + +/** + * @return New instance of main widget + */ +QWidget* +MovieRecordingDialog::createMainWidget() +{ + QLabel* windowLabel = new QLabel("Record from Window:"); + m_windowComboBox = new BrainBrowserWindowComboBox(BrainBrowserWindowComboBox::STYLE_NUMBER, + this); + m_windowComboBox->setToolTip("Sets window that is recorded"); + QObject::connect(m_windowComboBox, &BrainBrowserWindowComboBox::browserWindowIndexSelected, + this, &MovieRecordingDialog::windowIndexSelected); + + QLabel* regionLabel = new QLabel("Record Region:"); + m_movieRecorderCaptureRegionTypeComboBox = new EnumComboBoxTemplate(this); + m_movieRecorderCaptureRegionTypeComboBox->getWidget()->setToolTip("Choose region that is capture for movie"); + m_movieRecorderCaptureRegionTypeComboBox->setup(); + QObject::connect(m_movieRecorderCaptureRegionTypeComboBox, SIGNAL(itemActivated()), + this, SLOT(movieRecorderCaptureRegionTypeComboBoxActivated())); + + QGroupBox* sourceGroupBox = new QGroupBox("Source"); + QGridLayout* sourceLayout = new QGridLayout(sourceGroupBox); + sourceLayout->setColumnStretch(0, 0); + sourceLayout->setColumnStretch(0, 1); + sourceLayout->setColumnStretch(2, 100); + int sourceRow(0); + sourceLayout->addWidget(windowLabel, sourceRow, 0); + sourceLayout->addWidget(m_windowComboBox->getWidget(), sourceRow, 1); + sourceRow++; + sourceLayout->addWidget(regionLabel, sourceRow, 0); + sourceLayout->addWidget(m_movieRecorderCaptureRegionTypeComboBox->getWidget(), sourceRow, 1); + sourceRow++; + + m_recordingAutomaticRadioButton = new QRadioButton(MovieRecorderModeEnum::toGuiName(MovieRecorderModeEnum::AUTOMATIC)); + m_recordingAutomaticRadioButton->setToolTip("When selected, images are recorded as graphics updated"); + + const QString recordButtonText("Record"); + m_recordingManualRadioButton = new QRadioButton(MovieRecorderModeEnum::toGuiName(MovieRecorderModeEnum::MANUAL)); + m_recordingManualRadioButton->setToolTip("When selected, images recorded when " + + recordButtonText + + " is clicked"); + QButtonGroup* recordingButtonGroup = new QButtonGroup(this); + recordingButtonGroup->addButton(m_recordingAutomaticRadioButton); + recordingButtonGroup->addButton(m_recordingManualRadioButton); + QObject::connect(recordingButtonGroup, QOverload::of(&QButtonGroup::buttonClicked), + this, &MovieRecordingDialog::recordingModeRadioButtonClicked); + + m_manualCaptureToolButton = new QToolButton(); + m_manualCaptureToolButton->setText(recordButtonText); + m_manualCaptureToolButton->setToolTip("Duration of image displayed in movie"); + QObject::connect(m_manualCaptureToolButton, &QToolButton::clicked, + this, &MovieRecordingDialog::manualCaptureToolButtonClicked); + + m_manualCaptureSecondsSpinBox = new QSpinBox(); + m_manualCaptureSecondsSpinBox->setMinimum(1); + m_manualCaptureSecondsSpinBox->setMaximum(100); + m_manualCaptureSecondsSpinBox->setSingleStep(1); + m_manualCaptureSecondsSpinBox->setSizePolicy(QSizePolicy::Fixed, + m_manualCaptureSecondsSpinBox->sizePolicy().verticalPolicy()); + QObject::connect(m_manualCaptureSecondsSpinBox, QOverload::of(&QSpinBox::valueChanged), + this, &MovieRecordingDialog::manualCaptureSecondsSpinBoxValueChanged); + + QLabel* captureSecondsLabel = new QLabel("seconds"); + + QGroupBox* modeGroupBox = new QGroupBox("Recording Mode"); + QGridLayout* modeLayout = new QGridLayout(modeGroupBox); + modeLayout->setColumnStretch(0, 0); + modeLayout->setColumnStretch(1, 0); + modeLayout->setColumnStretch(2, 0); + modeLayout->setColumnStretch(3, 0); + modeLayout->setColumnStretch(4, 100); + int32_t modeRow(0); + modeLayout->addWidget(m_recordingAutomaticRadioButton, modeRow, 0); + modeRow++; + modeLayout->addWidget(m_recordingManualRadioButton, modeRow, 0); + modeLayout->addWidget(m_manualCaptureToolButton, modeRow, 1); + modeLayout->addWidget(m_manualCaptureSecondsSpinBox, modeRow, 2); + modeLayout->addWidget(captureSecondsLabel, modeRow, 3); + modeRow++; + + m_createMoviePushButton = new QPushButton("Create Movie"); + m_createMoviePushButton->setToolTip("Create a movie file using images that have been recorded"); + QObject::connect(m_createMoviePushButton, &QPushButton::clicked, this, + &MovieRecordingDialog::createMoviePushButtonClicked); + + m_resetPushButton = new QPushButton("Reset"); + m_resetPushButton->setToolTip("Remove all recorded images to start a new movie"); + QObject::connect(m_resetPushButton, &QPushButton::clicked, this, + &MovieRecordingDialog::resetPushButtonClicked); + + QLabel* frameCountLabel = new QLabel("Frames: "); + m_frameCountNumberLabel = new QLabel("0"); + + QLabel* lengthLabel = new QLabel("Length: "); + m_lengthLabel = new QLabel("0"); + + QGroupBox* movieFileGroupBox = new QGroupBox("Output Movie"); + QGridLayout* movieLayout = new QGridLayout(movieFileGroupBox); + movieLayout->setColumnStretch(0, 0); + movieLayout->setColumnStretch(1, 0); + movieLayout->setColumnStretch(2, 0); + movieLayout->setColumnStretch(3, 100); + int32_t movieRow(0); + movieLayout->addWidget(m_createMoviePushButton, movieRow, 0); + movieLayout->addWidget(lengthLabel, movieRow, 1); + movieLayout->addWidget(m_lengthLabel, movieRow, 2); + movieRow++; + movieLayout->addWidget(m_resetPushButton, movieRow, 0); + movieLayout->addWidget(frameCountLabel, movieRow, 1); + movieLayout->addWidget(m_frameCountNumberLabel, movieRow, 2); + movieRow++; + + + QWidget* widget = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->addWidget(sourceGroupBox); + layout->addWidget(modeGroupBox); + layout->addWidget(movieFileGroupBox); + layout->addStretch(); + + return widget; +} + +/** + * @return New instance of settings widget + */ +QWidget* +MovieRecordingDialog::createSettingsWidget() +{ + const int spinBoxWidth(100); + + QLabel* resolutionLabel = new QLabel("Resolution:"); + m_movieRecorderVideoResolutionTypeEnumComboBox = new EnumComboBoxTemplate(this); + m_movieRecorderVideoResolutionTypeEnumComboBox->getWidget()->setToolTip("Choose width and height of movie"); + m_movieRecorderVideoResolutionTypeEnumComboBox->setup(); + QObject::connect(m_movieRecorderVideoResolutionTypeEnumComboBox, SIGNAL(itemActivated()), + this, SLOT(movieRecorderVideoResolutionTypeEnumComboBoxItemActivated())); + + QLabel* customLabel = new QLabel("Custom Resolution:"); + m_customWidthSpinBox = new QSpinBox(); + m_customWidthSpinBox->setMinimum(1); + m_customWidthSpinBox->setMaximum(500000); + m_customWidthSpinBox->setSingleStep(1); + QObject::connect(m_customWidthSpinBox, QOverload::of(&QSpinBox::valueChanged), + this, &MovieRecordingDialog::customWidthSpinBoxValueChanged); + m_customWidthSpinBox->setFixedWidth(spinBoxWidth); + + m_customHeightSpinBox = new QSpinBox(); + m_customHeightSpinBox->setMinimum(1); + m_customHeightSpinBox->setMaximum(500000); + m_customHeightSpinBox->setSingleStep(1); + m_customHeightSpinBox->setFixedWidth(spinBoxWidth); + QObject::connect(m_customHeightSpinBox, QOverload::of(&QSpinBox::valueChanged), + this, &MovieRecordingDialog::customHeightSpinBoxValueChanged); + + QLabel* frameRateLabel = new QLabel("Frames Per Second:"); + m_frameRateSpinBox = new QSpinBox(); + m_frameRateSpinBox->setToolTip("20 or 30 recommended"); + m_frameRateSpinBox->setMinimum(1); + m_frameRateSpinBox->setMaximum(1000); + m_frameRateSpinBox->setSingleStep(1); + m_frameRateSpinBox->setFixedWidth(spinBoxWidth); + QObject::connect(m_frameRateSpinBox, QOverload::of(&QSpinBox::valueChanged), + this, &MovieRecordingDialog::frameRateSpinBoxValueChanged); + + m_removeTemporaryImagesAfterMovieCreationCheckBox = new QCheckBox("Remove temporary images after movie creation"); + m_removeTemporaryImagesAfterMovieCreationCheckBox->setToolTip("Temporary images are removed after a movie is created"); + QObject::connect(m_removeTemporaryImagesAfterMovieCreationCheckBox, &QCheckBox::clicked, + this, &MovieRecordingDialog::removeTemporaryImagesCheckBoxClicked); + + QWidget* widget = new QWidget(); + QGridLayout* gridLayout = new QGridLayout(widget); + gridLayout->setRowStretch(100, 100); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnStretch(2, 0); + gridLayout->setColumnStretch(3, 100); + int32_t row(0); + gridLayout->addWidget(resolutionLabel, row, 0); + gridLayout->addWidget(m_movieRecorderVideoResolutionTypeEnumComboBox->getWidget(), + row, 1, 1, 2, Qt::AlignLeft); + row++; + gridLayout->addWidget(customLabel, row, 0); + gridLayout->addWidget(m_customWidthSpinBox, row, 1); + gridLayout->addWidget(m_customHeightSpinBox, row, 2); + row++; + gridLayout->addWidget(frameRateLabel, row, 0); + gridLayout->addWidget(m_frameRateSpinBox, + row, 1, 1, 2, Qt::AlignLeft); + row++; + gridLayout->addWidget(m_removeTemporaryImagesAfterMovieCreationCheckBox, + row, 0, 1, 3, Qt::AlignLeft); + row++; + + return widget; +} + diff --git a/src/GuiQt/MovieRecordingDialog.h b/src/GuiQt/MovieRecordingDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..0b2abcf02f75fd5f93313847025f13c16d947c97 --- /dev/null +++ b/src/GuiQt/MovieRecordingDialog.h @@ -0,0 +1,154 @@ +#ifndef __MOVIE_RECORDING_DIALOG_H__ +#define __MOVIE_RECORDING_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + + +#include "EventListenerInterface.h" +#include "WuQDialogNonModal.h" + +class QAbstractButton; +class QCheckBox; +class QLabel; +class QPushButton; +class QRadioButton; +class QSpinBox; +class QToolButton; + +namespace caret { + + class BrainBrowserWindowComboBox; + class EnumComboBoxTemplate; + + class MovieRecordingDialog : public WuQDialogNonModal, public EventListenerInterface { + + Q_OBJECT + + public: + MovieRecordingDialog(QWidget* parent); + + virtual ~MovieRecordingDialog(); + + MovieRecordingDialog(const MovieRecordingDialog&) = delete; + + MovieRecordingDialog& operator=(const MovieRecordingDialog&) = delete; + + void setBrowserWindowIndex(const int32_t browserWindowIndex); + + void updateDialog(); + + void restorePositionAndSize(); + + // ADD_NEW_METHODS_HERE + + virtual void receiveEvent(Event* event); + + static void createMovie(QWidget* parent); + + static QString getMovieFileNameFromFileDialog(QWidget* parent); + + private slots: + void movieRecorderVideoResolutionTypeEnumComboBoxItemActivated(); + + void movieRecorderCaptureRegionTypeComboBoxActivated(); + + void recordingModeRadioButtonClicked(QAbstractButton* button); + + void customWidthSpinBoxValueChanged(int width); + + void customHeightSpinBoxValueChanged(int width); + + void frameRateSpinBoxValueChanged(int frameRate); + + void removeTemporaryImagesCheckBoxClicked(bool checked); + + void windowIndexSelected(const int32_t windowIndex); + + void createMoviePushButtonClicked(); + + void resetPushButtonClicked(); + + void manualCaptureToolButtonClicked(); + + void manualCaptureSecondsSpinBoxValueChanged(int seconds); + + protected: + virtual void closeEvent(QCloseEvent* event) override; + + private: + void updateFrameCountLabel(); + + void updateCustomWidthHeightSpinBoxes(); + + void updateManualRecordingOptions(); + + QWidget* createMainWidget(); + + QWidget* createSettingsWidget(); + + static void createMoviePrivate(QWidget* parent, + const bool askForFileNameFlag); + + QRadioButton* m_recordingAutomaticRadioButton; + + QRadioButton* m_recordingManualRadioButton; + + QToolButton* m_manualCaptureToolButton; + + QSpinBox* m_manualCaptureSecondsSpinBox; + + EnumComboBoxTemplate* m_movieRecorderVideoResolutionTypeEnumComboBox; + + QSpinBox* m_customWidthSpinBox; + + QSpinBox* m_customHeightSpinBox; + + QSpinBox* m_frameRateSpinBox; + + QCheckBox* m_removeTemporaryImagesAfterMovieCreationCheckBox; + + QPushButton* m_createMoviePushButton; + + QPushButton* m_resetPushButton; + + QLabel* m_frameCountNumberLabel; + + QLabel* m_lengthLabel; + + BrainBrowserWindowComboBox* m_windowComboBox; + + EnumComboBoxTemplate* m_movieRecorderCaptureRegionTypeComboBox; + + static QByteArray s_previousDialogGeometry; + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __MOVIE_RECORDING_DIALOG_DECLARE__ + QByteArray MovieRecordingDialog::s_previousDialogGeometry; +#endif // __MOVIE_RECORDING_DIALOG_DECLARE__ + +} // namespace +#endif //__MOVIE_RECORDING_DIALOG_H__ diff --git a/src/GuiQt/OverlaySetViewController.cxx b/src/GuiQt/OverlaySetViewController.cxx index fb090d8eebe1835c0df0bd46517edb42de16352d..1ec1c08293b76fa86d929fc8c63c700adca58672 100644 --- a/src/GuiQt/OverlaySetViewController.cxx +++ b/src/GuiQt/OverlaySetViewController.cxx @@ -60,11 +60,14 @@ using namespace caret; * Orientation for layout * @param browserWindowIndex * Index of browser window that contains this view controller. + * @param parentObjectName + * Name of parent * @param parent * Parent widget. */ OverlaySetViewController::OverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent) : QWidget(parent) { @@ -114,6 +117,7 @@ OverlaySetViewController::OverlaySetViewController(const Qt::Orientation orienta gridLayout, browserWindowIndex, i, + parentObjectName, this); this->overlayViewControllers.push_back(ovc); diff --git a/src/GuiQt/OverlaySetViewController.h b/src/GuiQt/OverlaySetViewController.h index a7299b5747a6876b7b550fb4a5b3afe291e6eb65..94c5da1e4826248c4bde81ad90a0a8bcd3f4f539 100644 --- a/src/GuiQt/OverlaySetViewController.h +++ b/src/GuiQt/OverlaySetViewController.h @@ -44,6 +44,7 @@ namespace caret { public: OverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectName, QWidget* parent = 0); virtual ~OverlaySetViewController(); diff --git a/src/GuiQt/OverlaySettingsEditorDialog.cxx b/src/GuiQt/OverlaySettingsEditorDialog.cxx index 3ce6004f250d22f1298284b90d79534575bddac7..675ccfe0fcad2c8391d095035d30b58bc6cf00b1 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.cxx +++ b/src/GuiQt/OverlaySettingsEditorDialog.cxx @@ -405,6 +405,8 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv } } else if (m_chartOverlay != NULL) { + mapFileName = m_caretMappableDataFile->getFileNameNoPath(); + bool hasMapsFlag = false; bool hasHistoryFlag = false; switch (m_chartOverlay->getChartTwoDataType()) { @@ -447,10 +449,6 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv } if ((selectedMapIndex >= 0) && (selectedMapIndex < m_caretMappableDataFile->getNumberOfMaps())) { - /* - * Get name of file and map - */ - mapFileName = m_caretMappableDataFile->getFileNameNoPath(); if (m_selectedMapFileIndex >= 0) { mapName = m_caretMappableDataFile->getMapName(selectedMapIndex); } @@ -501,6 +499,9 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv else if (hasHistoryFlag) { isLinesValid = true; m_lineHistoryWidget->updateContent(m_chartOverlay); + if (mapName.isEmpty()) { + mapName = "Line Chart History"; + } } } else { diff --git a/src/GuiQt/OverlayViewController.cxx b/src/GuiQt/OverlayViewController.cxx index 0ee46f04214366cc81d02d93a6b5511015aa5a91..2e006084e62b4518395dc62c0f060c59bd55cd36 100644 --- a/src/GuiQt/OverlayViewController.cxx +++ b/src/GuiQt/OverlayViewController.cxx @@ -54,6 +54,7 @@ #include "Overlay.h" #include "UsernamePasswordWidget.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "WuQGridLayoutGroup.h" @@ -70,10 +71,16 @@ using namespace caret; /** * Constructor. * + * @param orientation + * Orientation of overlay (horizontal/vertical) + * @param gridLayout + * Layout for widegets * @param browserWindowIndex * Index of browser window in which this view controller resides. - * @param showTopHorizontalLine - * If true, display a horizontal line above the controls. + * @param overlayIndex + * Index of the overlay + * @param parentObjectName + * Name of parent object for macros * @param parent * The parent widget. */ @@ -81,6 +88,7 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, QGridLayout* gridLayout, const int32_t browserWindowIndex, const int32_t overlayIndex, + const QString& parentObjectName, QObject* parent) : QObject(parent), browserWindowIndex(browserWindowIndex), @@ -97,49 +105,73 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, } const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContentsOnFirstShow; //QComboBox::AdjustToContents; + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + QString objectNamePrefix = QString(parentObjectName + + ":Overlay%1" + + ":").arg((int)(overlayIndex + 1), 2, 10, QLatin1Char('0')); + const QString descriptivePrefix = QString("overlay %1").arg(overlayIndex + 1); /* * Enabled Check Box */ const QString checkboxText = ((orientation == Qt::Horizontal) ? " " : " "); this->enabledCheckBox = new QCheckBox(checkboxText); + this->enabledCheckBox->setObjectName(objectNamePrefix + + "OnOff"); QObject::connect(this->enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(enabledCheckBoxClicked(bool))); this->enabledCheckBox->setToolTip("Enables display of this overlay"); + macroManager->addMacroSupportToObject(this->enabledCheckBox, + "Enable " + descriptivePrefix); /* - * File Selection Check Box + * File Selection Combo Box */ this->fileComboBox = WuQFactory::newComboBox(); + this->fileComboBox->setObjectName(objectNamePrefix + + "FileSelection"); this->fileComboBox->setMinimumWidth(minComboBoxWidth); this->fileComboBox->setMaximumWidth(maxComboBoxWidth); QObject::connect(this->fileComboBox, SIGNAL(activated(int)), this, SLOT(fileComboBoxSelected(int))); this->fileComboBox->setToolTip("Selects file for this overlay"); this->fileComboBox->setSizeAdjustPolicy(comboSizePolicy); + macroManager->addMacroSupportToObject(this->fileComboBox, + ("Select file in " + descriptivePrefix)); /* * Map Index Spin Box */ m_mapIndexSpinBox = WuQFactory::newSpinBox(); + this->m_mapIndexSpinBox->setObjectName(objectNamePrefix + + "MapIndex"); QObject::connect(m_mapIndexSpinBox, SIGNAL(valueChanged(int)), this, SLOT(mapIndexSpinBoxValueChanged(int))); m_mapIndexSpinBox->setToolTip("Select map by its index"); + macroManager->addMacroSupportToObject(m_mapIndexSpinBox, + ("Select " + descriptivePrefix + " map index")); /* * Map Name Combo Box */ this->mapNameComboBox = WuQFactory::newComboBox(); + this->mapNameComboBox->setObjectName(objectNamePrefix + + "MapSelection"); this->mapNameComboBox->setMinimumWidth(minComboBoxWidth); this->mapNameComboBox->setMaximumWidth(maxComboBoxWidth); QObject::connect(this->mapNameComboBox, SIGNAL(activated(int)), this, SLOT(mapNameComboBoxSelected(int))); this->mapNameComboBox->setToolTip("Select map by its name"); this->mapNameComboBox->setSizeAdjustPolicy(comboSizePolicy); + macroManager->addMacroSupportToObject(this->mapNameComboBox, + ("Select " + descriptivePrefix + " map name")); /* * Opacity double spin box */ this->opacityDoubleSpinBox = WuQFactory::newDoubleSpinBox(); + this->opacityDoubleSpinBox->setObjectName(objectNamePrefix + + "Opacity"); this->opacityDoubleSpinBox->setMinimum(0.0); this->opacityDoubleSpinBox->setMaximum(1.0); this->opacityDoubleSpinBox->setSingleStep(0.10); @@ -148,24 +180,40 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, QObject::connect(this->opacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(opacityDoubleSpinBoxValueChanged(double))); this->opacityDoubleSpinBox->setToolTip("Opacity (0.0=transparent, 1.0=opaque)"); + macroManager->addMacroSupportToObject(this->opacityDoubleSpinBox, + ("Set " + descriptivePrefix + " opacity")); /* * ColorBar Tool Button */ - QIcon colorBarIcon; - const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", - colorBarIcon); - this->colorBarAction = WuQtUtilities::createAction("CB", - "Display color bar for this overlay", - this, - this, - SLOT(colorBarActionTriggered(bool))); - this->colorBarAction->setCheckable(true); - if (colorBarIconValid) { - this->colorBarAction->setIcon(colorBarIcon); - } - QToolButton* colorBarToolButton = new QToolButton(); - colorBarToolButton->setDefaultAction(this->colorBarAction); + m_colorBarToolButton = WuQtUtilities::createToolButtonWithIcon("CB", + ":/LayersPanel/colorbar.png", + "Display color bar for this overlay", + this, + SLOT(colorBarActionTriggered(bool))); + m_colorBarToolButton->setCheckable(true); + m_colorBarToolButton->setObjectName(objectNamePrefix + + "ShowColorBar"); + macroManager->addMacroSupportToObject(m_colorBarToolButton, + ("Enable " + descriptivePrefix + " colorbar")); + +// /* +// * ColorBar Tool Button +// */ +// QIcon colorBarIcon; +// const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", +// colorBarIcon); +// this->colorBarAction = WuQtUtilities::createAction("CB", +// "Display color bar for this overlay", +// this, +// this, +// SLOT(colorBarActionTriggered(bool))); +// this->colorBarAction->setCheckable(true); +// if (colorBarIconValid) { +// this->colorBarAction->setIcon(colorBarIcon); +// } +// QToolButton* colorBarToolButton = new QToolButton(); +// colorBarToolButton->setDefaultAction(this->colorBarAction); /* * Settings Tool Button @@ -179,14 +227,19 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, this, this, SLOT(settingsActionTriggered())); + this->settingsAction->setObjectName(objectNamePrefix + + "ShowSettingsDialog"); if (settingsIconValid) { this->settingsAction->setIcon(settingsIcon); } QToolButton* settingsToolButton = new QToolButton(); settingsToolButton->setDefaultAction(this->settingsAction); + macroManager->addMacroSupportToObject(this->settingsAction, + ("Display " + descriptivePrefix + " palette settings")); /* * Construction Tool Button + * Note: macro support is on each action in menu in 'createConstructionMenu' */ QIcon constructionIcon; const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", @@ -198,7 +251,10 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, this->constructionAction->setIcon(constructionIcon); } m_constructionToolButton = new QToolButton(); - QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton); + QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton, + descriptivePrefix, + (objectNamePrefix + + "ConstructionMenu:")); this->constructionAction->setMenu(constructionMenu); m_constructionToolButton->setDefaultAction(this->constructionAction); m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); @@ -214,13 +270,14 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, /* * Yoking Group + * Note: macro support is in the class MapYokingGroupComboBox */ - m_mapYokingGroupComboBox = new MapYokingGroupComboBox(this); + m_mapYokingGroupComboBox = new MapYokingGroupComboBox(this, + (objectNamePrefix + + "MapYokingSelection"), + descriptivePrefix); m_mapYokingGroupComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); m_mapYokingGroupComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); -#ifdef CARET_OS_MACOSX - m_mapYokingGroupComboBox->getWidget()->setFixedWidth(m_mapYokingGroupComboBox->getWidget()->sizeHint().width() - 20); -#endif // CARET_OS_MACOSX QObject::connect(m_mapYokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokingGroupActivated())); @@ -237,7 +294,7 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, this->gridLayoutGroup->addWidget(settingsToolButton, row, 1, Qt::AlignHCenter); - this->gridLayoutGroup->addWidget(colorBarToolButton, + this->gridLayoutGroup->addWidget(m_colorBarToolButton, //colorBarToolButton, row, 2); this->gridLayoutGroup->addWidget(m_constructionToolButton, row, 3); @@ -268,7 +325,7 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, row, 0); this->gridLayoutGroup->addWidget(settingsToolButton, row, 1); - this->gridLayoutGroup->addWidget(colorBarToolButton, + this->gridLayoutGroup->addWidget(m_colorBarToolButton, //colorBarToolButton, row, 2); this->gridLayoutGroup->addWidget(m_constructionToolButton, row, 3); @@ -687,9 +744,10 @@ OverlayViewController::updateViewController(Overlay* overlay) m_mapYokingGroupComboBox->setMapYokingGroup(overlay->getMapYokingGroup()); - this->colorBarAction->blockSignals(true); - this->colorBarAction->setChecked(overlay->getColorBar()->isDisplayed()); - this->colorBarAction->blockSignals(false); + m_colorBarToolButton->setChecked(overlay->getColorBar()->isDisplayed()); +// this->colorBarAction->blockSignals(true); +// this->colorBarAction->setChecked(overlay->getColorBar()->isDisplayed()); +// this->colorBarAction->blockSignals(false); this->opacityDoubleSpinBox->blockSignals(true); this->opacityDoubleSpinBox->setValue(overlay->getOpacity()); @@ -758,7 +816,8 @@ OverlayViewController::updateViewController(Overlay* overlay) this->constructionAction->setEnabled(true); this->opacityDoubleSpinBox->setEnabled(haveOpacity); this->m_mapYokingGroupComboBox->getWidget()->setEnabled(haveYoking); - this->colorBarAction->setEnabled(dataIsMappedWithPalette); + //this->colorBarAction->setEnabled(dataIsMappedWithPalette); + this->m_colorBarToolButton->setEnabled(dataIsMappedWithPalette); this->settingsAction->setEnabled(true); } @@ -805,53 +864,102 @@ OverlayViewController::updateGraphicsWindow() * Create the construction menu. * @param parent * Parent widget. + * @param descriptivePrefix + * Descriptive prefix + * @param menuActionNamePrefix + * Prefix for macros */ QMenu* -OverlayViewController::createConstructionMenu(QWidget* parent) +OverlayViewController::createConstructionMenu(QWidget* parent, + const AString& descriptivePrefix, + const AString& menuActionNamePrefix) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + QMenu* menu = new QMenu(parent); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(menuConstructionAboutToShow())); - menu->addAction("Add Overlay Above", - this, - SLOT(menuAddOverlayAboveTriggered())); + QAction* addAboveAction = menu->addAction("Add Overlay Above", + this, + SLOT(menuAddOverlayAboveTriggered())); + addAboveAction->setObjectName(menuActionNamePrefix + + "AddOverlayAbove"); + addAboveAction->setToolTip("Add an overlay above this overlay"); + macroManager->addMacroSupportToObject(addAboveAction, + ("Add overlay above " + descriptivePrefix)); - menu->addAction("Add Overlay Below", - this, - SLOT(menuAddOverlayBelowTriggered())); + QAction* addBelowAction = menu->addAction("Add Overlay Below", + this, + SLOT(menuAddOverlayBelowTriggered())); + addBelowAction->setObjectName(menuActionNamePrefix + + "AddOverlayBelow"); + addBelowAction->setToolTip("Add an overlay below this overlay"); + macroManager->addMacroSupportToObject(addBelowAction, + ("Add overlay below " + descriptivePrefix)); menu->addSeparator(); - menu->addAction("Move Overlay Up", - this, - SLOT(menuMoveOverlayUpTriggered())); + QAction* moveUpAction = menu->addAction("Move Overlay Up", + this, + SLOT(menuMoveOverlayUpTriggered())); + moveUpAction->setObjectName(menuActionNamePrefix + + "MoveOverlayUp"); + moveUpAction->setToolTip("Move this overlay up"); + macroManager->addMacroSupportToObject(moveUpAction, + ("Move " + descriptivePrefix + " up")); - menu->addAction("Move Overlay Down", - this, - SLOT(menuMoveOverlayDownTriggered())); + QAction* moveDownAction = menu->addAction("Move Overlay Down", + this, + SLOT(menuMoveOverlayDownTriggered())); + moveDownAction->setObjectName(menuActionNamePrefix + + "MoveOverlayDown"); + moveDownAction->setToolTip("Move this overlay down"); + macroManager->addMacroSupportToObject(moveDownAction, + ("Move " + descriptivePrefix + " down")); menu->addSeparator(); - menu->addAction("Remove This Overlay", - this, - SLOT(menuRemoveOverlayTriggered())); + QAction* removeAction = menu->addAction("Remove This Overlay", + this, + SLOT(menuRemoveOverlayTriggered())); + removeAction->setObjectName(menuActionNamePrefix + + "RemoveOverlay"); + removeAction->setToolTip("Remove this overlay"); + macroManager->addMacroSupportToObject(removeAction, + ("Remove " + descriptivePrefix)); menu->addSeparator(); m_constructionReloadFileAction = menu->addAction("Reload Selected File", this, SLOT(menuReloadFileTriggered())); + m_constructionReloadFileAction->setObjectName(menuActionNamePrefix + + "ReloadSelectedFile"); + m_constructionReloadFileAction->setToolTip("Reload file in this overlay"); + macroManager->addMacroSupportToObject(m_constructionReloadFileAction, + ("Reload file in " + descriptivePrefix)); menu->addSeparator(); m_copyPathAndFileNameToClipboardAction = menu->addAction("Copy Path and File Name to Clipboard", this, SLOT(menuCopyFileNameToClipBoard())); + m_copyPathAndFileNameToClipboardAction->setObjectName(menuActionNamePrefix + + "CopyPathAndFileNameToClipboard"); + m_copyPathAndFileNameToClipboardAction->setToolTip("Copy path and file name of file in this overlay to clipboard"); + macroManager->addMacroSupportToObject(m_copyPathAndFileNameToClipboardAction, + ("Copy path and filename from " + descriptivePrefix + " to clipboard")); - menu->addAction("Copy Map Name to Clipboard", - this, - SLOT(menuCopyMapNameToClipBoard())); + QAction* copyMapNameAction = menu->addAction("Copy Map Name to Clipboard", + this, + SLOT(menuCopyMapNameToClipBoard())); + copyMapNameAction->setObjectName(menuActionNamePrefix + + "CopyMapNameToClipboard"); + copyMapNameAction->setToolTip("Copy name of selected map to the clipboard"); + macroManager->addMacroSupportToObject(copyMapNameAction, + ("Copy map namne in " + descriptivePrefix + " to clipboard")); return menu; @@ -881,9 +989,74 @@ OverlayViewController::menuConstructionAboutToShow() menuText += suffix; } - const bool notDynConnFileFlag = (caretDataFile->getDataFileType() != DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC); - m_constructionReloadFileAction->setEnabled(notDynConnFileFlag); - m_copyPathAndFileNameToClipboardAction->setEnabled(notDynConnFileFlag); + bool dynConnFlag(false); + switch (caretDataFile->getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + dynConnFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::METRIC_DYNAMIC: + dynConnFlag = true; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + case DataFileTypeEnum::VOLUME_DYNAMIC: + dynConnFlag = true; + break; + } + m_constructionReloadFileAction->setEnabled( ! dynConnFlag); + m_copyPathAndFileNameToClipboardAction->setEnabled( ! dynConnFlag); } m_constructionReloadFileAction->setText(menuText); diff --git a/src/GuiQt/OverlayViewController.h b/src/GuiQt/OverlayViewController.h index d68b2c54f080659cd1285d74efc1b83b52270ecd..cdfda6d27541024e193156f578ce4b08344c2c02 100644 --- a/src/GuiQt/OverlayViewController.h +++ b/src/GuiQt/OverlayViewController.h @@ -36,6 +36,7 @@ class QToolButton; namespace caret { + class AString; class MapYokingGroupComboBox; class Overlay; class WuQGridLayoutGroup; @@ -49,6 +50,7 @@ namespace caret { QGridLayout* gridLayout, const int32_t browserWindowIndex, const int32_t overlayIndex, + const QString& parentObjectName, QObject* parent); virtual ~OverlayViewController(); @@ -114,7 +116,9 @@ namespace caret { void updateGraphicsWindow(); - QMenu* createConstructionMenu(QWidget* parent); + QMenu* createConstructionMenu(QWidget* parent, + const AString& descriptivePrefix, + const AString& menuActionNamePrefix); void validateYokingSelection(); @@ -140,7 +144,8 @@ namespace caret { QAction* constructionAction; - QAction* colorBarAction; + QToolButton* m_colorBarToolButton; + //QAction* colorBarAction; QAction* settingsAction; diff --git a/src/GuiQt/PreferencesDialog.cxx b/src/GuiQt/PreferencesDialog.cxx index 6ed6728bef18dd7000fa4b16a3ca6a44fd705429..c7084ce82d6cc8fe1b4c7765306a78c3dfaaa550 100644 --- a/src/GuiQt/PreferencesDialog.cxx +++ b/src/GuiQt/PreferencesDialog.cxx @@ -176,6 +176,14 @@ PreferencesDialog::addColorButtonAndSwatch(QGridLayout* gridLayout, buttonText = "Chart Threshold"; m_chartHistogramThresholdColorWidget = colorSwatchWidget; break; + case PREF_COLOR_BACKGROUND_WINDOW: + buttonText = "Window Background"; + m_backgroundColorWindowWidget = colorSwatchWidget; + break; + case PREF_COLOR_FOREGROUND_WINDOW: + buttonText = "Window Foreground"; + m_foregroundColorWindowWidget = colorSwatchWidget; + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; @@ -207,6 +215,13 @@ PreferencesDialog::createColorsWidget() QGridLayout* gridLayout = new QGridLayout(); + addColorButtonAndSwatch(gridLayout, + PREF_COLOR_FOREGROUND_WINDOW, + colorSignalMapper); + addColorButtonAndSwatch(gridLayout, + PREF_COLOR_BACKGROUND_WINDOW, + colorSignalMapper); + addColorButtonAndSwatch(gridLayout, PREF_COLOR_FOREGROUND_ALL, colorSignalMapper); @@ -311,6 +326,14 @@ PreferencesDialog::updateColorWidget(CaretPreferences* prefs) colors.getColorChartHistogramThreshold(rgb); colorSwatchWidget = m_chartHistogramThresholdColorWidget; break; + case PREF_COLOR_BACKGROUND_WINDOW: + colors.getColorBackgroundWindow(rgb); + colorSwatchWidget = m_backgroundColorWindowWidget; + break; + case PREF_COLOR_FOREGROUND_WINDOW: + colors.getColorForegroundWindow(rgb); + colorSwatchWidget = m_foregroundColorWindowWidget; + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; @@ -458,6 +481,10 @@ PreferencesDialog::createIdentificationSymbolWidget() QObject::connect(m_volumeIdentificationSymbolComboBox, SIGNAL(statusChanged(bool)), this, SLOT(identificationSymbolToggled())); + m_dataToolTipsComboBox = new WuQTrueFalseComboBox("On", "Off", this); + QObject::connect(m_dataToolTipsComboBox, SIGNAL(statusChanged(bool)), + this, SLOT(identificationSymbolToggled())); + QGridLayout* gridLayout = new QGridLayout(); int row = gridLayout->rowCount(); gridLayout->addWidget(infoLabel, @@ -468,6 +495,9 @@ PreferencesDialog::createIdentificationSymbolWidget() addWidgetToLayout(gridLayout, "Show Volume ID Symbols: ", m_volumeIdentificationSymbolComboBox->getWidget()); + addWidgetToLayout(gridLayout, + "Show Data Tool Tips: ", + m_dataToolTipsComboBox->getWidget()); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); @@ -487,6 +517,7 @@ PreferencesDialog::updateIdentificationWidget(CaretPreferences* prefs) { m_surfaceIdentificationSymbolComboBox->setStatus(prefs->isShowSurfaceIdentificationSymbols()); m_volumeIdentificationSymbolComboBox->setStatus(prefs->isShowVolumeIdentificationSymbols()); + m_dataToolTipsComboBox->setStatus(prefs->isShowDataToolTipsEnabled()); } /** @@ -498,6 +529,7 @@ PreferencesDialog::identificationSymbolToggled() CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setShowSurfaceIdentificationSymbols(m_surfaceIdentificationSymbolComboBox->isTrue()); prefs->setShowVolumeIdentificationSymbols(m_volumeIdentificationSymbolComboBox->isTrue()); + prefs->setShowDataToolTipsEnabled(m_dataToolTipsComboBox->isTrue()); } /** @@ -626,10 +658,15 @@ PreferencesDialog::createTabDefaltsWidget() SLOT(volumeMontageCoordinatePrecisionChanged(int))); m_allWidgets->add(m_volumeMontageCoordinatePrecisionSpinBox); - m_allWidgets->add(m_volumeAxesCrosshairsComboBox); - m_allWidgets->add(m_volumeAxesLabelsComboBox); - m_allWidgets->add(m_volumeAxesMontageCoordinatesComboBox); - m_allWidgets->add(m_volumeMontageCoordinatePrecisionSpinBox); + /* + * All slice planes layout default + */ + m_volumeAllSlicePlanesLayoutComboBox = new EnumComboBoxTemplate(this); + m_volumeAllSlicePlanesLayoutComboBox->setup(); + QObject::connect(m_volumeAllSlicePlanesLayoutComboBox, SIGNAL(itemActivated()), + this, SLOT(m_volumeAllSlicePlanesLayoutItemActivated())); + m_allWidgets->add(m_volumeAllSlicePlanesLayoutComboBox->getWidget()); + QGridLayout* gridLayout = new QGridLayout(); @@ -661,6 +698,9 @@ PreferencesDialog::createTabDefaltsWidget() addWidgetToLayout(gridLayout, "Volume Montage Precision: ", m_volumeMontageCoordinatePrecisionSpinBox); + addWidgetToLayout(gridLayout, + "All Slice Planes Layout: ", + m_volumeAllSlicePlanesLayoutComboBox->getWidget()); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); @@ -683,6 +723,7 @@ PreferencesDialog::updateVolumeWidget(CaretPreferences* prefs) m_volumeAxesMontageCoordinatesComboBox->setStatus(prefs->isVolumeMontageAxesCoordinatesDisplayed()); m_volumeIdentificationComboBox->setStatus(prefs->isVolumeIdentificationDefaultedOn()); m_volumeMontageCoordinatePrecisionSpinBox->setValue(prefs->getVolumeMontageCoordinatePrecision()); + m_volumeAllSlicePlanesLayoutComboBox->setSelectedItem(prefs->getVolumeAllSlicePlanesLayout()); } /** @@ -809,6 +850,14 @@ PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) colors.getColorChartHistogramThreshold(rgb); prefColorName = "Chart Histogram Threshold"; break; + case PREF_COLOR_BACKGROUND_WINDOW: + colors.getColorBackgroundWindow(rgb); + prefColorName = "Background - Window"; + break; + case PREF_COLOR_FOREGROUND_WINDOW: + colors.getColorForegroundWindow(rgb); + prefColorName = "Foreground - Window"; + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; @@ -862,6 +911,12 @@ PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) case PREF_COLOR_CHART_THRESHOLD: colors.setColorChartHistogramThreshold(rgb); break; + case PREF_COLOR_BACKGROUND_WINDOW: + colors.setColorBackgroundWindow(rgb); + break; + case PREF_COLOR_FOREGROUND_WINDOW: + colors.setColorForegroundWindow(rgb); + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; @@ -973,6 +1028,18 @@ PreferencesDialog::volumeAxesMontageCoordinatesComboBoxToggled(bool value) EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } +/** + * Called when ALL view slice plane layout changed by user + */ +void +PreferencesDialog::m_volumeAllSlicePlanesLayoutItemActivated() +{ + VolumeSliceViewAllPlanesLayoutEnum::Enum layoutValue = m_volumeAllSlicePlanesLayoutComboBox->getSelectedItem(); + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->setVolumeAllSlicePlanesLayout(layoutValue); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + +} /** * Called when volume montage coordinate precision value is changed. */ diff --git a/src/GuiQt/PreferencesDialog.h b/src/GuiQt/PreferencesDialog.h index 5e915f4ff912f26b5fe7f194f64e78b6614e6def..1ff954fe9cea17a4ff8f1a2583566bb0fa228dc6 100644 --- a/src/GuiQt/PreferencesDialog.h +++ b/src/GuiQt/PreferencesDialog.h @@ -70,6 +70,7 @@ namespace caret { void volumeAxesMontageCoordinatesComboBoxToggled(bool value); void volumeMontageCoordinatePrecisionChanged(int value); void volumeIdentificationComboBoxToggled(bool value); + void m_volumeAllSlicePlanesLayoutItemActivated(); void yokingComboBoxToggled(bool value); @@ -87,7 +88,9 @@ namespace caret { PREF_COLOR_FOREGROUND_VOLUME = 7, PREF_COLOR_CHART_MATRIX_GRID_LINES = 8, PREF_COLOR_CHART_THRESHOLD = 9, - NUMBER_OF_PREF_COLORS = 10 + PREF_COLOR_BACKGROUND_WINDOW = 10, + PREF_COLOR_FOREGROUND_WINDOW = 11, + NUMBER_OF_PREF_COLORS = 12 }; QWidget* createColorsWidget(); @@ -120,10 +123,12 @@ namespace caret { PreferencesDialog& operator=(const PreferencesDialog&); + QWidget* m_foregroundColorWindowWidget; QWidget* m_foregroundColorAllWidget; QWidget* m_foregroundColorChartWidget; QWidget* m_foregroundColorSurfaceWidget; QWidget* m_foregroundColorVolumeWidget; + QWidget* m_backgroundColorWindowWidget; QWidget* m_backgroundColorAllWidget; QWidget* m_backgroundColorChartWidget; QWidget* m_backgroundColorSurfaceWidget; @@ -143,6 +148,7 @@ namespace caret { WuQTrueFalseComboBox* m_dynamicConnectivityComboBox; + EnumComboBoxTemplate* m_volumeAllSlicePlanesLayoutComboBox; WuQTrueFalseComboBox* m_volumeAxesCrosshairsComboBox; WuQTrueFalseComboBox* m_volumeAxesLabelsComboBox; WuQTrueFalseComboBox* m_volumeAxesMontageCoordinatesComboBox; @@ -153,6 +159,7 @@ namespace caret { WuQTrueFalseComboBox* m_surfaceIdentificationSymbolComboBox; WuQTrueFalseComboBox* m_volumeIdentificationSymbolComboBox; + WuQTrueFalseComboBox* m_dataToolTipsComboBox; WuQWidgetObjectGroup* m_allWidgets; }; diff --git a/src/GuiQt/QGLWidgetTextRenderer.cxx b/src/GuiQt/QGLWidgetTextRenderer.cxx index b1868147c77a15b49ff99961be643efcb2757069..6047516557458cdd0ae6988dc23c56a5ba940d2d 100644 --- a/src/GuiQt/QGLWidgetTextRenderer.cxx +++ b/src/GuiQt/QGLWidgetTextRenderer.cxx @@ -216,6 +216,7 @@ QGLWidgetTextRenderer::drawTextAtViewportCoords(const double viewportX, /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. + * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * @@ -227,9 +228,11 @@ QGLWidgetTextRenderer::drawTextAtViewportCoords(const double viewportX, * Model Z-coordinate. * @param annotationText * Annotation text and attributes. + * @param flags + * Drawing flags. */ void -QGLWidgetTextRenderer::drawTextAtModelCoords(const double modelX, +QGLWidgetTextRenderer::drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, @@ -307,6 +310,32 @@ QGLWidgetTextRenderer::drawTextAtModelCoords(const double modelX, } } +/** + * Draw text in model space using the current model transformations. + * + * Depth testing is ENABLED when drawing text with this method. + * + * @param annotationText + * Annotation text and attributes. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * If positive, use it to override width/height of viewport. + * @param normalVector + * Normal vector of text. + * @param flags + * Drawing flags. + */ +void +QGLWidgetTextRenderer::drawTextInModelSpace(const AnnotationText& /* annotationText */, + const float /*modelSpaceScaling*/, + const float /*heightOrWidthForPercentageSizeText*/, + const float* /*normalVector[3]*/, + const DrawingFlags& /* flags */) +{ + CaretAssertMessage(0, "Not implemented"); +} + /** * Draw horizontal annotation text at the given window coordinates. * @@ -735,6 +764,45 @@ QGLWidgetTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotati heightOut = yMax - yMin; } +/** + * Get the bounds of text drawn in model space using the current model transformations. + * + * @param annotationText + * Text that is to be drawn. + * @param modelSpaceScaling + * Scaling in the model space. + * @param heightOrWidthForPercentageSizeText + * Size of region used when converting percentage size to a fixed size + * @param flags + * Drawing flags. + * @param bottomLeftOut + * The bottom left corner of the text bounds. + * @param bottomRightOut + * The bottom right corner of the text bounds. + * @param topRightOut + * The top right corner of the text bounds. + * @param topLeftOut + * The top left corner of the text bounds. + * @param underlineStartOut + * Starting coordinate for drawing text underline. + * @param underlineEndOut + * Ending coordinate for drawing text underline. + */ +void +QGLWidgetTextRenderer::getBoundsForTextInModelSpace(const AnnotationText& /*annotationText*/, + const float /*modelSpaceScaling*/, + const float /*heightOrWidthForPercentageSizeText*/, + const DrawingFlags& /*flags*/, + double* /*bottomLeftOut[3]*/, + double* /*bottomRightOut[3]*/, + double* /*topRightOut[3]*/, + double* /*topLeftOut[3]*/, + double* /*underlineStartOut[3]*/, + double* /*underlineEndOut[3]*/) +{ + +} + /** * Get the bounds of text (in pixels) using the given text * attributes. diff --git a/src/GuiQt/QGLWidgetTextRenderer.h b/src/GuiQt/QGLWidgetTextRenderer.h index c793075f6d4b0cb41bf7b37721d703f1c7accbca..1dde1e63d380ceb3d85dc6ae85c259e8fc93df89 100644 --- a/src/GuiQt/QGLWidgetTextRenderer.h +++ b/src/GuiQt/QGLWidgetTextRenderer.h @@ -55,12 +55,18 @@ namespace caret { const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) override; - virtual void drawTextAtModelCoords(const double modelX, + virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) override; + virtual void drawTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const float normalVector[3], + const DrawingFlags& flags) override; + virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportWidth, @@ -68,6 +74,17 @@ namespace caret { double& widthOut, double& heightOut) override; + virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, + const float modelSpaceScaling, + const float heightOrWidthForPercentageSizeText, + const DrawingFlags& flags, + double bottomLeftOut[3], + double bottomRightOut[3], + double topRightOut[3], + double topLeftOut[3], + double underlineStartOut[3], + double underlineEndOut[3]) override; + virtual void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportX, diff --git a/src/GuiQt/SceneCreateReplaceDialog.cxx b/src/GuiQt/SceneCreateReplaceDialog.cxx index 4c0bb9944e7b49df851c16e63d18c936d612f268..e38522e60d362382620dd5cdd506a0875b3cafdb 100644 --- a/src/GuiQt/SceneCreateReplaceDialog.cxx +++ b/src/GuiQt/SceneCreateReplaceDialog.cxx @@ -45,6 +45,7 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabGetAllViewed.h" #include "EventImageCapture.h" +#include "EventSceneActive.h" #include "EventManager.h" #include "GuiManager.h" #include "ImageFile.h" @@ -701,6 +702,16 @@ SceneCreateReplaceDialog::okButtonClicked() imageErrorMessage); } + /* + * Copy macros from active scene to the new scene + */ + EventSceneActive activeSceneEvent(EventSceneActive::MODE_GET); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); + const Scene* activeScene = activeSceneEvent.getScene(); + if (activeScene != NULL) { + newScene->copyMacrosFromScene(activeScene); + } + switch (m_mode) { case MODE_ADD_NEW_SCENE: m_sceneFile->addScene(newScene); diff --git a/src/GuiQt/SceneDataFileTreeItem.cxx b/src/GuiQt/SceneDataFileTreeItem.cxx new file mode 100644 index 0000000000000000000000000000000000000000..87de03694bbbdbf10579ea67585b1e6ffcbee2c4 --- /dev/null +++ b/src/GuiQt/SceneDataFileTreeItem.cxx @@ -0,0 +1,130 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ +#include "SceneDataFileTreeItem.h" +#undef __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ + +#include "CaretAssert.h" +#include "FileInformation.h" + +using namespace caret; + + + +/** + * \class caret::SceneDataFileTreeItem + * \brief Item for insertion in a SceneDataFileTreeItemModel + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param text + * Text for the model item + * @param absolutePathName + * Absolute path name including name of file (if a data file) + * @param itemType + * Item type indicating file or directory. + * Use getItemTypeDirectory() or getItemTypeFile(). + */ +SceneDataFileTreeItem::SceneDataFileTreeItem(const AString& text, + const AString& absolutePathName, + const int32_t itemType) +: QStandardItem(text), +m_absolutePathName(absolutePathName), +m_itemType(itemType) +{ + FileInformation fileInfo(absolutePathName); + if ( ! fileInfo.exists()) { + setText(text + + " "); + } + + setColumnCount(1); +} + +/** + * Destructor. + */ +SceneDataFileTreeItem::~SceneDataFileTreeItem() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +SceneDataFileTreeItem::SceneDataFileTreeItem(const SceneDataFileTreeItem& obj) +: QStandardItem(obj) +{ + this->copyHelperSceneDataFileTreeItem(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +SceneDataFileTreeItem& +SceneDataFileTreeItem::operator=(const SceneDataFileTreeItem& obj) +{ + if (this != &obj) { + QStandardItem::operator=(obj); + this->copyHelperSceneDataFileTreeItem(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +SceneDataFileTreeItem::copyHelperSceneDataFileTreeItem(const SceneDataFileTreeItem& obj) +{ + m_absolutePathName = obj.m_absolutePathName; + m_itemType = obj.m_itemType; +} + +/** + * @return Full absolute path name + */ +AString +SceneDataFileTreeItem::getAbsolutePathName() const +{ + return m_absolutePathName; +} + +/** + * @return The type of this item. The type is used to distinguish custom items from the base class + */ +int +SceneDataFileTreeItem::type() const +{ + return m_itemType; +} + diff --git a/src/GuiQt/SceneDataFileTreeItem.h b/src/GuiQt/SceneDataFileTreeItem.h new file mode 100644 index 0000000000000000000000000000000000000000..bd59b55e947201326df599c02098f306d8acf6ef --- /dev/null +++ b/src/GuiQt/SceneDataFileTreeItem.h @@ -0,0 +1,79 @@ +#ifndef __SCENE_DATA_FILE_TREE_ITEM_H__ +#define __SCENE_DATA_FILE_TREE_ITEM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +#include "AString.h" + +namespace caret { + + class SceneDataFileTreeItem : public QStandardItem { + + public: + /** + * @return ItemType for a directory + */ + static int32_t getItemTypeDirectory() { return (QStandardItem::UserType + 1); } + + /** + * @return ItemType for a data file + */ + static int32_t getItemTypeFile() { return (QStandardItem::UserType + 2); } + + SceneDataFileTreeItem(const AString& text, + const AString& absolutePathName, + const int32_t itemType); + + virtual ~SceneDataFileTreeItem(); + + SceneDataFileTreeItem(const SceneDataFileTreeItem&); + + SceneDataFileTreeItem& operator=(const SceneDataFileTreeItem&); + + AString getAbsolutePathName() const; + + virtual int type() const; + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperSceneDataFileTreeItem(const SceneDataFileTreeItem& obj); + + AString m_absolutePathName; + + int32_t m_itemType; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ + // +#endif // __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ + +} // namespace +#endif //__SCENE_DATA_FILE_TREE_ITEM_H__ diff --git a/src/GuiQt/SceneDataFileTreeItemModel.cxx b/src/GuiQt/SceneDataFileTreeItemModel.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4c7ec0e6cb7153c8219cc592e1e868e9521ba9b5 --- /dev/null +++ b/src/GuiQt/SceneDataFileTreeItemModel.cxx @@ -0,0 +1,375 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ +#include "SceneDataFileTreeItemModel.h" +#undef __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "FileInformation.h" +#include "SceneDataFileTreeItem.h" + +using namespace caret; + +static bool debugFlag(false); + +/** + * \class caret::SceneDataFileTreeItemModel + * \brief Tree item model for hierarchical list of files in a scene file + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param sceneFilePathAndName + * Scene file path and name. + * @param baseDirectoryPath + * Path of the base directory. + * @param sceneDataFileInfo + * The scene file info. + * @param sortMode + * The sorting mode. + */ +SceneDataFileTreeItemModel::SceneDataFileTreeItemModel(const AString& sceneFilePathAndName, + const AString& baseDirectoryPath, + const std::vector& sceneDataFileInfo, + const SceneDataFileInfo::SortMode sortMode) +: QStandardItemModel() +{ + if ( ! baseDirectoryPath.isEmpty()) { + /* + * Add a root element to the tree containing the base path + */ + addDirectory(baseDirectoryPath, + ""); + } + + if ( ! sceneFilePathAndName.isEmpty()) { + /* + * Add the scene file and highlight the name to make it stand out from other files + */ + SceneDataFileTreeItem* sceneFileItem = addFile(sceneFilePathAndName, + ""); + CaretAssert(sceneFileItem); + QFont font = sceneFileItem->font(); + font.setBold(true); + sceneFileItem->setFont(font); + } + + /* + * Add the data files + */ + for (const auto dataFileInfo : sceneDataFileInfo) { + AString pathName; + AString pathAndFileName; + switch (sortMode) { + case SceneDataFileInfo::SortMode::AbsolutePath: + pathName = dataFileInfo.getAbsolutePath(); + pathAndFileName = dataFileInfo.getAbsolutePathAndFileName(); + break; + case SceneDataFileInfo::SortMode::RelativeToBasePath: + pathName = dataFileInfo.getRelativePathToBasePath(); + pathAndFileName = (dataFileInfo.getRelativePathToBasePath() + + "/" + + dataFileInfo.getDataFileName()); + break; + case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: + pathName = dataFileInfo.getRelativePathToSceneFile(); + pathAndFileName = (dataFileInfo.getRelativePathToSceneFile() + + "/" + + dataFileInfo.getDataFileName()); + break; + } + + addFile(pathAndFileName, + dataFileInfo.getSceneIndicesAsString()); + } +} + +/** + * Destructor. + */ +SceneDataFileTreeItemModel::~SceneDataFileTreeItemModel() +{ +} + +/** + * Find or add all components in a directory path. + * @param absoluteDirName + * Full path of directory. + * @return + * Tree item containing directory with the given name. + */ +SceneDataFileTreeItem* +SceneDataFileTreeItemModel::addFindDirectoryPath(const AString& absoluteDirName) +{ + SceneDataFileTreeItem* directoryItemOut = findDirectory(absoluteDirName); + + if (directoryItemOut == NULL) { + const AString httpsPrefix("https://"); + + AString rootPrefix("/"); + AString nameForSplitting(absoluteDirName); + if (absoluteDirName.startsWith(httpsPrefix)) { + nameForSplitting = absoluteDirName.mid(httpsPrefix.length()); + rootPrefix = httpsPrefix; + } + + QStringList components(nameForSplitting.split("/", + QString::SkipEmptyParts)); + const int32_t componentCount = components.length(); + + std::vector parentDirectoryHierarchy; + + /* + * Create a vector containing all directory paths + * in the hierarchy as absolute paths. This is necessary + * to avoid duplicating a hierarchy that matches the + * base path. + */ + AString dirName; + AString parentDirName; + for (int32_t i = 0; i < componentCount; i++) { + if (i == 0) { + if (absoluteDirName.startsWith(rootPrefix)) { + dirName = rootPrefix; + parentDirectoryHierarchy.push_back(dirName); + } + } + + parentDirName = dirName; + + if ( ! dirName.isEmpty()) { + if ( ! dirName.endsWith('/')) { + dirName.append("/"); + } + } + + dirName.append(components.at(i)); + parentDirectoryHierarchy.push_back(dirName); + } + + if (debugFlag) { + std::cout << "Parent directory hierarchy: " << std::endl; + for (const auto s : parentDirectoryHierarchy) { + std::cout << " " << s << std::endl; + } + } + + /* + * Start at the deepest directory path and work way up + * to find the deepest existing path. + */ + int32_t iStart(0); + const int32_t numDirs = static_cast(parentDirectoryHierarchy.size()); + for (int32_t iDir = (numDirs - 1); iDir >= 0; iDir--) { + CaretAssertVectorIndex(parentDirectoryHierarchy, iDir); + SceneDataFileTreeItem* dirItem = findDirectory(parentDirectoryHierarchy[iDir]); + if (dirItem != NULL) { + iStart = iDir + 1; + break; + } + } + if (iStart < numDirs) { + /* + * Create directories that are children of the deepest existing path + */ + for (int32_t iDir = iStart; iDir < numDirs; iDir++) { + AString parentDirName; + if (iDir > 0) { + CaretAssertVectorIndex(parentDirectoryHierarchy, iDir - 1); + parentDirName = parentDirectoryHierarchy[iDir - 1]; + } + CaretAssertVectorIndex(parentDirectoryHierarchy, iDir); + if (debugFlag) { + std::cout << "Creating directory " << parentDirectoryHierarchy[iDir] + << " with parent " << parentDirName << std::endl; + } + addDirectory(parentDirectoryHierarchy[iDir], + parentDirName); + } + } + + directoryItemOut = findDirectory(absoluteDirName); + CaretAssert(directoryItemOut); + } + + return directoryItemOut; +} + + +/** + * Add a directory. If directory already in tree, the existing item is returned. + * + * @param absoluteDirName + * Full path of directory. + * @param absoluteParentDirName + * Full path of parent directory. + * @return + * Tree item containing directory. + */ +SceneDataFileTreeItem* +SceneDataFileTreeItemModel::addDirectory(const AString& absoluteDirName, + const AString& absoluteParentDirName) +{ + SceneDataFileTreeItem* directoryItemOut = findDirectory(absoluteDirName); + + if (directoryItemOut == NULL) { + if (absoluteParentDirName.isEmpty()) { + directoryItemOut = new SceneDataFileTreeItem(absoluteDirName, + absoluteDirName, + SceneDataFileTreeItem::getItemTypeDirectory()); + invisibleRootItem()->appendRow(directoryItemOut); + m_directoryToTreeItemMap.insert(std::make_pair(absoluteDirName, + directoryItemOut)); + if (debugFlag) { + std::cout << "Added root directory: " << absoluteDirName << std::endl; + } + } + else { + SceneDataFileTreeItem* parentDirItem = findDirectory(absoluteParentDirName); + if (parentDirItem != NULL) { + FileInformation dirInfo(absoluteDirName); + const AString name = dirInfo.getFileName(); + directoryItemOut = new SceneDataFileTreeItem(name, + absoluteDirName, + SceneDataFileTreeItem::getItemTypeDirectory()); + parentDirItem->appendRow(directoryItemOut); + + m_directoryToTreeItemMap.insert(std::make_pair(absoluteDirName, + directoryItemOut)); + if (debugFlag) { + std::cout << "Added directory " << name << " to parent " << absoluteParentDirName << std::endl; + } + } + else { + CaretLogSevere("Unable to find parent directory named " + + absoluteParentDirName + + " for " + + absoluteDirName); + } + } + } + + return directoryItemOut; +} + +/** + * Find a directory with the given directory name. + * + * @param absoluteDirName + * Full path including directory. + * @return + * Tree item containing directory or NULL if not found. + */ +SceneDataFileTreeItem* +SceneDataFileTreeItemModel::findDirectory(const AString& absoluteDirName) +{ + SceneDataFileTreeItem* directoryItemOut = NULL; + + auto iter = m_directoryToTreeItemMap.find(absoluteDirName); + if (iter != m_directoryToTreeItemMap.end()) { + directoryItemOut = iter->second; + } + + return directoryItemOut; +} + +/** + * Add a file. If file already in tree, the existing item is returned. + * + * @param absoluteFilePathAndName + * Full path including directory and filename. + * @param sceneIndicesText + * Text containing indices of scenes using file. + * @return + * Tree item containing file. + */ +SceneDataFileTreeItem* +SceneDataFileTreeItemModel::addFile(const AString& absoluteFilePathAndName, + const AString& sceneIndicesText) +{ + SceneDataFileTreeItem* fileItemOut = findFile(absoluteFilePathAndName); + + if (fileItemOut == NULL) { + FileInformation fileInfo(absoluteFilePathAndName); + /* + * First look for parent directory, which may be the base directory. + */ + SceneDataFileTreeItem* directoryItem = findDirectory(fileInfo.getAbsolutePath()); + if (directoryItem == NULL) { + /* + * Start looking/adding directory from root down to file's parent + */ + directoryItem = addFindDirectoryPath(fileInfo.getAbsolutePath()); + } + if (directoryItem != NULL) { + AString itemText(fileInfo.getFileName()); + if ( ! sceneIndicesText.isEmpty()) { + itemText.append(" (" + + sceneIndicesText + + ")"); + } + fileItemOut = new SceneDataFileTreeItem(itemText, + absoluteFilePathAndName, + SceneDataFileTreeItem::getItemTypeFile()); + directoryItem->appendRow(fileItemOut); + m_fileNameToTreeItemMap.insert(std::make_pair(absoluteFilePathAndName, + fileItemOut)); + } + else { + CaretLogSevere("Failed to find directory named " + + fileInfo.getAbsolutePath() + + " for inserting file named " + + fileInfo.getFileName()); + } + } + + return fileItemOut; +} + +/** + * Find a file with the given filename. + * + * @param absoluteFilePathAndName + * Full path including directory and filename. + * @return + * Tree item containing file or NULL if not found. + */ +SceneDataFileTreeItem* +SceneDataFileTreeItemModel::findFile(const AString& absoluteFilePathAndName) +{ + SceneDataFileTreeItem* fileItemOut = NULL; + + auto iter = m_fileNameToTreeItemMap.find(absoluteFilePathAndName); + if (iter != m_fileNameToTreeItemMap.end()) { + fileItemOut = iter->second; + } + + return fileItemOut; +} + + diff --git a/src/GuiQt/SceneDataFileTreeItemModel.h b/src/GuiQt/SceneDataFileTreeItemModel.h new file mode 100644 index 0000000000000000000000000000000000000000..dbdf251a80606c367f0d48be43f032f07fa0d137 --- /dev/null +++ b/src/GuiQt/SceneDataFileTreeItemModel.h @@ -0,0 +1,81 @@ +#ifndef __SCENE_DATA_FILE_TREE_ITEM_MODEL_H__ +#define __SCENE_DATA_FILE_TREE_ITEM_MODEL_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include + +#include "SceneDataFileInfo.h" + + +namespace caret { + + class SceneDataFileTreeItem; + + class SceneDataFileTreeItemModel : public QStandardItemModel { + + Q_OBJECT + + public: + SceneDataFileTreeItemModel(const AString& sceneFilePathAndName, + const AString& baseDirectoryPath, + const std::vector& sceneDataFileInfo, + const SceneDataFileInfo::SortMode sortMode); + + virtual ~SceneDataFileTreeItemModel(); + + SceneDataFileTreeItemModel(const SceneDataFileTreeItemModel&) = delete; + + SceneDataFileTreeItemModel& operator=(const SceneDataFileTreeItemModel&) = delete; + + SceneDataFileTreeItem* addFindDirectoryPath(const AString& absoluteDirName); + + SceneDataFileTreeItem* addDirectory(const AString& absoluteDirName, + const AString& absoluteParentDirName); + + SceneDataFileTreeItem* findDirectory(const AString& absoluteDirName); + + SceneDataFileTreeItem* addFile(const AString& absoluteFilePathAndName, + const AString& sceneIndicesText); + + SceneDataFileTreeItem* findFile(const AString& absoluteFilePathAndName); + + // ADD_NEW_METHODS_HERE + + private: + std::map m_directoryToTreeItemMap; + + std::map m_fileNameToTreeItemMap; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ + // +#endif // __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ + +} // namespace +#endif //__SCENE_DATA_FILE_TREE_ITEM_MODEL_H__ diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index f668269375ddb0ff45fa025f27b48af2c9b7afe6..cb2a893097ddf444690963858991c34ddc837b6a 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -44,6 +44,8 @@ #include "SceneDialog.h" #undef __SCENE_DIALOG_DECLARE__ +#include "Annotation.h" +#include "AnnotationManager.h" #include "ApplicationInformation.h" #include "BalsaDatabaseUploadSceneFileDialog.h" #include "Brain.h" @@ -66,8 +68,10 @@ #include "EventImageCapture.h" #include "EventManager.h" #include "EventModelGetAll.h" +#include "EventHelpViewerDisplay.h" #include "EventUserInterfaceUpdate.h" #include "EventShowDataFileReadWarningsDialog.h" +#include "EventSceneActive.h" #include "FileInformation.h" #include "GuiManager.h" #include "ImageFile.h" @@ -77,8 +81,10 @@ #include "SceneClass.h" #include "SceneCreateReplaceDialog.h" #include "SceneFile.h" +#include "SceneFileInformationDialog.h" #include "SceneInfo.h" #include "ScenePreviewDialog.h" +#include "SceneReplaceAllDialog.h" #include "SceneShowOptionsDialog.h" #include "SessionManager.h" #include "UsernamePasswordWidget.h" @@ -125,9 +131,11 @@ SceneDialog::SceneDialog(QWidget* parent) m_testAllScenesDescription = WuQtUtilities::createWordWrappedToolTipText(m_testAllScenesDescription); /* - * No apply buton + * No apply buton and show help button */ setApplyButtonText(""); + setStandardButtonText(QDialogButtonBox::Help, + "Help"); /* @@ -410,13 +418,18 @@ SceneDialog::loadScenesIntoDialog(Scene* selectedSceneIn) selectedScene = getSelectedScene(); } + EventSceneActive activeSceneEvent(EventSceneActive::MODE_GET); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); + const Scene* activeScene = activeSceneEvent.getScene(); + for (std::vector::iterator iter = m_sceneClassInfoWidgets.begin(); iter != m_sceneClassInfoWidgets.end(); iter++) { SceneClassInfoWidget* sciw = *iter; sciw->blockSignals(true); sciw->updateContent(NULL, - -1); + -1, + false); } int32_t numberOfValidSceneInfoWidgets = 0; @@ -448,8 +461,10 @@ SceneDialog::loadScenesIntoDialog(Scene* selectedSceneIn) sciw = m_sceneClassInfoWidgets[i]; } + const bool activeSceneFlag(scene == activeScene); sciw->updateContent(scene, - i); + i, + activeSceneFlag); sciw->setBackgroundForSelected(i == 1); @@ -1102,6 +1117,12 @@ SceneDialog::sceneFileSelected(int /*index*/) updateSceneFileModifiedStatusLabel(); } +//Modified status for both scenes and _LIBCPP_POP_MACROS +//In Scene info panel indicate if scene is the active scene +//Add macro group to Scene +//Remove macro group from scene FILE +//List active scene file on macros Dialog + /** * Called when add new scene button clicked. */ @@ -1123,13 +1144,22 @@ SceneDialog::addNewSceneButtonClicked() sceneFile); if (newScene != NULL) { s_informUserAboutScenesOnExitFlag = false; + + /* + * Set the active scene + */ + EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); + activeSceneEvent.setScene(newScene); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); } loadScenesIntoDialog(newScene); } - updateSceneFileModifiedStatusLabel(); + + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** @@ -1156,6 +1186,13 @@ SceneDialog::insertSceneButtonClicked() scene); if (newScene != NULL) { s_informUserAboutScenesOnExitFlag = false; + + /* + * Set the active scene + */ + EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); + activeSceneEvent.setScene(newScene); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); } loadScenesIntoDialog(newScene); @@ -1163,6 +1200,9 @@ SceneDialog::insertSceneButtonClicked() } updateSceneFileModifiedStatusLabel(); + + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** @@ -1222,9 +1262,9 @@ SceneDialog::replaceAllScenesPushButtonClicked() return; } - if ( ! WuQMessageBox::warningOkCancel(m_replaceAllScenesPushButton, - "Replace All Scenes", - m_replaceAllScenesDescription)) { + SceneReplaceAllDialog replaceDialog(m_replaceAllScenesDescription, + m_replaceAllScenesPushButton); + if (replaceDialog.exec() == SceneReplaceAllDialog::Rejected) { return; } @@ -1324,10 +1364,10 @@ SceneDialog::replaceAllScenesPushButtonClicked() * Display the scene */ AString errorMessage; - displayScenePrivateWithErrorMessage(sceneFile, - origScene, - false, - errorMessage); + SceneDialog::displayScenePrivateWithErrorMessage(sceneFile, + origScene, + false, + errorMessage); sceneNames.push_back(origScene->getName()); /* @@ -1339,6 +1379,24 @@ SceneDialog::replaceAllScenesPushButtonClicked() newScene->setDescription(origScene->getDescription()); newScene->setBalsaSceneID(origScene->getBalsaSceneID()); + /* + * Set the active scene + */ + EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); + activeSceneEvent.setScene(newScene); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); + + /* + * Process options + */ + if (replaceDialog.isChangeSurfaceAnnotationOffsetToOffset()) { + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + std::vector annotations = annMan->getAllAnnotations(); + for (auto ann : annotations) { + ann->changeSurfaceSpaceToTangentOffset(); + } + } + const std::vector windowIndices = GuiManager::get()->getAllOpenBrainBrowserWindowIndices(); /* @@ -1374,7 +1432,10 @@ SceneDialog::replaceAllScenesPushButtonClicked() getSelectedSceneFile()->replaceScene(newScene, origScene); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - + + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + loadScenesIntoDialog(newScene); const QImage* newImage = getQImageFromSceneInfo(newScene->getSceneInfo()); if (newImage != NULL) { @@ -1393,6 +1454,7 @@ SceneDialog::replaceAllScenesPushButtonClicked() } } + progressDialog.close(); CaretAssert(sceneNames.size() == sceneErrors.size()); @@ -1595,12 +1657,22 @@ SceneDialog::testScenesPushButtonClicked() } AString errorMessage; - displayScenePrivateWithErrorMessage(sceneFile, - origScene, - false, - errorMessage); + SceneDialog::displayScenePrivateWithErrorMessage(sceneFile, + origScene, + false, + errorMessage); + /* + * Set the active scene + */ + EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); + activeSceneEvent.setScene(origScene); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - + + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + /* * Always generate an image, even if the scene fails and failure may * be a very minor error. @@ -1793,6 +1865,13 @@ SceneDialog::replaceSceneButtonClicked() scene); if (newScene != NULL) { s_informUserAboutScenesOnExitFlag = false; + + /* + * Set the active scene + */ + EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); + activeSceneEvent.setScene(newScene); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); } loadScenesIntoDialog(newScene); @@ -1800,6 +1879,9 @@ SceneDialog::replaceSceneButtonClicked() updateSceneFileModifiedStatusLabel(); } } + + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** @@ -1887,71 +1969,15 @@ SceneDialog::showFileStructure() SceneFile* sceneFile = getSelectedSceneFile(); CaretAssert(sceneFile); - const std::set fileSceneInfo = sceneFile->getAllDataFileNamesFromAllScenes(); - - if (fileSceneInfo.empty()) { - WuQMessageBox::errorOk(m_showFileStructurePushButton, - "Scene file is empty."); - return; - } - - const AString sceneFileName = sceneFile->getFileName(); - AString text(""); - - AString baseDirectoryName; - std::vector missingFileNames; - AString errorMessage; - const bool validBasePathFlag = sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, - missingFileNames, - errorMessage); - text.appendWithNewLine("Automatic Base Path: " - + (validBasePathFlag ? baseDirectoryName : ("INVALID: " + errorMessage)) - + "

"); - text.appendWithNewLine("Scene File: " - + sceneFileName - + "

"); - text.append("Data File paths relative to Scene File:"); - text.append("

    "); - - for (const auto& fileData : fileSceneInfo) { - AString name(fileData.m_dataFileName); - FileInformation fileInfo(name); - AString missingText; - if ( ! fileInfo.exists()) { - missingText = "MISSING: "; - } - - if (fileInfo.isAbsolute()) { - FileInformation specFileInfo(sceneFileName); - if (specFileInfo.isAbsolute()) { - const AString newPath = SystemUtilities::relativePath(fileInfo.getPathName(), - specFileInfo.getPathName()); - if (newPath.isEmpty()) { - name = fileInfo.getFileName(); - } - else { - name = (newPath - + "/" - + fileInfo.getFileName()); - } - } - } - - text.append("
  • " - + missingText - + " (" - + fileData.getSceneIndices() - + ") " - + name); - } - text.append("
"); - text.append(""); - - WuQTextEditorDialog::runNonModal("Scene File Paths", - text, - WuQTextEditorDialog::TextMode::HTML, - WuQTextEditorDialog::WrapMode::NO, - this); + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + + SceneFileInformationDialog* infoDialog = new SceneFileInformationDialog(sceneFile, + this); + infoDialog->setVisible(true); + infoDialog->show(); + infoDialog->activateWindow(); + infoDialog->raise(); } /** @@ -2186,9 +2212,9 @@ SceneDialog::createSceneFileWidget() /* * File structure buttons */ - m_showFileStructurePushButton = new QPushButton("List Files..."); + m_showFileStructurePushButton = new QPushButton("Show Files and Folders..."); WuQtUtilities::setWordWrappedToolTip(m_showFileStructurePushButton, - "In a dialog, show data files from all scenes with paths relative to the scene file"); + "In a dialog, show the organization files and folders contained in the Scene File"); QObject::connect(m_showFileStructurePushButton, &QPushButton::clicked, this, &SceneDialog::showFileStructure); @@ -2374,6 +2400,9 @@ SceneDialog::deleteSceneButtonClicked() SceneFile* sceneFile = getSelectedSceneFile(); sceneFile->removeScene(scene); updateDialog(); + + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } } } @@ -2423,10 +2452,14 @@ SceneDialog::showSceneButtonClicked() this); progressDialog.setValue(0); - displayScenePrivateWithErrorMessageDialog(sceneFile, - scene, - false); + displayScenePrivateWithErrorMessageDialog(this, + sceneFile, + scene, + false); } + + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** @@ -2566,12 +2599,16 @@ bool SceneDialog::displayScene(SceneFile* sceneFile, Scene* scene) { - const bool isSuccessful = displayScenePrivateWithErrorMessageDialog(sceneFile, - scene, - true); + const bool isSuccessful = displayScenePrivateWithErrorMessageDialog(this, + sceneFile, + scene, + true); loadSceneFileComboBox(sceneFile); loadScenesIntoDialog(scene); + /* Ensures macros dialog gets updated with active scene */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + return isSuccessful; } @@ -2580,17 +2617,47 @@ SceneDialog::displayScene(SceneFile* sceneFile, * If the scene fails to load, an error message is displayed * in a dialog. * + * @param dialogParent + * Parent for error message dialog * @param sceneFile * Scene file. * @param scene * Scene that is displayed. - * param showWaitCursor - * Show a wait cursor while loading scene * @return * true if scene was displayed without error, else false. */ bool -SceneDialog::displayScenePrivateWithErrorMessageDialog(SceneFile* sceneFile, +SceneDialog::displaySceneWithErrorMessageDialog(QWidget* dialogParent, + SceneFile* sceneFile, + Scene* scene) +{ + const bool showWaitCursorFlag(true); + const bool flag = SceneDialog::displayScenePrivateWithErrorMessageDialog(dialogParent, + sceneFile, + scene, + showWaitCursorFlag); + return flag; +} + +/** + * Display the given scene from the given scene file. + * If the scene fails to load, an error message is displayed + * in a dialog. + * + * @param dialogParent + * Parent for error message dialog + * @param sceneFile + * Scene file. + * @param scene + * Scene that is displayed. + * @param showWaitCursor + * If true, show a wait cursor + * @return + * true if scene was displayed without error, else false. + */ +bool +SceneDialog::displayScenePrivateWithErrorMessageDialog(QWidget* dialogParent, + SceneFile* sceneFile, Scene* scene, const bool showWaitCursor) { @@ -2609,7 +2676,7 @@ SceneDialog::displayScenePrivateWithErrorMessageDialog(SceneFile* sceneFile, CaretLogInfo(msg); if ( ! successFlag) { - WuQMessageBox::errorOk(this, + WuQMessageBox::errorOk(dialogParent, errorMessage); } @@ -2702,6 +2769,13 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, cursor.restoreCursor(); + /* + * Set the active scene + */ + EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); + activeSceneEvent.setScene(scene); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); + const AString sceneErrorMessage = sceneAttributes->getErrorMessage(); if (sceneErrorMessage.isEmpty()) { /* @@ -2905,6 +2979,17 @@ SceneDialog::updateSceneFileModifiedStatusLabel() m_uploadSceneFilePushButton->setEnabled(haveScenesFlag); } +/** + * Called when help button is clicked. + */ +void +SceneDialog::helpButtonClicked() +{ + EventHelpViewerDisplay helpViewerEvent(NULL, + "Scenes_Window"); + EventManager::get()->sendEvent(helpViewerEvent.getPointer()); +} + /* ======================================================================== */ @@ -2926,6 +3011,7 @@ SceneClassInfoWidget::SceneClassInfoWidget() m_defaultBackgroundRole = backgroundRole(); m_defaultAutoFillBackgroundStatus = autoFillBackground(); + m_activeSceneLabel = new QLabel(); m_nameLabel = new QLabel(); m_nameLabel->setWordWrap(true); @@ -2941,6 +3027,7 @@ SceneClassInfoWidget::SceneClassInfoWidget() QVBoxLayout* rightLayout = new QVBoxLayout(m_rightSideWidget); rightLayout->setContentsMargins(0, 0, 0, 0); rightLayout->setSpacing(3); + rightLayout->addWidget(m_activeSceneLabel); rightLayout->addWidget(m_nameLabel,1); rightLayout->addWidget(m_sceneIdLabel); rightLayout->addWidget(m_descriptionLabel, 100); @@ -2995,10 +3082,13 @@ SceneClassInfoWidget::setBackgroundForSelected(const bool selected) * Scene for display. * @param sceneIndex * Index of the scene. + * @param activeSceneFlag + * True if this is the active scene */ void SceneClassInfoWidget::updateContent(Scene* scene, - const int32_t sceneIndex) + const int32_t sceneIndex, + const bool activeSceneFlag) { m_scene = scene; m_sceneIndex = sceneIndex; @@ -3016,6 +3106,14 @@ SceneClassInfoWidget::updateContent(Scene* scene, descriptionText, numLinesToDisplay); + if (activeSceneFlag) { + m_activeSceneLabel->setText("Current Scene"); + m_activeSceneLabel->setVisible(true); + } + else { + m_activeSceneLabel->setText(""); + m_activeSceneLabel->setVisible(false); + } m_nameLabel->setText(nameText); m_sceneIdLabel->setText(sceneIdText); m_descriptionLabel->setText(descriptionText); diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index 307fe98f484683aeab68abdd4fc95d10c14481e5..0b4e4f5c292d1404c910d6d2336764343b51e78a 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -68,6 +68,10 @@ namespace caret { static bool checkForModifiedFiles(const GuiManager::TestModifiedMode testMode, QWidget* parent); + static bool displaySceneWithErrorMessageDialog(QWidget* dialogParent, + SceneFile* sceneFile, + Scene* scene); + private: SceneDialog(const SceneDialog&); @@ -129,6 +133,8 @@ namespace caret { protected: virtual void closeEvent(QCloseEvent* event); + virtual void helpButtonClicked() override; + private: SceneFile* getSelectedSceneFile(); @@ -152,11 +158,12 @@ namespace caret { QWidget* createSceneFileWidget(); - bool displayScenePrivateWithErrorMessageDialog(SceneFile* sceneFile, - Scene* scene, - const bool showWaitCursor); - - bool displayScenePrivateWithErrorMessage(SceneFile* sceneFile, + static bool displayScenePrivateWithErrorMessageDialog(QWidget* dialogParent, + SceneFile* sceneFile, + Scene* scene, + const bool showWaitCursor); + + static bool displayScenePrivateWithErrorMessage(SceneFile* sceneFile, Scene* scene, const bool showWaitCursor, AString& errorMessageOut); @@ -272,7 +279,8 @@ namespace caret { ~SceneClassInfoWidget(); void updateContent(Scene* scene, - const int32_t sceneIndex); + const int32_t sceneIndex, + const bool activeSceneFlag); void setBackgroundForSelected(const bool selected); @@ -315,6 +323,8 @@ namespace caret { QLabel* m_previewImageLabel; + QLabel* m_activeSceneLabel; + QLabel* m_nameLabel; QLabel* m_sceneIdLabel; diff --git a/src/GuiQt/SceneFileInformationDialog.cxx b/src/GuiQt/SceneFileInformationDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..94b3f938348072bc51c573db60931b0259547241 --- /dev/null +++ b/src/GuiQt/SceneFileInformationDialog.cxx @@ -0,0 +1,353 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ +#include "SceneFileInformationDialog.h" +#undef __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CursorDisplayScoped.h" +#include "FileInformation.h" +#include "SceneDataFileTreeItemModel.h" +#include "SceneFile.h" +#include "WuQMessageBox.h" + +using namespace caret; + + + +/** + * \class caret::SceneFileInformationDialog + * \brief Dialog for display of scene file organization + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param sceneFile + * The scene file whose file information is displayed. + * @param parent + * Dialog's parent widget. + */ +SceneFileInformationDialog::SceneFileInformationDialog(const SceneFile* sceneFile, + QWidget* parent) +: WuQDialogNonModal("Files and Folders", + parent), +m_sceneFile(sceneFile) +{ + setDeleteWhenClosed(true); + setApplyButtonText(""); + + AString basePathName; + std::vector missingDataFiles; + AString basePathErrorMessage; + const bool validBasePathFlag = sceneFile->findBaseDirectoryForDataFiles(basePathName, + missingDataFiles, + basePathErrorMessage); + if ( ! validBasePathFlag) { + basePathName = basePathErrorMessage; + } + + QLabel* basePathLabel = new QLabel("Base Path:"); + m_basePathLineEdit = new QLineEdit(); + m_basePathLineEdit->setReadOnly(true); + m_basePathLineEdit->setText(basePathName); + m_basePathLineEdit->home(true); + + FileInformation sceneFileInfo(sceneFile->getFileName()); + QLabel* sceneFileNameLabel = new QLabel("Scene File Name:"); + m_sceneFileNameLineEdit = new QLineEdit(); + m_sceneFileNameLineEdit->setReadOnly(true); + m_sceneFileNameLineEdit->setText(sceneFileInfo.getFileName()); + m_sceneFileNameLineEdit->home(true); + + QLabel* sceneFilePathLabel = new QLabel("Scene File Path:"); + m_sceneFilePathLineEdit = new QLineEdit(); + m_sceneFilePathLineEdit->setReadOnly(true); + m_sceneFilePathLineEdit->setText(sceneFileInfo.getPathName()); + m_sceneFilePathLineEdit->home(true); + + m_textEdit = new QTextEdit(); + + m_sceneFileHierarchyTreeView = new QTreeView(); + m_sceneFileHierarchyTreeView->setHeaderHidden(true); + + QTabWidget* tabWidget = new QTabWidget(); + tabWidget->addTab(m_sceneFileHierarchyTreeView, "Hierarchy"); + tabWidget->addTab(m_textEdit, "List"); + + QGridLayout* namesLayout = new QGridLayout(); + namesLayout->setColumnStretch(0, 0); + namesLayout->setColumnStretch(1, 100); + namesLayout->addWidget(basePathLabel, 0, 0); + namesLayout->addWidget(m_basePathLineEdit, 0, 1); + namesLayout->addWidget(sceneFileNameLabel, 1, 0); + namesLayout->addWidget(m_sceneFileNameLineEdit, 1, 1); + namesLayout->addWidget(sceneFilePathLabel, 2, 0); + namesLayout->addWidget(m_sceneFilePathLineEdit, 2, 1); + + QWidget* dialogWidget = new QWidget(); + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->setSpacing(3); + dialogLayout->addLayout(namesLayout, 0); + dialogLayout->addWidget(tabWidget, 100); + + setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); + + displayFilesHierarchy(); + displayFilesList(); + + setSizeOfDialogWhenDisplayed(QSize(600, 800)); +} + +/** + * Destructor. + */ +SceneFileInformationDialog::~SceneFileInformationDialog() +{ +} + +///** +// * Setup the list of files +// */ +//void +//SceneFileInformationDialog::displayFilesList() +//{ +// const SceneDataFileInfo::SortMode sortMode = SceneDataFileInfo::SortMode::RelativeToSceneFilePath; +// CaretAssert(m_sceneFile); +// +// std::vector fileSceneInfo = m_sceneFile->getAllDataFileInfoFromAllScenes(); +// SceneDataFileInfo::sort(fileSceneInfo, +// sortMode); +// +// if (fileSceneInfo.empty()) { +// WuQMessageBox::errorOk(this, +// "Scene file is empty."); +// return; +// } +// +// AString baseDirectoryName; +// std::vector missingFileNames; +// AString errorMessage; +// const bool validBasePathFlag = m_sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, +// missingFileNames, +// errorMessage); +// +// const AString sceneFileName = m_sceneFile->getFileName(); +// AString text(""); +// +// text.appendWithNewLine("Automatic Base Path: " +// + (validBasePathFlag ? baseDirectoryName : ("INVALID: " + errorMessage)) +// + "

"); +// text.appendWithNewLine("Scene File: " +// + sceneFileName +// + "

"); +// +// bool needListEndElementFlag = false; +// AString lastPathName("bogus ##(*&$UI()#NFGK path name"); +// for (const auto& fileData : fileSceneInfo) { +// AString missingText; +// +// AString pathName; +// switch (sortMode) { +// case SceneDataFileInfo::SortMode::AbsolutePath: +// pathName = fileData.getAbsolutePath(); +// break; +// case SceneDataFileInfo::SortMode::RelativeToBasePath: +// pathName = fileData.getRelativePathToBasePath(); +// if (pathName.isEmpty()) { +// pathName = "Files in Base Path"; +// } +// break; +// case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: +// pathName = fileData.getRelativePathToSceneFile(); +// if (pathName.isEmpty()) { +// pathName = "Files in Scene File Path"; +// } +// break; +// } +// +// if (pathName != lastPathName) { +// if (needListEndElementFlag) { +// text.append(""); +// } +// text.append("

" +// + pathName +// + ""); +// text.append("

    "); +// needListEndElementFlag = true; +// lastPathName = pathName; +// } +// +// if (fileData.isMissing()) { +// missingText = "MISSING "; +// } +// +// text.append("
  • " +// + missingText +// + fileData.getDataFileName() +// + " (" +// + fileData.getSceneIndicesAsString() +// + ")"); +// } +// if (needListEndElementFlag) { +// text.append("
"); +// } +// text.append(""); +// +// m_textEdit->clear(); +// m_textEdit->setHtml(text); +//} + +/** + * Setup the list of files + */ +void +SceneFileInformationDialog::displayFilesList() +{ + const SceneDataFileInfo::SortMode sortMode = SceneDataFileInfo::SortMode::RelativeToSceneFilePath; + CaretAssert(m_sceneFile); + + std::vector fileSceneInfo = m_sceneFile->getAllDataFileInfoFromAllScenes(); + SceneDataFileInfo::sort(fileSceneInfo, + sortMode); + + if (fileSceneInfo.empty()) { + WuQMessageBox::errorOk(this, + "Scene file is empty."); + return; + } + + AString baseDirectoryName; + std::vector missingFileNames; + AString errorMessage; + const bool validBasePathFlag = m_sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, + missingFileNames, + errorMessage); + + const AString sceneFileName = m_sceneFile->getFileName(); + AString text(""); + + text.appendWithNewLine("Automatic Base Path: " + + (validBasePathFlag ? baseDirectoryName : ("INVALID: " + errorMessage)) + + "

"); + text.appendWithNewLine("Scene File: " + + sceneFileName + + "

"); + + AString pathName; + switch (sortMode) { + case SceneDataFileInfo::SortMode::AbsolutePath: + pathName = "Absolute File Paths"; + break; + case SceneDataFileInfo::SortMode::RelativeToBasePath: + pathName = "Files in Base Path"; + break; + case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: + pathName = "Data File paths relative to Scene File"; + break; + } + text.append("" + + pathName + + ""); + + text.append("

    "); + + for (const auto& fileData : fileSceneInfo) { + AString missingText; + + AString pathName; + switch (sortMode) { + case SceneDataFileInfo::SortMode::AbsolutePath: + pathName = fileData.getAbsolutePath(); + break; + case SceneDataFileInfo::SortMode::RelativeToBasePath: + pathName = fileData.getRelativePathToBasePath(); + break; + case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: + pathName = fileData.getRelativePathToSceneFile(); + break; + } + if (! pathName.isEmpty()) { + pathName.append("/ "); + } + + if (fileData.isMissing()) { + missingText = " "; + } + + text.append("
  • " + + missingText + + pathName + + fileData.getDataFileName() + + " (" + + fileData.getSceneIndicesAsString() + + ")"); + } + + text.append("
"); + text.append(""); + + m_textEdit->clear(); + m_textEdit->setHtml(text); +} + +/** + * Setup the hierarchy of files + */ +void +SceneFileInformationDialog::displayFilesHierarchy() +{ + AString baseDirectoryName; + std::vector missingFileNames; + AString errorMessage; + const bool validBasePathFlag = m_sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, + missingFileNames, + errorMessage); + if ( ! validBasePathFlag) { + return; + } + CaretAssert(m_sceneFile); + + std::vector fileSceneInfo = m_sceneFile->getAllDataFileInfoFromAllScenes(); + SceneDataFileInfo::sort(fileSceneInfo, + SceneDataFileInfo::SortMode::AbsolutePath); + + m_sceneFileHierarchyTreeModel.reset(new SceneDataFileTreeItemModel(m_sceneFile->getFileName(), + baseDirectoryName, + fileSceneInfo, + SceneDataFileInfo::SortMode::AbsolutePath)); + m_sceneFileHierarchyTreeView->setModel(m_sceneFileHierarchyTreeModel.get()); + m_sceneFileHierarchyTreeView->expandAll(); +} + + + diff --git a/src/GuiQt/SceneFileInformationDialog.h b/src/GuiQt/SceneFileInformationDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..18234bb577f471fcf1392bc3e1bdc2932fb8a881 --- /dev/null +++ b/src/GuiQt/SceneFileInformationDialog.h @@ -0,0 +1,84 @@ +#ifndef __SCENE_FILE_INFORMATION_DIALOG_H__ +#define __SCENE_FILE_INFORMATION_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQDialogNonModal.h" + +class QLineEdit; +class QTextEdit; +class QTreeView; + +namespace caret { + + class SceneDataFileTreeItemModel; + class SceneFile; + + class SceneFileInformationDialog : public WuQDialogNonModal { + + Q_OBJECT + + public: + SceneFileInformationDialog(const SceneFile* sceneFile, + QWidget* parent); + + virtual ~SceneFileInformationDialog(); + + SceneFileInformationDialog(const SceneFileInformationDialog&) = delete; + + SceneFileInformationDialog& operator=(const SceneFileInformationDialog&) = delete; + + + // ADD_NEW_METHODS_HERE + + private: + void displayFilesList(); + + void displayFilesHierarchy(); + + const SceneFile* m_sceneFile; + + QTextEdit* m_textEdit; + + QTreeView* m_sceneFileHierarchyTreeView; + + std::unique_ptr m_sceneFileHierarchyTreeModel; + + QLineEdit* m_basePathLineEdit; + + QLineEdit* m_sceneFileNameLineEdit; + + QLineEdit* m_sceneFilePathLineEdit; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ + // +#endif // __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ + +} // namespace +#endif //__SCENE_FILE_INFORMATION_DIALOG_H__ diff --git a/src/GuiQt/SceneReplaceAllDialog.cxx b/src/GuiQt/SceneReplaceAllDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b852eb3e7ef7b3694dc525bcb95a34f64e0054ae --- /dev/null +++ b/src/GuiQt/SceneReplaceAllDialog.cxx @@ -0,0 +1,93 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_REPLACE_ALL_DIALOG_DECLARE__ +#include "SceneReplaceAllDialog.h" +#undef __SCENE_REPLACE_ALL_DIALOG_DECLARE__ + +#include +#include +#include +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SceneReplaceAllDialog + * \brief Dialog for replacing scenes + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +SceneReplaceAllDialog::SceneReplaceAllDialog(const AString& replaceDescription, + QWidget* parent) +: WuQDialogModal("Replace All Scenes", + parent) +{ + QLabel* slowLabel = new QLabel(replaceDescription); + slowLabel->setWordWrap(true); + + m_changeSurfaceAnntotationOffsetCheckBox = new QCheckBox("Change offset of all surface annotations to TANGENT"); + + QGroupBox* optionsGroupBox = new QGroupBox("Options"); + QVBoxLayout* optionsLayout = new QVBoxLayout(optionsGroupBox); + optionsLayout->addWidget(m_changeSurfaceAnntotationOffsetCheckBox); + + QWidget* widget = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->addWidget(slowLabel); + layout->addWidget(optionsGroupBox); + + setCentralWidget(widget, + WuQDialogModal::SCROLL_AREA_NEVER); +} + +/** + * Destructor. + */ +SceneReplaceAllDialog::~SceneReplaceAllDialog() +{ +} + +/** + * Is true if the offset for all surface annotations should be changed + * to TANGENT. + */ +bool +SceneReplaceAllDialog::isChangeSurfaceAnnotationOffsetToOffset() const +{ + return m_changeSurfaceAnntotationOffsetCheckBox->isChecked(); +} + +/** + * Called when OK button is clicked. + */ +void +SceneReplaceAllDialog::okButtonClicked() +{ + WuQDialogModal::okButtonClicked(); +} + diff --git a/src/GuiQt/SceneReplaceAllDialog.h b/src/GuiQt/SceneReplaceAllDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..bbecfd1d4779aa1895d73ab7cabe69e01b1873ae --- /dev/null +++ b/src/GuiQt/SceneReplaceAllDialog.h @@ -0,0 +1,67 @@ +#ifndef __SCENE_REPLACE_ALL_DIALOG_H__ +#define __SCENE_REPLACE_ALL_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQDialogModal.h" + +class QCheckBox; + +namespace caret { + + class SceneReplaceAllDialog : public WuQDialogModal { + + Q_OBJECT + + public: + SceneReplaceAllDialog(const AString& replaceDescription, + QWidget* parent = 0); + + virtual ~SceneReplaceAllDialog(); + + SceneReplaceAllDialog(const SceneReplaceAllDialog&) = delete; + + SceneReplaceAllDialog& operator=(const SceneReplaceAllDialog&) = delete; + + bool isChangeSurfaceAnnotationOffsetToOffset() const; + + protected: + virtual void okButtonClicked(); + + // ADD_NEW_METHODS_HERE + + private: + QCheckBox* m_changeSurfaceAnntotationOffsetCheckBox; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_REPLACE_ALL_DIALOG_DECLARE__ + // +#endif // __SCENE_REPLACE_ALL_DIALOG_DECLARE__ + +} // namespace +#endif //__SCENE_REPLACE_ALL_DIALOG_H__ diff --git a/src/GuiQt/SpecFileManagementDialog.cxx b/src/GuiQt/SpecFileManagementDialog.cxx index 83dbc3b68c6a814ff8b46d42b0bdd34205abcbb3..28e8ee78dc551a0b62d051b63b6cc2a9091442f0 100644 --- a/src/GuiQt/SpecFileManagementDialog.cxx +++ b/src/GuiQt/SpecFileManagementDialog.cxx @@ -56,6 +56,7 @@ #include "DataFileContentCopyMoveDialog.h" #include "DataFileContentCopyMoveInterface.h" #include "DataFileException.h" +#include "DataFileContentInformation.h" #include "EventBrowserTabGetAllViewed.h" #include "EventDataFileRead.h" #include "EventDataFileReload.h" @@ -77,6 +78,7 @@ #include "UsernamePasswordWidget.h" #include "WuQImageLabel.h" #include "WuQMessageBox.h" +#include "WuQTextEditorDialog.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -2273,6 +2275,7 @@ SpecFileManagementDialog::fileOptionsActionSelected(int rowIndex) QAction* copyMoveFileContentAction = NULL; QAction* editMetaDataAction = NULL; QAction* setFileNameAction = NULL; + QAction* showFileInformationAction = NULL; QAction* setStructureAction = NULL; QAction* unloadFileMapsAction = NULL; QAction* viewMetaDataAction = NULL; @@ -2291,6 +2294,7 @@ SpecFileManagementDialog::fileOptionsActionSelected(int rowIndex) copyFilePathToClipboardAction = menu.addAction(copyPathText); editMetaDataAction = menu.addAction("Edit Metadata..."); setFileNameAction = menu.addAction("Set File Name..."); + showFileInformationAction = menu.addAction("Show File Information..."); } } else if ( ! sceneAnnotationFileFlag) { @@ -2328,6 +2332,9 @@ SpecFileManagementDialog::fileOptionsActionSelected(int rowIndex) specFileDataFile, caretDataFile); } + else if (selectedAction == showFileInformationAction) { + showFileInformation(caretDataFile); + } else if (selectedAction == setStructureAction) { CaretAssert(0); } @@ -2537,6 +2544,30 @@ SpecFileManagementDialog::changeFileName(QWidget* parent, // } } +/** + * Show information about a file. + * + * @param caretDataFileIn + * File for which information is displayed. + */ +void +SpecFileManagementDialog::showFileInformation(CaretDataFile* caretDataFile) +{ + DataFileContentInformation dataFileContentInformation; + const bool showMapInformationFlag(true); + dataFileContentInformation.setOptionFlag(DataFileContentInformation::OPTION_SHOW_MAP_INFORMATION, + showMapInformationFlag); + + caretDataFile->addToDataFileContentInformation(dataFileContentInformation); + + WuQTextEditorDialog::runNonModal("File Information", + dataFileContentInformation.getInformationInString(), + WuQTextEditorDialog::TextMode::PLAIN, + WuQTextEditorDialog::WrapMode::NO, + this); +} + + ///** // * Called when spec file options tool button is triggered. // */ diff --git a/src/GuiQt/SpecFileManagementDialog.h b/src/GuiQt/SpecFileManagementDialog.h index f3beb59abc1ec58cbd5f8d03ed7b296617a6445b..780a53d8ac6605d865bcb4c19e19bbcce22de15a 100644 --- a/src/GuiQt/SpecFileManagementDialog.h +++ b/src/GuiQt/SpecFileManagementDialog.h @@ -194,6 +194,8 @@ namespace caret { SpecFileDataFile* specFileDataFile, CaretDataFile* caretDataFile); + void showFileInformation(CaretDataFile* caretDataFile); + void copyMoveFileContent(QWidget* parent, CaretDataFile* caretDataFile); diff --git a/src/GuiQt/StructureSurfaceSelectionControl.cxx b/src/GuiQt/StructureSurfaceSelectionControl.cxx index c3f9674ebaef51d1da46b2bfb23ac89d10cdef53..2c8f2700d169f69b85b57ec03ea8c6b552ff3311 100644 --- a/src/GuiQt/StructureSurfaceSelectionControl.cxx +++ b/src/GuiQt/StructureSurfaceSelectionControl.cxx @@ -30,6 +30,7 @@ #include "EventModelGetAll.h" #include "WuQFactory.h" #include "GuiManager.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" #define __STRUCTURE_SURFACE_SELECTION_CONTROL_DECLARE__ @@ -50,9 +51,21 @@ using namespace caret; /** * Constructor. + * + * @param showLabels + * Show labels on controls + * @param objectNamePrefix + * Object name prefix used for macros + * @param descriptivePrefix + * Descriptive prefix for macros + * @param parent + * Parent widget for controls */ -StructureSurfaceSelectionControl::StructureSurfaceSelectionControl(const bool showLabels) -: QWidget() +StructureSurfaceSelectionControl::StructureSurfaceSelectionControl(const bool showLabels, + const QString& objectNamePrefix, + const QString& descriptivePrefix, + QWidget* parent) +: QWidget(parent) { this->surfaceControllerSelector = NULL; @@ -60,11 +73,21 @@ StructureSurfaceSelectionControl::StructureSurfaceSelectionControl(const bool sh this->structureSelectionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); QObject::connect(this->structureSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(structureSelected(int))); + this->structureSelectionComboBox->setToolTip("Selects Structure of Surface"); + this->structureSelectionComboBox->setObjectName(objectNamePrefix + + ":StructureSelection"); + WuQMacroManager::instance()->addMacroSupportToObject(this->structureSelectionComboBox, + "Select structure for " + descriptivePrefix); this->surfaceControllerSelectionComboBox = WuQFactory::newComboBox(); this->surfaceControllerSelectionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); QObject::connect(this->surfaceControllerSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(surfaceControllerSelected(int))); + this->surfaceControllerSelectionComboBox->setToolTip("Selects Surface"); + this->surfaceControllerSelectionComboBox->setObjectName(objectNamePrefix + + ":SurfaceSelection"); + WuQMacroManager::instance()->addMacroSupportToObject(this->surfaceControllerSelectionComboBox, + "Select surface for " + descriptivePrefix); QGridLayout* layout = new QGridLayout(this); layout->setColumnStretch(0, 0); diff --git a/src/GuiQt/StructureSurfaceSelectionControl.h b/src/GuiQt/StructureSurfaceSelectionControl.h index c878fee003409887dd3ea221fcb129283037fb8b..9cb75fd91933d8ba11323e477c310bbb3c47045f 100644 --- a/src/GuiQt/StructureSurfaceSelectionControl.h +++ b/src/GuiQt/StructureSurfaceSelectionControl.h @@ -39,7 +39,10 @@ namespace caret { Q_OBJECT public: - StructureSurfaceSelectionControl(const bool showLabels); + StructureSurfaceSelectionControl(const bool showLabels, + const QString& objectNamePrefix, + const QString& descriptivePrefix, + QWidget* parent); virtual ~StructureSurfaceSelectionControl(); diff --git a/src/GuiQt/SurfacePropertiesEditorDialog.cxx b/src/GuiQt/SurfacePropertiesEditorDialog.cxx index 96baaf7aef413817e7d6d5f5c2b36d2250d3ae69..c3116b3629a547ca9a8b260f66ff5e74f50a8f0b 100644 --- a/src/GuiQt/SurfacePropertiesEditorDialog.cxx +++ b/src/GuiQt/SurfacePropertiesEditorDialog.cxx @@ -25,24 +25,22 @@ #include +#include #include #include #include using namespace caret; -#include "Brain.h" #include "CaretAssert.h" -#include "DisplayPropertiesSurface.h" -#include "GuiManager.h" -#include "EnumComboBoxTemplate.h" -#include "EventGraphicsUpdateAllWindows.h" -#include "EventSurfaceColoringInvalidate.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "SceneClass.h" #include "SceneWindowGeometry.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" +#include "WuQMacroWidgetAction.h" +#include "WbMacroWidgetActionNames.h" #include "WuQTrueFalseComboBox.h" #include "WuQtUtilities.h" @@ -61,52 +59,77 @@ SurfacePropertiesEditorDialog::SurfacePropertiesEditorDialog(QWidget* parent) { m_updateInProgress = true; + WuQMacroManager* mm = WuQMacroManager::instance(); + CaretAssert(mm); + QLabel* surfaceDrawingTypeLabel = new QLabel("Drawing Type: "); - m_surfaceDrawingTypeComboBox = new EnumComboBoxTemplate(this); - QObject::connect(m_surfaceDrawingTypeComboBox, SIGNAL(itemActivated()), - this, SLOT(surfaceDisplayPropertyChanged())); - m_surfaceDrawingTypeComboBox->setup(); + QWidget* drawTypeWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesDrawingTypeName()); + if (drawTypeWidget != NULL) { + m_surfaceDrawingTypeComboBox = qobject_cast(drawTypeWidget); + CaretAssert(m_surfaceDrawingTypeComboBox); + } + if (m_surfaceDrawingTypeComboBox == NULL) { + m_surfaceDrawingTypeComboBox = new QComboBox(); + m_surfaceDrawingTypeComboBox->setEnabled(false); + } QLabel* linkSizeLabel = new QLabel("Link Diameter: "); - m_linkSizeSpinBox = WuQFactory::newDoubleSpinBox(); - m_linkSizeSpinBox->setRange(0.0, std::numeric_limits::max()); - m_linkSizeSpinBox->setSingleStep(1.0); - m_linkSizeSpinBox->setDecimals(1); + + QWidget* linkSizeMacroWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesLinkDiameterName()); + if (linkSizeMacroWidget != NULL) { + m_linkSizeSpinBox = qobject_cast(linkSizeMacroWidget); + CaretAssert(m_linkSizeSpinBox); + } + if (m_linkSizeSpinBox == NULL) { + m_linkSizeSpinBox = WuQFactory::newDoubleSpinBox(); + m_linkSizeSpinBox->setEnabled(false); + } m_linkSizeSpinBox->setSuffix("mm"); - QObject::connect(m_linkSizeSpinBox, SIGNAL(valueChanged(double)), - this, SLOT(surfaceDisplayPropertyChanged())); QLabel* nodeSizeLabel = new QLabel("Vertex Diameter: "); - m_nodeSizeSpinBox = WuQFactory::newDoubleSpinBox(); - m_nodeSizeSpinBox->setRange(0.0, std::numeric_limits::max()); - m_nodeSizeSpinBox->setSingleStep(1.0); - m_nodeSizeSpinBox->setDecimals(1); + + QWidget* nodeSizeWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesVertexDiameterName()); + if (nodeSizeWidget != NULL) { + m_nodeSizeSpinBox = qobject_cast(nodeSizeWidget); + CaretAssert(m_nodeSizeSpinBox); + } + if (m_nodeSizeSpinBox == NULL) { + m_nodeSizeSpinBox = WuQFactory::newDoubleSpinBox(); + m_nodeSizeSpinBox->setEnabled(false); + } m_nodeSizeSpinBox->setSuffix("mm"); - QObject::connect(m_nodeSizeSpinBox, SIGNAL(valueChanged(double)), - this, SLOT(surfaceDisplayPropertyChanged())); - QLabel* displayNormalVectorsLabel = new QLabel("Display Normal Vectors: "); - m_displayNormalVectorsComboBox = new WuQTrueFalseComboBox(this); - QObject::connect(m_displayNormalVectorsComboBox, SIGNAL(statusChanged(bool)), - this, SLOT(surfaceDisplayPropertyChanged())); + QWidget* displayNormalsWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesDisplayNormalVectorsName()); + if (displayNormalsWidget != NULL) { + m_displayNormalVectorsCheckBox = qobject_cast(displayNormalsWidget); + CaretAssert(m_displayNormalVectorsCheckBox); + } + if (m_displayNormalVectorsCheckBox == NULL) { + m_displayNormalVectorsCheckBox = new QCheckBox(); + m_displayNormalVectorsCheckBox->setEnabled(false); + } + m_displayNormalVectorsCheckBox->setText("Display Normal Vectors"); QLabel* opacityLabel = new QLabel("Opacity: "); - m_opacitySpinBox = WuQFactory::newDoubleSpinBox(); - m_opacitySpinBox->setRange(0.0, 1.0); - m_opacitySpinBox->setSingleStep(0.1); - m_opacitySpinBox->setDecimals(2); - QObject::connect(m_opacitySpinBox, SIGNAL(valueChanged(double)), - this, SLOT(surfaceDisplayPropertyChanged())); + + QWidget* opacityMacroWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesOpacityName()); + if (opacityMacroWidget != NULL) { + m_opacitySpinBox = qobject_cast(opacityMacroWidget); + CaretAssert(m_opacitySpinBox); + } + if (m_opacitySpinBox == NULL) { + m_opacitySpinBox = new QDoubleSpinBox(); + m_opacitySpinBox->setEnabled(false); + } QWidget* w = new QWidget(); QGridLayout* gridLayout = new QGridLayout(w); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); int row = gridLayout->rowCount(); - gridLayout->addWidget(displayNormalVectorsLabel, row, 0); - gridLayout->addWidget(m_displayNormalVectorsComboBox->getWidget(), row, 1); + gridLayout->addWidget(m_displayNormalVectorsCheckBox, row, 0, 1, 2); row++; gridLayout->addWidget(surfaceDrawingTypeLabel, row, 0); - gridLayout->addWidget(m_surfaceDrawingTypeComboBox->getWidget(), row, 1); + gridLayout->addWidget(m_surfaceDrawingTypeComboBox, row, 1); row++; gridLayout->addWidget(linkSizeLabel, row, 0); gridLayout->addWidget(m_linkSizeSpinBox, row, 1); @@ -138,32 +161,12 @@ SurfacePropertiesEditorDialog::SurfacePropertiesEditorDialog(QWidget* parent) SurfacePropertiesEditorDialog::~SurfacePropertiesEditorDialog() { EventManager::get()->removeAllEventsFromListener(this); -} - -/** - * Called when a surface display property is changed. - */ -void -SurfacePropertiesEditorDialog::surfaceDisplayPropertyChanged() -{ - /* - * Updating some widgets causes signals to be emitted - */ - if (m_updateInProgress) { - return; - } - - const SurfaceDrawingTypeEnum::Enum surfaceDrawingType = m_surfaceDrawingTypeComboBox->getSelectedItem(); - - DisplayPropertiesSurface* dps = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); - dps->setSurfaceDrawingType(surfaceDrawingType); - dps->setDisplayNormalVectors(m_displayNormalVectorsComboBox->isTrue()); - dps->setLinkSize(m_linkSizeSpinBox->value()); - dps->setNodeSize(m_nodeSizeSpinBox->value()); - dps->setOpacity(m_opacitySpinBox->value()); - EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + WuQMacroManager::instance()->releaseWidgetFromMacroWidgetAction(m_surfaceDrawingTypeComboBox, + m_linkSizeSpinBox, + m_nodeSizeSpinBox, + m_opacitySpinBox, + m_displayNormalVectorsCheckBox); } /** @@ -174,13 +177,11 @@ SurfacePropertiesEditorDialog::updateDialog() { m_updateInProgress = true; - const DisplayPropertiesSurface* dps = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); - - m_surfaceDrawingTypeComboBox->setSelectedItem(dps->getSurfaceDrawingType()); - m_displayNormalVectorsComboBox->setStatus(dps->isDisplayNormalVectors()); - m_linkSizeSpinBox->setValue(dps->getLinkSize()); - m_nodeSizeSpinBox->setValue(dps->getNodeSize()); - m_opacitySpinBox->setValue(dps->getOpacity()); + WuQMacroManager::instance()->updateValueInWidgetFromMacroWidgetAction(m_surfaceDrawingTypeComboBox, + m_linkSizeSpinBox, + m_nodeSizeSpinBox, + m_opacitySpinBox, + m_displayNormalVectorsCheckBox); m_updateInProgress = false; } @@ -257,5 +258,3 @@ SurfacePropertiesEditorDialog::restoreFromScene(const SceneAttributes* sceneAttr swg.restoreFromScene(sceneAttributes, sceneClass->getClass("geometry")); } - - diff --git a/src/GuiQt/SurfacePropertiesEditorDialog.h b/src/GuiQt/SurfacePropertiesEditorDialog.h index 1f3d3dc24e3cf6f528c4d5217ca467188ec5ffd5..1f56343d482c95af77a9ee3598cc56c7e12f3d99 100644 --- a/src/GuiQt/SurfacePropertiesEditorDialog.h +++ b/src/GuiQt/SurfacePropertiesEditorDialog.h @@ -25,12 +25,14 @@ #include "SceneableInterface.h" #include "WuQDialogNonModal.h" +class QCheckBox; +class QComboBox; class QDoubleSpinBox; namespace caret { class EnumComboBoxTemplate; class WuQTrueFalseComboBox; - + class SurfacePropertiesEditorDialog : public WuQDialogNonModal, public EventListenerInterface, public SceneableInterface { Q_OBJECT @@ -49,21 +51,18 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); - private slots: - void surfaceDisplayPropertyChanged(); - private: SurfacePropertiesEditorDialog(const SurfacePropertiesEditorDialog&); SurfacePropertiesEditorDialog& operator=(const SurfacePropertiesEditorDialog&); - WuQTrueFalseComboBox* m_displayNormalVectorsComboBox; + QCheckBox* m_displayNormalVectorsCheckBox; QDoubleSpinBox* m_linkSizeSpinBox; QDoubleSpinBox* m_nodeSizeSpinBox; - EnumComboBoxTemplate* m_surfaceDrawingTypeComboBox; + QComboBox* m_surfaceDrawingTypeComboBox; QDoubleSpinBox* m_opacitySpinBox; @@ -74,7 +73,6 @@ namespace caret { }; #ifdef __SURFACE_PROPERTIES_EDITOR_DIALOG_DECLARE__ - // #endif // __SURFACE_PROPERTIES_EDITOR_DIALOG_DECLARE__ } // namespace diff --git a/src/GuiQt/SurfaceSelectionViewController.cxx b/src/GuiQt/SurfaceSelectionViewController.cxx index f8b52c432d008d25b03a965b2b2ce560629d1e02..e80935c33082562e4cdeb04d2c99853a7c45c6c6 100644 --- a/src/GuiQt/SurfaceSelectionViewController.cxx +++ b/src/GuiQt/SurfaceSelectionViewController.cxx @@ -32,6 +32,7 @@ #include "SurfaceSelectionModel.h" #include "WuQEventBlockingFilter.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" using namespace caret; @@ -50,13 +51,21 @@ using namespace caret; * The parent. * @param surfaceSelection * Surface selection that is controlled through this control. + * @param objectName + * Name for combo box + * @param descriptiveName + * Descriptive name for macros */ SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, - SurfaceSelectionModel* surfaceSelectionModel) + SurfaceSelectionModel* surfaceSelectionModel, + const QString& objectName, + const QString& descriptiveName) : WuQWidget(parent) { this->initializeControl(MODE_SELECTION_MODEL_STATIC, - surfaceSelectionModel); + surfaceSelectionModel, + objectName, + descriptiveName); } /** @@ -65,9 +74,15 @@ SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, * The parent. * @param brainStructure * Allows selection of any surface with the specified brain structure. + * @param objectName + * Name for combo box + * @param descriptiveName + * Descriptive name for macros */ SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, - BrainStructure* brainStructure) + BrainStructure* brainStructure, + const QString& objectName, + const QString& descriptiveName) : WuQWidget(parent) { std::vector allSurfaceTypes; @@ -76,7 +91,9 @@ SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, SurfaceSelectionModel* ss = new SurfaceSelectionModel(brainStructure->getStructure(), allSurfaceTypes); this->initializeControl(MODE_BRAIN_STRUCTURE, - ss); + ss, + objectName, + descriptiveName); } /** @@ -108,26 +125,47 @@ SurfaceSelectionViewController::~SurfaceSelectionViewController() * * @param parent * The parent. + * @param objectName + * Name for combo box */ -SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent) +SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, + const QString& objectName, + const QString& descriptiveName) : WuQWidget(parent) { this->initializeControl(MODE_SELECTION_MODEL_DYNAMIC, - NULL); + NULL, + objectName, + descriptiveName); } /** - * Help initialize an instance. + * @param mode + * The mode. + * @param surfaceSelectionModel + * Model for surface selection + * @param objectName + * Name for combo box + * @param descriptiveName + * Descriptive name for macros */ void SurfaceSelectionViewController::initializeControl(const Mode mode, - SurfaceSelectionModel* surfaceSelectionModel) + SurfaceSelectionModel* surfaceSelectionModel, + const QString& objectName, + const QString& descriptiveName) { this->mode = mode; this->surfaceComboBox = WuQFactory::newComboBox(); this->surfaceComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); QObject::connect(this->surfaceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxCurrentIndexChanged(int))); + + this->surfaceComboBox->setToolTip("Selects a surface in a combo box"); + this->surfaceComboBox->setObjectName(objectName); + WuQMacroManager::instance()->addMacroSupportToObject(this->surfaceComboBox, + "Select surface for " + descriptiveName); + //#ifdef CARET_OS_MACOSX // /* diff --git a/src/GuiQt/SurfaceSelectionViewController.h b/src/GuiQt/SurfaceSelectionViewController.h index 6254b129baef4757579a6c15462d80efed4c2990..01b5268122f943e4a3c2085ff49854c381bcf80a 100644 --- a/src/GuiQt/SurfaceSelectionViewController.h +++ b/src/GuiQt/SurfaceSelectionViewController.h @@ -36,12 +36,18 @@ namespace caret { public: SurfaceSelectionViewController(QObject* parent, - SurfaceSelectionModel* surfaceSelectionModel); + SurfaceSelectionModel* surfaceSelectionModel, + const QString& objectName, + const QString& descriptiveName); SurfaceSelectionViewController(QObject* parent, - BrainStructure* brainStructure); + BrainStructure* brainStructure, + const QString& objectName, + const QString& descriptiveName); - SurfaceSelectionViewController(QObject* parent); + SurfaceSelectionViewController(QObject* parent, + const QString& objectName, + const QString& descriptiveName); virtual ~SurfaceSelectionViewController(); @@ -78,7 +84,9 @@ namespace caret { }; void initializeControl(const Mode mode, - SurfaceSelectionModel* surfaceSelectionModel); + SurfaceSelectionModel* surfaceSelectionModel, + const QString& objectName, + const QString& descriptiveName); Mode mode; diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 707f5d5348232c5b52832acfe4cfd727e4a8e999..cc2bc54ee1016f7034c9d9ea0e8f628c30331371 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -20,16 +20,19 @@ /*LICENSE_END*/ #include +#include #include #include #include #include #include #include +#include #include #include #include #include +#include #include @@ -42,14 +45,19 @@ #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretPreferences.h" +#include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateOneWindow.h" +#include "EventHelpViewerDisplay.h" #include "EventManager.h" +#include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "SessionManager.h" #include "TileTabsConfiguration.h" +#include "TileTabsGridRowColumnElement.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" +#include "WuQGridLayoutGroup.h" #include "WuQListWidget.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -77,6 +85,7 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par m_blockReadConfigurationsFromPreferences = false; m_caretPreferences = SessionManager::get()->getCaretPreferences(); + QWidget* dialogWidget = new QWidget(); QHBoxLayout* configurationLayout = new QHBoxLayout(dialogWidget); configurationLayout->setSpacing(0); @@ -86,12 +95,12 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par 0, Qt::AlignTop); configurationLayout->addWidget(createUserConfigurationSelectionWidget(), - 0, + 100, Qt::AlignTop); - disableAutoDefaultForAllPushButtons(); - setApplyButtonText(""); + setStandardButtonText(QDialogButtonBox::Help, + "Help"); updateDialogWithSelectedTileTabsFromWindow(parentBrainBrowserWindow); @@ -100,8 +109,10 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); - resize(sizeHint().width(), - 400); + resize(750, + 500); + + disableAutoDefaultForAllPushButtons(); } /** @@ -251,8 +262,10 @@ BrainBrowserWindow* TileTabsConfigurationDialog::getBrowserWindow() { m_browserWindowComboBox->updateComboBox(); + /* + * This can be NULL when wb_view is closing. + */ BrainBrowserWindow* bbw = m_browserWindowComboBox->getSelectedBrowserWindow(); - CaretAssert(bbw); return bbw; } @@ -260,13 +273,16 @@ TileTabsConfigurationDialog::getBrowserWindow() /** * @return The browser window content for the selected window index. + * May be NULL when no tabs are open. */ BrowserWindowContent* TileTabsConfigurationDialog::getBrowserWindowContent() { + BrowserWindowContent* bwc(NULL); BrainBrowserWindow* bbw = getBrowserWindow(); - BrowserWindowContent* bwc = bbw->getBrowerWindowContent(); - CaretAssert(bwc); + if (bbw != NULL) { + bwc = bbw->getBrowerWindowContent(); + } return bwc; } @@ -349,14 +365,215 @@ TileTabsConfigurationDialog::createWorkbenchWindowWidget() } /** - * @return Instance of workbench window widget. + * @return The rows/columns stretch layout + */ +QWidget* +TileTabsConfigurationDialog::createCustomOptionsWidget() +{ + const QString toolTip("" + "Removes any space between rows and columns in the tile tabs configuration. " + "Some scenes created in previous versions of wb_view may not appear correctly " + "due to changes in layout of the tabs. Enabling this option may fix the " + "problem. In addition, if the Lock Aspect option is selected prior to " + "to enabling tile tabs, this option may improve the layout." + ""); + m_centeringCorrectionCheckBox = new QCheckBox("Centering Correction"); + m_centeringCorrectionCheckBox->setToolTip(toolTip); + QObject::connect(m_centeringCorrectionCheckBox, &QCheckBox::clicked, + this, &TileTabsConfigurationDialog::centeringCorrectionCheckBoxClicked); + + QGroupBox* groupBox = new QGroupBox("Options"); + QVBoxLayout* layout = new QVBoxLayout(groupBox); + layout->addWidget(m_centeringCorrectionCheckBox); + + return groupBox; +} + +/** + * Called when user checks/unchecks the centering correction checkbox + * + * @bool checked + * New checked status + */ +void +TileTabsConfigurationDialog::centeringCorrectionCheckBoxClicked(bool checked) +{ + TileTabsConfiguration* config = getCustomTileTabsConfiguration(); + if (config != NULL) { + config->setCenteringCorrectionEnabled(checked); + updateGraphicsWindow(); + } +} + +/** + * Update the custom options + */ +void +TileTabsConfigurationDialog::updateCustomOptionsWidget() +{ + TileTabsConfiguration* config = getCustomTileTabsConfiguration(); + if (config != NULL) { + m_centeringCorrectionCheckBox->setChecked(config->isCenteringCorrectionEnabled()); + } +} + +/** + * @return The rows/columns stretch layout */ QWidget* -TileTabsConfigurationDialog::createCustomConfigurationWidget() +TileTabsConfigurationDialog::createRowColumnStretchWidget() { - const int32_t maximumNumberOfRows = TileTabsConfiguration::getMaximumNumberOfRows(); - const int32_t maximumNumberOfColumns = TileTabsConfiguration::getMaximumNumberOfColumns(); + QGroupBox* rowGroupBox = new QGroupBox("Rows"); + rowGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_rowElementsGridLayout = new QGridLayout(rowGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(m_rowElementsGridLayout, 4, 2); + + QGroupBox* columnsGroupBox = new QGroupBox("Columns"); + m_columnElementsGridLayout = new QGridLayout(columnsGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(m_columnElementsGridLayout, 2, 2); + + QWidget* widget = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(rowGroupBox); + layout->addSpacing(6); + layout->addWidget(columnsGroupBox); + layout->addStretch(); + + return widget; +} + +/** + * update the row and column stretching widgets. + * + * @param configuration + * Current custom configuration. + */ +void +TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsConfiguration* configuration) +{ + /* + * Update rows + */ + { + const int32_t numRows = configuration->getNumberOfRows(); + int32_t numRowElements = static_cast(m_rowElements.size()); + + /** + * Add elements as needed. + */ + const int32_t numToAdd = numRows - numRowElements; + for (int32_t iRow = 0; iRow < numToAdd; iRow++) { + addRowColumnStretchWidget(EventTileTabsConfigurationModification::RowColumnType::ROW, + m_rowElementsGridLayout, + m_rowElements); + } + + /* + * Update widgets with element content + */ + numRowElements = static_cast(m_rowElements.size()); + for (int32_t iRow = 0; iRow < numRowElements; iRow++) { + TileTabsGridRowColumnElement* element(NULL); + if (iRow < numRows) { + element = configuration->getRow(iRow); + } + + CaretAssertVectorIndex(m_rowElements, iRow); + m_rowElements[iRow]->updateContent(element); + } + + m_rowElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); + } + /* + * Update columns + */ + { + const int32_t numColumns = configuration->getNumberOfColumns(); + int32_t numColumnElements = static_cast(m_columnElements.size()); + + /** + * Add elements as needed. + */ + const int32_t numToAdd = numColumns - numColumnElements; + for (int32_t iColumn = 0; iColumn < numToAdd; iColumn++) { + addRowColumnStretchWidget(EventTileTabsConfigurationModification::RowColumnType::COLUMN, + m_columnElementsGridLayout, + m_columnElements); + } + + /* + * Update widgets with element content + */ + numColumnElements = static_cast(m_columnElements.size()); + for (int32_t iColumn = 0; iColumn < numColumnElements; iColumn++) { + TileTabsGridRowColumnElement* element(NULL); + if (iColumn < numColumns) { + element = configuration->getColumn(iColumn); + } + + CaretAssertVectorIndex(m_columnElements, iColumn); + m_columnElements[iColumn]->updateContent(element); + } + + m_columnElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); + } + + updateCustomOptionsWidget(); + +// m_customConfigurationWidget->adjustSize(); +} + +/** + * Add a row/column stretch widget. + * + * @param rowColumnType + * The row or column type. + * @param gridLayout + * Grid layout for widgets. + * @param elementVector + * Container for row/column elements. + */ +void +TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsConfigurationModification::RowColumnType rowColumnType, + QGridLayout* gridLayout, + std::vector& elementVector) +{ + const int32_t index = static_cast(elementVector.size()); + if (index == 0) { + int32_t columnIndex(0); + int32_t row = gridLayout->rowCount(); + gridLayout->addWidget(new QLabel("Index"), row, columnIndex++, Qt::AlignRight); + gridLayout->addWidget(new QLabel(" "), row, columnIndex++); + gridLayout->addWidget(new QLabel("Content"), row, columnIndex++, Qt::AlignHCenter); + gridLayout->addWidget(new QLabel("Type"), row, columnIndex++, Qt::AlignHCenter); + gridLayout->addWidget(new QLabel("Stretch"), row, columnIndex++, Qt::AlignHCenter); + for (int32_t i = 0; i < columnIndex; i++) { + gridLayout->setColumnStretch(i, 0); + } + } + + TileTabElementWidgets* elementWidget = new TileTabElementWidgets(this, + rowColumnType, + index, + gridLayout, + this); + QObject::connect(elementWidget, &TileTabElementWidgets::itemChanged, + this, &TileTabsConfigurationDialog::configurationStretchFactorWasChanged); + QObject::connect(elementWidget, &TileTabElementWidgets::modificationRequested, + this, &TileTabsConfigurationDialog::tileTabsModificationRequested); + + elementVector.push_back(elementWidget); +} + + +/** + * @return The active configuration widget. + */ +QWidget* +TileTabsConfigurationDialog::createActiveConfigurationWidget() +{ const AString autoToolTip("Workbench adjusts the number of rows and columns so " "that all tabs are displayed"); m_automaticConfigurationRadioButton = new QRadioButton("Automatic Configuration"); @@ -372,10 +589,9 @@ TileTabsConfigurationDialog::createCustomConfigurationWidget() QObject::connect(buttonGroup, static_cast(&QButtonGroup::buttonClicked), this, &TileTabsConfigurationDialog::automaticCustomButtonClicked); - QLabel* dimensionsLabel = new QLabel("Dimensions"); QLabel* rowsLabel = new QLabel("Rows"); m_numberOfRowsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, - maximumNumberOfRows, + s_maximumRowsColumns, 1, this, SLOT(configurationNumberOfRowsOrColumnsChanged())); @@ -383,159 +599,59 @@ TileTabsConfigurationDialog::createCustomConfigurationWidget() QLabel* columnsLabel = new QLabel("Columns"); m_numberOfColumnsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, - maximumNumberOfColumns, + s_maximumRowsColumns, 1, this, SLOT(configurationNumberOfRowsOrColumnsChanged())); m_numberOfColumnsSpinBox->setToolTip("Number of columns for the tab configuration"); + m_customConfigurationWidget = createRowColumnStretchWidget(); + m_customConfigurationWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - QGridLayout* dimensionsLayout = new QGridLayout(); - dimensionsLayout->setContentsMargins(0, 0, 0, 0); - dimensionsLayout->setColumnStretch(0, 100); - dimensionsLayout->setColumnStretch(5, 100); - dimensionsLayout->addWidget(dimensionsLabel, 0, 1, 1, 4, Qt::AlignHCenter); - dimensionsLayout->addWidget(rowsLabel, 1, 1); - dimensionsLayout->addWidget(m_numberOfRowsSpinBox, 1, 2); - dimensionsLayout->addWidget(columnsLabel, 1, 3); - dimensionsLayout->addWidget(m_numberOfColumnsSpinBox, 1, 4); - - const float stretchFactorMinimumValue = 0.1; - const float stretchFactorMaximumValue = 10000000.0; - const float stretchFactorStep = 0.1; - const float stretchFactorDigitsRightOfDecimal = 2; - - const int32_t spinBoxWidth = 80; - - QWidget* rowStretchFactorWidget = new QWidget(); - QGridLayout* rowStretchFactorLayout = new QGridLayout(rowStretchFactorWidget); - rowStretchFactorLayout->setContentsMargins(0, 0, 0, 0); - rowStretchFactorLayout->setSpacing(2); - { - rowStretchFactorLayout->addWidget(new QLabel("Rows"), 0, 0, 1, 2, Qt::AlignHCenter); - - for (int32_t i = 0; i < maximumNumberOfRows; i++) { - AString labelSpace = ((i >= 10) ? "" : " "); - if (i < maximumNumberOfRows) { - QLabel* numberLabel = new QLabel(labelSpace + AString::number(i + 1)); - m_rowStretchFactorIndexLabels.push_back(numberLabel); - - QDoubleSpinBox* spinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(stretchFactorMinimumValue, - stretchFactorMaximumValue, - stretchFactorStep, - stretchFactorDigitsRightOfDecimal, - this, - SLOT(configurationStretchFactorWasChanged())); - spinBox->setFixedWidth(spinBoxWidth); - spinBox->setToolTip("Weight for row " + AString::number(i + 1)); - m_rowStretchFactorSpinBoxes.push_back(spinBox); - - QLabel* pctLabel = new QLabel("000%"); - m_rowStretchPercentageLabels.push_back(pctLabel); - - const int layoutRow = rowStretchFactorLayout->rowCount(); - rowStretchFactorLayout->addWidget(numberLabel, layoutRow, 0, Qt::AlignRight); - rowStretchFactorLayout->addWidget(spinBox, layoutRow, 1); - rowStretchFactorLayout->addWidget(pctLabel, layoutRow, 2); - } - } - - rowStretchFactorLayout->setRowStretch(maximumNumberOfRows, 100); - } - - QWidget* columnStretchFactorWidget = new QWidget(); - QGridLayout* columnStretchFactorLayout = new QGridLayout(columnStretchFactorWidget); - columnStretchFactorLayout->setContentsMargins(0, 0, 0, 0); - columnStretchFactorLayout->setSpacing(2); - { - columnStretchFactorLayout->addWidget(new QLabel("Columns"), 0, 0, 1, 2, Qt::AlignHCenter); - - for (int32_t i = 0; i < maximumNumberOfColumns; i++) { - AString labelSpace = ((i >= 10) ? "" : " "); - if (i < maximumNumberOfColumns) { - QLabel* numberLabel = new QLabel(labelSpace + AString::number(i + 1)); - m_columnStretchFactorIndexLabels.push_back(numberLabel); - - QDoubleSpinBox* spinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(stretchFactorMinimumValue, - stretchFactorMaximumValue, - stretchFactorStep, - stretchFactorDigitsRightOfDecimal, - this, - SLOT(configurationStretchFactorWasChanged())); - spinBox->setFixedWidth(spinBoxWidth); - spinBox->setToolTip("Weight for column " + AString::number(i + 1)); - m_columnStretchFactorSpinBoxes.push_back(spinBox); - - QLabel* pctLabel = new QLabel("111%"); - m_columnStretchPercentageLabels.push_back(pctLabel); - - const int layoutRow = columnStretchFactorLayout->rowCount(); - columnStretchFactorLayout->addWidget(numberLabel, layoutRow, 0, Qt::AlignRight); - columnStretchFactorLayout->addWidget(spinBox, layoutRow, 1); - columnStretchFactorLayout->addWidget(pctLabel, layoutRow, 2); - } - } - - columnStretchFactorLayout->setRowStretch(maximumNumberOfColumns, 100); - } - - QLabel* stretchFactorLabel = new QLabel("Stretch Factors"); - - QWidget* stretchFactorWidget = new QWidget(); - stretchFactorWidget->setSizePolicy(stretchFactorWidget->sizePolicy().horizontalPolicy(), - QSizePolicy::Fixed); - QHBoxLayout* stretchFactorLayout = new QHBoxLayout(stretchFactorWidget); - stretchFactorLayout->setContentsMargins(0, 0, 0, 0); - stretchFactorLayout->addWidget(rowStretchFactorWidget, 0, Qt::AlignHCenter | Qt::AlignTop); - stretchFactorLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0); - stretchFactorLayout->addWidget(columnStretchFactorWidget, 0, Qt::AlignHCenter | Qt::AlignTop); - - - m_customConfigurationWidget = new QWidget(); - QVBoxLayout* customConfigurationLayout = new QVBoxLayout(m_customConfigurationWidget); - customConfigurationLayout->addLayout(dimensionsLayout); - customConfigurationLayout->addWidget(stretchFactorLabel, - 0, - Qt::AlignHCenter); - customConfigurationLayout->addWidget(stretchFactorWidget, - 0, - Qt::AlignHCenter); - - return m_customConfigurationWidget; -} + m_customOptionsWidget = createCustomOptionsWidget(); + m_customOptionsWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + -/** - * @return The active configuration widget. - */ -QWidget* -TileTabsConfigurationDialog::createActiveConfigurationWidget() -{ - - QScrollArea* stretchFactorScrollArea = new QScrollArea(); - stretchFactorScrollArea->setWidget(createCustomConfigurationWidget()); + stretchFactorScrollArea->setWidget(m_customConfigurationWidget); + stretchFactorScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); +// stretchFactorScrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents); stretchFactorScrollArea->setWidgetResizable(true); - + QGroupBox* widget = new QGroupBox("Tile Tabs Configuration in Workbench Window"); QGridLayout* widgetLayout = new QGridLayout(widget); widgetLayout->setColumnStretch(0, 0); - widgetLayout->setColumnStretch(1, 100); + widgetLayout->setColumnStretch(1, 0); + widgetLayout->setColumnStretch(2, 0); + widgetLayout->setColumnStretch(3, 0); + widgetLayout->setColumnStretch(4, 0); + widgetLayout->setColumnStretch(5, 100); widgetLayout->setColumnMinimumWidth(0, 20); widgetLayout->addWidget(createWorkbenchWindowWidget(), - 0, 0, 1, 2, + 0, 0, 1, 6, Qt::AlignLeft); widgetLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), - 1, 0, 1, 2); + 1, 0, 1, 6); widgetLayout->addWidget(m_automaticConfigurationRadioButton, - 2, 0, 1, 2, + 2, 0, 1, 6, Qt::AlignLeft); widgetLayout->addWidget(m_customConfigurationRadioButton, - 3, 0, 1, 2, + 3, 0, 1, 1, Qt::AlignLeft); + widgetLayout->addWidget(rowsLabel, + 3, 1, 1, 1); + widgetLayout->addWidget(m_numberOfRowsSpinBox, + 3, 2, 1, 1); + widgetLayout->addWidget(columnsLabel, + 3, 3, 1, 1); + widgetLayout->addWidget(m_numberOfColumnsSpinBox, + 3, 4, 1, 1); widgetLayout->addWidget(stretchFactorScrollArea, - 4, 1, - Qt::AlignLeft); - widgetLayout->setRowStretch(widgetLayout->rowCount(), 100); + 4, 0, 1, 6); + widgetLayout->addWidget(m_customOptionsWidget, + 5, 0, 1, 6, Qt::AlignLeft); + + widget->setFixedWidth(widget->sizeHint().width()); return widget; } @@ -565,10 +681,10 @@ TileTabsConfigurationDialog::automaticCustomButtonClicked(QAbstractButton* butto { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); if (button == m_automaticConfigurationRadioButton) { - browserWindowContent->setTileTabsConfigurationMode(TileTabsConfigurationModeEnum::AUTOMATIC); + browserWindowContent->setTileTabsConfigurationMode(TileTabsGridModeEnum::AUTOMATIC); } else if (button == m_customConfigurationRadioButton) { - browserWindowContent->setTileTabsConfigurationMode(TileTabsConfigurationModeEnum::CUSTOM); + browserWindowContent->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); } else { CaretAssert(0); @@ -618,11 +734,15 @@ void TileTabsConfigurationDialog::updateDialog() { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); + if (browserWindowContent == NULL) { + return; + } + switch (browserWindowContent->getTileTabsConfigurationMode()) { - case TileTabsConfigurationModeEnum::AUTOMATIC: + case TileTabsGridModeEnum::AUTOMATIC: m_automaticConfigurationRadioButton->setChecked(true); break; - case TileTabsConfigurationModeEnum::CUSTOM: + case TileTabsGridModeEnum::CUSTOM: m_customConfigurationRadioButton->setChecked(true); break; } @@ -677,102 +797,27 @@ void TileTabsConfigurationDialog::updateStretchFactors() { BrainBrowserWindow* browserWindow = getBrowserWindow(); - m_automaticConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsConfigurationModeEnum::AUTOMATIC, + m_automaticConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsGridModeEnum::AUTOMATIC, true)); - m_customConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsConfigurationModeEnum::CUSTOM, + m_customConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsGridModeEnum::CUSTOM, false)); - int32_t numValidRows = 0; - int32_t numValidColumns = 0; - const TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); if (configuration != NULL) { - numValidRows = configuration->getNumberOfRows(); - numValidColumns = configuration->getNumberOfColumns(); - } - - QSignalBlocker rowNumBlocker(m_numberOfRowsSpinBox); - m_numberOfRowsSpinBox->setValue(numValidRows); - - QSignalBlocker colNumBlocker(m_numberOfColumnsSpinBox); - m_numberOfColumnsSpinBox->setValue(numValidColumns); - - CaretAssert(m_columnStretchFactorIndexLabels.size() == m_columnStretchFactorSpinBoxes.size()); - CaretAssert(m_columnStretchPercentageLabels.size() == m_columnStretchFactorSpinBoxes.size()); - const int32_t numColSpinBoxes = static_cast(m_columnStretchFactorSpinBoxes.size()); - for (int32_t i = 0; i < numColSpinBoxes; i++) { - CaretAssertVectorIndex(m_columnStretchFactorSpinBoxes, i); - CaretAssertVectorIndex(m_columnStretchFactorIndexLabels, i); - CaretAssertVectorIndex(m_columnStretchPercentageLabels, i); - QDoubleSpinBox* sb = m_columnStretchFactorSpinBoxes[i]; - QLabel* indexLabel = m_columnStretchFactorIndexLabels[i]; - QLabel* pctLabel = m_columnStretchPercentageLabels[i]; - if (i < numValidColumns) { - QSignalBlocker blocker(sb); - sb->setValue(configuration->getColumnStretchFactor(i)); - } - indexLabel->setVisible(i < numValidColumns); - sb->setVisible(i < numValidColumns); - pctLabel->setVisible(i < numValidColumns); + updateRowColumnStretchWidgets(const_cast(configuration)); + QSignalBlocker rowBlocker(m_numberOfRowsSpinBox); + m_numberOfRowsSpinBox->setValue(configuration->getNumberOfRows()); + QSignalBlocker columnBlocker(m_numberOfColumnsSpinBox); + m_numberOfColumnsSpinBox->setValue(configuration->getNumberOfColumns()); } - updatePercentageLabels(m_columnStretchFactorSpinBoxes, - m_columnStretchPercentageLabels, - numValidColumns); - - CaretAssert(m_rowStretchFactorIndexLabels.size() == m_rowStretchFactorSpinBoxes.size()); - CaretAssert(m_rowStretchPercentageLabels.size() == m_rowStretchFactorSpinBoxes.size()); - const int32_t numRowSpinBoxes = static_cast(m_rowStretchFactorSpinBoxes.size()); - for (int32_t i = 0; i < numRowSpinBoxes; i++) { - CaretAssertVectorIndex(m_rowStretchFactorIndexLabels, i); - CaretAssertVectorIndex(m_rowStretchFactorSpinBoxes, i); - CaretAssertVectorIndex(m_rowStretchPercentageLabels, i); - QDoubleSpinBox* sb = m_rowStretchFactorSpinBoxes[i]; - QLabel* indexLabel = m_rowStretchFactorIndexLabels[i]; - QLabel* pctLabel = m_rowStretchPercentageLabels[i]; - if (i < numValidRows) { - QSignalBlocker blocker(sb); - sb->setValue(configuration->getRowStretchFactor(i)); - } - indexLabel->setVisible(i < numValidRows); - sb->setVisible(i < numValidRows); - pctLabel->setVisible(i < numValidRows); - } - updatePercentageLabels(m_rowStretchFactorSpinBoxes, - m_rowStretchPercentageLabels, - numValidRows); const bool editableFlag = ( ! m_automaticConfigurationRadioButton->isChecked()); - m_customConfigurationWidget->setFixedSize(m_customConfigurationWidget->sizeHint()); - m_customConfigurationWidget->setEnabled(editableFlag); - m_loadPushButton->setEnabled(editableFlag); -} - -/** - * Update the percentage labels. - */ -void -TileTabsConfigurationDialog::updatePercentageLabels(const std::vector& factorSpinBoxes, - std::vector& percentageLabels, - const int32_t validCount) -{ - float sum = 0.0; + // This does not re-enable the construction menu + //m_customConfigurationWidget->setEnabled(editableFlag); - for (int32_t i = 0; i < validCount; i++) { - CaretAssertVectorIndex(factorSpinBoxes, i); - sum += factorSpinBoxes[i]->value(); - } - - if (sum > 0.0) { - for (int32_t i = 0; i < validCount; i++) { - CaretAssertVectorIndex(factorSpinBoxes, i); - const float pct = (factorSpinBoxes[i]->value() / sum) * 100.0; - CaretAssertVectorIndex(percentageLabels, i); - percentageLabels[i]->setText(QString::number(pct, 'f', 0) + "%"); - } - } + m_loadPushButton->setEnabled(editableFlag); } - /** * Select the tile tabs configuration with the given name. */ @@ -988,26 +1033,31 @@ TileTabsConfigurationDialog::configurationStretchFactorWasChanged() return; } - const int32_t numColSpinBoxes = static_cast(m_columnStretchFactorSpinBoxes.size()); - for (int32_t i = 0; i < numColSpinBoxes; i++) { - if (m_columnStretchFactorSpinBoxes[i]->isEnabled()) { - configuration->setColumnStretchFactor(i, - m_columnStretchFactorSpinBoxes[i]->value()); - } - } - - const int32_t numRowSpinBoxes = static_cast(m_rowStretchFactorSpinBoxes.size()); - for (int32_t i = 0; i < numRowSpinBoxes; i++) { - if (m_rowStretchFactorSpinBoxes[i]->isEnabled()) { - configuration->setRowStretchFactor(i, - m_rowStretchFactorSpinBoxes[i]->value()); - } - } - updateStretchFactors(); updateGraphicsWindow(); } +/** + * Called when a tile tabs configuration modification is requested + * + * @param modification + * Modification that is requested. + */ +void +TileTabsConfigurationDialog::tileTabsModificationRequested(EventTileTabsConfigurationModification& modification) +{ + TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); + if (configuration != NULL) { + + modification.setWindowIndex(m_browserWindowComboBox->getSelectedBrowserWindowIndex()); + + EventManager::get()->sendEvent(modification.getPointer()); + + updateStretchFactors(); + + updateGraphicsWindow(); + } +} /** * Update the graphics for the selected window. @@ -1018,7 +1068,353 @@ TileTabsConfigurationDialog::updateGraphicsWindow() const BrowserWindowContent* bwc = getBrowserWindowContent(); if (bwc->isTileTabsEnabled()) { const int32_t windowIndex = bwc->getWindowIndex(); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex).getPointer()); } } +/** + * Called when help button is clicked. + */ +void +TileTabsConfigurationDialog::helpButtonClicked() +{ + EventHelpViewerDisplay helpViewerEvent(getBrowserWindow(), + "Tile_Tabs_Configuration"); + EventManager::get()->sendEvent(helpViewerEvent.getPointer()); +} + + +/** + * Constructor. + * + * @param tileTabsConfigurationDialog + * The tile tabs configuration dialog. + * @param rowColumnType + * 'Row' or 'Column' + * @param index + * Index of the row/column + * @param gridLayout + * Gridlayout for widgets + * @param parent + * Parent QObject + */ +TileTabElementWidgets::TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, + const EventTileTabsConfigurationModification::RowColumnType rowColumnType, + const int32_t index, + QGridLayout* gridLayout, + QObject* parent) +: QObject(parent), +m_tileTabsConfigurationDialog(tileTabsConfigurationDialog), +m_rowColumnType(rowColumnType), +m_index(index), +m_element(NULL) +{ + m_indexLabel = new QLabel(QString::number(m_index + 1)); + m_indexLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + const AString rowColText((rowColumnType == EventTileTabsConfigurationModification::RowColumnType::ROW) + ? "Row" + : "Column"); + const AString contructionToolTip(WuQtUtilities::createWordWrappedToolTipText("Delete, Duplicate, or Move " + + rowColText)); + const AString contentToolTip(WuQtUtilities::createWordWrappedToolTipText("Content of the " + + rowColText + + ": Spacer (empty space for Annotations) " + "or Tabs (Browser Tabs)")); + const AString typeToolTip(WuQtUtilities::createWordWrappedToolTipText("Type of Stretching: Percent or Weight")); + const AString stretchToolTip(WuQtUtilities::createWordWrappedToolTipText("Value of Stretching Percentage [0, 100] or Stretching Weight")); + + /* + * Construction Tool Button + */ + QIcon constructionIcon; + const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", + constructionIcon); + m_constructionAction = WuQtUtilities::createAction("M", + "Add/Move/Remove", + this); + if (constructionIconValid) { + m_constructionAction->setIcon(constructionIcon); + } + m_constructionToolButton = new QToolButton(); + QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton); + QObject::connect(constructionMenu, &QMenu::aboutToShow, + this, &TileTabElementWidgets::constructionMenuAboutToShow); + QObject::connect(constructionMenu, &QMenu::triggered, + this, &TileTabElementWidgets::constructionMenuTriggered); + m_constructionAction->setMenu(constructionMenu); + m_constructionToolButton->setDefaultAction(m_constructionAction); + m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); + m_constructionToolButton->setFixedWidth(m_constructionToolButton->sizeHint().width()); + m_constructionToolButton->setToolTip(contructionToolTip); + + /* + * Content type combo box + */ + m_contentTypeComboBox = new EnumComboBoxTemplate(this); + m_contentTypeComboBox->setup(); + QObject::connect(m_contentTypeComboBox, &EnumComboBoxTemplate::itemActivated, + this, &TileTabElementWidgets::contentTypeActivated); + m_contentTypeComboBox->getComboBox()->setFixedWidth(m_contentTypeComboBox->getComboBox()->sizeHint().width()); + m_contentTypeComboBox->getComboBox()->setToolTip(contentToolTip); + + /* + * Stretch type combo box + */ + m_stretchTypeComboBox = new EnumComboBoxTemplate(this); + m_stretchTypeComboBox->setup(); + QObject::connect(m_stretchTypeComboBox, &EnumComboBoxTemplate::itemActivated, + this, &TileTabElementWidgets::stretchTypeActivated); + m_stretchTypeComboBox->getComboBox()->setFixedWidth(m_stretchTypeComboBox->getComboBox()->sizeHint().width()); + m_stretchTypeComboBox->getComboBox()->setToolTip(typeToolTip); + + /* + * Stretch value spin box + */ + m_stretchValueSpinBox = new QDoubleSpinBox(); + m_stretchValueSpinBox->setKeyboardTracking(false); + m_stretchValueSpinBox->setRange(0.0, 1000.0); + m_stretchValueSpinBox->setDecimals(2); + m_stretchValueSpinBox->setSingleStep(0.1); + QObject::connect(m_stretchValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &TileTabElementWidgets::stretchValueChanged); + m_stretchValueSpinBox->setFixedWidth(m_stretchValueSpinBox->sizeHint().width()); + m_stretchValueSpinBox->setToolTip(stretchToolTip); + + m_gridLayoutGroup = new WuQGridLayoutGroup(gridLayout); + const int32_t rowIndex(gridLayout->rowCount()); + int32_t columnIndex(0); + m_gridLayoutGroup->addWidget(m_indexLabel, rowIndex, columnIndex++, Qt::AlignRight); + m_gridLayoutGroup->addWidget(m_constructionToolButton, rowIndex, columnIndex++); + m_gridLayoutGroup->addWidget(m_contentTypeComboBox->getWidget(), rowIndex, columnIndex++); + m_gridLayoutGroup->addWidget(m_stretchTypeComboBox->getWidget(), rowIndex, columnIndex++); + m_gridLayoutGroup->addWidget(m_stretchValueSpinBox, rowIndex, columnIndex++); +} + +/** + * Destructor. + */ +TileTabElementWidgets::~TileTabElementWidgets() +{ + +} + +/** + * @return The construction menu. + * + * @param toolButton + * The parent toolbutton. + */ +QMenu* +TileTabElementWidgets::createConstructionMenu(QToolButton* toolButton) +{ + const AString deleteText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + ? "Delete this Column" + : "Delete this Row"); + + const AString duplicateAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + ? "Duplicate this Column to Right" + : "Duplicate this Row Below"); + + const AString duplicateBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + ? "Duplicate this Column to Left" + : "Duplicate this Row Above"); + + const AString insertSpacerAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + ? "Insert Spacer Column to Right" + : "Insert Spacer Row Below"); + const AString insertSpacerBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + ? "Insert Spacer Column to Left" + : "Insert Spacer Row Above"); + const AString moveAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + ? "Move this Column to Right" + : "Move this Row Down"); + + const AString moveBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + ? "Move this Column to Left" + : "Move this Row Up"); + + m_menuDeleteAction = new QAction(deleteText); + m_menuDeleteAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DELETE_IT)); + + m_menuDuplicateAfterAction = new QAction(duplicateAfterText); + m_menuDuplicateAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER)); + + m_menuDuplicateBeforeAction = new QAction(duplicateBeforeText); + m_menuDuplicateBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE)); + + m_insertSpacerAfterAction = new QAction(insertSpacerAfterText); + m_insertSpacerAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER)); + + m_insertSpacerBeforeAction = new QAction(insertSpacerBeforeText); + m_insertSpacerBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE)); + + m_menuMoveAfterAction = new QAction(moveAfterText); + m_menuMoveAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::MOVE_AFTER)); + + m_menuMoveBeforeAction = new QAction(moveBeforeText); + m_menuMoveBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::MOVE_BEFORE)); + + QMenu* menu = new QMenu(toolButton); + menu->addAction(m_menuDuplicateBeforeAction); + menu->addAction(m_menuDuplicateAfterAction); + menu->addSeparator(); + menu->addAction(m_insertSpacerBeforeAction); + menu->addAction(m_insertSpacerAfterAction); + menu->addSeparator(); + menu->addAction(m_menuMoveBeforeAction); + menu->addAction(m_menuMoveAfterAction); + menu->addSeparator(); + menu->addAction(m_menuDeleteAction); + + return menu; +} + +/** + * Update with the given row/column element. + */ +void +TileTabElementWidgets::updateContent(TileTabsGridRowColumnElement* element) +{ + m_element = element; + const bool showFlag(m_element != NULL); + + if (showFlag) { + m_contentTypeComboBox->setSelectedItem(element->getContentType()); + m_stretchTypeComboBox->setSelectedItem(element->getStretchType()); + QSignalBlocker valueBlocker(m_stretchValueSpinBox); + switch (m_element->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + m_stretchValueSpinBox->setRange(0.0, 100.0); + m_stretchValueSpinBox->setSingleStep(1.0); + m_stretchValueSpinBox->setValue(m_element->getPercentStretch()); + m_stretchValueSpinBox->setSuffix("%"); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + m_stretchValueSpinBox->setRange(0.0, 1000.0); + m_stretchValueSpinBox->setSingleStep(0.1); + m_stretchValueSpinBox->setValue(m_element->getWeightStretch()); + m_stretchValueSpinBox->setSuffix(""); + break; + } + } + + m_gridLayoutGroup->setVisible(showFlag); +} + +/** + * Called when an item is selected from the construction menu + * + * @param action + * Action that was selected. + */ +void +TileTabElementWidgets::constructionMenuTriggered(QAction* action) +{ + if (action != NULL) { + const EventTileTabsConfigurationModification::Operation operation + = static_cast(action->data().toInt()); + + /* + * This switch is here so that it will cause a compilation error + * if the operations are changed. + */ + switch (operation) { + case EventTileTabsConfigurationModification::Operation::DELETE_IT: + break; + case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: + break; + case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + break; + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: + break; + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: + break; + case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: + break; + case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + break; + } + + EventTileTabsConfigurationModification modification(m_tileTabsConfigurationDialog->getCustomTileTabsConfiguration(), + m_index, + m_rowColumnType, + operation); + emit modificationRequested(modification); + } + +} + +/** + * Called when construction menu is about to show. + */ +void +TileTabElementWidgets::constructionMenuAboutToShow() +{ + const TileTabsConfiguration* config = m_tileTabsConfigurationDialog->getCustomTileTabsConfiguration(); + if (config != NULL) { + int32_t numItems(-1); + switch (m_rowColumnType) { + case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + numItems = config->getNumberOfColumns(); + break; + case EventTileTabsConfigurationModification::RowColumnType::ROW: + numItems = config->getNumberOfRows(); + break; + } + + m_menuDeleteAction->setEnabled(numItems > 1); + m_menuDuplicateAfterAction->setEnabled(numItems >= 1); + m_menuDuplicateBeforeAction->setEnabled(numItems >= 1); + m_menuMoveAfterAction->setEnabled((numItems > 1) + && (m_index < (numItems - 1))); + m_menuMoveBeforeAction->setEnabled((numItems > 1) + && (m_index > 0)); + } +} + + +/** + * Called when content type combo box changed. + */ +void +TileTabElementWidgets::contentTypeActivated() +{ + if (m_element != NULL) { + m_element->setContentType(m_contentTypeComboBox->getSelectedItem()); + emit itemChanged(); + } +} + +/** + * Called when stretch type combo box changed. + */ +void +TileTabElementWidgets::stretchTypeActivated() +{ + if (m_element != NULL) { + m_element->setStretchType(m_stretchTypeComboBox->getSelectedItem()); + emit itemChanged(); + } +} + +/** + * Called when stretch value changed. + */ +void +TileTabElementWidgets::stretchValueChanged(double) +{ + if (m_element != NULL) { + switch (m_element->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + m_element->setPercentStretch(m_stretchValueSpinBox->value()); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + m_element->setWeightStretch(m_stretchValueSpinBox->value()); + break; + } + emit itemChanged(); + } +} + diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index f06036c54c077b7d80627c979e5fb9c1b6d7062d..29e31cff26ed966f0ba6cff5356d6608f96ed44f 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -22,22 +22,32 @@ /*LICENSE_END*/ #include "EventListenerInterface.h" +#include "EventTileTabsConfigurationModification.h" +#include "TileTabsGridRowColumnContentTypeEnum.h" +#include "TileTabsGridRowColumnStretchTypeEnum.h" #include "WuQDialogNonModal.h" +class QCheckBox; class QDoubleSpinBox; +class QGridLayout; class QLabel; class QLineEdit; class QListWidgetItem; class QPushButton; class QRadioButton; class QSpinBox; +class QToolButton; namespace caret { class BrainBrowserWindow; class BrainBrowserWindowComboBox; class BrowserWindowContent; class CaretPreferences; + class EnumComboBoxTemplate; class TileTabsConfiguration; + class TileTabElementWidgets; + class TileTabsGridRowColumnElement; + class WuQGridLayoutGroup; class WuQListWidget; class TileTabsConfigurationDialog : public WuQDialogNonModal, public EventListenerInterface { @@ -83,9 +93,15 @@ namespace caret { void automaticCustomButtonClicked(QAbstractButton*); + void tileTabsModificationRequested(EventTileTabsConfigurationModification& modification); + + void centeringCorrectionCheckBoxClicked(bool checked); + protected: void focusGained(); + virtual void helpButtonClicked() override; + private: // ADD_NEW_MEMBERS_HERE @@ -105,26 +121,34 @@ namespace caret { QWidget* createActiveConfigurationWidget(); - QWidget* createCustomConfigurationWidget(); + QWidget* createRowColumnStretchWidget(); + + QWidget* createCustomOptionsWidget(); + + void updateRowColumnStretchWidgets(TileTabsConfiguration* configuration); + + void addRowColumnStretchWidget(const EventTileTabsConfigurationModification::RowColumnType rowColumnType, + QGridLayout* gridLayout, + std::vector& elementVector); void updateStretchFactors(); void updateGraphicsWindow(); + void updateCustomOptionsWidget(); + void readConfigurationsFromPreferences(); BrainBrowserWindow* getBrowserWindow(); BrowserWindowContent* getBrowserWindowContent(); - void updatePercentageLabels(const std::vector& factorSpinBoxes, - std::vector& percentageLabels, - const int32_t validCount); - BrainBrowserWindowComboBox* m_browserWindowComboBox; QWidget* m_customConfigurationWidget; + QWidget* m_customOptionsWidget; + QRadioButton* m_automaticConfigurationRadioButton; QRadioButton* m_customConfigurationRadioButton; @@ -145,17 +169,15 @@ namespace caret { QSpinBox* m_numberOfColumnsSpinBox; - std::vector m_rowStretchFactorIndexLabels; - - std::vector m_rowStretchFactorSpinBoxes; + std::vector m_columnElements; - std::vector m_rowStretchPercentageLabels; + std::vector m_rowElements; - std::vector m_columnStretchFactorIndexLabels; + QGridLayout* m_rowElementsGridLayout = NULL; - std::vector m_columnStretchFactorSpinBoxes; + QGridLayout* m_columnElementsGridLayout = NULL; - std::vector m_columnStretchPercentageLabels; + QCheckBox* m_centeringCorrectionCheckBox; /** Blocks reading of preferences since that may invalidate data pointers */ bool m_blockReadConfigurationsFromPreferences; @@ -166,6 +188,71 @@ namespace caret { * manager. */ CaretPreferences* m_caretPreferences; + + friend class TileTabElementWidgets; + + static const int32_t s_maximumRowsColumns = 50; + }; + + + /** + * Contains widgets for one row or column of stretching. + */ + class TileTabElementWidgets : public QObject { + Q_OBJECT + + public: + TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, + const EventTileTabsConfigurationModification::RowColumnType rowColumnType, + const int32_t index, + QGridLayout* gridLayout, + QObject* parent); + + virtual ~TileTabElementWidgets(); + + void updateContent(TileTabsGridRowColumnElement* element); + + signals: + void itemChanged(); + + void modificationRequested(EventTileTabsConfigurationModification& modification); + + private slots: + void constructionMenuAboutToShow(); + + void constructionMenuTriggered(QAction*); + + void contentTypeActivated(); + + void stretchTypeActivated(); + + void stretchValueChanged(double); + + private: + QMenu* createConstructionMenu(QToolButton* toolButton); + + TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; + const EventTileTabsConfigurationModification::RowColumnType m_rowColumnType; + const int32_t m_index; + TileTabsGridRowColumnElement* m_element; + + QLabel* m_indexLabel; + QAction* m_constructionAction; + QToolButton* m_constructionToolButton; + EnumComboBoxTemplate* m_contentTypeComboBox; + EnumComboBoxTemplate* m_stretchTypeComboBox; + QDoubleSpinBox* m_stretchValueSpinBox; + + QAction* m_menuDeleteAction; + QAction* m_menuDuplicateAfterAction; + QAction* m_menuDuplicateBeforeAction; + QAction* m_insertSpacerAfterAction; + QAction* m_insertSpacerBeforeAction; + QAction* m_menuMoveAfterAction; + QAction* m_menuMoveBeforeAction; + + WuQGridLayoutGroup* m_gridLayoutGroup; + }; #ifdef __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ diff --git a/src/GuiQt/TileTabsConfigurationModifier.cxx b/src/GuiQt/TileTabsConfigurationModifier.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3b04e14c40805eb9be3b682135329cb2e1936429 --- /dev/null +++ b/src/GuiQt/TileTabsConfigurationModifier.cxx @@ -0,0 +1,619 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#define __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ +#include "TileTabsConfigurationModifier.h" +#undef __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrainOpenGLViewportContent.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "EventBrowserTabNewClone.h" +#include "EventBrowserTabDelete.h" +#include "EventBrowserTabNew.h" +#include "EventBrowserWindowTileTabOperation.h" +#include "EventManager.h" +#include "EventTileTabsConfigurationModification.h" +#include "GuiManager.h" +#include "SpacerTabContent.h" +#include "TileTabsConfiguration.h" + +using namespace caret; + +static bool debugFlag = false; + +/** + * \class caret::TileTabsConfigurationModifier + * \brief Modifies a tile tabs configuration. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param existingTabs + * All tabs in the window. + * @param modifyEvent + * Event describing modification. + */ +TileTabsConfigurationModifier::TileTabsConfigurationModifier(const std::vector& existingTabs, + EventTileTabsConfigurationModification* modifyEvent) +: CaretObject(), +m_existingTabs(existingTabs), +m_modifyEvent(modifyEvent) +{ + CaretAssert(modifyEvent); + m_currentTileTabsConfiguration = modifyEvent->getTileTabsConfiguration(); + CaretAssert(m_currentTileTabsConfiguration); +} + +/** + * Destructor. + */ +TileTabsConfigurationModifier::~TileTabsConfigurationModifier() +{ + for (auto rc : m_rowColumns) { + delete rc; + } + m_rowColumns.clear(); +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +TileTabsConfigurationModifier::toString() const +{ + AString s; + for (const auto rc : m_rowColumns) { + if ( ! s.isEmpty()) { + s.append("\n"); + } + s.append(rc->toString()); + } + return s; +} + +/** + * Run to perform the operation. + * + * @param errorMessageOut + * Contains error information if operation fails. + * @return + * True if successful, else false. + */ +bool +TileTabsConfigurationModifier::run(AString& errorMessageOut) +{ + errorMessageOut.clear(); + + loadRowColumnsFromTileTabsConfiguration(); + if (debugFlag) { + std::cout << "Loaded: " << toString() << std::endl << std::flush; + } + bool validFlag = performModification(errorMessageOut); + if (debugFlag) { + std::cout << "After Modification: " << toString() << std::endl << std::endl << std::flush; + } + + if (validFlag) { + validFlag = loadRowColumnsIntoTileTabsConfiguration(errorMessageOut); + } + + return validFlag; +} + +/** + * Load the rows or columns from the Tile Tabs Configuration + */ +void +TileTabsConfigurationModifier::loadRowColumnsFromTileTabsConfiguration() +{ + const int32_t numRows = m_currentTileTabsConfiguration->getNumberOfRows(); + const int32_t numColumns = m_currentTileTabsConfiguration->getNumberOfColumns(); + + switch (m_modifyEvent->getRowColumnType()) { + case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + for (int32_t jCol = 0; jCol < numColumns; jCol++) { + m_rowColumns.push_back(new RowColumnContent(m_existingTabs, + m_modifyEvent->getTileTabsConfiguration(), + jCol, + false)); + } + break; + case EventTileTabsConfigurationModification::RowColumnType::ROW: + for (int32_t iRow = 0; iRow < numRows; iRow++) { + m_rowColumns.push_back(new RowColumnContent(m_existingTabs, + m_modifyEvent->getTileTabsConfiguration(), + iRow, + true)); + } + break; + } +} + +/** + * Perform the modification. + * + * @param errorMessageOut + * Contains error information if operation fails. + * @return + * True if successful, else false. + */ +bool +TileTabsConfigurationModifier::performModification(AString& errorMessageOut) +{ + + const int32_t rowColumnIndex = m_modifyEvent->getRowColumnIndex(); + + const int32_t numRowColumns = static_cast(m_rowColumns.size()); + switch (m_modifyEvent->getOperation()) { + case EventTileTabsConfigurationModification::Operation::DELETE_IT: + if (numRowColumns <= 1) { + errorMessageOut = "Cannot delete ROWCOL when there is only one ROWCOL"; + } + else if ((rowColumnIndex >= 0) + && (rowColumnIndex < numRowColumns)) { + CaretAssertVectorIndex(m_rowColumns, rowColumnIndex); + RowColumnContent* deleteRowColumn = m_rowColumns[rowColumnIndex]; + CaretAssert(deleteRowColumn); + m_rowColumns.erase(m_rowColumns.begin() + rowColumnIndex); + CaretAssert(std::find(m_rowColumns.begin(), + m_rowColumns.end(), + deleteRowColumn) == m_rowColumns.end()); + + for (auto t : deleteRowColumn->m_tabElements) { + if (t->m_browserTabContent != NULL) { + m_browserTabsToDelete.push_back(t->m_browserTabContent); + } + } + delete deleteRowColumn; + } + else { + errorMessageOut = "Invalid ROWCOL index=RCINDEX when deleting"; + } + break; + case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: + if ((rowColumnIndex >= 0) + && (rowColumnIndex < numRowColumns)) { + RowColumnContent* rowColumnCopy = m_rowColumns[rowColumnIndex]->clone(errorMessageOut); + if (rowColumnCopy != NULL) { + const int32_t insertOffset = (rowColumnIndex + 1); + m_rowColumns.insert(m_rowColumns.begin() + + insertOffset, + rowColumnCopy); + } + } + else { + errorMessageOut = "Invalid ROWCOL index=RCINDEX when duplicating"; + } + break; + case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + if ((rowColumnIndex >= 0) + && (rowColumnIndex < numRowColumns)) { + RowColumnContent* rowColumnCopy = m_rowColumns[rowColumnIndex]->clone(errorMessageOut); + if (rowColumnCopy != NULL) { + const int32_t insertOffset = rowColumnIndex; + m_rowColumns.insert(m_rowColumns.begin() + + insertOffset, + rowColumnCopy); + } + } + else { + errorMessageOut = "Invalid ROWCOL index=RCINDEX when duplicating"; + } + break; + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: + case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: + if ((rowColumnIndex >= 0) + && (rowColumnIndex < numRowColumns)) { + CaretAssertVectorIndex(m_rowColumns, 0); + const int32_t numberOfElements = m_rowColumns[0]->m_tabElements.size(); + RowColumnContent* rowColumnSpacer = RowColumnContent::newInstanceContainingSpacers(numberOfElements); + if (rowColumnSpacer != NULL) { + int32_t insertOffset = rowColumnIndex; + if (m_modifyEvent->getOperation() == EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER) { + insertOffset++; + } + m_rowColumns.insert(m_rowColumns.begin() + + insertOffset, + rowColumnSpacer); + } + } + else { + errorMessageOut = "Invalid ROWCOL index=RCINDEX when insert spacer"; + } + break; + case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: + if (numRowColumns <= 1) { + errorMessageOut = "Cannot move ROWCOL when there is only one ROWCOL"; + } + else if (rowColumnIndex == (numRowColumns - 1)) { + errorMessageOut = "Cannot move last ROWCOL after itself"; + } + else if ((rowColumnIndex >= 0) + && (rowColumnIndex < (numRowColumns - 1))) { + CaretAssertVectorIndex(m_rowColumns, rowColumnIndex); + CaretAssertVectorIndex(m_rowColumns, rowColumnIndex + 1); + std::swap(m_rowColumns[rowColumnIndex], + m_rowColumns[rowColumnIndex + 1]); + } + else { + errorMessageOut = "Invalid ROWCOL index=RCINDEX when moving"; + } + break; + case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + if (numRowColumns <= 1) { + errorMessageOut = "Cannot move ROWCOL when there is only one ROWCOL"; + } + else if (rowColumnIndex == 0) { + errorMessageOut = "Cannot move last ROWCOL before itself"; + } + else if ((rowColumnIndex >= 1) + && (rowColumnIndex < numRowColumns)) { + CaretAssertVectorIndex(m_rowColumns, rowColumnIndex); + CaretAssertVectorIndex(m_rowColumns, rowColumnIndex - 1); + std::swap(m_rowColumns[rowColumnIndex], + m_rowColumns[rowColumnIndex - 1]); + } + else { + errorMessageOut = "Invalid ROWCOL index=RCINDEX when moving"; + } + break; + } + + if ( ! errorMessageOut.isEmpty()) { + AString nameText; + switch (m_modifyEvent->getRowColumnType()) { + case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + nameText = " Column "; + break; + case EventTileTabsConfigurationModification::RowColumnType::ROW: + nameText = " Row "; + break; + } + + /* + * "substite names" + */ + errorMessageOut = errorMessageOut.replace("ROWCOL", nameText); + errorMessageOut = errorMessageOut.replace("RCINDEX", AString::number(rowColumnIndex + 1)); + } + + const bool validFlag = errorMessageOut.isEmpty(); + return validFlag; +} + +/** + * Load the modified rows/columns into the tile tabs configuration current in the browser window + * + * @param errorMessageOut + * Contains error information if operation fails. + * @return + * True if successful, else false. + */ +bool +TileTabsConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& errorMessageOut) +{ + TileTabsConfiguration newConfiguration(*m_currentTileTabsConfiguration); + std::vector browserTabs; + + switch (m_modifyEvent->getRowColumnType()) { + case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + { + const int32_t numRows = static_cast(m_rowColumns[0]->m_tabElements.size()); + CaretAssert(numRows == m_currentTileTabsConfiguration->getNumberOfRows()); + const int32_t numColumns = static_cast(m_rowColumns.size()); + + newConfiguration.setNumberOfRows(numRows); + newConfiguration.setNumberOfColumns(numColumns); + + for (int32_t iRow = 0; iRow < numRows; iRow++) { + for (int32_t jCol = 0; jCol < numColumns; jCol++) { + RowColumnContent* columnContent = m_rowColumns[jCol]; + CaretAssertVectorIndex(columnContent->m_tabElements, iRow); + BrowserTabContent* btc = columnContent->m_tabElements[iRow]->m_browserTabContent; + if (btc != NULL) { + browserTabs.push_back(btc); + } + } + } + + for (int32_t jCol = 0; jCol < numColumns; jCol++) { + TileTabsGridRowColumnElement* rce = newConfiguration.getColumn(jCol); + CaretAssertVectorIndex(m_rowColumns, jCol); + CaretAssert(m_rowColumns[jCol]->m_stretching); + *rce = *m_rowColumns[jCol]->m_stretching; + } + } + break; + case EventTileTabsConfigurationModification::RowColumnType::ROW: + { + const int32_t numRows = static_cast(m_rowColumns.size()); + const int32_t numColumns = static_cast(m_rowColumns[0]->m_tabElements.size()); + CaretAssert(numColumns == m_currentTileTabsConfiguration->getNumberOfColumns()); + + newConfiguration.setNumberOfRows(numRows); + newConfiguration.setNumberOfColumns(numColumns); + + for (int32_t iRow = 0; iRow < numRows; iRow++) { + CaretAssertVectorIndex(m_rowColumns, iRow); + RowColumnContent* rowContent = m_rowColumns[iRow]; + for (int32_t jCol = 0; jCol < numColumns; jCol++) { + CaretAssertVectorIndex(rowContent->m_tabElements, jCol); + BrowserTabContent* btc = rowContent->m_tabElements[jCol]->m_browserTabContent; + if (btc != NULL) { + browserTabs.push_back(btc); + } + } + } + + for (int32_t iRow = 0; iRow < numRows; iRow++) { + TileTabsGridRowColumnElement* rce = newConfiguration.getRow(iRow); + CaretAssertVectorIndex(m_rowColumns, iRow); + CaretAssert(m_rowColumns[iRow]->m_stretching); + *rce = *m_rowColumns[iRow]->m_stretching; + } + } + break; + } + + /* + * Copy new tile tabs configuration into the current configuration + */ + *m_currentTileTabsConfiguration = newConfiguration; + + /* + * Update tabs in the window's toolbar + */ + QWidget* parentWindow(GuiManager::get()->getBrowserWindowByWindowIndex(m_modifyEvent->getWindowIndex())); + const int32_t invalidTabIndex(-1); + EventBrowserWindowTileTabOperation updateTabsEvent(EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS, + parentWindow, + m_modifyEvent->getWindowIndex(), + invalidTabIndex, + browserTabs); + EventManager::get()->sendEvent(updateTabsEvent.getPointer()); + + if (updateTabsEvent.isError()) { + errorMessageOut.appendWithNewLine(updateTabsEvent.getErrorMessage()); + } + + if ( ! m_browserTabsToDelete.empty()) { + for (auto btc : m_browserTabsToDelete) { + EventBrowserTabDelete deleteEvent(btc, + btc->getTabNumber()); + EventManager::get()->sendEvent(deleteEvent.getPointer()); + if (deleteEvent.isError()) { + errorMessageOut.appendWithNewLine(deleteEvent.getErrorMessage()); + } + } + m_browserTabsToDelete.clear(); + } + + if (errorMessageOut.isEmpty()) { + return true; + } + + return false; +} + +/* + * Constructor for element in the row column matrix. + * + * @param rowIndex + * The row index + * @param columnIndex + * The column index + * @param browserTabContent + * Browser tab content at (rowIndex, columnIndex) in the current + * Tile Tabs Configuration + */ +TileTabsConfigurationModifier::Element::Element(const int32_t rowIndex, + const int32_t columnIndex, + BrowserTabContent* browserTabContent) +: +m_targetRowIndex(rowIndex), +m_targetColumnIndex(columnIndex), +m_sourceRowIndex(rowIndex), +m_sourceColumnIndex(columnIndex), +m_browserTabContent(browserTabContent) +{ + +} + +/** + * @return String representation of object. + */ +AString +TileTabsConfigurationModifier::Element::toString() const +{ + AString s("(row=%1, column=%2)"); + s = s.arg(m_sourceRowIndex).arg(m_sourceColumnIndex); + return s; +} + +/* + * Constructor for content of a row/column element that + * contains the tabs and stretching for one row or one column + * + * @param existingTabs + * Existing browser tabs. + * @param tileTabsConfiguration + * The current tile tabs configuration in the browser window. + * @param rowColumnIndex + * Index of the row or column related to modification. + * @param rowFlag + * True if rows are being operated upon, false if operating on columns + */ +TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const std::vector& existingTabs, + TileTabsConfiguration* tileTabsConfiguration, + const int32_t rowColumnIndex, + const bool rowFlag) +{ + const int32_t numRows = tileTabsConfiguration->getNumberOfRows(); + const int32_t numColumns = tileTabsConfiguration->getNumberOfColumns(); + const int32_t numberOfTabs =static_cast(existingTabs.size()); + + if (rowFlag) { + for (int32_t jCol = 0; jCol < numColumns; jCol++) { + BrowserTabContent* browserTabContent(NULL); + const int32_t tabIndex = (rowColumnIndex * numColumns) + jCol; + if (tabIndex < numberOfTabs) { + CaretAssertVectorIndex(existingTabs, tabIndex); + browserTabContent = existingTabs[tabIndex]->getBrowserTabContent(); + } + + m_tabElements.push_back(new Element(rowColumnIndex, + jCol, + browserTabContent)); + } + + m_stretching = new TileTabsGridRowColumnElement(*tileTabsConfiguration->getRow(rowColumnIndex)); + } + else { + for (int32_t iRow = 0; iRow < numRows; iRow++) { + BrowserTabContent* browserTabContent(NULL); + const int32_t tabIndex = (iRow * numColumns) + rowColumnIndex; + if (tabIndex < numberOfTabs) { + CaretAssertVectorIndex(existingTabs, tabIndex); + browserTabContent = existingTabs[tabIndex]->getBrowserTabContent(); + } + + m_tabElements.push_back(new Element(iRow, + rowColumnIndex, + browserTabContent)); + } + + m_stretching = new TileTabsGridRowColumnElement(*tileTabsConfiguration->getColumn(rowColumnIndex)); + } +} + +/* + * Constructor that creates the given number of elements. + * + * @param numberOfElements + * Number of elements for row/column. + */ +TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const int32_t numberOfElements) +{ + for (int32_t i = 0; i < numberOfElements; i++) { + m_tabElements.push_back(new Element(i, i, NULL)); + } + m_stretching = new TileTabsGridRowColumnElement(); +} + +/** + * @return New instance containing the given number of elements setup as spacers. + * + * @param numberOfElements + * Number of elements for row/column. + */ +TileTabsConfigurationModifier::RowColumnContent* +TileTabsConfigurationModifier::RowColumnContent::newInstanceContainingSpacers(const int32_t numberOfElements) +{ + RowColumnContent* content = new RowColumnContent(numberOfElements); + + content->m_stretching->setContentType(TileTabsGridRowColumnContentTypeEnum::SPACE); + content->m_stretching->setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); + content->m_stretching->setWeightStretch(1.0); + + return content; +} + +/** + * Destructor. + */ +TileTabsConfigurationModifier::RowColumnContent::~RowColumnContent() +{ + for (auto te : m_tabElements) { + delete te; + } + m_tabElements.clear(); + + delete m_stretching; + m_stretching = NULL; +} + +/** + * Copy constructor. + * + * @param obj + * Instance that is copied. + */ +TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const RowColumnContent& obj) +: CaretObject(obj) +{ + for (auto te : obj.m_tabElements) { + m_tabElements.push_back(new Element(*te)); + } + + m_stretching = new TileTabsGridRowColumnElement(*obj.m_stretching); +} + +/** + * @return String representation of object. + */ +AString +TileTabsConfigurationModifier::RowColumnContent::toString() const +{ + AString s; + for (const auto te : m_tabElements) { + s += (" " + te->toString()); + } + return s; +} + +/** + * Clone this Row/column content instance. + * + * @param errorMessageOut + * Output with error message. + * @return + * True if successful, else false + */ +TileTabsConfigurationModifier::RowColumnContent* +TileTabsConfigurationModifier::RowColumnContent::clone(AString& errorMessageOut) const +{ + RowColumnContent* cloned = new RowColumnContent(*this); + CaretAssert(cloned); + + for (auto te : cloned->m_tabElements) { + if (te->m_browserTabContent != NULL) { + EventBrowserTabNewClone cloneTabEvent(te->m_browserTabContent->getTabNumber()); + EventManager::get()->sendEvent(cloneTabEvent.getPointer()); + if (cloneTabEvent.isError()) { + errorMessageOut.appendWithNewLine(cloneTabEvent.getErrorMessage()); + te->m_browserTabContent = NULL; + } + else { + te->m_browserTabContent = cloneTabEvent.getNewBrowserTab(); + } + } + } + + return cloned; +} + diff --git a/src/GuiQt/TileTabsConfigurationModifier.h b/src/GuiQt/TileTabsConfigurationModifier.h new file mode 100644 index 0000000000000000000000000000000000000000..c0b57e106f9a082d171ca3da329dc8fbaebe2011 --- /dev/null +++ b/src/GuiQt/TileTabsConfigurationModifier.h @@ -0,0 +1,138 @@ +#ifndef __TILE_TABS_CONFIGURATION_MODIFIER_H__ +#define __TILE_TABS_CONFIGURATION_MODIFIER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include +#include +#include "CaretObject.h" + + + +namespace caret { + + class BrainOpenGLViewportContent; + class BrowserTabContent; + class EventTileTabsConfigurationModification; + class SpacerTabContent; + class TileTabsConfiguration; + class TileTabsGridRowColumnElement; + + class TileTabsConfigurationModifier : public CaretObject { + + public: + TileTabsConfigurationModifier(const std::vector& existingTabs, + EventTileTabsConfigurationModification* modifyEvent); + + virtual ~TileTabsConfigurationModifier(); + + TileTabsConfigurationModifier(const TileTabsConfigurationModifier&) = delete; + + TileTabsConfigurationModifier& operator=(const TileTabsConfigurationModifier&) = delete; + + bool run(AString& errorMessageOut); + + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + class Element : public CaretObject { + public: + Element(const int32_t rowIndex, + const int32_t columnIndex, + BrowserTabContent* browserTabContent); + + AString toString() const override; + + int32_t m_targetRowIndex; + + int32_t m_targetColumnIndex; + + int32_t m_sourceRowIndex; + + int32_t m_sourceColumnIndex; + + BrowserTabContent* m_browserTabContent; + + }; + + /** + * Contains the tabs and stretching for one row or one column + */ + class RowColumnContent : public CaretObject { + public: + RowColumnContent(const std::vector& existingTabs, + TileTabsConfiguration* tileTabsConfiguration, + const int32_t rowColumnIndex, + const bool rowFlag); + + RowColumnContent(const RowColumnContent& obj); + + static RowColumnContent* newInstanceContainingSpacers(const int32_t numberOfElements); + + ~RowColumnContent(); + + RowColumnContent* clone(AString& errorMessageOut) const; + + AString toString() const override; + + std::vector m_tabElements; + + TileTabsGridRowColumnElement* m_stretching; + + private: + RowColumnContent(const int32_t numberOfElements); + }; + + private: + + void loadRowColumnsFromTileTabsConfiguration(); + + bool loadRowColumnsIntoTileTabsConfiguration(AString& errorMessageOut); + + bool performModification(AString& errorMessageOut); + + const std::vector& m_existingTabs; + + EventTileTabsConfigurationModification* m_modifyEvent; + + std::vector m_rowColumns; + + std::vector m_browserTabsToDelete; + + /** + * This is the current tile tabs configuration in the window so DO NOT delete it + */ + TileTabsConfiguration* m_currentTileTabsConfiguration = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ + // +#endif // __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ + +} // namespace +#endif //__TILE_TABS_CONFIGURATION_MODIFIER_H__ diff --git a/src/GuiQt/UserInputModeAbstract.cxx b/src/GuiQt/UserInputModeAbstract.cxx index 0d8c480590cf30a431dd058ef20ef381898566ba..453b2067492b0071ec07680282e367b991771c82 100644 --- a/src/GuiQt/UserInputModeAbstract.cxx +++ b/src/GuiQt/UserInputModeAbstract.cxx @@ -48,7 +48,7 @@ using namespace caret; /** * Constructor. */ -UserInputModeAbstract::UserInputModeAbstract(const UserInputMode inputMode) +UserInputModeAbstract::UserInputModeAbstract(const UserInputModeEnum::Enum inputMode) : CaretObject(), m_userInputMode(inputMode), m_widgetForToolBar(NULL), @@ -87,7 +87,7 @@ UserInputModeAbstract::~UserInputModeAbstract() /** * @return The input mode enumerated type. */ -UserInputModeAbstract::UserInputMode +UserInputModeEnum::Enum UserInputModeAbstract::getUserInputMode() const { return m_userInputMode; diff --git a/src/GuiQt/UserInputModeAbstract.h b/src/GuiQt/UserInputModeAbstract.h index 967be344095a6facdb85bc0e17e0237796258a4e..7ff4cc8be0c48256ecbcc26e6319e7b1dd521963 100644 --- a/src/GuiQt/UserInputModeAbstract.h +++ b/src/GuiQt/UserInputModeAbstract.h @@ -25,6 +25,7 @@ #include "CaretObject.h" #include "CaretPointer.h" #include "CursorEnum.h" +#include "UserInputModeEnum.h" class QPoint; class QWidget; @@ -39,25 +40,8 @@ namespace caret { class UserInputModeAbstract : public CaretObject { public: - /** Enumerated type for input modes */ - enum UserInputMode { - /** Invalid */ - INVALID, - /** Annotation Operations */ - ANNOTATIONS, - /** Border Operations */ - BORDERS, - /** Foci Operations */ - FOCI, - /** Image Operations */ - IMAGE, - /** Viewing Operations */ - VIEW, - /** Volume Edit Operations */ - VOLUME_EDIT - }; - - UserInputModeAbstract(const UserInputMode inputMode); + + UserInputModeAbstract(const UserInputModeEnum::Enum inputMode); virtual ~UserInputModeAbstract(); @@ -65,7 +49,7 @@ namespace caret { /** * @return The input mode enumerated type. */ - UserInputMode getUserInputMode() const; + UserInputModeEnum::Enum getUserInputMode() const; /** * Called when 'this' user input receiver is set @@ -96,8 +80,12 @@ namespace caret { * * @param keyEvent * Key event information. + * @return + * True if the input process recognized the key event + * and the key event SHOULD NOT be propagated to parent + * widgets */ - virtual void keyPressEvent(const KeyEvent& /*keyEvent*/) { } + virtual bool keyPressEvent(const KeyEvent& /*keyEvent*/) { return false; } /** * Process a mouse left double-click event. @@ -238,7 +226,7 @@ namespace caret { UserInputModeAbstract& operator=(const UserInputModeAbstract&); - const UserInputMode m_userInputMode; + const UserInputModeEnum::Enum m_userInputMode; QWidget* m_widgetForToolBar; diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index eeded042368d7be4f4c551983ad894696970c73d..91e649bdb1e7030eead8da2915d5722310627bc4 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -84,7 +84,7 @@ using namespace caret; * Constructor. */ UserInputModeAnnotations::UserInputModeAnnotations(const int32_t windowIndex) -: UserInputModeView(UserInputModeAbstract::ANNOTATIONS), +: UserInputModeView(UserInputModeEnum::ANNOTATIONS), m_browserWindowIndex(windowIndex), m_annotationUnderMouse(NULL), m_annotationBeingDragged(NULL) @@ -337,10 +337,16 @@ UserInputModeAnnotations::deleteSelectedAnnotations() * * @param keyEvent * Key event information. + * @return + * True if the input process recognized the key event + * and the key event SHOULD NOT be propagated to parent + * widgets */ -void +bool UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) { + bool keyWasProcessedFlag(false); + const int32_t keyCode = keyEvent.getKeyCode(); switch (keyCode) { case Qt::Key_Backspace: @@ -357,6 +363,7 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) break; case MODE_SELECT: deleteSelectedAnnotations(); + keyWasProcessedFlag = true; break; case MODE_SET_COORDINATE_ONE: break; @@ -391,6 +398,7 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) if (selectModeFlag) { setMode(MODE_SELECT); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + keyWasProcessedFlag = true; } } break; @@ -407,6 +415,10 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) case AnnotationCoordinateSpaceEnum::CHART: changeCoordFlag = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + changeCoordFlag = true; + moveOnePixelFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: changeCoordFlag = true; break; @@ -425,6 +437,8 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) } if (changeCoordFlag) { + keyWasProcessedFlag = true; + float distanceX = 1.0; float distanceY = 1.0; if (moveOnePixelFlag) { @@ -470,6 +484,8 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) switch (selectedAnnotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -542,6 +558,8 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) } break; } + + return keyWasProcessedFlag; } /** @@ -620,6 +638,8 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) switch (draggingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -674,6 +694,16 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) } } break; + case AnnotationCoordinateSpaceEnum::SPACER: + { + int viewport[4]; + vpContent->getTabViewportBeforeApplyingMargins(viewport); + spaceOriginX = viewport[0]; + spaceOriginY = viewport[1]; + spaceWidth = viewport[2]; + spaceHeight = viewport[3]; + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: { /* @@ -766,22 +796,22 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) dx, dy, mouseEvent.isFirstDragging()); - if (coordInfo.m_surfaceNodeValid) { - annSpatialMod.setSurfaceCoordinateAtMouseXY(coordInfo.m_surfaceStructure, - coordInfo.m_surfaceNumberOfNodes, - coordInfo.m_surfaceNodeIndex); + if (coordInfo.m_surfaceSpaceInfo.m_validFlag) { + annSpatialMod.setSurfaceCoordinateAtMouseXY(coordInfo.m_surfaceSpaceInfo.m_structure, + coordInfo.m_surfaceSpaceInfo.m_numberOfNodes, + coordInfo.m_surfaceSpaceInfo.m_nodeIndex); } - if (coordInfo.m_modelXYZValid) { - annSpatialMod.setStereotaxicCoordinateAtMouseXY(coordInfo.m_modelXYZ[0], - coordInfo.m_modelXYZ[1], - coordInfo.m_modelXYZ[2]); + if (coordInfo.m_modelSpaceInfo.m_validFlag) { + annSpatialMod.setStereotaxicCoordinateAtMouseXY(coordInfo.m_modelSpaceInfo.m_xyz[0], + coordInfo.m_modelSpaceInfo.m_xyz[1], + coordInfo.m_modelSpaceInfo.m_xyz[2]); } - if (coordInfo.m_chartXYZValid) { - annSpatialMod.setChartCoordinateAtMouseXY(coordInfo.m_chartXYZ[0], - coordInfo.m_chartXYZ[1], - coordInfo.m_chartXYZ[2]); + if (coordInfo.m_chartSpaceInfo.m_validFlag) { + annSpatialMod.setChartCoordinateAtMouseXY(coordInfo.m_chartSpaceInfo.m_xyz[0], + coordInfo.m_chartSpaceInfo.m_xyz[1], + coordInfo.m_chartSpaceInfo.m_xyz[2]); } if ((dx != 0.0) @@ -792,10 +822,10 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) mouseEvent.getX() - dx, mouseEvent.getY() - dy, previousMouseXYCoordInfo); - if (previousMouseXYCoordInfo.m_chartXYZValid) { - annSpatialMod.setChartCoordinateAtPreviousMouseXY(previousMouseXYCoordInfo.m_chartXYZ[0], - previousMouseXYCoordInfo.m_chartXYZ[1], - previousMouseXYCoordInfo.m_chartXYZ[2]); + if (previousMouseXYCoordInfo.m_chartSpaceInfo.m_validFlag) { + annSpatialMod.setChartCoordinateAtPreviousMouseXY(previousMouseXYCoordInfo.m_chartSpaceInfo.m_xyz[0], + previousMouseXYCoordInfo.m_chartSpaceInfo.m_xyz[1], + previousMouseXYCoordInfo.m_chartSpaceInfo.m_xyz[2]); } } @@ -1007,11 +1037,17 @@ UserInputModeAnnotations::setAnnotationUnderMouse(const MouseEvent& mouseEvent, } openGLWidget->updateCursor(); + + /* + * Update graphics only if an annotation was passed to this method (WB-820) + */ + if (annotationIDIn != NULL) { #if BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS - openGLWidget->updateGL(); + openGLWidget->updateGL(); #else - openGLWidget->update(); + openGLWidget->update(); #endif + } } /** @@ -1222,10 +1258,10 @@ UserInputModeAnnotations::processModeSetCoordinate(const MouseEvent& mouseEvent) int32_t numNodes = -1; int32_t nodeIndex = -1; float surfaceOffset = 0.0; - AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; - coordinate->getSurfaceSpace(structure, numNodes, nodeIndex, surfaceOffset, surfaceVector); - coordInfo.m_surfaceNodeOffset = surfaceOffset; - coordInfo.m_surfaceNodeVector = surfaceVector; + AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceVectorType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; + coordinate->getSurfaceSpace(structure, numNodes, nodeIndex, surfaceOffset, surfaceVectorType); + coordInfo.m_surfaceSpaceInfo.m_nodeOffsetLength = surfaceOffset; + coordInfo.m_surfaceSpaceInfo.m_nodeVectorOffsetType = surfaceVectorType; } AnnotationChangeCoordinateDialog changeCoordDialog(coordInfo, diff --git a/src/GuiQt/UserInputModeAnnotations.h b/src/GuiQt/UserInputModeAnnotations.h index e4b673703c91f54e41f59823ca6c2bc17e0112c0..2aa73142a3eca16f5291323397cc63747f8a3c71 100644 --- a/src/GuiQt/UserInputModeAnnotations.h +++ b/src/GuiQt/UserInputModeAnnotations.h @@ -80,7 +80,7 @@ namespace caret { Mode getMode() const; - virtual void keyPressEvent(const KeyEvent& /*keyEvent*/); + virtual bool keyPressEvent(const KeyEvent& /*keyEvent*/) override; virtual void mouseLeftDoubleClick(const MouseEvent& mouseEvent); diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index dc94e111bdb2316cff66996d3f91528ade183a61..8a6d89e61da8f75b45b7bf26aef5bde2c45b19f2 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -115,6 +115,8 @@ m_newAnnotationCreatedByContextMenu(NULL) case AnnotationCoordinateSpaceEnum::CHART: threeDimCoordFlag = true; break; + case AnnotationCoordinateSpaceEnum::SPACER: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: threeDimCoordFlag = true; break; diff --git a/src/GuiQt/UserInputModeBorders.cxx b/src/GuiQt/UserInputModeBorders.cxx index 6679dd8db3c25abc012489e6d1c89fd689dd7fa7..041c82703506e6f835e79b8ec2aeb147378ac1ac 100644 --- a/src/GuiQt/UserInputModeBorders.cxx +++ b/src/GuiQt/UserInputModeBorders.cxx @@ -72,7 +72,7 @@ using namespace caret; */ UserInputModeBorders::UserInputModeBorders(Border* borderBeingDrawnByOpenGL, const int32_t windowIndex) -: UserInputModeView(UserInputModeAbstract::BORDERS) +: UserInputModeView(UserInputModeEnum::BORDERS) { this->borderBeingDrawnByOpenGL = borderBeingDrawnByOpenGL; this->windowIndex = windowIndex; diff --git a/src/GuiQt/UserInputModeFoci.cxx b/src/GuiQt/UserInputModeFoci.cxx index 3d6ffa0d554a2bd4ff1b02cd3165c198673c2844..7205b558acec6a21c710aef6c664f8d391f4fc1a 100644 --- a/src/GuiQt/UserInputModeFoci.cxx +++ b/src/GuiQt/UserInputModeFoci.cxx @@ -61,7 +61,7 @@ using namespace caret; * Constructor. */ UserInputModeFoci::UserInputModeFoci(const int32_t windowIndex) -: UserInputModeView(UserInputModeAbstract::FOCI), +: UserInputModeView(UserInputModeEnum::FOCI), m_windowIndex(windowIndex) { m_inputModeFociWidget = new UserInputModeFociWidget(this, diff --git a/src/GuiQt/UserInputModeImage.cxx b/src/GuiQt/UserInputModeImage.cxx index 7b567a8ad097fc0e443230ef09a0348374dea031..4404dd03e7d197a059cdef2f58b1b297645b121a 100644 --- a/src/GuiQt/UserInputModeImage.cxx +++ b/src/GuiQt/UserInputModeImage.cxx @@ -63,7 +63,7 @@ using namespace caret; * Constructor. */ UserInputModeImage::UserInputModeImage(const int32_t windowIndex) -: UserInputModeView(UserInputModeAbstract::IMAGE), +: UserInputModeView(UserInputModeEnum::IMAGE), m_windowIndex(windowIndex) { m_inputModeImageWidget = new UserInputModeImageWidget(this, diff --git a/src/GuiQt/UserInputModeView.cxx b/src/GuiQt/UserInputModeView.cxx index 158453e5ef802da97fbcdf61964958f728c193f0..c92d5b611c88c882864650f441d8de5655f915b9 100644 --- a/src/GuiQt/UserInputModeView.cxx +++ b/src/GuiQt/UserInputModeView.cxx @@ -61,7 +61,7 @@ using namespace caret; * Constructor. */ UserInputModeView::UserInputModeView() -: UserInputModeAbstract(UserInputModeAbstract::VIEW) +: UserInputModeAbstract(UserInputModeEnum::VIEW) { } @@ -72,7 +72,7 @@ UserInputModeView::UserInputModeView() * @param inputMode * Subclass' input mode. */ -UserInputModeView::UserInputModeView(const UserInputMode inputMode) +UserInputModeView::UserInputModeView(const UserInputModeEnum::Enum inputMode) : UserInputModeAbstract(inputMode) { @@ -117,8 +117,17 @@ UserInputModeView::processModelViewIdentification(BrainOpenGLViewportContent* vi const int32_t tabIndex = btc->getTabNumber(); GuiManager::get()->processIdentification(tabIndex, selectionManager, - openGLWidget); - } + openGLWidget); + + /* + * Keep the main window as the active window NOT the identification window. + * This does not work correctly on Linux as the identication window + * may hide behind the main window. + */ +#ifdef CARET_OS_MACOSX + openGLWidget->parentWidget()->activateWindow(); +#endif + } } /** @@ -279,13 +288,34 @@ UserInputModeView::mouseLeftDrag(const MouseEvent& mouseEvent) if (browserTabContent == NULL) { return; } - browserTabContent->applyMouseRotation(viewportContent, - mouseEvent.getPressedX(), - mouseEvent.getPressedY(), - mouseEvent.getX(), - mouseEvent.getY(), - mouseEvent.getDx(), - mouseEvent.getDy()); + + bool scrollVolumeSlicesFlag(false); + if (browserTabContent->isVolumeSlicesDisplayed()) { + switch (browserTabContent->getSliceProjectionType()) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + scrollVolumeSlicesFlag = true; + break; + } + } + if (scrollVolumeSlicesFlag) { + browserTabContent->applyMouseVolumeSliceIncrement(viewportContent, + mouseEvent.getPressedX(), + mouseEvent.getPressedY(), + mouseEvent.getDy()); + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR); + } + else { + browserTabContent->applyMouseRotation(viewportContent, + mouseEvent.getPressedX(), + mouseEvent.getPressedY(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getDx(), + mouseEvent.getDy()); + } + /* * Update graphics. */ diff --git a/src/GuiQt/UserInputModeView.h b/src/GuiQt/UserInputModeView.h index e1192307516b712b067b9894374b89ec61f412a1..6f8e7b86b672f7e5f49e62b984aba70e8d1e0070 100644 --- a/src/GuiQt/UserInputModeView.h +++ b/src/GuiQt/UserInputModeView.h @@ -63,7 +63,7 @@ namespace caret { BrainOpenGLWidget* openGLWidget); protected: - UserInputModeView(const UserInputMode inputMode); + UserInputModeView(const UserInputModeEnum::Enum inputMode); private: UserInputModeView(const UserInputModeView&); diff --git a/src/GuiQt/UserInputModeViewContextMenu.cxx b/src/GuiQt/UserInputModeViewContextMenu.cxx index cb9dc83929e12ad9836b4d91777daa6cfcbb1605..141684efbc7187a34c8d0574d787766f663e9c29 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextMenu.cxx @@ -35,6 +35,7 @@ #include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" +#include "CaretLogger.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "ChartingDataManager.h" #include "ChartTwoCartesianAxis.h" @@ -45,6 +46,7 @@ #include "CiftiFiberTrajectoryManager.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CursorDisplayScoped.h" +#include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUpdateInformationWindows.h" @@ -57,8 +59,10 @@ #include "IdentifiedItemNode.h" #include "IdentificationManager.h" #include "LabelFile.h" +#include "MapFileDataSelector.h" #include "Overlay.h" #include "OverlaySet.h" +#include "MetricDynamicConnectivityFile.h" #include "Model.h" #include "ProgressReportingDialog.h" #include "SelectionItemBorderSurface.h" @@ -73,6 +77,7 @@ #include "Surface.h" #include "UserInputModeFociWidget.h" #include "UserInputTileTabsContextMenu.h" +#include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" @@ -364,13 +369,21 @@ UserInputModeViewContextMenu::addBorderRegionOfInterestActions() Brain* brain = borderID->getBrain(); std::vector ciftiMatrixFiles; brain->getAllCiftiConnectivityMatrixFiles(ciftiMatrixFiles); - bool hasCiftiConnectivity = (ciftiMatrixFiles.empty() == false); + bool hasConnectivityFile = (ciftiMatrixFiles.empty() == false); + + std::vector metricDynConnFiles; + brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); + for (auto mdc : metricDynConnFiles) { + if (mdc->isDataLoadingEnabled()) { + hasConnectivityFile = true; + } + } /* * Connectivity actions for borders */ - if (hasCiftiConnectivity) { - const QString text = ("Show CIFTI Connectivity for Nodes Inside Border " + if (hasConnectivityFile) { + const QString text = ("Show Connectivity for Vertices Inside Border " + borderID->getBorder()->getName()); QAction* action = WuQtUtilities::createAction(text, "", @@ -384,7 +397,7 @@ UserInputModeViewContextMenu::addBorderRegionOfInterestActions() brain->getAllChartableBrainordinateDataFiles(chartableFiles); if (chartableFiles.empty() == false) { - const QString text = ("Show Charts for Nodes Inside Border " + const QString text = ("Show Charts for Vertices Inside Border " + borderID->getBorder()->getName()); QAction* action = WuQtUtilities::createAction(text, "", @@ -400,13 +413,20 @@ UserInputModeViewContextMenu::addBorderRegionOfInterestActions() } /** - * Add all label region of interest options to the menu + * Create the parcel (label) information. It finds + * ALL label files and uses the label from every map + * in the file that is associated withe the selected + * brainordinate. */ void -UserInputModeViewContextMenu::addLabelRegionOfInterestActions() +UserInputModeViewContextMenu::createParcelConnectivities() { Brain* brain = NULL; + /* + * Note that in an 'ALL' view there may be both + * an identified surface node and an identified voxel + */ float voxelXYZ[3] = { 0.0, 0.0, 0.0 }; SelectionItemVoxel* idVoxel = this->selectionManager->getVoxelIdentification(); if (idVoxel->isValid()) { @@ -432,87 +452,68 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() brain = idNode->getBrain(); } - /* - * If Brain is invalid, then there is no identified node or voxel - */ if (brain == NULL) { return; } + + if (idNode->isValid() + && idVoxel->isValid()) { + std::cout << "Have both surface and volume ID" << std::endl; + } /* - * Manager for connectivity matrix files + * If true, only labels in file in the selected tab + * are available. */ - CiftiConnectivityMatrixDataFileManager* ciftiConnectivityMatrixManager = SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(); - std::vector ciftiMatrixFiles; - brain->getAllCiftiConnectivityMatrixFiles(ciftiMatrixFiles); - bool hasCiftiConnectivity = (ciftiMatrixFiles.empty() == false); + const bool limitToFilesInSelectedTabFlag(true); - /* - * Manager for fiber trajectory - */ - CiftiFiberTrajectoryManager* ciftiFiberTrajectoryManager = SessionManager::get()->getCiftiFiberTrajectoryManager(); - std::vector ciftiFiberTrajectoryFiles; - const int32_t numFiberFiles = brain->getNumberOfConnectivityFiberTrajectoryFiles(); - for (int32_t i = 0; i < numFiberFiles; i++) { - ciftiFiberTrajectoryFiles.push_back(brain->getConnectivityFiberTrajectoryFile(i)); + std::vector mapFiles; + if (limitToFilesInSelectedTabFlag) { + CaretAssert(this->browserTabContent); + std::vector dataFiles; + this->browserTabContent->getFilesDisplayedInTab(dataFiles); + + for (auto df : dataFiles) { + CaretMappableDataFile* cmdf = dynamic_cast(df); + if (cmdf != NULL) { + mapFiles.push_back(cmdf); + } + } + } + else { + brain->getAllMappableDataFiles(mapFiles); } - const bool haveCiftiFiberTrajectoryFiles = (ciftiFiberTrajectoryFiles.empty() == false); - - /* - * Manager for Chartable files - */ - std::vector chartableFiles; - brain->getAllChartableBrainordinateDataFiles(chartableFiles); - const bool haveChartableFiles = (chartableFiles.empty() == false); - ChartingDataManager* chartingDataManager = brain->getChartingDataManager(); - - /* - * Actions for each file type - */ - QList ciftiConnectivityActions; - QActionGroup* ciftiConnectivityActionGroup = new QActionGroup(this); - QObject::connect(ciftiConnectivityActionGroup, SIGNAL(triggered(QAction*)), - this, SLOT(parcelCiftiConnectivityActionSelected(QAction*))); - QList ciftiFiberTrajectoryActions; - QActionGroup* ciftiFiberTrajectoryActionGroup = new QActionGroup(this); - QObject::connect(ciftiFiberTrajectoryActionGroup, SIGNAL(triggered(QAction*)), - this, SLOT(parcelCiftiFiberTrajectoryActionSelected(QAction*))); - QList chartableDataActions; - QActionGroup* chartableDataActionGroup = new QActionGroup(this); - QObject::connect(chartableDataActionGroup, SIGNAL(triggered(QAction*)), - this, SLOT(parcelChartableDataActionSelected(QAction*))); - - /* - * Get all mappable files and find files mapped with using labels - */ - std::vector mappableFiles; - brain->getAllMappableDataFiles(mappableFiles); - - /* - * Process each map file - */ - for (std::vector::iterator mapFileIterator = mappableFiles.begin(); - mapFileIterator != mappableFiles.end(); - mapFileIterator++) { - CaretMappableDataFile* mappableLabelFile = *mapFileIterator; - - if (mappableLabelFile->isMappedWithLabelTable()) { - const int32_t numMaps = mappableLabelFile->getNumberOfMaps(); - for (int32_t mapIndex = 0; mapIndex < numMaps; mapIndex++) { + for (auto mapFile : mapFiles) { + if (mapFile->isMappedWithLabelTable()) { + const int32_t numberOfMaps = mapFile->getNumberOfMaps(); + for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { Surface* labelSurface = NULL; int32_t labelNodeNumber = -1; int32_t labelKey = -1; AString labelName; int64_t volumeDimensions[3] = { -1, -1, -1 }; - ParcelConnectivity::ParcelType parcelType = ParcelConnectivity::PARCEL_TYPE_INVALID; + ParcelType parcelType = ParcelType::PARCEL_TYPE_INVALID; + + AString mapName = AString::number(mapIndex + 1); + if (mapFile->getMapName(mapIndex).isEmpty()) { + mapName.append(": "); + } + else { + mapName.append(": " + + mapFile->getMapName(mapIndex)); + } - if (mappableLabelFile->isVolumeMappable()) { - CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mappableLabelFile); - VolumeFile* volumeLabelFile = dynamic_cast(mappableLabelFile); - VolumeMappableInterface* volumeInterface = dynamic_cast(mappableLabelFile); + /* + * Is this a volume label file, if so, find the + * label for this 'mapIndex' + */ + if (mapFile->isVolumeMappable()) { + CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mapFile); + VolumeFile* volumeLabelFile = dynamic_cast(mapFile); + VolumeMappableInterface* volumeInterface = dynamic_cast(mapFile); if (volumeInterface != NULL) { int64_t voxelIJK[3]; float voxelValue; @@ -531,7 +532,7 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() labelName = labelTable->getLabelName(labelKey); if (labelName.isEmpty() == false) { - parcelType = ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS; + parcelType = ParcelType::PARCEL_TYPE_VOLUME_VOXELS; } } } @@ -547,9 +548,9 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() const GiftiLabelTable* labelTable = volumeLabelFile->getMapLabelTable(mapIndex); labelKey = static_cast(voxelValue); labelName = labelTable->getLabelName(voxelValue); - + if (labelName.isEmpty() == false) { - parcelType = ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS; + parcelType = ParcelType::PARCEL_TYPE_VOLUME_VOXELS; } } } @@ -565,17 +566,44 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() volumeDimensions[1] = dims[1]; volumeDimensions[2] = dims[2]; } + + /* + * Create the parcel connectivity + */ + if (labelName == "???") { + parcelType = ParcelType::PARCEL_TYPE_INVALID; + } + if (parcelType != ParcelType::PARCEL_TYPE_INVALID) { + ParcelConnectivity* parcelConnectivity = new ParcelConnectivity(brain, + parcelType, + mapFile, + mapIndex, + mapName, + labelKey, + labelName, + labelSurface, + labelNodeNumber, + volumeDimensions, + brain->getChartingDataManager(), + SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(), + SessionManager::get()->getCiftiFiberTrajectoryManager()); + this->parcelConnectivities.push_back(parcelConnectivity); + } } } - if (mappableLabelFile->isSurfaceMappable()) { + /* + * Is this a surface mapped label file, if so, + * find the label for this 'mapIndex' + */ + if (mapFile->isSurfaceMappable()) { if (labelName.isEmpty()) { if (idNode->isValid()) { labelSurface = idNode->getSurface(); labelNodeNumber = idNode->getNodeNumber(); - LabelFile* labelFile = dynamic_cast(mappableLabelFile); - CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mappableLabelFile); + LabelFile* labelFile = dynamic_cast(mapFile); + CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mapFile); if (labelFile != NULL) { labelKey = labelFile->getLabelKey(labelNodeNumber, mapIndex); @@ -583,7 +611,7 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() labelName = labelTable->getLabelName(labelKey); if (labelName.isEmpty() == false) { - parcelType = ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES; + parcelType = ParcelType::PARCEL_TYPE_SURFACE_NODES; } } else if (ciftiLabelFile != NULL) { @@ -601,118 +629,212 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() labelKey = nodeValue; const GiftiLabelTable* labelTable = ciftiLabelFile->getMapLabelTable(mapIndex); labelName = labelTable->getLabelName(labelKey); - + if (labelName.isEmpty() == false) { - parcelType = ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES; + parcelType = ParcelType::PARCEL_TYPE_SURFACE_NODES; } } } } + + /* + * Create the parcel connectivity + */ + if (labelName == "???") { + parcelType = ParcelType::PARCEL_TYPE_INVALID; + } + if (parcelType != ParcelType::PARCEL_TYPE_INVALID) { + ParcelConnectivity* parcelConnectivity = new ParcelConnectivity(brain, + parcelType, + mapFile, + mapIndex, + mapName, + labelKey, + labelName, + labelSurface, + labelNodeNumber, + volumeDimensions, + brain->getChartingDataManager(), + SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(), + SessionManager::get()->getCiftiFiberTrajectoryManager()); + this->parcelConnectivities.push_back(parcelConnectivity); + } } } } - - if (parcelType != ParcelConnectivity::PARCEL_TYPE_INVALID) { - const AString mapName = (AString::number(mapIndex + 1) - + ": " - + mappableLabelFile->getMapName(mapIndex)); - - ParcelConnectivity* parcelConnectivity = new ParcelConnectivity(brain, - parcelType, - mappableLabelFile, - mapIndex, - labelKey, - labelName, - labelSurface, - labelNodeNumber, - volumeDimensions, - chartingDataManager, - ciftiConnectivityMatrixManager, - ciftiFiberTrajectoryManager); - this->parcelConnectivities.push_back(parcelConnectivity); + } + } + } +} - if (hasCiftiConnectivity) { - bool matchFlag = false; - if (parcelType == ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES) { - matchFlag = true; - } - else if (parcelType == ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS) { - for (std::vector::iterator iter = ciftiMatrixFiles.begin(); - iter != ciftiMatrixFiles.end(); - iter++) { - const CiftiMappableConnectivityMatrixDataFile* ciftiFile = *iter; - if (ciftiFile->matchesDimensions(volumeDimensions[0], - volumeDimensions[1], - volumeDimensions[2])) { - matchFlag = true; - break; - } - } - } - - if (matchFlag) { - const AString actionName("Show Cifti Connectivity For Parcel " - + labelName - + " in map " - + mapName); - QAction* action = ciftiConnectivityActionGroup->addAction(actionName); - action->setData(qVariantFromValue((void*)parcelConnectivity)); - ciftiConnectivityActions.push_back(action); - } +/** + * Add all label region of interest options to the menu + */ +void +UserInputModeViewContextMenu::addLabelRegionOfInterestActions() +{ + createParcelConnectivities(); + + /* + * File types of interest + */ + std::vector ciftiMatrixFiles; + std::vector ciftiFiberTrajectoryFiles; + std::vector chartableFiles; + std::vector metricDynConnFiles; + std::vector volDynConnFiles; + /* + * Get all files in displayed overlays + */ + EventCaretMappableDataFilesAndMapsInDisplayedOverlays allOverlayDisplayedFilesEvent; + EventManager::get()->sendEvent(allOverlayDisplayedFilesEvent.getPointer()); + auto mapFilesAndIndices = allOverlayDisplayedFilesEvent.getFilesAndMaps(); + + /* + * Find matrix, fiber trajectory, and line-series files that are displayed + */ + for (auto mapFileAndIndex : mapFilesAndIndices) { + CaretMappableDataFile* mapFile = mapFileAndIndex.m_mapFile; + CaretAssert(mapFile); + + CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(mapFile); + if (matrixFile != NULL) { + ciftiMatrixFiles.push_back(matrixFile); + } + + CiftiFiberTrajectoryFile* fiberTrajFile = dynamic_cast(mapFile); + if (fiberTrajFile != NULL) { + ciftiFiberTrajectoryFiles.push_back(fiberTrajFile); + } + + ChartableLineSeriesBrainordinateInterface* lineSeriesFile = dynamic_cast(mapFile); + if (lineSeriesFile != NULL) { + chartableFiles.push_back(lineSeriesFile); + } + + MetricDynamicConnectivityFile* metricDynConnFile = dynamic_cast(mapFile); + if (metricDynConnFile != NULL) { + metricDynConnFiles.push_back(metricDynConnFile); + } + + VolumeDynamicConnectivityFile* volDynnFile = dynamic_cast(mapFile); + if (volDynnFile != NULL) { + volDynConnFiles.push_back(volDynnFile); + } + } + const bool hasDynamicConnectivity = ( ( ! ciftiMatrixFiles.empty()) + || ( ! metricDynConnFiles.empty()) + || ( ! volDynConnFiles.empty()) ); + const bool haveCiftiFiberTrajectoryFiles = ( ! ciftiFiberTrajectoryFiles.empty()); + const bool haveChartableFiles = ( ! chartableFiles.empty()); + + /* + * Actions for each file type + */ + QList connectivityActions; + QActionGroup* connectivityActionGroup = new QActionGroup(this); + QObject::connect(connectivityActionGroup, SIGNAL(triggered(QAction*)), + this, SLOT(connectivityActionSelected(QAction*))); + + QList ciftiFiberTrajectoryActions; + QActionGroup* ciftiFiberTrajectoryActionGroup = new QActionGroup(this); + QObject::connect(ciftiFiberTrajectoryActionGroup, SIGNAL(triggered(QAction*)), + this, SLOT(parcelCiftiFiberTrajectoryActionSelected(QAction*))); + + QList chartableDataActions; + QActionGroup* chartableDataActionGroup = new QActionGroup(this); + QObject::connect(chartableDataActionGroup, SIGNAL(triggered(QAction*)), + this, SLOT(parcelChartableDataActionSelected(QAction*))); + + for (auto parcelConnectivity : this->parcelConnectivities) { + const ParcelType parcelType = parcelConnectivity->parcelType; + const AString sourceLabelName("Region \"" + + parcelConnectivity->labelName + + "\" from map \"" + + parcelConnectivity->mapName + + "\""); + if (hasDynamicConnectivity) { + bool matchFlag = false; + if (parcelType == ParcelType::PARCEL_TYPE_SURFACE_NODES) { + matchFlag = true; + } + else if (parcelType == ParcelType::PARCEL_TYPE_VOLUME_VOXELS) { + for (std::vector::iterator iter = ciftiMatrixFiles.begin(); + iter != ciftiMatrixFiles.end(); + iter++) { + const CiftiMappableConnectivityMatrixDataFile* ciftiFile = *iter; + if (ciftiFile->matchesDimensions(parcelConnectivity->volumeDimensions[0], + parcelConnectivity->volumeDimensions[1], + parcelConnectivity->volumeDimensions[2])) { + matchFlag = true; + break; } - - if (haveCiftiFiberTrajectoryFiles) { - const AString fiberTrajActionName("Show Average Fiber Trajectory for Parcel " - + labelName - + " in map " - + mapName); - QAction* fiberTrajAction = ciftiFiberTrajectoryActionGroup->addAction(fiberTrajActionName); - fiberTrajAction->setData(qVariantFromValue((void*)parcelConnectivity)); - ciftiFiberTrajectoryActions.push_back(fiberTrajAction); + } + + for (auto volDynFile : volDynConnFiles) { + if (volDynFile->matchesDimensions(parcelConnectivity->volumeDimensions[0], + parcelConnectivity->volumeDimensions[1], + parcelConnectivity->volumeDimensions[2])) { + matchFlag = true; + break; } - - if (haveChartableFiles) { - bool matchFlag = false; - if (parcelType == ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES) { - matchFlag = true; - } - else if (parcelType == ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS) { - for (std::vector::iterator iter = chartableFiles.begin(); - iter != chartableFiles.end(); - iter++) { - const ChartableLineSeriesBrainordinateInterface* chartFile = *iter; - const CaretMappableDataFile* mapDataFile = chartFile->getLineSeriesChartCaretMappableDataFile(); - if (mapDataFile != NULL){ - if (mapDataFile->isVolumeMappable()) { - const VolumeMappableInterface* volMap = dynamic_cast(mapDataFile); - if (volMap->matchesDimensions(volumeDimensions[0], - volumeDimensions[1], - volumeDimensions[2])) { - matchFlag = true; - break; - } - - } - } + } + } + + if (matchFlag) { + const AString actionName("Show Connectivity for " + + sourceLabelName); + QAction* action = connectivityActionGroup->addAction(actionName); + action->setData(qVariantFromValue((void*)parcelConnectivity)); + connectivityActions.push_back(action); + } + } + + if (haveCiftiFiberTrajectoryFiles) { + const AString fiberTrajActionName("Show Average Fiber Trajectory for " + + sourceLabelName); + QAction* fiberTrajAction = ciftiFiberTrajectoryActionGroup->addAction(fiberTrajActionName); + fiberTrajAction->setData(qVariantFromValue((void*)parcelConnectivity)); + ciftiFiberTrajectoryActions.push_back(fiberTrajAction); + } + + if (haveChartableFiles) { + bool matchFlag = false; + if (parcelType == ParcelType::PARCEL_TYPE_SURFACE_NODES) { + matchFlag = true; + } + else if (parcelType == ParcelType::PARCEL_TYPE_VOLUME_VOXELS) { + for (std::vector::iterator iter = chartableFiles.begin(); + iter != chartableFiles.end(); + iter++) { + const ChartableLineSeriesBrainordinateInterface* chartFile = *iter; + const CaretMappableDataFile* mapDataFile = chartFile->getLineSeriesChartCaretMappableDataFile(); + if (mapDataFile != NULL){ + if (mapDataFile->isVolumeMappable()) { + const VolumeMappableInterface* volMap = dynamic_cast(mapDataFile); + if (volMap->matchesDimensions(parcelConnectivity->volumeDimensions[0], + parcelConnectivity->volumeDimensions[1], + parcelConnectivity->volumeDimensions[2])) { + matchFlag = true; + break; } - } - - if (matchFlag) { - const AString tsActionName("Show Data/Time Series Graph For Parcel " - + labelName - + " in map " - + mapName); - QAction* tsAction = chartableDataActionGroup->addAction(tsActionName); - tsAction->setData(qVariantFromValue((void*)parcelConnectivity)); - chartableDataActions.push_back(tsAction); + } } } } + + if (matchFlag) { + const AString tsActionName("Show Data/Time Series Graph For " + + sourceLabelName); + QAction* tsAction = chartableDataActionGroup->addAction(tsActionName); + tsAction->setData(qVariantFromValue((void*)parcelConnectivity)); + chartableDataActions.push_back(tsAction); + } } } - addActionsToMenu(ciftiConnectivityActions, + addActionsToMenu(connectivityActions, true); addActionsToMenu(ciftiFiberTrajectoryActions, true); @@ -891,7 +1013,7 @@ UserInputModeViewContextMenu::addFociActions() * Action that was selected. */ void -UserInputModeViewContextMenu::parcelCiftiConnectivityActionSelected(QAction* action) +UserInputModeViewContextMenu::connectivityActionSelected(QAction* action) { void* pointer = action->data().value(); ParcelConnectivity* pc = (ParcelConnectivity*)pointer; @@ -900,9 +1022,9 @@ UserInputModeViewContextMenu::parcelCiftiConnectivityActionSelected(QAction* act std::vector voxelIndices; switch (pc->parcelType) { - case ParcelConnectivity::PARCEL_TYPE_INVALID: + case ParcelType::PARCEL_TYPE_INVALID: break; - case ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES: + case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->getNodeIndices(nodeIndices); if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, @@ -916,7 +1038,7 @@ UserInputModeViewContextMenu::parcelCiftiConnectivityActionSelected(QAction* act } } break; - case ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS: + case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: pc->getVoxelIndices(voxelIndices); if (voxelIndices.empty()) { WuQMessageBox::errorOk(this, @@ -942,17 +1064,35 @@ UserInputModeViewContextMenu::parcelCiftiConnectivityActionSelected(QAction* act progressDialog.setValue(0); switch (pc->parcelType) { - case ParcelConnectivity::PARCEL_TYPE_INVALID: + case ParcelType::PARCEL_TYPE_INVALID: break; - case ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES: + case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->ciftiConnectivityManager->loadAverageDataForSurfaceNodes(pc->brain, pc->surface, nodeIndices); + { + std::vector metricDynConnFiles; + pc->brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); + for (auto mdcf : metricDynConnFiles) { + mdcf->loadAverageDataForSurfaceNodes(pc->surface->getNumberOfNodes(), + pc->surface->getStructure(), + nodeIndices); + } + } break; - case ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS: + case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: pc->ciftiConnectivityManager->loadAverageDataForVoxelIndices(pc->brain, pc->volumeDimensions, voxelIndices); + + { + std::vector volDynConnFiles; + pc->brain->getVolumeDynamicConnectivityFiles(volDynConnFiles); + for (auto vdcf : volDynConnFiles) { + vdcf->loadMapAverageDataForVoxelIndices(pc->volumeDimensions, + voxelIndices); + } + } break; } } @@ -980,9 +1120,9 @@ UserInputModeViewContextMenu::parcelCiftiFiberTrajectoryActionSelected(QAction* std::vector nodeIndices; switch (pc->parcelType) { - case ParcelConnectivity::PARCEL_TYPE_INVALID: + case ParcelType::PARCEL_TYPE_INVALID: break; - case ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES: + case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->getNodeIndices(nodeIndices); if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, @@ -990,7 +1130,7 @@ UserInputModeViewContextMenu::parcelCiftiFiberTrajectoryActionSelected(QAction* return; } break; - case ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS: + case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: break; } @@ -1005,14 +1145,14 @@ UserInputModeViewContextMenu::parcelCiftiFiberTrajectoryActionSelected(QAction* progressDialog.setValue(0); switch (pc->parcelType) { - case ParcelConnectivity::PARCEL_TYPE_INVALID: + case ParcelType::PARCEL_TYPE_INVALID: break; - case ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES: + case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->ciftiFiberTrajectoryManager->loadDataAverageForSurfaceNodes(pc->brain, pc->surface, nodeIndices); break; - case ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS: + case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: std::vector voxelIndices; pc->getVoxelIndices(voxelIndices); pc->ciftiFiberTrajectoryManager->loadAverageDataForVoxelIndices(pc->brain, @@ -1088,6 +1228,17 @@ UserInputModeViewContextMenu::borderCiftiConnectivitySelected() ciftiConnMann->loadAverageDataForSurfaceNodes(borderID->getBrain(), surface, nodeIndices); + + { + Brain* brain = GuiManager::get()->getBrain(); + std::vector metricDynConnFiles; + brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); + for (auto mdcf : metricDynConnFiles) { + mdcf->loadAverageDataForSurfaceNodes(surface->getNumberOfNodes(), + surface->getStructure(), + nodeIndices); + } + } } catch (const DataFileException& e) { cursor.restoreCursor(); @@ -1118,9 +1269,9 @@ UserInputModeViewContextMenu::parcelChartableDataActionSelected(QAction* action) std::vector voxelIndices; switch (pc->parcelType) { - case ParcelConnectivity::PARCEL_TYPE_INVALID: + case ParcelType::PARCEL_TYPE_INVALID: break; - case ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES: + case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->getNodeIndices(nodeIndices); if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, @@ -1134,7 +1285,7 @@ UserInputModeViewContextMenu::parcelChartableDataActionSelected(QAction* action) } } break; - case ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS: + case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: pc->getVoxelIndices(voxelIndices); if (voxelIndices.empty()) { WuQMessageBox::errorOk(this, @@ -1160,13 +1311,13 @@ UserInputModeViewContextMenu::parcelChartableDataActionSelected(QAction* action) progressDialog.setValue(0); switch (pc->parcelType) { - case ParcelConnectivity::PARCEL_TYPE_INVALID: + case ParcelType::PARCEL_TYPE_INVALID: break; - case ParcelConnectivity::PARCEL_TYPE_SURFACE_NODES: + case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->chartingDataManager->loadAverageChartForSurfaceNodes(pc->surface, nodeIndices); break; - case ParcelConnectivity::PARCEL_TYPE_VOLUME_VOXELS: + case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: cursor.restoreCursor(); WuQMessageBox::errorOk(this, "Charting of voxel average has not been implemented."); @@ -1548,6 +1699,7 @@ UserInputModeViewContextMenu::ParcelConnectivity::ParcelConnectivity(Brain* brai const ParcelType parcelType, CaretMappableDataFile* mappableLabelFile, const int32_t labelFileMapIndex, + const AString& mapName, const int32_t labelKey, const QString& labelName, Surface* surface, @@ -1560,6 +1712,7 @@ UserInputModeViewContextMenu::ParcelConnectivity::ParcelConnectivity(Brain* brai this->parcelType = parcelType; this->mappableLabelFile = mappableLabelFile; this->labelFileMapIndex = labelFileMapIndex; + this->mapName = mapName; this->labelKey = labelKey; this->labelName = labelName; this->surface = surface; @@ -1591,7 +1744,7 @@ UserInputModeViewContextMenu::ParcelConnectivity::getNodeIndices(std::vectorparcelType != PARCEL_TYPE_SURFACE_NODES) { + if (this->parcelType != ParcelType::PARCEL_TYPE_SURFACE_NODES) { return; } @@ -1626,7 +1779,7 @@ UserInputModeViewContextMenu::ParcelConnectivity::getVoxelIndices(std::vectorparcelType != PARCEL_TYPE_VOLUME_VOXELS) { + if (this->parcelType != ParcelType::PARCEL_TYPE_VOLUME_VOXELS) { return; } diff --git a/src/GuiQt/UserInputModeViewContextMenu.h b/src/GuiQt/UserInputModeViewContextMenu.h index 7879cc9920c9f345e14d16da2487c5a3dd188052..1f2021948c4c396aaa8f4dfa70432d87107fc989 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.h +++ b/src/GuiQt/UserInputModeViewContextMenu.h @@ -26,6 +26,7 @@ #include +#include "StructureEnum.h" #include "VolumeSliceViewPlaneEnum.h" #include "VoxelIJK.h" @@ -83,7 +84,7 @@ namespace caret { void parcelCiftiFiberTrajectoryActionSelected(QAction* action); - void parcelCiftiConnectivityActionSelected(QAction* action); + void connectivityActionSelected(QAction* action); void parcelChartableDataActionSelected(QAction* action); @@ -94,18 +95,19 @@ namespace caret { void editChartLabelSelected(); private: + enum class ParcelType { + PARCEL_TYPE_INVALID, + PARCEL_TYPE_SURFACE_NODES, + PARCEL_TYPE_VOLUME_VOXELS + }; + class ParcelConnectivity { public: - enum ParcelType { - PARCEL_TYPE_INVALID, - PARCEL_TYPE_SURFACE_NODES, - PARCEL_TYPE_VOLUME_VOXELS - }; - ParcelConnectivity(Brain* brain, const ParcelType parcelType, CaretMappableDataFile* mappableLabelFile, const int32_t labelFileMapIndex, + const AString& mapName, const int32_t labelKey, const QString& labelName, Surface* surface, @@ -125,6 +127,7 @@ namespace caret { ParcelType parcelType; CaretMappableDataFile* mappableLabelFile; int32_t labelFileMapIndex; + AString mapName; int32_t labelKey; QString labelName; Surface* surface; @@ -159,6 +162,8 @@ namespace caret { void addActionsToMenu(QList& actionsToAdd, const bool addSeparatorBeforeActions); + void createParcelConnectivities(); + BrainOpenGLWidget* parentOpenGLWidget; std::vector parcelConnectivities; diff --git a/src/GuiQt/UserInputModeVolumeEdit.cxx b/src/GuiQt/UserInputModeVolumeEdit.cxx index 44bd838d0946ec824bf4102b81d4a44deee65feb..c5900750c2109c720740df6a926ed6d09cfc1ac1 100644 --- a/src/GuiQt/UserInputModeVolumeEdit.cxx +++ b/src/GuiQt/UserInputModeVolumeEdit.cxx @@ -62,7 +62,7 @@ using namespace caret; * Index of window using this volume editor input handler. */ UserInputModeVolumeEdit::UserInputModeVolumeEdit(const int32_t windowIndex) -: UserInputModeView(UserInputModeAbstract::VOLUME_EDIT), +: UserInputModeView(UserInputModeEnum::VOLUME_EDIT), m_windowIndex(windowIndex) { m_inputModeVolumeEditWidget = new UserInputModeVolumeEditWidget(this, diff --git a/src/GuiQt/UserInputTileTabsContextMenu.cxx b/src/GuiQt/UserInputTileTabsContextMenu.cxx index 051dfd164c10fbe8a5d5d9cc06459a7b68e78320..2efb41af3b71931e73c5f420e2b790cf88785009 100644 --- a/src/GuiQt/UserInputTileTabsContextMenu.cxx +++ b/src/GuiQt/UserInputTileTabsContextMenu.cxx @@ -125,10 +125,12 @@ UserInputTileTabsContextMenu::actionTriggered(QAction* action) } if (validOperationFlag) { + std::vector emptyBrowserTabs; EventBrowserWindowTileTabOperation tileTabOperation(operation, m_parentWidget, m_windowIndex, - m_tabIndex); + m_tabIndex, + emptyBrowserTabs); EventManager::get()->sendEvent(tileTabOperation.getPointer()); } } diff --git a/src/GuiQt/VolumePropertiesEditorDialog.cxx b/src/GuiQt/VolumePropertiesEditorDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..118fd0f8984e0c0aa14ce628082fae48934424ff --- /dev/null +++ b/src/GuiQt/VolumePropertiesEditorDialog.cxx @@ -0,0 +1,194 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ +#include "VolumePropertiesEditorDialog.h" +#undef __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ + +#include + +#include +#include +#include + +using namespace caret; + +#include "Brain.h" +#include "CaretAssert.h" +#include "DisplayPropertiesVolume.h" +#include "GuiManager.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "EventUserInterfaceUpdate.h" +#include "SceneClass.h" +#include "SceneWindowGeometry.h" +#include "WuQFactory.h" +#include "WuQtUtilities.h" + +/** + * \class caret::VolumePropertiesEditorDialog + * \brief Dialog for adjusting volume display properties. + * \ingroup GuitQt + */ + +/** + * Constructor. + */ +VolumePropertiesEditorDialog::VolumePropertiesEditorDialog(QWidget* parent) +: WuQDialogNonModal("Volume Properties", + parent) +{ + QLabel* opacityLabel = new QLabel("Opacity: "); + m_opacitySpinBox = WuQFactory::newDoubleSpinBox(); + m_opacitySpinBox->setRange(0.0, 1.0); + m_opacitySpinBox->setSingleStep(0.1); + m_opacitySpinBox->setDecimals(2); + QObject::connect(m_opacitySpinBox, SIGNAL(valueChanged(double)), + this, SLOT(displayPropertyChanged())); + + QWidget* w = new QWidget(); + QGridLayout* gridLayout = new QGridLayout(w); + WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); + int row = gridLayout->rowCount(); + gridLayout->addWidget(opacityLabel, row, 0); + gridLayout->addWidget(m_opacitySpinBox, row, 1); + row++; + + setCentralWidget(w, + WuQDialog::SCROLL_AREA_NEVER); + + updateDialog(); + + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); + + /* + * No apply button + */ + setApplyButtonText(""); +} + +/** + * Destructor. + */ +VolumePropertiesEditorDialog::~VolumePropertiesEditorDialog() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Called when a display property is changed. + */ +void +VolumePropertiesEditorDialog::displayPropertyChanged() +{ + DisplayPropertiesVolume* dps = GuiManager::get()->getBrain()->getDisplayPropertiesVolume(); + dps->setOpacity(m_opacitySpinBox->value()); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + +/** + * Update the properties editor. + */ +void +VolumePropertiesEditorDialog::updateDialog() +{ + const DisplayPropertiesVolume* dpv = GuiManager::get()->getBrain()->getDisplayPropertiesVolume(); + + QSignalBlocker blocker(m_opacitySpinBox); + m_opacitySpinBox->setValue(dpv->getOpacity()); +} + +/** + * Receive events from the event manager. + * + * @param event + * Event sent by event manager. + */ +void +VolumePropertiesEditorDialog::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { + CaretAssert(dynamic_cast(event) != NULL); + + updateDialog(); + } +} + +/** + * Create a scene for an instance of a class. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @return Pointer to SceneClass object representing the state of + * this object. Under some circumstances a NULL pointer may be + * returned. Caller will take ownership of returned object. + */ +SceneClass* +VolumePropertiesEditorDialog::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "VolumePropertiesEditorDialog", + 1); + /* + * Position and size + */ + SceneWindowGeometry swg(this); + sceneClass->addClass(swg.saveToScene(sceneAttributes, + "geometry")); + + return sceneClass; +} + +/** + * Restore the state of an instance of a class. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * SceneClass containing the state that was previously + * saved and should be restored. + */ +void +VolumePropertiesEditorDialog::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + /* + * Position and size + */ + SceneWindowGeometry swg(this); + swg.restoreFromScene(sceneAttributes, sceneClass->getClass("geometry")); +} + + + diff --git a/src/GuiQt/VolumePropertiesEditorDialog.h b/src/GuiQt/VolumePropertiesEditorDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..1686f12c79f569318f6318234289b5e53d4ed1c6 --- /dev/null +++ b/src/GuiQt/VolumePropertiesEditorDialog.h @@ -0,0 +1,68 @@ +#ifndef __VOLUME_PROPERTIES_EDITOR_DIALOG__H_ +#define __VOLUME_PROPERTIES_EDITOR_DIALOG__H_ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "EventListenerInterface.h" +#include "SceneableInterface.h" +#include "WuQDialogNonModal.h" + +class QDoubleSpinBox; + +namespace caret { + class VolumePropertiesEditorDialog : public WuQDialogNonModal, public EventListenerInterface, public SceneableInterface { + Q_OBJECT + + public: + VolumePropertiesEditorDialog(QWidget* parent = 0); + + virtual ~VolumePropertiesEditorDialog(); + + void receiveEvent(Event* event); + + void updateDialog(); + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + private slots: + void displayPropertyChanged(); + + private: + VolumePropertiesEditorDialog(const VolumePropertiesEditorDialog&); + + VolumePropertiesEditorDialog& operator=(const VolumePropertiesEditorDialog&); + + QDoubleSpinBox* m_opacitySpinBox; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ + // +#endif // __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ + +} // namespace +#endif //__VOLUME_PROPERTIES_EDITOR_DIALOG__H_ diff --git a/src/GuiQt/VolumeSurfaceOutlineSetViewController.cxx b/src/GuiQt/VolumeSurfaceOutlineSetViewController.cxx index 0479a45718e0fea6f7090d3d755dce8c82369bab..0b6a1c46dfe169bddb0e5fbf1a81dac0f5c5968c 100644 --- a/src/GuiQt/VolumeSurfaceOutlineSetViewController.cxx +++ b/src/GuiQt/VolumeSurfaceOutlineSetViewController.cxx @@ -36,6 +36,7 @@ #include "VolumeSurfaceOutlineSetModel.h" #include "VolumeSurfaceOutlineViewController.h" #include "WuQFactory.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -53,11 +54,17 @@ using namespace caret; * Orientation for layout * @param browserWindowIndex * Index of browser window that contains this view controller. + * @param parentObjectNamePrefix + * Name of parent object for macros + * @param descriptivePrefix + * Descriptive prefix for macros * @param parent * Parent widget. */ VolumeSurfaceOutlineSetViewController::VolumeSurfaceOutlineSetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectNamePrefix, + const QString& descriptivePrefix, QWidget* parent) : QWidget(parent) { @@ -91,8 +98,12 @@ VolumeSurfaceOutlineSetViewController::VolumeSurfaceOutlineSetViewController(con } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { + const QString name = QString(parentObjectNamePrefix + + ":VolumeSurfaceOutline%1").arg((int)(i + 1), 2, 10, QLatin1Char('0')); VolumeSurfaceOutlineViewController* ovc = new VolumeSurfaceOutlineViewController(orientation, - gridLayout); + gridLayout, + name, + descriptivePrefix + " " + QString::number(i + 1)); this->outlineViewControllers.push_back(ovc); } @@ -103,6 +114,11 @@ VolumeSurfaceOutlineSetViewController::VolumeSurfaceOutlineSetViewController(con this->outlineCountSpinBox->setSingleStep(1); QObject::connect(this->outlineCountSpinBox, SIGNAL(valueChanged(int)), this, SLOT(outlineCountSpinBoxValueChanged(int))); + this->outlineCountSpinBox->setObjectName(parentObjectNamePrefix + + ":VolumeSurfaceOutlineNumberOfOutlines"); + this->outlineCountSpinBox->setToolTip("Number of volume surface outlines"); + WuQMacroManager::instance()->addMacroSupportToObject(this->outlineCountSpinBox, + "Set number of displayed volume/surface outlines for " + descriptivePrefix); QHBoxLayout* overlayCountLayout = new QHBoxLayout(); overlayCountLayout->addWidget(outlineCountLabel); diff --git a/src/GuiQt/VolumeSurfaceOutlineSetViewController.h b/src/GuiQt/VolumeSurfaceOutlineSetViewController.h index 380b227dda708e8114e465bb65c075a058228480..d1ea1fa9ebeb4f2a1f5187c24ba8e9cf9da00ceb 100644 --- a/src/GuiQt/VolumeSurfaceOutlineSetViewController.h +++ b/src/GuiQt/VolumeSurfaceOutlineSetViewController.h @@ -42,6 +42,8 @@ namespace caret { public: VolumeSurfaceOutlineSetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, + const QString& parentObjectNamePrefix, + const QString& descriptivePrefix, QWidget* parent = 0); virtual ~VolumeSurfaceOutlineSetViewController(); diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx index cd54c9d8ebc06e2ba794257775956c14a271fd3e..0407ffb6c188ab612ab771671b24964423400196 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx @@ -40,6 +40,7 @@ #include "WuQDoubleSpinBox.h" #include "WuQFactory.h" #include "WuQGridLayoutGroup.h" +#include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; @@ -53,21 +54,40 @@ using namespace caret; */ /** * Constructor. + * + * @param orientation + * Orientation for controller + * @param gridLayout + * Layout for widgets + * @param objectNamePrefix + * Object name prefix for macros + * @param descriptivePrefix + * Descriptive name prefix for macros */ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt::Orientation orientation, QGridLayout* gridLayout, + const QString& objectNamePrefix, + const QString& descriptivePrefix, QObject* parent) : QObject(parent) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + this->outlineModel = NULL; this->enabledCheckBox = new QCheckBox(" "); - QObject::connect(this->enabledCheckBox, SIGNAL(stateChanged(int)), - this, SLOT(enabledCheckBoxStateChanged(int))); + QObject::connect(this->enabledCheckBox, &QCheckBox::clicked, + this, &VolumeSurfaceOutlineViewController::enabledCheckBoxChecked); this->enabledCheckBox->setToolTip("Enables display of this volume surface outline"); + this->enabledCheckBox->setObjectName(objectNamePrefix + + ":Enable"); + macroManager->addMacroSupportToObject(this->enabledCheckBox, + "Enable volume surface outline for " + descriptivePrefix); - - this->surfaceSelectionViewController = new SurfaceSelectionViewController(this); + this->surfaceSelectionViewController = new SurfaceSelectionViewController(this, + (objectNamePrefix + + ":Surface"), + "Select volume surface outline surface for " + descriptivePrefix); QObject::connect(this->surfaceSelectionViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(surfaceSelected(Surface*))); this->surfaceSelectionViewController->getWidget()->setToolTip("Select surface drawn as outline over volume slices"); @@ -78,13 +98,22 @@ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt: this->colorOrTabSelectionControl->getWidget()->setToolTip("Select coloring for surface outline.\n" "If tab, coloring assigned to selected surface\n" "in the selected tab is used.\n"); + this->colorOrTabSelectionControl->getWidget()->setObjectName(objectNamePrefix + + ":ColorSource"); + macroManager->addMacroSupportToObject(this->colorOrTabSelectionControl->getWidget(), + "Set surface outline color for " + descriptivePrefix); + this->thicknessSpinBox = new WuQDoubleSpinBox(this); this->thicknessSpinBox->setRange(0.0, 100.0); this->thicknessSpinBox->setSingleStep(0.10); this->thicknessSpinBox->setSuffix("%"); QObject::connect(this->thicknessSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged); - this->thicknessSpinBox->setToolTip("Thickness of surface outline as percentage of viewport height"); + this->thicknessSpinBox->getWidget()->setToolTip("Thickness of surface outline as percentage of viewport height"); + this->thicknessSpinBox->getWidget()->setObjectName(objectNamePrefix + + ":Thickness"); + macroManager->addMacroSupportToObject(this->thicknessSpinBox->getWidget(), + "Set thickness for volume surface outline for " + descriptivePrefix); if (orientation == Qt::Horizontal) { @@ -159,15 +188,14 @@ VolumeSurfaceOutlineViewController::colorTabSelected(VolumeSurfaceOutlineColorOr /** * Called when enabled checkbox is selected. - * @param state + * @param checked * New state of checkbox. */ void -VolumeSurfaceOutlineViewController::enabledCheckBoxStateChanged(int state) +VolumeSurfaceOutlineViewController::enabledCheckBoxChecked(bool checked) { if (this->outlineModel != NULL) { - const bool selected = (state == Qt::Checked); - this->outlineModel->setDisplayed(selected); + this->outlineModel->setDisplayed(checked); } this->updateGraphics(); } @@ -197,11 +225,7 @@ VolumeSurfaceOutlineViewController::updateViewController(VolumeSurfaceOutlineMod this->outlineModel = outlineModel; if (this->outlineModel != NULL) { - Qt::CheckState state = Qt::Unchecked; - if (this->outlineModel->isDisplayed()) { - state = Qt::Checked; - } - this->enabledCheckBox->setCheckState(state); + this->enabledCheckBox->setChecked(this->outlineModel->isDisplayed()); this->thicknessSpinBox->blockSignals(true); float thickness = outlineModel->getThicknessPercentageViewportHeight(); diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.h b/src/GuiQt/VolumeSurfaceOutlineViewController.h index 74cb338850798da06208dab0ad9d492f6912d1f7..4b240146862cd74c5a3c76b866715218438d1314 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.h +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.h @@ -43,6 +43,8 @@ namespace caret { public: VolumeSurfaceOutlineViewController(const Qt::Orientation orientation, QGridLayout* gridLayout, + const QString& objectNamePrefix, + const QString& descriptivePrefix, QObject* parent = 0); virtual ~VolumeSurfaceOutlineViewController(); @@ -52,7 +54,7 @@ namespace caret { void updateViewController(VolumeSurfaceOutlineModel* outlineModel); private slots: - void enabledCheckBoxStateChanged(int); + void enabledCheckBoxChecked(bool checked); void thicknessSpinBoxValueChanged(double); diff --git a/src/GuiQt/WbMacroCustomDataInfo.cxx b/src/GuiQt/WbMacroCustomDataInfo.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5dfd0a4375d7dfe0f7e1e37655bcc737309f445a --- /dev/null +++ b/src/GuiQt/WbMacroCustomDataInfo.cxx @@ -0,0 +1,175 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ +#include "WbMacroCustomDataInfo.h" +#undef __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ + +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::WbMacroCustomDataInfo + * \brief Information about custom data such as valid data range + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomDataInfo::WbMacroCustomDataInfo(const WuQMacroDataValueTypeEnum::Enum dataType) +: CaretObject(), +m_dataType(dataType) +{ + m_integerRange[0] = std::numeric_limits::min(); + m_integerRange[1] = std::numeric_limits::max(); + + m_floatRange[0] = -std::numeric_limits::max(); + m_floatRange[1] = std::numeric_limits::max(); +} + +/** + * Destructor. + */ +WbMacroCustomDataInfo::~WbMacroCustomDataInfo() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +WbMacroCustomDataInfo::WbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj) +: CaretObject(obj) +{ + this->copyHelperWbMacroCustomDataInfo(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +WbMacroCustomDataInfo& +WbMacroCustomDataInfo::operator=(const WbMacroCustomDataInfo& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperWbMacroCustomDataInfo(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +WbMacroCustomDataInfo::copyHelperWbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj) +{ + m_dataType = obj.m_dataType; + m_floatRange = obj.m_floatRange; + m_integerRange = obj.m_integerRange; + m_stringListValues = obj.m_stringListValues; +} + +/** + * @return The data type + */ +WuQMacroDataValueTypeEnum::Enum +WbMacroCustomDataInfo::getDataType() const +{ + return m_dataType; +} + +/** + * @return Range for float data + */ +std::array +WbMacroCustomDataInfo::getFloatRange() const +{ + return m_floatRange; +} + +/** + * Set the range of float data + * + * @param range + * Range of the float data + */ +void +WbMacroCustomDataInfo::setFloatRange(const std::array& range) +{ + m_floatRange = range; +} + +/** + * @return Range for integer data + */ +std::array +WbMacroCustomDataInfo::getIntegerRange() const +{ + return m_integerRange; +} + +/** + * Set the range of integer data + * + * @param range + * Range of the integer data + */ +void +WbMacroCustomDataInfo::setIntegerRange(const std::array& range) +{ + m_integerRange = range; +} + +/** + * @return List of string values + */ +std::vector +WbMacroCustomDataInfo::getStringListValues() const +{ + return m_stringListValues; +} + +/** + * Set the list of string values + * + * @param range + * List of string values + */ +void +WbMacroCustomDataInfo::setStringListValues(const std::vector& values) +{ + m_stringListValues = values; +} + + + diff --git a/src/GuiQt/WbMacroCustomDataInfo.h b/src/GuiQt/WbMacroCustomDataInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..87aa81f3c3cefa2bed5c331e4d293a020599e999 --- /dev/null +++ b/src/GuiQt/WbMacroCustomDataInfo.h @@ -0,0 +1,81 @@ +#ifndef __WB_MACRO_CUSTOM_DATA_INFO_H__ +#define __WB_MACRO_CUSTOM_DATA_INFO_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include "CaretObject.h" +#include "WuQMacroDataValueTypeEnum.h" + + +namespace caret { + + class WbMacroCustomDataInfo : public CaretObject { + + public: + WbMacroCustomDataInfo(const WuQMacroDataValueTypeEnum::Enum dataType); + + virtual ~WbMacroCustomDataInfo(); + + WbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj); + + WbMacroCustomDataInfo& operator=(const WbMacroCustomDataInfo& obj); + + WuQMacroDataValueTypeEnum::Enum getDataType() const; + + std::array getFloatRange() const; + + void setFloatRange(const std::array& range); + + std::array getIntegerRange() const; + + void setIntegerRange(const std::array& range); + + std::vector getStringListValues() const; + + void setStringListValues(const std::vector& values); + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperWbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj); + + WuQMacroDataValueTypeEnum::Enum m_dataType; + + std::array m_floatRange; + + std::array m_integerRange; + + std::vector m_stringListValues; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_DATA_INFO_H__ diff --git a/src/GuiQt/WbMacroCustomDataTypeEnum.cxx b/src/GuiQt/WbMacroCustomDataTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4df4a71d6f6c00e59e0d9ba9fe4836a9c3a494d1 --- /dev/null +++ b/src/GuiQt/WbMacroCustomDataTypeEnum.cxx @@ -0,0 +1,380 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ +#include "WbMacroCustomDataTypeEnum.h" +#undef __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WbMacroCustomDataTypeEnum + * \brief Enumerated type for a user defined macro data type + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_WbMacroCustomDataTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void WbMacroCustomDataTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WbMacroCustomDataTypeEnum.h" + * + * Instatiate: + * m_WbMacroCustomDataTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_WbMacroCustomDataTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_WbMacroCustomDataTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(WbMacroCustomDataTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_WbMacroCustomDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WbMacroCustomDataTypeEnum::Enum VARIABLE = m_WbMacroCustomDataTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WbMacroCustomDataTypeEnum::WbMacroCustomDataTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WbMacroCustomDataTypeEnum::~WbMacroCustomDataTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WbMacroCustomDataTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WbMacroCustomDataTypeEnum(OVERLAY_INDEX, + "OVERLAY_INDEX", + "Overlay Index")); + + enumData.push_back(WbMacroCustomDataTypeEnum(OVERLAY_FILE_NAME_OR_FILE_INDEX, + "OVERLAY_FILE_NAME_OR_FILE_INDEX", + "Overlay File or File Index")); + + enumData.push_back(WbMacroCustomDataTypeEnum(OVERLAY_MAP_NAME_OR_MAP_INDEX, + "OVERLAY_MAP_NAME_OR_MAP_INDEX", + "Overlay Map Name or Index")); + + enumData.push_back(WbMacroCustomDataTypeEnum(SURFACE, + "SURFACE", + "Surface")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WbMacroCustomDataTypeEnum* +WbMacroCustomDataTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WbMacroCustomDataTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WbMacroCustomDataTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WbMacroCustomDataTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WbMacroCustomDataTypeEnum::Enum +WbMacroCustomDataTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WbMacroCustomDataTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WbMacroCustomDataTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WbMacroCustomDataTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WbMacroCustomDataTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WbMacroCustomDataTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WbMacroCustomDataTypeEnum::Enum +WbMacroCustomDataTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WbMacroCustomDataTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WbMacroCustomDataTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WbMacroCustomDataTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WbMacroCustomDataTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WbMacroCustomDataTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WbMacroCustomDataTypeEnum::Enum +WbMacroCustomDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WbMacroCustomDataTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WbMacroCustomDataTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WbMacroCustomDataTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WbMacroCustomDataTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WbMacroCustomDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WbMacroCustomDataTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WbMacroCustomDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WbMacroCustomDataTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/GuiQt/WbMacroCustomDataTypeEnum.h b/src/GuiQt/WbMacroCustomDataTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..1cc46abcf102e0b1c0d61d3b4a2a28548f4f1154 --- /dev/null +++ b/src/GuiQt/WbMacroCustomDataTypeEnum.h @@ -0,0 +1,108 @@ +#ifndef __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_H__ +#define __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WbMacroCustomDataTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Index of an overlay */ + OVERLAY_INDEX, + /** Name of file in overlay or index of file */ + OVERLAY_FILE_NAME_OR_FILE_INDEX, + /** Name of map or index of map */ + OVERLAY_MAP_NAME_OR_MAP_INDEX, + /** Surface selection */ + SURFACE + }; + + + ~WbMacroCustomDataTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WbMacroCustomDataTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WbMacroCustomDataTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ +std::vector WbMacroCustomDataTypeEnum::enumData; +bool WbMacroCustomDataTypeEnum::initializedFlag = false; +int32_t WbMacroCustomDataTypeEnum::integerCodeCounter = 0; +#endif // __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_DATA_TYPE_ENUM_H__ diff --git a/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.cxx b/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3ab2c97ebfd2d3d9a3f7b743f5d2e3f24036ac7f --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.cxx @@ -0,0 +1,676 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ +#include "WbMacroCustomOperationAnimateOverlayCrossFade.h" +#undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "CaretMappableDataFile.h" +#include "GuiManager.h" +#include "Overlay.h" +#include "OverlaySet.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationAnimateOverlayCrossFade + * \brief Custom Macro Command for Overlay Crossfade + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationAnimateOverlayCrossFade::WbMacroCustomOperationAnimateOverlayCrossFade() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_OVERLAY_CROSS_FADE) +{ +} + +/** + * Destructor. + */ +WbMacroCustomOperationAnimateOverlayCrossFade::~WbMacroCustomOperationAnimateOverlayCrossFade() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationAnimateOverlayCrossFade::createCommand() +{ + WuQMacroCommand* command(NULL); + const int32_t versionNumber(2); + switch (versionNumber) { + case 1: + command = createCommandVersionOne(); + break; + case 2: + command = createCommandVersionTwo(); + break; + } + CaretAssert(command); + + return command; +} + +/** + * Get a new instance of the macro command for version one + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationAnimateOverlayCrossFade::createCommandVersionOne() +{ + const int32_t versionOne(1); + + const QString description("Crossfade (blend) from one overlay to another:\n" + "(1) The opacity of the \"Fade to Overlay\" is set to zero;\n" + "(2) The opacity of the \"Fade from Overlay\" is set to one;\n" + "(3) The opacity of the \"Fade to Overlay\" increases until it is one\n" + " and simultaneously, the opacity of the \"Face from Overlay\"\n" + " decreases until it reaches zero.\n"); + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), + versionOne, + "none", + "Overlay CrossFade", + description, + 1.0, + errorMessage); + if (command != NULL) { + command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Fade to Overlay", + (int)1); + command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Fade from Overlay", + (int)2); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Duration (secs)", + (float)10.0); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; +} + +/** + * Get a new instance of the macro command for version two + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationAnimateOverlayCrossFade::createCommandVersionTwo() +{ + const int32_t versionTwo(2); + + const QString description("Crossfade (blend) from file in overlay to selected file/map:\n" + "(1) A copy of the selected overlay is inserted below it; \n" + "(2) Selected file/map is placed in new the overlay;\n" + "(3) The opacity of selected overlay is decreased until it\n" + " becomes 0.0 revealing the selected file/map;\n" + "(4) The selected overlay is removed;\n" + "(5) The selected file/map remains displayed in its overlay\n"); + + WuQMacroCommandParameter* paramSurfaceOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Overlay Number", + 1); + paramSurfaceOne->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::OVERLAY_INDEX)); + + WuQMacroCommandParameter* paramSurfaceTwo = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, + "Fade to File", + ""); + paramSurfaceTwo->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::OVERLAY_FILE_NAME_OR_FILE_INDEX)); + + WuQMacroCommandParameter* paramSurfaceThree = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, + "Fade to Map", + ""); + paramSurfaceThree->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::OVERLAY_MAP_NAME_OR_MAP_INDEX)); + + + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), + versionTwo, + "none", + WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), + description, + 1.0, + errorMessage); + if (command != NULL) { + command->addParameter(paramSurfaceOne); + command->addParameter(paramSurfaceTwo); + command->addParameter(paramSurfaceThree); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Duration (secs)", + (float)2.0); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; + +} + + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * the executor options + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationAnimateOverlayCrossFade::executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + bool resultFlag(false); + switch (macroCommand->getVersion()) { + case 1: + resultFlag = executeCommandVersionOne(parent, + executorOptions, + macroCommand); + break; + case 2: + resultFlag = executeCommandVersionTwo(parent, + executorMonitor, + executorOptions, + macroCommand); + break; + default: + appendUnsupportedVersionToErrorMessage(macroCommand->getVersion()); + break; + } + + return resultFlag; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * The macro executor's monitor + * @param executorOptions + * The executor options, + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationAnimateOverlayCrossFade::executeCommandVersionTwo(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 4)) { + return false; + } + /* + * Get overlay indices and subtract one from them since they stat at 1 + */ + const int32_t overlayIndex(macroCommand->getParameterAtIndex(0)->getValue().toInt() - 1); + const QString mapFileName(macroCommand->getParameterAtIndex(1)->getValue().toString()); + const QString mapName(macroCommand->getParameterAtIndex(2)->getValue().toString()); + const float durationSeconds(macroCommand->getParameterAtIndex(3)->getValue().toFloat()); + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running surface macro is not a browser window"); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window"); + return false; + } + + Model* model = tabContent->getModelForDisplay(); + if (model == NULL) { + appendToErrorMessage("No model is displayed"); + return false; + } + + bool validModelTypeFlag(false); + switch (model->getModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + validModelTypeFlag = true; + break; + } + if ( ! validModelTypeFlag) { + appendToErrorMessage("For Overlay CrossFace, model must be a brain model"); + return false; + } + + OverlaySet* overlaySet = tabContent->getOverlaySet(); + CaretAssert(overlaySet); + const int32_t numberOfOverlays = overlaySet->getNumberOfDisplayedOverlays(); + if ((overlayIndex < 0) + || (overlayIndex >= numberOfOverlays)) { + appendToErrorMessage("Overlay index is invalid."); + } + if (overlayIndex == (BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS - 1)) { + appendToErrorMessage("Selected overlay cannot be the last (bottom-most) overlay"); + } + if (mapFileName.isEmpty()) { + appendToErrorMessage("Map File Name is empty."); + } + if (mapName.isEmpty()) { + appendToErrorMessage("Map Name is empty."); + } + if ( ! getErrorMessage().isEmpty()) { + return false; + } + + Overlay* overlay = overlaySet->getOverlay(overlayIndex); + if ( ! overlay->isEnabled()) { + overlay->setEnabled(true); + } + + std::vector mapFiles; + CaretMappableDataFile* selectedMapFile(NULL); + int32_t selectedMapIndex(-1); + overlay->getSelectionData(mapFiles, + selectedMapFile, + selectedMapIndex); + + CaretMappableDataFile* fadeToMapFile(NULL); + for (auto mf : mapFiles) { + if (mf->getFileName().endsWith(mapFileName)) { + fadeToMapFile = mf; + break; + } + } + if (fadeToMapFile == NULL) { + appendToErrorMessage("Unable to find data file with name " + + mapFileName); + return false; + } + + int32_t fadeToMapIndex(-1); + const int32_t numMaps = fadeToMapFile->getNumberOfMaps(); + for (int32_t i = 0; i < numMaps; i++) { + if (mapName == fadeToMapFile->getMapName(i)) { + fadeToMapIndex = i; + break; + } + } + if (fadeToMapIndex < 0) { + appendToErrorMessage("Unable to find map named " + + mapName); + return false; + } + + const bool successFlag = performCrossFadeVersionTwo(executorMonitor, + executorOptions, + overlaySet, + overlayIndex, + fadeToMapFile, + fadeToMapIndex, + durationSeconds); + + return successFlag; +} + +/** + * Perform crossfade version two + * + * @param executorMonitor + * The macro executor's monitor + * @param executorOptions + * The executor options + * @param overlaySet + * OverlaySet for the in the tab + * @param overlayIndex + * Index of the overlay that fades off + * @param fadeToMapFile + * File that is fades on + * @param fadeToMapIndex + * Index of map in file that fades on + * @param durationSeconds + * Total duration for cross fade + * @return + * True if successful, else false + */ +bool +WbMacroCustomOperationAnimateOverlayCrossFade::performCrossFadeVersionTwo(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + OverlaySet* overlaySet, + const int32_t overlayIndex, + CaretMappableDataFile* fadeToMapFile, + const int32_t fadeToMapIndex, + const float durationSeconds) +{ + CaretAssert(overlaySet); + CaretAssert(fadeToMapFile); + CaretAssert((fadeToMapIndex >= 0) + && (fadeToMapIndex < fadeToMapFile->getNumberOfMaps())); + + /* + * Insert a new overlay below the fade-from overlay + */ + overlaySet->insertOverlayBelow(overlayIndex); + + /* + * Copy content of fade-from overlay to the new fade-to overlay + */ + Overlay* fadeFromOverlay = overlaySet->getOverlay(overlayIndex); + const int32_t nextOverlayIndex = overlayIndex + 1; + Overlay* fadeToOverlay = overlaySet->getOverlay(nextOverlayIndex); + fadeToOverlay->copyData(fadeFromOverlay); + + /* + * Load fade-to file and map into the new overlay + */ + fadeToOverlay->setSelectionData(fadeToMapFile, + fadeToMapIndex); + + const float defaultNumberOfSteps(25.0); + float numberOfSteps(0.0); + float iterationSleepTime(0.0); + getNumberOfStepsAndSleepTime(executorOptions, + defaultNumberOfSteps, + durationSeconds, + numberOfSteps, + iterationSleepTime); + + float fadeFromOpacity(fadeFromOverlay->getOpacity()); + const float opacityDelta = fadeFromOpacity / numberOfSteps; + + fadeToOverlay->setEnabled(true); + fadeFromOverlay->setEnabled(true); + + /* + * Iterate while decreasing the opacity of the fade-from overlay + */ + for (int iStep = 0; iStep < numberOfSteps; iStep++) { + fadeFromOverlay->setOpacity(fadeFromOpacity); + updateSurfaceColoring(); + updateUserInterface(); + updateGraphics(); + + fadeFromOpacity -= opacityDelta; + if (fadeFromOpacity < 0.0) { + fadeFromOpacity = 0.0; + } + + if (executorMonitor->testForStop()) { + appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); + return false; + } + + sleepForSecondsAtEndOfIteration(iterationSleepTime); + } + + fadeFromOverlay->setOpacity(0.0); + + /* + * Remove the fade-from overlay so that the fade-to overlay is visible + */ + overlaySet->removeDisplayedOverlay(overlayIndex); + + updateSurfaceColoring(); + updateUserInterface(); + updateGraphics(); + + return true; + +} + + + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorOptions + * The executor options + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationAnimateOverlayCrossFade::executeCommandVersionOne(QWidget* parent, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 3)) { + return false; + } + /* + * Get overlay indices and subtract one from them since they stat at 1 + */ + const int32_t fadeToOverlayIndex(macroCommand->getParameterAtIndex(0)->getValue().toInt() - 1); + const int32_t fadeFromOverlayIndex(macroCommand->getParameterAtIndex(1)->getValue().toInt() - 1); + const float durationSeconds(macroCommand->getParameterAtIndex(2)->getValue().toFloat()); + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running surface macro is not a browser window"); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window"); + return false; + } + + Model* model = tabContent->getModelForDisplay(); + if (model == NULL) { + appendToErrorMessage("No model is displayed"); + return false; + } + + bool validModelTypeFlag(false); + switch (model->getModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + validModelTypeFlag = true; + break; + } + if ( ! validModelTypeFlag) { + appendToErrorMessage("For Overlay CrossFace, model must be a brain model"); + return false; + } + + OverlaySet* overlaySet = tabContent->getOverlaySet(); + CaretAssert(overlaySet); + const int32_t numberOfOverlays = overlaySet->getNumberOfDisplayedOverlays(); + + if ((fadeToOverlayIndex < 0) + || (fadeToOverlayIndex >= numberOfOverlays)) { + appendToErrorMessage("Fade To Overlay Index is not a valid overlay"); + } + if ((fadeFromOverlayIndex < 0) + || (fadeFromOverlayIndex >= numberOfOverlays)) { + appendToErrorMessage("Fade From Overlay Index is not a valid overlay"); + } + if ( ! getErrorMessage().isEmpty()) { + return false; + } + + Overlay* fadeToOverlay = overlaySet->getOverlay(fadeToOverlayIndex); + if ( ! fadeToOverlay->isEnabled()) { + appendToErrorMessage("Fade To Overlay is not enabled"); + } + Overlay* fadeFromOverlay = overlaySet->getOverlay(fadeFromOverlayIndex); + if ( ! fadeFromOverlay->isEnabled()) { + appendToErrorMessage("Fade From Overlay is not enabled"); + } + if ( ! getErrorMessage().isEmpty()) { + return false; + } + + CaretMappableDataFile* fadeToMapFile(NULL); + int32_t fadeToMapIndex(-1); + fadeToOverlay->getSelectionData(fadeToMapFile, fadeToMapIndex); + if (fadeToMapFile == NULL) { + appendToErrorMessage("Fade To Overlay does not contain a valid data file"); + } + + CaretMappableDataFile* fadeFromMapFile(NULL); + int32_t fadeFromMapIndex(-1); + fadeToOverlay->getSelectionData(fadeFromMapFile, fadeFromMapIndex); + if (fadeFromMapFile == NULL) { + appendToErrorMessage("Fade From Overlay does not contain a valid data file"); + } + + if ( ! getErrorMessage().isEmpty()) { + return false; + } + + bool successFlag = performCrossFadeVersionOne(executorOptions, + fadeToOverlay, + fadeFromOverlay, + durationSeconds); + + return successFlag; +} + +/** + * Perform crossfade version one + * + * @param executorOptions + * The executor options + * @param fadeToOverlay + * Overlay that starts with opacity zero and increases to one + * @param fadeFromOverlay + * Overlay that starts with opacity one and decreases to zero + * @param durationSeconds + * Total duration for cross fade + * @return + * True if successful, else false + */ +bool +WbMacroCustomOperationAnimateOverlayCrossFade::performCrossFadeVersionOne(const WuQMacroExecutorOptions* executorOptions, + Overlay* fadeToOverlay, + Overlay* fadeFromOverlay, + const float durationSeconds) +{ + CaretAssert(fadeToOverlay); + CaretAssert(fadeFromOverlay); + + const float defaultNumberOfSteps(25.0); + float numberOfSteps(0.0); + float iterationSleepTime(0.0); + getNumberOfStepsAndSleepTime(executorOptions, + defaultNumberOfSteps, + durationSeconds, + numberOfSteps, + iterationSleepTime); + + const float opacityDelta = 1.0 / numberOfSteps; + float fadeToOpacity(0.0); + float fadeFromOpacity(1.0); + + /* + * Initialize the opacities + */ + + for (int iStep = 0; iStep < numberOfSteps; iStep++) { + fadeToOverlay->setOpacity(fadeToOpacity); + fadeFromOverlay->setOpacity(fadeFromOpacity); + updateSurfaceColoring(); + updateUserInterface(); + updateGraphics(); + + fadeToOpacity += opacityDelta; + if (fadeToOpacity > 1.0) { + fadeToOpacity = 1.0; + } + fadeFromOpacity -= opacityDelta; + if (fadeFromOpacity < 0.0) { + fadeFromOpacity = 0.0; + } + + sleepForSecondsAtEndOfIteration(iterationSleepTime); + } + + fadeToOverlay->setOpacity(1.0); + fadeFromOverlay->setOpacity(0.0); + + updateSurfaceColoring(); + updateUserInterface(); + updateGraphics(); + + return true; +} + diff --git a/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.h b/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.h new file mode 100644 index 0000000000000000000000000000000000000000..03baf81e34cd0c89397f51cff2d8f26f0e5a2b88 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.h @@ -0,0 +1,94 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_H__ +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + +namespace caret { + class CaretMappableDataFile; + class Overlay; + class OverlaySet; + + class WbMacroCustomOperationAnimateOverlayCrossFade : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationAnimateOverlayCrossFade(); + + virtual ~WbMacroCustomOperationAnimateOverlayCrossFade(); + + WbMacroCustomOperationAnimateOverlayCrossFade(const WbMacroCustomOperationAnimateOverlayCrossFade&) = delete; + + WbMacroCustomOperationAnimateOverlayCrossFade& operator=(const WbMacroCustomOperationAnimateOverlayCrossFade&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + + + // ADD_NEW_METHODS_HERE + + private: + WuQMacroCommand* createCommandVersionOne(); + + WuQMacroCommand* createCommandVersionTwo(); + + virtual bool executeCommandVersionTwo(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand); + + bool performCrossFadeVersionTwo(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + OverlaySet* overlaySet, + const int32_t overlayIndex, + CaretMappableDataFile* fadeToMapFile, + const int32_t fadeToMapIndex, + const float durationSeconds); + + virtual bool executeCommandVersionOne(QWidget* parent, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand); + + bool performCrossFadeVersionOne(const WuQMacroExecutorOptions* executorOptions, + Overlay* fadeToOverlay, + Overlay* fadeFromOverlay, + const float durationSeconds); + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_H__ diff --git a/src/GuiQt/WbMacroCustomOperationAnimateRotation.cxx b/src/GuiQt/WbMacroCustomOperationAnimateRotation.cxx new file mode 100644 index 0000000000000000000000000000000000000000..205d338fb6a79d4d949837e7099d00d2dddd8594 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateRotation.cxx @@ -0,0 +1,252 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ +#include "WbMacroCustomOperationAnimateRotation.h" +#undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "Matrix4x4.h" +#include "Model.h" +#include "SystemUtilities.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationAnimateRotation + * \brief Macro custom operation for model rotation + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationAnimateRotation::WbMacroCustomOperationAnimateRotation() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION) +{ + +} + +/** + * Destructor. + */ +WbMacroCustomOperationAnimateRotation::~WbMacroCustomOperationAnimateRotation() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationAnimateRotation::createCommand() +{ + const int32_t versionOne(1); + + WuQMacroCommandParameter* paramOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::AXIS, + "Screen Axis", + "Y"); + + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION), + versionOne, + "none", + WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), + "Rotate the Brain Model About a Screen Axis", + 1.0, + errorMessage); + if (command != NULL) { + command->addParameter(paramOne); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Total Rotation (Degrees)", + (float)360.0); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Duration (secs)", + (float)15.0); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * Options for executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationAnimateRotation::executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 3)) { + return false; + } + const QString axisName(macroCommand->getParameterAtIndex(0)->getValue().toString().toUpper()); + const float totalRotation = macroCommand->getParameterAtIndex(1)->getValue().toFloat(); + const float durationSeconds = macroCommand->getParameterAtIndex(2)->getValue().toFloat(); + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running surface macro is not a browser window."); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window."); + return false; + } + + Axis axis = Axis::X; + if (axisName == "X") { + axis = Axis::X; + } + else if (axisName == "Y") { + axis = Axis::Y; + } + else if (axisName == "Z") { + axis = Axis::Z; + } + else { + appendToErrorMessage("Axis named \"" + + axisName + + "\" is invalid. Use X, Y, or Z."); + } + + if (totalRotation < 0.0) { + appendToErrorMessage("Total Rotation must be greater than zero."); + } + if (durationSeconds < 0.0) { + appendToErrorMessage("Duration must be greater than zero."); + } + + if ( ! getErrorMessage().isEmpty()) { + return false; + } + Model* model = tabContent->getModelForDisplay(); + if (model != NULL) { + } + + const bool successFlag = performRotation(executorMonitor, + executorOptions, + tabContent, + axis, + totalRotation, + durationSeconds); + return successFlag; +} + +/** + * Perform the rotation + * + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * executor options + * @param tabContent + * Content of the tab + * @param axis + * The screen axis of rotation + * @param totalRotation + * Total amount of rotation + * @param durationSeconds + * To time for command to run + * + */ +bool +WbMacroCustomOperationAnimateRotation::performRotation(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + BrowserTabContent* tabContent, + const Axis axis, + const float totalRotation, + const float durationSeconds) +{ + const float defaultNumberOfSteps(60.0); + float numberOfSteps(0.0); + float iterationSleepTime(0.0); + getNumberOfStepsAndSleepTime(executorOptions, + defaultNumberOfSteps, + durationSeconds, + numberOfSteps, + iterationSleepTime); + +// const double rotationIncrement = 1.0; +// const int32_t rotationStepCount = static_cast(totalRotation / rotationIncrement); +// const float sleepTimeSeconds = durationSeconds / rotationStepCount; + const int32_t rotationStepCount = numberOfSteps; + const float rotationIncrement = totalRotation / numberOfSteps; + + for (int32_t i = 0; i < rotationStepCount; i++) { + Matrix4x4 rotationMatrix = tabContent->getRotationMatrix(); + switch (axis) { + case Axis::X: + rotationMatrix.rotateX(rotationIncrement); + break; + case Axis::Y: + rotationMatrix.rotateY(rotationIncrement); + break; + case Axis::Z: + rotationMatrix.rotateZ(rotationIncrement); + break; + } + + tabContent->setRotationMatrix(rotationMatrix); + updateGraphics(); + + if (executorMonitor->testForStop()) { + appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); + return false; + } + + sleepForSecondsAtEndOfIteration(iterationSleepTime); + } + + return true; +} diff --git a/src/GuiQt/WbMacroCustomOperationAnimateRotation.h b/src/GuiQt/WbMacroCustomOperationAnimateRotation.h new file mode 100644 index 0000000000000000000000000000000000000000..69e8d627acd31ee5fed89599913da53c9ae47b70 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateRotation.h @@ -0,0 +1,80 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_H__ +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + + + +namespace caret { + + class BrowserTabContent; + + class WbMacroCustomOperationAnimateRotation : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationAnimateRotation(); + + virtual ~WbMacroCustomOperationAnimateRotation(); + + WbMacroCustomOperationAnimateRotation(const WbMacroCustomOperationAnimateRotation&) = delete; + + WbMacroCustomOperationAnimateRotation& operator=(const WbMacroCustomOperationAnimateRotation&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + + // ADD_NEW_METHODS_HERE + + private: + enum class Axis { + X, + Y, + Z + }; + + bool performRotation(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + BrowserTabContent* tabContent, + const Axis axis, + const float totalRotation, + const float durationSeconds); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_H__ diff --git a/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.cxx b/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f2d9ef32083ff9d1e54769d480d8d3ff5cf0dc4e --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.cxx @@ -0,0 +1,402 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ +#include "WbMacroCustomOperationAnimateSurfaceInterpolation.h" +#undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "EventDataFileAdd.h" +#include "EventDataFileDelete.h" +#include "EventCaretDataFilesGet.h" +#include "FileInformation.h" +#include "GuiManager.h" +#include "MathFunctions.h" +#include "ModelSurface.h" +#include "ModelWholeBrain.h" +#include "SpecFile.h" +#include "Surface.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationAnimateSurfaceInterpolation + * \brief Custom Macro Command for Surface Interpolation + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationAnimateSurfaceInterpolation::WbMacroCustomOperationAnimateSurfaceInterpolation() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION) +{ +} + +/** + * Destructor. + */ +WbMacroCustomOperationAnimateSurfaceInterpolation::~WbMacroCustomOperationAnimateSurfaceInterpolation() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationAnimateSurfaceInterpolation::createCommand() +{ + const int32_t versionOne(1); + + WuQMacroCommandParameter* paramSurfaceOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, + "Starting Surface", + ""); + paramSurfaceOne->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::SURFACE)); + + WuQMacroCommandParameter* paramSurfaceTwo = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, + "Ending Surface", + ""); + paramSurfaceTwo->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::SURFACE)); + + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION), + versionOne, + "none", + WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), + "Interpolate Between Two Surfaces", + 1.0, + errorMessage); + if (command != NULL) { + command->addParameter(paramSurfaceOne); + command->addParameter(paramSurfaceTwo); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Duration (secs)", + (float)5.0); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * Options for executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationAnimateSurfaceInterpolation::executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 3)) { + return false; + } + const QString startSurfaceName(macroCommand->getParameterAtIndex(0)->getValue().toString()); + Surface* startSurface = findSurface(startSurfaceName, + "Starting surface"); + const QString endSurfaceName(macroCommand->getParameterAtIndex(1)->getValue().toString()); + Surface* endSurface = findSurface(endSurfaceName, + "Ending surface"); + const float durationSeconds = macroCommand->getParameterAtIndex(2)->getValue().toFloat(); + + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running surface macro is not a browser window"); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window"); + return false; + } + + ModelWholeBrain* wholeBrainModel = tabContent->getDisplayedWholeBrainModel(); + if (wholeBrainModel == NULL) { + appendToErrorMessage("View selected is not ALL view"); + return false; + } + + if ((startSurface != NULL) + && (endSurface != NULL)) { + if (startSurface == endSurface) { + appendToErrorMessage("Starting and ending surfaces are the same surfaces"); + } + if (startSurface->getStructure() != endSurface->getStructure()) { + appendToErrorMessage("The surfaces' structures are different"); + } + if (startSurface->getNumberOfNodes() != endSurface->getNumberOfNodes()) { + appendToErrorMessage("The surfaces contain a different number of vertices"); + } + switch (startSurface->getStructure()) { + case StructureEnum::CEREBELLUM: + case StructureEnum::CORTEX_LEFT: + case StructureEnum::CORTEX_RIGHT: + break; + default: + appendToErrorMessage("Supported surface structures are: " + + StructureEnum::toGuiName(StructureEnum::CEREBELLUM) + ", " + + StructureEnum::toGuiName(StructureEnum::CORTEX_LEFT) + ", " + + StructureEnum::toGuiName(StructureEnum::CORTEX_RIGHT)); + break; + } + } + + if ( ! getErrorMessage().isEmpty()) { + return false; + } + + bool successFlag = interpolateSurface(executorMonitor, + executorOptions, + tabContent->getTabNumber(), + wholeBrainModel, + startSurface, + endSurface, + durationSeconds); + + return successFlag; +} + +/** + * Interpolate from starting to ending surface + * + * @param executorMonitor + * The macro executor's monitor + * @param executorOptions + * The executor options + * @param tabIndex + * Index of selected tab + * @param wholeBrainModel + * The whole brain model + * @param startSurface + * The starting surface + * @param endSurface + * The ending surface + * @param durationSeconds + * Total duration for surface interpolation + * @return + * True if successful, else false + */ +bool +WbMacroCustomOperationAnimateSurfaceInterpolation::interpolateSurface(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const int32_t tabIndex, + ModelWholeBrain* wholeBrainModel, + const Surface* startSurface, + const Surface* endSurface, + const float durationSeconds) +{ + CaretAssert(wholeBrainModel); + CaretAssert(startSurface); + CaretAssert(endSurface); + + const float defaultNumberOfSteps(50.0); + float numberOfSteps(0.0); + float iterationSleepTime(0.0); + getNumberOfStepsAndSleepTime(executorOptions, + defaultNumberOfSteps, + durationSeconds, + numberOfSteps, + iterationSleepTime); + + const StructureEnum::Enum structure = startSurface->getStructure(); + + createInterpolationSurface(startSurface); + CaretAssert(m_interpolationSurface); + + const float* startingXYZ = startSurface->getCoordinateData(); + const float* endingXYZ = endSurface->getCoordinateData(); + + /* + * XYZ that will be interpolated + */ + const int32_t numberOfVertices = endSurface->getNumberOfNodes(); + const int32_t numberOfComponents = numberOfVertices * 3; + + /* + * Initialize with starting coordinates + */ + std::vector xyz(startingXYZ, + startingXYZ + numberOfComponents); + + /* + * Amount to move each interpolation iteration + */ + std::vector deltaXYZ(numberOfComponents); + for (int32_t i = 0; i < numberOfComponents; i++) { + const float distance = endingXYZ[i] - startingXYZ[i]; + const float stepDistance = distance / numberOfSteps; + CaretAssertVectorIndex(deltaXYZ, i); + deltaXYZ[i] = stepDistance; + } + + /* + * Put interpolation surface into view + */ + wholeBrainModel->setSelectedSurfaceType(tabIndex, + m_interpolationSurface->getSurfaceType()); + wholeBrainModel->setSelectedSurface(structure, + tabIndex, + m_interpolationSurface); + + updateUserInterface(); + updateGraphics(); + + for (int iStep = 0; iStep < numberOfSteps; iStep++) { + /* + * Move coordinate components + */ + for (int32_t i = 0; i < numberOfComponents; i++) { + CaretAssertVectorIndex(xyz, i); + CaretAssertVectorIndex(deltaXYZ, i); + xyz[i] += deltaXYZ[i]; + } + + + /* + * Update surface coordinates + */ + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i3 = i * 3; + m_interpolationSurface->setCoordinate(i, + &xyz[i3]); + } + m_interpolationSurface->invalidateNormals(); + m_interpolationSurface->computeNormals(); + + const bool debugFlag(false); + if (debugFlag) { + const int32_t vertexIndex = 16764; + const float* p = endSurface->getCoordinate(vertexIndex); + std::cout << "XYZ " << iStep << ": " + << AString::number(p[0]) << " " + << AString::number(p[1]) << " " + << AString::number(p[2]) << std::endl; + } + + updateGraphics(); + + if (executorMonitor->testForStop()) { + appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); + return false; + } + + sleepForSecondsAtEndOfIteration(iterationSleepTime); + } + + /* + * View ending surface + */ + /* + * Put interpolation surface into view + */ + wholeBrainModel->setSelectedSurfaceType(tabIndex, + endSurface->getSurfaceType()); + wholeBrainModel->setSelectedSurface(structure, + tabIndex, + const_cast(endSurface)); + + updateGraphics(); + updateUserInterface(); + + deleteInterpolationSurface(); + + return true; +} + +/** + * Create the interpolation surface + * + * @param surface + * Surface that is copied to create the interpolation surface + */ +void +WbMacroCustomOperationAnimateSurfaceInterpolation::createInterpolationSurface(const Surface* surface) +{ + CaretAssert(surface); + + std::vector specFileVector = EventCaretDataFilesGet::getCaretDataFilesForType(DataFileTypeEnum::SPECIFICATION); + if ( ! specFileVector.empty()) { + m_specFile = dynamic_cast(specFileVector[0]); + m_specFileModificationStatus = m_specFile->isModified(); + } + + m_interpolationSurface = new Surface(*surface); + CaretAssert(m_interpolationSurface); + + FileInformation fileInfo(m_interpolationSurface->getFileName()); + AString path, name, ext; + fileInfo.getFileComponents(path, name, ext); + const AString newName = FileInformation::assembleFileComponents(path, "Interpolation", ext); + m_interpolationSurface->setFileName(newName); + + EventDataFileAdd addSurfaceEvent(m_interpolationSurface); + EventManager::get()->sendEvent(addSurfaceEvent.getPointer()); +} + +/** + * Delete the interpolation surface + */ +void +WbMacroCustomOperationAnimateSurfaceInterpolation::deleteInterpolationSurface() +{ + if (m_interpolationSurface != NULL) { + EventDataFileDelete deleteFileEvent(m_interpolationSurface); + EventManager::get()->sendEvent(deleteFileEvent.getPointer()); + } + + if (m_specFile != NULL) { + if ( ! m_specFileModificationStatus) { + m_specFile->clearModified(); + } + } +} + diff --git a/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.h b/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.h new file mode 100644 index 0000000000000000000000000000000000000000..51d4495e09c931bf2c21a0b64c20de7bd50d8078 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.h @@ -0,0 +1,87 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_H__ +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + +namespace caret { + + class ModelSurface; + class ModelWholeBrain; + class SpecFile; + class Surface; + + class WbMacroCustomOperationAnimateSurfaceInterpolation : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationAnimateSurfaceInterpolation(); + + virtual ~WbMacroCustomOperationAnimateSurfaceInterpolation(); + + WbMacroCustomOperationAnimateSurfaceInterpolation(const WbMacroCustomOperationAnimateSurfaceInterpolation&) = delete; + + WbMacroCustomOperationAnimateSurfaceInterpolation& operator=(const WbMacroCustomOperationAnimateSurfaceInterpolation&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + + + // ADD_NEW_METHODS_HERE + + private: + bool interpolateSurface(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const int32_t tabIndex, + ModelWholeBrain* wholeBrainModel, + const Surface* startSurface, + const Surface* endSurface, + const float durationSeconds); + + void createInterpolationSurface(const Surface* surface); + + void deleteInterpolationSurface(); + + Surface* m_interpolationSurface = NULL; + + SpecFile* m_specFile = NULL; + + bool m_specFileModificationStatus = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_H__ diff --git a/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.cxx b/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1edf91d78fc67abe8e4b72619ddbac054e815d5c --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.cxx @@ -0,0 +1,330 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ +#include "WbMacroCustomOperationAnimateVolumeSliceSequence.h" +#undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "Matrix4x4.h" +#include "Model.h" +#include "ModelVolume.h" +#include "ModelWholeBrain.h" +#include "Overlay.h" +#include "OverlaySet.h" +#include "SystemUtilities.h" +#include "VolumeMappableInterface.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationAnimateVolumeSliceSequence + * \brief Macro custom operation incrementing volume slices + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationAnimateVolumeSliceSequence::WbMacroCustomOperationAnimateVolumeSliceSequence() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_SLICE_SEQUENCE) +{ + +} + +/** + * Destructor. + */ +WbMacroCustomOperationAnimateVolumeSliceSequence::~WbMacroCustomOperationAnimateVolumeSliceSequence() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationAnimateVolumeSliceSequence::createCommand() +{ + const int32_t versionOne(1); + + + const QString description("Sequence through the volume slices: \n" + "(1) start at the \"selected slice\"; \n" + "(2) decrement the slice index to the first slice; \n" + "(3) increment the slice index to the last slice; \n" + "(4) decrement the slice index returning to the \"selected slice\""); + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), + versionOne, + "none", + WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), + description, + 1.0, + errorMessage); + if (command != NULL) { + WuQMacroCommandParameter* paramOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::AXIS, + "Volume Axis", + "Z"); + command->addParameter(paramOne); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Duration (secs)", + (float)20.0); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * Options for executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationAnimateVolumeSliceSequence::executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 2)) { + return false; + } + const QString axisName(macroCommand->getParameterAtIndex(0)->getValue().toString().toUpper()); + const float durationSeconds = macroCommand->getParameterAtIndex(1)->getValue().toFloat(); + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running surface macro is not a browser window."); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window."); + return false; + } + + + Axis axis = Axis::X; + if (axisName == "X") { + axis = Axis::X; + } + else if (axisName == "Y") { + axis = Axis::Y; + } + else if (axisName == "Z") { + axis = Axis::Z; + } + else { + appendToErrorMessage("Axis named \"" + + axisName + + "\" is invalid. Use X, Y, or Z."); + } + + if (durationSeconds < 0.0) { + appendToErrorMessage("Duration must be greater than zero."); + } + + Model* model = tabContent->getModelForDisplay(); + if (model == NULL) { + appendToErrorMessage("No model for surface rotation"); + } + + if ( ! getErrorMessage().isEmpty()) { + return false; + } + + const bool successFlag = performSliceIncrement(executorMonitor, + executorOptions, + tabContent, + axis, + durationSeconds); + return successFlag; +} + +/** + * @param executorMonitor + * The macro executor's monitor + * @param executorOptions + * The executor options + * @param tabContent + * Content in the selected tab + * @param axis + * Axis for viewing + * @param durationSecondes + * Duration of time for command to run + */ +bool +WbMacroCustomOperationAnimateVolumeSliceSequence::performSliceIncrement(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + BrowserTabContent* tabContent, + const Axis axis, + const float durationSeconds) +{ + ModelVolume* volumeModel(tabContent->getDisplayedVolumeModel()); + ModelWholeBrain* wholeBrainModel(tabContent->getDisplayedWholeBrainModel()); + if ((volumeModel == NULL) + && (wholeBrainModel == NULL)) { + appendToErrorMessage("For slice increment, View must be All or Volume"); + return false; + } + + const VolumeMappableInterface* vmi = tabContent->getOverlaySet()->getUnderlayVolume(); + if (vmi == NULL) { + appendToErrorMessage("No volume is selected as an overlay"); + return false; + } + std::vector dims; + vmi->getDimensions(dims); + if (dims.size() < 3) { + appendToErrorMessage("Dimensions are invalid for underlay volume"); + } + + int32_t numberOfSlices(0); + int32_t startingSliceIndex(0); + switch (axis) { + case Axis::X: + numberOfSlices = dims[0]; + startingSliceIndex = tabContent->getSliceIndexParasagittal(vmi); + break; + case Axis::Y: + numberOfSlices = dims[1]; + startingSliceIndex = tabContent->getSliceIndexCoronal(vmi); + break; + case Axis::Z: + numberOfSlices = dims[2]; + startingSliceIndex = tabContent->getSliceIndexAxial(vmi); + break; + } + if (numberOfSlices <= 0) { + appendToErrorMessage("No slices in underlay volume for selected dimension"); + } + + const float defaultNumberOfSteps(numberOfSlices); + float numberOfSteps(0.0); + float iterationSleepTime(0.0); + getNumberOfStepsAndSleepTime(executorOptions, + defaultNumberOfSteps, + durationSeconds, + numberOfSteps, + iterationSleepTime); + + enum SliceMode { + DECREMENT_TO_ZERO, + INCREMENT_TO_LAST, + DECREMENT_TO_START + }; + SliceMode sliceMode = DECREMENT_TO_ZERO; + + float sliceIndex = startingSliceIndex; + float sliceIncrement = numberOfSlices / (numberOfSteps / 2); + + bool doneFlag(false); + while ( ! doneFlag) { + switch (axis) { + case Axis::X: + tabContent->setSliceIndexParasagittal(vmi, sliceIndex); + break; + case Axis::Y: + tabContent->setSliceIndexCoronal(vmi, sliceIndex); + break; + case Axis::Z: + tabContent->setSliceIndexAxial(vmi, sliceIndex); + break; + } + + switch (sliceMode) { + case DECREMENT_TO_START: + sliceIndex -= sliceIncrement; + if (sliceIndex <= startingSliceIndex) { + doneFlag = true; + } + break; + case DECREMENT_TO_ZERO: + sliceIndex -= sliceIncrement; + if (sliceIndex <= 0.0) { + sliceIndex = 0; + sliceMode = INCREMENT_TO_LAST; + } + break; + case INCREMENT_TO_LAST: + sliceIndex += sliceIncrement; + if (sliceIndex >= (numberOfSlices - 1)) { + sliceIndex = (numberOfSlices - 1); + sliceMode = DECREMENT_TO_START; + } + break; + } + + + updateGraphics(); + + if (executorMonitor->testForStop()) { + appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); + return false; + } + + sleepForSecondsAtEndOfIteration(iterationSleepTime); + } + + switch (axis) { + case Axis::X: + tabContent->setSliceIndexParasagittal(vmi, startingSliceIndex); + break; + case Axis::Y: + tabContent->setSliceIndexCoronal(vmi, startingSliceIndex); + break; + case Axis::Z: + tabContent->setSliceIndexAxial(vmi, startingSliceIndex); + break; + } + updateGraphics(); + + return true; +} diff --git a/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.h b/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.h new file mode 100644 index 0000000000000000000000000000000000000000..a57c5afe4ad387689131bc5dda77cf21885f1b56 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.h @@ -0,0 +1,79 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_SEQUENCE_H__ +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_SEQUENCE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + + + +namespace caret { + + class BrowserTabContent; + + class WbMacroCustomOperationAnimateVolumeSliceSequence : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationAnimateVolumeSliceSequence(); + + virtual ~WbMacroCustomOperationAnimateVolumeSliceSequence(); + + WbMacroCustomOperationAnimateVolumeSliceSequence(const WbMacroCustomOperationAnimateVolumeSliceSequence&) = delete; + + WbMacroCustomOperationAnimateVolumeSliceSequence& operator=(const WbMacroCustomOperationAnimateVolumeSliceSequence&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + + // ADD_NEW_METHODS_HERE + + private: + enum class Axis { + X, + Y, + Z + }; + + bool performSliceIncrement(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + BrowserTabContent* tabContent, + const Axis axis, + const float durationSeconds); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_SEQUENCE_H__ diff --git a/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.cxx b/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.cxx new file mode 100644 index 0000000000000000000000000000000000000000..43d2313f4acf36ecb1dc16362ca3883e44eca100 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.cxx @@ -0,0 +1,256 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ +#include "WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h" +#undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ + +#include "Brain.h" +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "DisplayPropertiesSurface.h" +#include "DisplayPropertiesVolume.h" +#include "GuiManager.h" +#include "ModelWholeBrain.h" +#include "Overlay.h" +#include "OverlaySet.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade + * \brief Custom Macro Command for Surface Interpolation + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE) +{ +} + +/** + * Destructor. + */ +WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::~WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::createCommand() +{ + const int32_t versionOne(1); + + const QString description("Crossfade (blend) from volume to surface:\n" + "ALL View must be selected.\n" + "(1) The opacity of the surface is set to zero;\n" + "(2) The opacity of the volume overlay is set to one\n" + "(3) The opacity of the surface increases until it is one\n" + " and simultaneously, the opacity of the volume\n" + " decreases until it reaches zero.\n"); + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), + versionOne, + "none", + WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), + description, + 1.0, + errorMessage); + if (command != NULL) { +// command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, +// "Fade from Overlay", +// (int)2); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Duration (secs)", + (float)10.0); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * Options for executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 1)) { + return false; + } + const float durationSeconds(macroCommand->getParameterAtIndex(0)->getValue().toFloat()); + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running surface macro is not a browser window"); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window"); + return false; + } + + ModelWholeBrain* wholeBrainModel = tabContent->getDisplayedWholeBrainModel(); + if (wholeBrainModel == NULL) { + appendToErrorMessage("All view must be selected"); + return false; + } + + OverlaySet* overlaySet = tabContent->getOverlaySet(); + CaretAssert(overlaySet); + + Overlay* volumeOverlay = overlaySet->getUnderlayContainingVolume(); + if (volumeOverlay == NULL) { + appendToErrorMessage("An overlay must contain a volume"); + return false; + } + if ( ! getErrorMessage().isEmpty()) { + return false; + } + + + bool successFlag = performCrossFade(executorMonitor, + executorOptions, + volumeOverlay, + durationSeconds); + + return successFlag; +} + +/** + * Interpolate from starting to ending surface + * + * @param executorMonitor + * The macro executor's monitor + * @param executorOptions + * The executor options + * @param volumeOverlay + * Overlay that contains the volume + * @param durationSeconds + * Total duration for cross fade + * @return + * True if successful, else false + */ +bool +WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::performCrossFade(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + Overlay* volumeOverlay, + const float durationSeconds) +{ + CaretAssert(volumeOverlay); + + const float defaultNumberOfSteps(25.0); + float numberOfSteps(0.0); + float iterationSleepTime(0.0); + getNumberOfStepsAndSleepTime(executorOptions, + defaultNumberOfSteps, + durationSeconds, + numberOfSteps, + iterationSleepTime); + + const float opacityDelta = 1.0 / numberOfSteps; + float surfaceOpacity(0.0); + float volumeOpacity(1.0); + + DisplayPropertiesSurface* surfaceProperties = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); + CaretAssert(surfaceProperties); + DisplayPropertiesVolume* volumeProperties = GuiManager::get()->getBrain()->getDisplayPropertiesVolume(); + CaretAssert(volumeProperties); + + /* + * Initialize the opacities + */ + + for (int iStep = 0; iStep < numberOfSteps; iStep++) { + surfaceProperties->setOpacity(surfaceOpacity); + volumeProperties->setOpacity(volumeOpacity); + volumeOverlay->setOpacity(volumeOpacity); + updateSurfaceColoring(); + updateUserInterface(); + updateGraphics(); + + surfaceOpacity += opacityDelta; + if (surfaceOpacity > 1.0) { + surfaceOpacity = 1.0; + } + volumeOpacity -= opacityDelta; + if (volumeOpacity < 0.0) { + volumeOpacity = 0.0; + } + + if (executorMonitor->testForStop()) { + appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); + return false; + } + + sleepForSecondsAtEndOfIteration(iterationSleepTime); + } + + surfaceProperties->setOpacity(1.0); + volumeProperties->setOpacity(0.0); + volumeOverlay->setOpacity(0.0); + + updateSurfaceColoring(); + updateUserInterface(); + updateGraphics(); + + return true; +} + diff --git a/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h b/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h new file mode 100644 index 0000000000000000000000000000000000000000..3790d6b37edda228a7b632904e9424ce037827b4 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h @@ -0,0 +1,72 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_H__ +#define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + +namespace caret { + + class Overlay; + + class WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(); + + virtual ~WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(); + + WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(const WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade&) = delete; + + WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade& operator=(const WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + + + // ADD_NEW_METHODS_HERE + + private: + bool performCrossFade(const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + Overlay* volumeOverlay, + const float durationSeconds); + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_H__ diff --git a/src/GuiQt/WbMacroCustomOperationBase.cxx b/src/GuiQt/WbMacroCustomOperationBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4c5ad830cae674bffc3df1556da4eac311830a8f --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationBase.cxx @@ -0,0 +1,296 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ +#include "WbMacroCustomOperationBase.h" +#undef __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "EventSurfaceColoringInvalidate.h" +#include "EventSurfacesGet.h" +#include "EventUserInterfaceUpdate.h" +#include "MovieRecorder.h" +#include "SessionManager.h" +#include "Surface.h" +#include "SystemUtilities.h" +#include "WuQMacroCommand.h" +#include "WuQMacroExecutorOptions.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationBase + * \brief Base class for all macro custom operations + * \ingroup GuiQt + */ + +/** + * Constructor + * + * @param operationTye + * Type of custom command operation + */ +WbMacroCustomOperationBase::WbMacroCustomOperationBase(const WbMacroCustomOperationTypeEnum::Enum operationType) +: m_operationType(operationType) +{ + +} + + +/** + * Destructor + */ +WbMacroCustomOperationBase::~WbMacroCustomOperationBase() +{ + +} + +/** + * @return The custom operation type + */ +WbMacroCustomOperationTypeEnum::Enum +WbMacroCustomOperationBase::getOperationType() const +{ + return m_operationType; +} + +/** + * @return The error message + */ +QString +WbMacroCustomOperationBase::getErrorMessage() const +{ + return m_errorMessage; +} + +/** + * Validate that the command contains the correct number of parameters + * + * @param command + * The command + * @param correctNumberOfParameters + * The correct number of parameters (this must be passed in since a command + * may change its number of parameters in a new version of the command) + */ +bool +WbMacroCustomOperationBase::validateCorrectNumberOfParameters(const WuQMacroCommand* command, + const int32_t correctNumberOfParameters) +{ + const int32_t paramCount = command->getNumberOfParameters(); + + if (paramCount < correctNumberOfParameters) { + appendToErrorMessage("Command " + + command->getDescriptiveName() + + " should contain " + + QString::number(correctNumberOfParameters) + + " parameters but contains " + + QString::number(paramCount) + + " parameters"); + return false; + } + + return true; +} + +/** + * Append text to the error message. If the current error message + * is not empty, a newline is added prior to the text. + * + * @param text + * Text to append to error message + */ +void +WbMacroCustomOperationBase::appendToErrorMessage(const QString& text) +{ + if ( m_errorMessage.isEmpty()) { + m_errorMessage.append("\n"); + } + m_errorMessage.append(text); +} + +/** + * Create a unsupported version messagge and append it to the error message. + * + * @param unsupportedVersionNumber + * Verson not supported + */ +void +WbMacroCustomOperationBase::appendUnsupportedVersionToErrorMessage(const int32_t unsupportedVersionNumber) +{ + QString msg("Version " + + QString::number(unsupportedVersionNumber) + + " is not supported for " + + getOperationName() + + ". You may need to update your version of wb_view"); + appendToErrorMessage(msg); +} + + +/** + * Find the surface with the given name + * + * @param name + * Name of surface + * @param errorMessagePrefix + * Prefix inserted into error message if an error occurs + * @return + * Pointer to surface or NULL if not found. + * If not found getErrorMessage() explains why + */ +Surface* +WbMacroCustomOperationBase::findSurface(const QString& name, + const QString& errorMessagePrefix) +{ + if (name.isEmpty()) { + appendToErrorMessage(errorMessagePrefix + + " name is empty"); + return NULL; + } + + EventSurfacesGet eventSurfaces; + EventManager::get()->sendEvent(eventSurfaces.getPointer()); + std::vector allSurfaces = eventSurfaces.getSurfaces(); + + for (auto s : allSurfaces) { + if (s->getFileName().endsWith(name)) { + return s; + } + } + + appendToErrorMessage(errorMessagePrefix + + " with name \"" + + name + + "\" not found."); + return NULL; + +} + +/** + * Update graphics + */ +void +WbMacroCustomOperationBase::updateGraphics() +{ + /* + * Passing 'true' indicate do a repaint(). A 'repaint' is performed immediately. + * Otherwise, the graphics update is scheduled for a later time. + */ + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows(true).getPointer()); + + /* + * Qt needs time to update stuff + */ + QApplication::processEvents(); +} + +/** + * Update the user-interface + */ +void +WbMacroCustomOperationBase::updateUserInterface() +{ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} + +/** + * Update surface coloring + */ +void +WbMacroCustomOperationBase::updateSurfaceColoring() +{ + EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); +} + +/** + * Get number of steps and sleep time. If a movie is being recorded, the number of + * steps is set so that the command will run for the requested duration using the + * frame rate of the movie recorder. If a movie + * is NOT being recorded, the number of steps out is the default number of steps and + * the sleep time is set so that the command will run for approximately the duration. + * + * @param defaultNumberOfSteps + * The default number of steps used when a movie is not being recorded + * @param durationSeconds + * The number of seconds for which the command should run + * @param numberOfStepsOut + * Output with number of steps for the command + * @param sleepTimeOut + * Output with time command should sleep at the end of each iteration + * when a movie is not being recorded + */ +void +WbMacroCustomOperationBase::getNumberOfStepsAndSleepTime(const WuQMacroExecutorOptions* executorOptions, + const float defaultNumberOfSteps, + const float durationSeconds, + float& numberOfStepsOut, + float& sleepTimeOut) +{ + numberOfStepsOut = defaultNumberOfSteps; + sleepTimeOut = 0.0; + + const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + switch (movieRecorder->getRecordingMode()) { + case MovieRecorderModeEnum::MANUAL: + sleepTimeOut = durationSeconds / numberOfStepsOut; + break; + case MovieRecorderModeEnum::AUTOMATIC: + numberOfStepsOut = (durationSeconds + * movieRecorder->getFramesRate()); + break; + } + + if (executorOptions->isIgnoreDelaysAndDurations()) { + sleepTimeOut = 0.0; + numberOfStepsOut = 2; + } +} + +/** + * Sleep for the given number of seconds at the end of an iteration + * + * @param seconds + * Seconds to sleep + */ +void +WbMacroCustomOperationBase::sleepForSecondsAtEndOfIteration(const float seconds) +{ + if (seconds > 0.0) { + SystemUtilities::sleepSeconds(seconds); + } +} + +/** + * @return User friendly name for command + * Sub-classes may override to provide more descriptive name + */ +QString +WbMacroCustomOperationBase::getOperationName() const +{ + return WbMacroCustomOperationTypeEnum::toGuiName(m_operationType); +} + + diff --git a/src/GuiQt/WbMacroCustomOperationBase.h b/src/GuiQt/WbMacroCustomOperationBase.h new file mode 100644 index 0000000000000000000000000000000000000000..89f910cc600e524b78eb4e6d4b18a696c532a4f1 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationBase.h @@ -0,0 +1,121 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_BASE_H__ +#define __WB_MACRO_CUSTOM_OPERATION_BASE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" +#include "WbMacroCustomOperationTypeEnum.h" + +class QString; +class QWidget; + +namespace caret { + class Surface; + class WuQMacroExecutorMonitor; + class WuQMacroExecutorOptions; + class WuQMacroCommand; + + class WbMacroCustomOperationBase : public CaretObject { + public: + ~WbMacroCustomOperationBase(); + + WbMacroCustomOperationBase(const WbMacroCustomOperationBase&) = delete; + + WbMacroCustomOperationBase& operator=(const WbMacroCustomOperationBase&) = delete; + + WbMacroCustomOperationTypeEnum::Enum getOperationType() const; + + /** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions, + * Options for the executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) = 0; + + /** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ + virtual WuQMacroCommand* createCommand() = 0; + + QString getErrorMessage() const; + + void sleepForSecondsAtEndOfIteration(const float seconds); + + virtual QString getOperationName() const; + + protected: + WbMacroCustomOperationBase(const WbMacroCustomOperationTypeEnum::Enum operationType); + + void getNumberOfStepsAndSleepTime(const WuQMacroExecutorOptions* executorOptions, + const float defaultNumberOfSteps, + const float durationSeconds, + float& numberOfStepsOut, + float& sleepTimeOut); + + bool validateCorrectNumberOfParameters(const WuQMacroCommand* command, + const int32_t correctNumberOfParameters); + + Surface* findSurface(const QString& surfaceName, + const QString& errorMessagePrefix); + + void appendToErrorMessage(const QString& text); + + void appendUnsupportedVersionToErrorMessage(const int32_t unsupportedVersionNumber); + + void updateGraphics(); + + void updateSurfaceColoring(); + + void updateUserInterface(); + + const WbMacroCustomOperationTypeEnum::Enum m_operationType; + + QString m_errorMessage; + }; + + +#ifdef __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_BASE_H__ diff --git a/src/GuiQt/WbMacroCustomOperationDelay.cxx b/src/GuiQt/WbMacroCustomOperationDelay.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d4b65788ed4ed08bff4c8c6af07a0f6805c2a0ea --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationDelay.cxx @@ -0,0 +1,109 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ +#include "WbMacroCustomOperationDelay.h" +#undef __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ + +#include "CaretAssert.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationDelay + * \brief Custom Macro Command for Delay + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationDelay::WbMacroCustomOperationDelay() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::DELAY) +{ +} + +/** + * Destructor. + */ +WbMacroCustomOperationDelay::~WbMacroCustomOperationDelay() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationDelay::createCommand() +{ + const int32_t versionOne(1); + + /* + * No parameters are needed as the base command's delay value is used + */ + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::DELAY), + versionOne, + "none", + "Delay", + "Delay for Seconds", + 5.0, + errorMessage); + + return command; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * Options for executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationDelay::executeCommand(QWidget* /*parent*/, + const WuQMacroExecutorMonitor* /*executorMonitor*/, + const WuQMacroExecutorOptions* /*executorOptions*/, + const WuQMacroCommand* /*macroCommand*/) +{ + /* + * Nothing to do since the base command's delay time performs the delay + */ + return true; +} + diff --git a/src/GuiQt/WbMacroCustomOperationDelay.h b/src/GuiQt/WbMacroCustomOperationDelay.h new file mode 100644 index 0000000000000000000000000000000000000000..0f0848a99933f6508273934ff1d3a543dd887c77 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationDelay.h @@ -0,0 +1,62 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_DELAY_H__ +#define __WB_MACRO_CUSTOM_OPERATION_DELAY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + +namespace caret { + + class WbMacroCustomOperationDelay : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationDelay(); + + virtual ~WbMacroCustomOperationDelay(); + + WbMacroCustomOperationDelay(const WbMacroCustomOperationDelay&) = delete; + + WbMacroCustomOperationDelay& operator=(const WbMacroCustomOperationDelay&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + // ADD_NEW_METHODS_HERE + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_DELAY_H__ diff --git a/src/GuiQt/WbMacroCustomOperationIncrementRotation.cxx b/src/GuiQt/WbMacroCustomOperationIncrementRotation.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cc6319e24e6b2634f5997a3449b41d29fe228c76 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationIncrementRotation.cxx @@ -0,0 +1,232 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ +#include "WbMacroCustomOperationIncrementRotation.h" +#undef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "Matrix4x4.h" +#include "Model.h" +#include "SystemUtilities.h" +#include "ViewingTransformations.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationIncrementRotation + * \brief Macro custom operation for incremental rotation + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationIncrementRotation::WbMacroCustomOperationIncrementRotation() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::INCREMENTAL_ROTATION) +{ + +} + +/** + * Destructor. + */ +WbMacroCustomOperationIncrementRotation::~WbMacroCustomOperationIncrementRotation() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationIncrementRotation::createCommand() +{ + const int32_t versionOne(1); + + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), + versionOne, + "none", + WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), + "Incremental Rotation (degrees) About Screen Axis", + 1.0, + errorMessage); + if (command != NULL) { + command->addParameter(WuQMacroDataValueTypeEnum::AXIS, + "Screen Axis", + "Y"); + command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, + "Rotation (Degrees)", + (float)360.0); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * Options for executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationIncrementRotation::executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* /*executorMonitor*/, + const WuQMacroExecutorOptions* /*executorOptions*/, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 2)) { + return false; + } + const QString axisName(macroCommand->getParameterAtIndex(0)->getValue().toString().toUpper()); + const float incrementalRotation = macroCommand->getParameterAtIndex(1)->getValue().toFloat(); + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running surface macro is not a browser window."); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window."); + return false; + } + + Axis axis = Axis::X; + if (axisName == "X") { + axis = Axis::X; + } + else if (axisName == "Y") { + axis = Axis::Y; + } + else if (axisName == "Z") { + axis = Axis::Z; + } + else { + appendToErrorMessage("Axis named \"" + + axisName + + "\" is invalid. Use X, Y, or Z."); + return false; + } + + Model* model = tabContent->getModelForDisplay(); + if (model == NULL) { + appendToErrorMessage("No model is displayed that can be rotated"); + return false; + } + + + + int32_t mousePressX(0); + int32_t mousePressY(0); + int32_t mouseX(0); + int32_t mouseY(0); + int32_t mouseDeltaX(0); + int32_t mouseDeltaY(0); + bool doMouseFlag(false); + bool doZFlag(false); + switch (axis) { + case Axis::X: + doMouseFlag = true; + mousePressX = 50; + mouseX = 50; + mouseDeltaY = incrementalRotation; + if (mouseDeltaY >= 0.0) { + mousePressY = 1; + mouseY = mouseDeltaY + mousePressY; + } + else { + mouseY = 1; + mousePressY = 1 - mouseDeltaY; + } + break; + case Axis::Y: + doMouseFlag = true; + mousePressY = 50; + mouseY = 50; + mouseDeltaX = incrementalRotation; + if (mouseDeltaX >= 0.0) { + mousePressX = 1; + mouseX = mouseDeltaX + mousePressX; + } + else { + mouseX = 1; + mousePressX = 1 - mouseDeltaX; + } + break; + case Axis::Z: + if (incrementalRotation != 0.0) { + doZFlag = true; + } + break; + } + + if (doMouseFlag) { + BrainOpenGLViewportContent* viewportContent(NULL); + tabContent->applyMouseRotation(viewportContent, + mousePressX, + mousePressY, + mouseX, + mouseY, + mouseDeltaX, + mouseDeltaY); + } + else if (doZFlag) { + ViewingTransformations* viewingTransform = tabContent->getViewingTransformation(); + Matrix4x4 rotationMatrix = viewingTransform->getRotationMatrix(); + rotationMatrix.rotateZ(incrementalRotation); + viewingTransform->setRotationMatrix(rotationMatrix); + } + + updateGraphics(); + updateUserInterface(); + + return true; +} diff --git a/src/GuiQt/WbMacroCustomOperationIncrementRotation.h b/src/GuiQt/WbMacroCustomOperationIncrementRotation.h new file mode 100644 index 0000000000000000000000000000000000000000..b33a8cb41c31abfe965ec7a776baf1e401f1c7de --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationIncrementRotation.h @@ -0,0 +1,74 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_H__ +#define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + + + +namespace caret { + + class BrowserTabContent; + + class WbMacroCustomOperationIncrementRotation : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationIncrementRotation(); + + virtual ~WbMacroCustomOperationIncrementRotation(); + + WbMacroCustomOperationIncrementRotation(const WbMacroCustomOperationIncrementRotation&) = delete; + + WbMacroCustomOperationIncrementRotation& operator=(const WbMacroCustomOperationIncrementRotation&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + + // ADD_NEW_METHODS_HERE + + private: + enum class Axis { + X, + Y, + Z + }; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_H__ diff --git a/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.cxx b/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f64d6fe49d2f1451c7830a0f857a61ffd0ffbd70 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.cxx @@ -0,0 +1,191 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ +#include "WbMacroCustomOperationIncrementVolumeSlice.h" +#undef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "Matrix4x4.h" +#include "Model.h" +#include "ModelVolume.h" +#include "ModelWholeBrain.h" +#include "SystemUtilities.h" +#include "ViewingTransformations.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroCustomOperationIncrementVolumeSlice + * \brief Macro custom operation for incremental rotation + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationIncrementVolumeSlice::WbMacroCustomOperationIncrementVolumeSlice() +: WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::INCREMENTAL_VOLUME_SLICE) +{ + +} + +/** + * Destructor. + */ +WbMacroCustomOperationIncrementVolumeSlice::~WbMacroCustomOperationIncrementVolumeSlice() +{ +} + +/** + * Get a new instance of the macro command + * + * @return + * Pointer to command or NULL if not valid + * Use getErrorMessage() for error information if NULL returned + */ +WuQMacroCommand* +WbMacroCustomOperationIncrementVolumeSlice::createCommand() +{ + const int32_t versionOne(1); + + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), + versionOne, + "none", + WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), + "Increment Volume Slice", + 1.0, + errorMessage); + if (command != NULL) { + command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Increment Slice Index By", + (int)1); + } + else { + appendToErrorMessage(errorMessage); + } + + return command; +} + +/** + * Execute the macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * the macro executor monitor + * @param executorOptions + * Options for executor + * @param macroCommand + * macro command to run + * @return + * True if command executed successfully, else false + * Use getErrorMessage() for error information if false returned + */ +bool +WbMacroCustomOperationIncrementVolumeSlice::executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* /*executorMonitor*/, + const WuQMacroExecutorOptions* /*executorOptions*/, + const WuQMacroCommand* macroCommand) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + if ( ! validateCorrectNumberOfParameters(macroCommand, 1)) { + return false; + } + + const float incrementSlice = macroCommand->getParameterAtIndex(0)->getValue().toFloat(); + + BrainBrowserWindow* bbw = qobject_cast(parent); + if (bbw == NULL) { + appendToErrorMessage("Parent for running macro is not a browser window."); + return false; + } + + BrowserTabContent* tabContent = bbw->getBrowserTabContent(); + if (tabContent == NULL) { + appendToErrorMessage("No tab is selected in browser window."); + return false; + } + const int32_t tabIndex = tabContent->getTabNumber(); + + VolumeMappableInterface* underlayVolumeFile(NULL); + ModelVolume* volumeModel = tabContent->getDisplayedVolumeModel(); + + if (volumeModel != NULL) { + underlayVolumeFile = volumeModel->getUnderlayVolumeFile(tabIndex); + } + ModelWholeBrain* wholeBrainModel = tabContent->getDisplayedWholeBrainModel(); + if (wholeBrainModel != NULL) { + underlayVolumeFile = wholeBrainModel->getUnderlayVolumeFile(tabIndex); + } + + if (underlayVolumeFile == NULL) { + appendToErrorMessage("Must have ALL or Volume view for slice increment or no volume is displayed."); + return false; + } + + int32_t sliceIndexAxial = tabContent->getSliceIndexAxial(underlayVolumeFile); + int32_t sliceIndexCoronal = tabContent->getSliceIndexCoronal(underlayVolumeFile); + int32_t sliceIndexParasagittal = tabContent->getSliceIndexParasagittal(underlayVolumeFile); + + VolumeSliceViewPlaneEnum::Enum slicePlane = tabContent->getSliceViewPlane(); + switch (slicePlane) { + case VolumeSliceViewPlaneEnum::ALL: + sliceIndexAxial += incrementSlice; + sliceIndexCoronal += incrementSlice; + sliceIndexParasagittal += incrementSlice; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + sliceIndexAxial += incrementSlice; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + sliceIndexCoronal += incrementSlice; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + sliceIndexParasagittal += incrementSlice; + break; + } + + tabContent->setSliceIndexAxial(underlayVolumeFile, + sliceIndexAxial); + tabContent->setSliceIndexCoronal(underlayVolumeFile, + sliceIndexCoronal); + tabContent->setSliceIndexParasagittal(underlayVolumeFile, + sliceIndexParasagittal); + + updateGraphics(); + updateUserInterface(); + + return true; +} diff --git a/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.h b/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.h new file mode 100644 index 0000000000000000000000000000000000000000..fd1cf1051b132e9b24eb65f7ac6a9c3261f5a206 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.h @@ -0,0 +1,74 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_H__ +#define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WbMacroCustomOperationBase.h" + + + +namespace caret { + + class BrowserTabContent; + + class WbMacroCustomOperationIncrementVolumeSlice : public WbMacroCustomOperationBase { + + public: + WbMacroCustomOperationIncrementVolumeSlice(); + + virtual ~WbMacroCustomOperationIncrementVolumeSlice(); + + WbMacroCustomOperationIncrementVolumeSlice(const WbMacroCustomOperationIncrementVolumeSlice&) = delete; + + WbMacroCustomOperationIncrementVolumeSlice& operator=(const WbMacroCustomOperationIncrementVolumeSlice&) = delete; + + virtual bool executeCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand) override; + + virtual WuQMacroCommand* createCommand() override; + + + // ADD_NEW_METHODS_HERE + + private: + enum class Axis { + X, + Y, + Z + }; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_H__ diff --git a/src/GuiQt/WbMacroCustomOperationManager.cxx b/src/GuiQt/WbMacroCustomOperationManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f92123655e50fdf3b6dbcbbf22fe33a97dae5a57 --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationManager.cxx @@ -0,0 +1,796 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ +#include "WbMacroCustomOperationManager.h" +#undef __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ + +#include + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "CaretMappableDataFile.h" +#include "EventCaretMappableDataFilesGet.h" +#include "EventManager.h" +#include "EventSurfacesGet.h" +#include "GuiManager.h" +#include "Overlay.h" +#include "OverlaySet.h" +#include "Surface.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroCustomOperationDelay.h" +#include "WbMacroCustomOperationAnimateRotation.h" +#include "WbMacroCustomOperationAnimateOverlayCrossFade.h" +#include "WbMacroCustomOperationAnimateSurfaceInterpolation.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WbMacroCustomOperationAnimateVolumeSliceSequence.h" +#include "WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h" +#include "WbMacroCustomOperationIncrementRotation.h" +#include "WbMacroCustomOperationIncrementVolumeSlice.h" +#include "WbMacroCustomDataInfo.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMessageBox.h" + +using namespace caret; + +/** + * \class caret::WbMacroCustomOperationManager + * \brief Mananager for macro custom operations + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroCustomOperationManager::WbMacroCustomOperationManager() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +WbMacroCustomOperationManager::~WbMacroCustomOperationManager() +{ +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +WbMacroCustomOperationManager::toString() const +{ + return "WbMacroCustomOperationManager"; +} + +/** + * Get names of all surfaces + * + * @param surfaceNamesOut + * Output with names of surfaces + * @param errorMessageOut + * Ouput with error messages + * @return + * True if surface names are valid, else false + */ +bool +WbMacroCustomOperationManager::getSurfaceNames(std::vector& surfaceNamesOut, + QString& errorMessageOut) +{ + surfaceNamesOut.clear(); + + EventSurfacesGet surfacesEvent; + EventManager::get()->sendEvent(surfacesEvent.getPointer()); + std::vector surfaces = surfacesEvent.getSurfaces(); + bool okFlag(false); + if (surfaces.empty()) { + errorMessageOut = "There are no surfaces available"; + } + else { + for (const auto s : surfaces) { + surfaceNamesOut.push_back(s->getFileNameNoPath()); + } + okFlag = true; + } + + return okFlag; +} + +/** + * Get mappable files selection info + * + * @param macroCommand + * Macro command containing parameter being edited + * @param overlayFileParameter + * Parameter for overlay file selection + * @param mapNameParameter + * Parameter for map name selection + * @param mapFileNamesOut + * Output with map file names + * @param selectedFileNameOut + * Output with name of selected file + * @param mapNamesOut + * Output with name of maps in selected file + * @param selectedMapNameOut + * Name of selected map + * @param errorMessageOut + * Output error message if finding map files fails + * @return + * True if map file names valid + */ +bool +WbMacroCustomOperationManager::getMappableFilesSelection(WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* overlayFileParameterIn, + WuQMacroCommandParameter* mapParameterIn, + std::vector& mapFileNamesOut, + QString& selectedFileNameOut, + std::vector& mapNamesOut, + QString& selectedMapNameOut, + QString& errorMessageOut) +{ + CaretAssert(macroCommand); + mapFileNamesOut.clear(); + selectedFileNameOut.clear(); + mapNamesOut.clear(); + selectedMapNameOut.clear(); + errorMessageOut.clear(); + + WuQMacroCommandParameter* fileParameter = overlayFileParameterIn; + WuQMacroCommandParameter* mapParameter = mapParameterIn; + if ((fileParameter != NULL) + && (mapParameter != NULL)) { + /* OK, have both */ + } + else { + /* + * Map selection parameter should be immediately after file selection parameter + */ + int32_t fileParameterIndex(-1); + int32_t mapParameterIndex(-1); + if (fileParameter != NULL) { + fileParameterIndex = macroCommand->getIndexOfParameter(fileParameter); + mapParameterIndex = fileParameterIndex + 1; + } + else if (mapParameter != NULL) { + mapParameterIndex = macroCommand->getIndexOfParameter(mapParameter); + fileParameterIndex = mapParameterIndex - 1; + } + else { + errorMessageOut = "Both overlay file and map parameter are NULL, one must be valid"; + return false; + } + + if ((fileParameterIndex < 0) + || (fileParameterIndex >= macroCommand->getNumberOfParameters())) { + errorMessageOut.append("Unable to find file parameter. "); + } + if ((mapParameterIndex < 0) + || (mapParameterIndex >= macroCommand->getNumberOfParameters())) { + errorMessageOut.append("Unable to find map parameter. "); + } + if ( ! errorMessageOut.isEmpty()) { + return false; + } + + fileParameter = macroCommand->getParameterAtIndex(fileParameterIndex); + mapParameter = macroCommand->getParameterAtIndex(mapParameterIndex); + } + + CaretAssert(fileParameter); + CaretAssert(mapParameter); + + bool validFileParamFlag(false); + const WbMacroCustomDataTypeEnum::Enum overlayParamType = WbMacroCustomDataTypeEnum::fromName(fileParameter->getCustomDataType(), + &validFileParamFlag); + if (overlayParamType != WbMacroCustomDataTypeEnum::OVERLAY_FILE_NAME_OR_FILE_INDEX) { + errorMessageOut.append("Overlay file parameter is not of type OVERLAY_FILE_NAME_OR_FILE_INDEX. "); + } + + bool validMapNameParamFlag(false); + const WbMacroCustomDataTypeEnum::Enum mapParamType = WbMacroCustomDataTypeEnum::fromName(mapParameter->getCustomDataType(), + &validMapNameParamFlag); + if (mapParamType != WbMacroCustomDataTypeEnum::OVERLAY_MAP_NAME_OR_MAP_INDEX) { + errorMessageOut.append("Overlay map parameter is not of type OVERLAY_MAP_NAME_OR_MAP_INDEX. "); + } + + if ( ! errorMessageOut.isEmpty()) { + return false; + } + + const QString selectedFileName = fileParameter->getValue().toString(); + const QString selectedMapName = mapParameter->getValue().toString(); + + CaretMappableDataFile* selectedFile(NULL); + EventCaretMappableDataFilesGet mapFilesEvent; + EventManager::get()->sendEvent(mapFilesEvent.getPointer()); + std::vector allFiles; + mapFilesEvent.getAllFiles(allFiles); + if ( ! allFiles.empty()) { + for (auto mf : allFiles) { + CaretAssert(mf); + const QString name(mf->getFileNameNoPath()); + if ( ! selectedFileName.isEmpty()) { + if (name == selectedFileName) { + selectedFile = mf; + } + } + mapFileNamesOut.push_back(name); + } + + if (selectedFile == NULL) { + CaretAssertVectorIndex(allFiles, 0); + selectedFile = allFiles[0]; + } + CaretAssert(selectedFile); + selectedFileNameOut = selectedFile->getFileNameNoPath(); + + bool selectedMapNameFoundFlag(false); + const int32_t numMaps = selectedFile->getNumberOfMaps(); + for (int32_t i = 0; i < numMaps; i++) { + const QString name(selectedFile->getMapName(i)); + if ( ! selectedMapName.isEmpty()) { + if (selectedMapName == name) { + selectedMapNameFoundFlag = true; + } + } + mapNamesOut.push_back(name); + } + + if (selectedMapNameFoundFlag) { + selectedMapNameOut = selectedMapName; + } + else { + if (selectedFile->getNumberOfMaps() > 0) { + selectedMapNameOut = selectedFile->getMapName(0); + } + } + } + + /** + * Selection may change. For example, if the selected overlay file + * is changed, the selected map name is likely to change so that + * it is a map that is in the new file and was not in the previous file + */ + if (selectedFileNameOut != fileParameter->getValue().toString()) { + fileParameter->setValue(selectedFileNameOut); + } + if (selectedMapNameOut != mapParameter->getValue().toString()) { + mapParameter->setValue(selectedMapNameOut); + } + + return true; +} + +/** + * Get the map file in the overlay for this command + * + * @param browserWindowIndex + * Index of browser window + * @param macroCommand + * Macro command containing parameter being edited + * @param overlayFileParameter + * Parameter for overlay file. Note that index of the overlay + * will be obtained from the most previous parameter that is of + * type OVERLAY_INDEX. + * @param mapFileNamesOut + * Output with map file names + * @param selectedMapFileOut + * Map file selected in overlay or NULL if none selected + * @param selectedMapFileMapNamesOut + * Names of maps in selected map file, empty if no map file + * @param errorMessageOut + * Output error message if finding map files fails + * @return + * True if map file names valid + */ +bool +WbMacroCustomOperationManager::getOverlayContents(const int32_t browserWindowIndex, + const WuQMacroCommand* macroCommand, + const WuQMacroCommandParameter* overlayFileParameter, + std::vector& mapFileNamesOut, + CaretMappableDataFile* &selectedMapFileOut, + std::vector& selectedMapFileMapNamesOut, + QString& errorMessageOut) +{ + CaretAssert(macroCommand); + CaretAssert(overlayFileParameter); + + mapFileNamesOut.clear(); + selectedMapFileOut = NULL; + selectedMapFileMapNamesOut.clear(); + + /* + * Find the overlay index parameter that should be before this parameter + */ + const int32_t parameterIndex = macroCommand->getIndexOfParameter(overlayFileParameter); + if (parameterIndex < 0) { + errorMessageOut = "Parameter is invalid for command"; + return false; + } + + int32_t overlayIndex(-1); + for (int32_t ip = (parameterIndex - 1); ip >= 0; --ip) { + const WuQMacroCommandParameter* p = macroCommand->getParameterAtIndex(ip); + if (p->getDataType() == WuQMacroDataValueTypeEnum::INTEGER) { + bool valid(false); + WbMacroCustomDataTypeEnum::Enum customType = WbMacroCustomDataTypeEnum::fromName(p->getCustomDataType(), + &valid); + if (valid) { + if (customType == WbMacroCustomDataTypeEnum::OVERLAY_INDEX) { + overlayIndex = p->getValue().toInt(); + break; + } + } + } + } + + /* + * Overlay index is 1..N for user so need to decrement + */ + if (overlayIndex < 1) { + errorMessageOut = "Unable to find overlay index"; + return false; + } + --overlayIndex; + + BrowserTabContent* tabContent = getTabContent(browserWindowIndex, + errorMessageOut); + if (tabContent == NULL) { + errorMessageOut = "Unable to find tab content"; + return false; + } + + Overlay* overlay = tabContent->getOverlaySet()->getOverlay(overlayIndex); + if (overlay == NULL) { + errorMessageOut = ("Overlay " + + AString::number(overlayIndex) + + " not found"); + return false; + } + + int32_t selectedMapIndex(-1); + std::vector mapFiles; + CaretMappableDataFile* selectedMapFile(NULL); + overlay->getSelectionData(mapFiles, + selectedMapFile, + selectedMapIndex); + + if (mapFiles.empty()) { + errorMessageOut = "The overlay does not contain any files"; + return false; + } + + selectedMapFileOut = selectedMapFile; + for (const auto mf : mapFiles) { + mapFileNamesOut.push_back(mf->getFileNameNoPath()); + } + if (selectedMapFileOut != NULL) { + const int32_t numMaps = selectedMapFileOut->getNumberOfMaps(); + for (int32_t i = 0; i < numMaps; i++) { + selectedMapFileMapNamesOut.push_back(selectedMapFileOut->getMapName(i)); + } + } + + return true; +} + +/** + * Get info for data in a custom parameter + * + * @param browserWindowIndex + * Index of browser window + * @param macroCommand + * Macro command that contains the parameter + * @param parameter + * Parameter for info + * @param dataInfo + * Updated with data info in this method + * @return + * True if the data info is valid + */ +bool +WbMacroCustomOperationManager::getCustomParameterDataInfo(const int32_t /*browserWindowIndex*/, + WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* parameter, + WbMacroCustomDataInfo& dataInfoOut) +{ + CaretAssert(macroCommand); + CaretAssert(parameter); + + const QString customTypeName(parameter->getCustomDataType()); + bool customTypeNameValid(false); + const WbMacroCustomDataTypeEnum::Enum userType = WbMacroCustomDataTypeEnum::fromName(customTypeName, + &customTypeNameValid); + if ( ! customTypeNameValid) { + CaretLogSevere("\"" + + customTypeName + + "\" is not a valid name for a custom parameter"); + return false; + } + + const QString dataTypeName(WuQMacroDataValueTypeEnum::toName(dataInfoOut.getDataType())); + + bool unsupportedFlag(false); + switch (dataInfoOut.getDataType()) { + case WuQMacroDataValueTypeEnum::AXIS: + unsupportedFlag = true; + break; + case WuQMacroDataValueTypeEnum::BOOLEAN: + unsupportedFlag = true; + break; + case WuQMacroDataValueTypeEnum::FLOAT: + break; + case WuQMacroDataValueTypeEnum::INTEGER: + break; + case WuQMacroDataValueTypeEnum::INVALID: + unsupportedFlag = true; + break; + case WuQMacroDataValueTypeEnum::MOUSE: + unsupportedFlag = true; + break; + case WuQMacroDataValueTypeEnum::NONE: + unsupportedFlag = true; + break; + case WuQMacroDataValueTypeEnum::STRING: + unsupportedFlag = true; + break; + case WuQMacroDataValueTypeEnum::STRING_LIST: + break; + } + + if (unsupportedFlag) { + CaretLogSevere("Unsupported data type for parameter info " + + WuQMacroDataValueTypeEnum::toName(dataInfoOut.getDataType())); + return false; + } + + bool validFlag(false); + QString errorMessage("Unknown error"); + QString invalidTypeName; + switch (userType) { + case WbMacroCustomDataTypeEnum::OVERLAY_INDEX: + if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::INTEGER) { + std::array dataRange { 1, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS }; + dataInfoOut.setIntegerRange(dataRange); + validFlag = true; + } + else { + invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::INTEGER); + } + break; + case WbMacroCustomDataTypeEnum::OVERLAY_FILE_NAME_OR_FILE_INDEX: + if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::STRING_LIST) { + std::vector filenames; + std::vector mapNames; + QString selectedFileName; + QString selectedMapName; + if (getMappableFilesSelection(macroCommand, + parameter, + NULL, + filenames, + selectedFileName, + mapNames, + selectedMapName, + errorMessage)) { + dataInfoOut.setStringListValues(filenames); + validFlag = true; + } + } + else { + invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::STRING_LIST); + } + break; + case WbMacroCustomDataTypeEnum::OVERLAY_MAP_NAME_OR_MAP_INDEX: + if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::STRING_LIST) { + std::vector filenames; + std::vector mapNames; + QString selectedFileName; + QString selectedMapName; + if (getMappableFilesSelection(macroCommand, + NULL, + parameter, + filenames, + selectedFileName, + mapNames, + selectedMapName, + errorMessage)) { + dataInfoOut.setStringListValues(mapNames); + validFlag = true; + } + } + else { + invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::STRING_LIST); + } + break; + case WbMacroCustomDataTypeEnum::SURFACE: + if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::STRING_LIST) { + std::vector surfaceNames; + if (getSurfaceNames(surfaceNames, errorMessage)) { + dataInfoOut.setStringListValues(surfaceNames); + validFlag = true; + } + } + else { + invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::STRING_LIST); + } + break; + } + + if ( ! validFlag) { + if ( ! invalidTypeName.isEmpty()) { + errorMessage = ("Custom parameter " + + customTypeName + + " data type should be " + + invalidTypeName + + " but is " + + dataTypeName); + } + + CaretLogSevere(errorMessage); + } + + return validFlag; +} + +/** + * Run a custom-defined macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * The executor monitor + * @param executorOptions + * Options for the executor + * @param customMacroCommand + * Custom macro command to run + * @param errorMessageOut + * Contains any error information or empty if no error + * @return + * True if command executed successfully, else false + */ +bool +WbMacroCustomOperationManager::executeCustomOperationMacroCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* customMacroCommand, + QString& errorMessageOut) +{ + CaretAssert(parent); + CaretAssert(customMacroCommand); + errorMessageOut.clear(); + + if (customMacroCommand->getCommandType() != WuQMacroCommandTypeEnum::CUSTOM_OPERATION) { + errorMessageOut = "Requesting non-custom command execution in user-executor"; + return false; + } + + const QString customCommandName(customMacroCommand->getCustomOperationTypeName()); + bool nameValid(false); + const WbMacroCustomOperationTypeEnum::Enum commandType = WbMacroCustomOperationTypeEnum::fromName(customCommandName, + &nameValid); + if ( ! nameValid) { + errorMessageOut = ("\"" + + customCommandName + + "\" is not a valid name for a custom macro command"); + return false; + } + + std::unique_ptr customOperation; + customOperation.reset(createCommand(commandType)); + + bool successFlag(false); + if (customOperation) { + successFlag = customOperation->executeCommand(parent, + executorMonitor, + executorOptions, + customMacroCommand); + if ( ! successFlag) { + errorMessageOut = customOperation->getErrorMessage(); + } + } + else { + errorMessageOut = "Custom Operation is missing"; + CaretLogSevere(errorMessageOut); + } + + return successFlag; +} + +/** + * @return Names of custom operation defined macro commands + */ +std::vector +WbMacroCustomOperationManager::getNamesOfCustomOperationMacroCommands() +{ + std::vector names; + + WbMacroCustomOperationTypeEnum::getAllNames(names, + true); + + std::vector namesOut(names.begin(), + names.end()); + return namesOut; +} + +/** + * @return All custom operation commands. Caller is responsible for deleting + * all content of the returned vector. + */ +std::vector +WbMacroCustomOperationManager::getAllCustomOperationMacroCommands() +{ + std::vector customCommandTypes; + WbMacroCustomOperationTypeEnum::getAllEnums(customCommandTypes); + + std::vector customCommands; + for (auto cct : customCommandTypes) { + if (cct == WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE) { + continue; + } + std::unique_ptr customOperation(createCommand(cct)); + customCommands.push_back(customOperation->createCommand()); + } + + return customCommands; +} + +/** + * Get a new instance of a custom operation for the given macro command name + * + * @param customMacroCommandName + * Name of custom macro command + * @param errorMessageOut + * Contains any error information or empty if no error + * @return + * Pointer to command or NULL if not valid + */ +WuQMacroCommand* +WbMacroCustomOperationManager::newInstanceOfCustomOperationMacroCommand(const QString& customMacroCommandName, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + + bool nameValid(false); + const WbMacroCustomOperationTypeEnum::Enum commandType = WbMacroCustomOperationTypeEnum::fromName(customMacroCommandName, + &nameValid); + if ( ! nameValid) { + errorMessageOut = ("\"" + + customMacroCommandName + + "\" is not a valid name for a custom macro command"); + return NULL; + } + + WuQMacroCommand* command(NULL); + + std::unique_ptr customOperation; + customOperation.reset(createCommand(commandType)); + + if (customOperation) { + command = customOperation->createCommand(); + if (command == NULL) { + errorMessageOut = customOperation->getErrorMessage(); + } + } + else { + errorMessageOut = "Custom Operation is missing"; + CaretLogSevere(errorMessageOut); + } + + return command; +} + +/** + * Create a custom operation of the given type + * + * @param operationType + * The operation type + * @return + * New instance of command caller is responsible for destroying + */ +WbMacroCustomOperationBase* +WbMacroCustomOperationManager::createCommand(const WbMacroCustomOperationTypeEnum::Enum operationType) +{ + WbMacroCustomOperationBase* operationOut(NULL); + + switch (operationType) { + case WbMacroCustomOperationTypeEnum::DELAY: + operationOut = new WbMacroCustomOperationDelay(); + break; + case WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION: + operationOut = new WbMacroCustomOperationAnimateRotation(); + break; + case WbMacroCustomOperationTypeEnum::ANIMATE_OVERLAY_CROSS_FADE: + operationOut = new WbMacroCustomOperationAnimateOverlayCrossFade(); + break; + case WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION: + operationOut = new WbMacroCustomOperationAnimateSurfaceInterpolation(); + break; + case WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_SLICE_SEQUENCE: + operationOut = new WbMacroCustomOperationAnimateVolumeSliceSequence(); + break; + case WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE: + operationOut = new WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(); + break; + case WbMacroCustomOperationTypeEnum::INCREMENTAL_ROTATION: + operationOut = new WbMacroCustomOperationIncrementRotation(); + break; + case WbMacroCustomOperationTypeEnum::INCREMENTAL_VOLUME_SLICE: + operationOut = new WbMacroCustomOperationIncrementVolumeSlice(); + break; + } + + CaretAssert(operationOut); + return operationOut; +} + +/** + * Get the active tab content in the active window. If there is more + * than one window open, the user is prompted to select a window + * + * @param browserWindowIndex + * Widget for any dialogs + * @param errorMessageOut + * Output with error information if failure + * @return + * Pointer to active tab content or none found + */ +BrowserTabContent* +WbMacroCustomOperationManager::getTabContent(const int32_t browserWindowIndex, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + + const std::vector allWindows = GuiManager::get()->getAllOpenBrainBrowserWindows(); + if (allWindows.empty()) { + errorMessageOut = "No window are open. This should never happen."; + return NULL; + } + + BrowserTabContent* tabContent(NULL); + BrainBrowserWindow* bbw(NULL); + + if (allWindows.size() == 1) { + CaretAssertVectorIndex(allWindows, 0); + bbw = allWindows[0]; + } + else { + for (auto w : allWindows) { + if (w->getBrowserWindowIndex() == browserWindowIndex) { + bbw = w; + break; + } + } + } + + if (bbw != NULL) { + tabContent = bbw->getBrowserTabContent(); + } + else { + errorMessageOut = "Failed to find window selected by user"; + } + + return tabContent; +} diff --git a/src/GuiQt/WbMacroCustomOperationManager.h b/src/GuiQt/WbMacroCustomOperationManager.h new file mode 100644 index 0000000000000000000000000000000000000000..e2d5fbe06f86b535314147f52f5ad30199613dae --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationManager.h @@ -0,0 +1,110 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_MANAGER_H__ +#define __WB_MACRO_CUSTOM_OPERATION_MANAGER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WuQMacroCustomOperationManagerInterface.h" + +class QWidget; + +namespace caret { + class BrowserTabContent; + class CaretMappableDataFile; + class WbMacroCustomOperationBase; + class WuQMacroCommand; + class WuQMacroCommandParameter; + + class WbMacroCustomOperationManager : public CaretObject, public WuQMacroCustomOperationManagerInterface { + + public: + WbMacroCustomOperationManager(); + + virtual ~WbMacroCustomOperationManager(); + + WbMacroCustomOperationManager(const WbMacroCustomOperationManager&) = delete; + + WbMacroCustomOperationManager& operator=(const WbMacroCustomOperationManager&) = delete; + + virtual bool getCustomParameterDataInfo(const int32_t browserWindowIndex, + WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* parameter, + WbMacroCustomDataInfo& dataInfoOut) override; + + virtual bool executeCustomOperationMacroCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand, + QString& errorMessageOut) override; + + virtual std::vector getNamesOfCustomOperationMacroCommands() override; + + virtual std::vector getAllCustomOperationMacroCommands() override; + + virtual WuQMacroCommand* newInstanceOfCustomOperationMacroCommand(const QString& customMacroCommandName, + QString& errorMessageOut) override; + + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + + WbMacroCustomOperationBase* createCommand(const WbMacroCustomOperationTypeEnum::Enum operationType); + + bool getSurfaceNames(std::vector& surfaceNamesOut, + QString& errorMessageOut); + + bool getOverlayContents(const int32_t browserWindowIndex, + const WuQMacroCommand* macroCommand, + const WuQMacroCommandParameter* overlayFileParameter, + std::vector& mapFileNamesOut, + CaretMappableDataFile* &selectedMapFileOut, + std::vector& selectedMapFileMapNamesOut, + QString& errorMessageOut); + + bool getMappableFilesSelection(WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* overlayFileParameter, + WuQMacroCommandParameter* mapParameter, + std::vector& mapFileNamesOut, + QString& selectedFileNameOut, + std::vector& mapNamesOut, + QString& selectedMapNameOut, + QString& errorMessageOut); + + BrowserTabContent* getTabContent(const int32_t browserWindowIndex, + QString& errorMessageOut); + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ + // +#endif // __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_MANAGER_H__ diff --git a/src/GuiQt/WbMacroCustomOperationTypeEnum.cxx b/src/GuiQt/WbMacroCustomOperationTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c5d08aa69613496f8c7e8834dd8b59796f1a0d7a --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationTypeEnum.cxx @@ -0,0 +1,417 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ +#include "WbMacroCustomOperationTypeEnum.h" +#undef __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WbMacroCustomOperationTypeEnum + * \brief Enumerated type for a user defined macro command + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_WbMacroCustomOperationTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void WbMacroCustomOperationTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WbMacroCustomOperationTypeEnum.h" + * + * Instatiate: + * m_WbMacroCustomOperationTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_WbMacroCustomOperationTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_WbMacroCustomOperationTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(WbMacroCustomOperationTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_WbMacroCustomOperationTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WbMacroCustomOperationTypeEnum::Enum VARIABLE = m_WbMacroCustomOperationTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WbMacroCustomOperationTypeEnum::WbMacroCustomOperationTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WbMacroCustomOperationTypeEnum::~WbMacroCustomOperationTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WbMacroCustomOperationTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_ROTATION, + "ANIMATE_ROTATION", + "Animate Rotation")); + + enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_OVERLAY_CROSS_FADE, + "ANIMATE_OVERLAY_CROSS_FADE", + "Animate Overlay CrossFade")); + + enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_SURFACE_INTERPOLATION, + "ANIMATE_SURFACE_INTERPOLATION", + "Animate Surface Interpolation")); + + enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_VOLUME_SLICE_SEQUENCE, + "ANIMATE_VOLUME_SLICE_SEQUENCE", + "Animate Volume Slice Sequence")); + + enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE, + "ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE", + "Animate Volume to Surface Cross Fade")); + + enumData.push_back(WbMacroCustomOperationTypeEnum(DELAY, + "DELAY", + "Delay")); + + enumData.push_back(WbMacroCustomOperationTypeEnum(INCREMENTAL_ROTATION, + "INCREMENTAL_ROTATION", + "Incremental Rotation")); + + enumData.push_back(WbMacroCustomOperationTypeEnum(INCREMENTAL_VOLUME_SLICE, + "INCREMENTAL_VOLUME_SLICE", + "Increment Volume Slice")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WbMacroCustomOperationTypeEnum* +WbMacroCustomOperationTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WbMacroCustomOperationTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WbMacroCustomOperationTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WbMacroCustomOperationTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WbMacroCustomOperationTypeEnum::Enum +WbMacroCustomOperationTypeEnum::fromName(const AString& nameIn, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + AString name(nameIn); + + /* + * Convert old names for operations that were renamed + */ + if (nameIn == "MODEL_ROTATION") { + name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION); + } + else if (nameIn == "OVERLAY_CROSS_FADE") { + name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_OVERLAY_CROSS_FADE); + } + else if (nameIn == "SURFACE_INTERPOLATION") { + name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION); + } + else if (nameIn == "VOLUME_SLICE_INCREMENT") { + name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_SLICE_SEQUENCE); + } + else if (nameIn == "VOLUME_TO_SURFACE_CROSS_FADE") { + name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE); + } + + bool validFlag = false; + Enum enumValue = WbMacroCustomOperationTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WbMacroCustomOperationTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WbMacroCustomOperationTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WbMacroCustomOperationTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WbMacroCustomOperationTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WbMacroCustomOperationTypeEnum::Enum +WbMacroCustomOperationTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WbMacroCustomOperationTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WbMacroCustomOperationTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WbMacroCustomOperationTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WbMacroCustomOperationTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WbMacroCustomOperationTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WbMacroCustomOperationTypeEnum::Enum +WbMacroCustomOperationTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WbMacroCustomOperationTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WbMacroCustomOperationTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WbMacroCustomOperationTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WbMacroCustomOperationTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WbMacroCustomOperationTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WbMacroCustomOperationTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WbMacroCustomOperationTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WbMacroCustomOperationTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/GuiQt/WbMacroCustomOperationTypeEnum.h b/src/GuiQt/WbMacroCustomOperationTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..dc70417027e613ca6f78e84674971ce76e70902a --- /dev/null +++ b/src/GuiQt/WbMacroCustomOperationTypeEnum.h @@ -0,0 +1,116 @@ +#ifndef __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_H__ +#define __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WbMacroCustomOperationTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Animate rotation of viewed model */ + ANIMATE_ROTATION, + /** Animate CrossFade of overlays */ + ANIMATE_OVERLAY_CROSS_FADE, + /** Animate Surface Interpolation */ + ANIMATE_SURFACE_INTERPOLATION, + /** Animate Volume slice sequence */ + ANIMATE_VOLUME_SLICE_SEQUENCE, + /** Animate Volume to surface cross fade */ + ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE, + /** Delay **/ + DELAY, + /** Incremental Rotation */ + INCREMENTAL_ROTATION, + /** Increment volume slice */ + INCREMENTAL_VOLUME_SLICE + }; + + + ~WbMacroCustomOperationTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WbMacroCustomOperationTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WbMacroCustomOperationTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ +std::vector WbMacroCustomOperationTypeEnum::enumData; +bool WbMacroCustomOperationTypeEnum::initializedFlag = false; +int32_t WbMacroCustomOperationTypeEnum::integerCodeCounter = 0; +#endif // __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_H__ diff --git a/src/GuiQt/WbMacroHelper.cxx b/src/GuiQt/WbMacroHelper.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7c84c77c2919dc444be337733b277f0cfc24857d --- /dev/null +++ b/src/GuiQt/WbMacroHelper.cxx @@ -0,0 +1,476 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_HELPER_DECLARE__ +#include "WbMacroHelper.h" +#undef __WB_MACRO_HELPER_DECLARE__ + +#include "Brain.h" +#include "BrainBrowserWindow.h" +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "CaretPreferences.h" +#include "DisplayPropertiesSurface.h" +#include "EventCaretDataFilesGet.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventGraphicsUpdateOneWindow.h" +#include "EventManager.h" +#include "EventMovieManualModeRecording.h" +#include "EventSceneActive.h" +#include "EventSurfaceColoringInvalidate.h" +#include "EventUserInterfaceUpdate.h" +#include "GuiManager.h" +#include "MovieRecorder.h" +#include "MovieRecordingDialog.h" +#include "Scene.h" +#include "SceneFile.h" +#include "SceneInfo.h" +#include "SessionManager.h" +#include "WbMacroCustomOperationTypeEnum.h" +#include "WbMacroCustomDataTypeEnum.h" +#include "WbMacroWidgetActionsManager.h" +#include "WuQMacro.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" +#include "WuQMacroExecutorOptions.h" +#include "WuQMacroGroup.h" +#include "WuQMacroManager.h" +#include "WuQMessageBox.h" +#include "WuQMacroWidgetAction.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroHelper + * \brief Implementation of WuQMacroHelperInterface that provides macro groups + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WbMacroHelper::WbMacroHelper(QObject* parent) +: WuQMacroHelperInterface(parent) +{ + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); +} + +/** + * Destructor. + */ +WbMacroHelper::~WbMacroHelper() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Receive an event + * + * @param event + * The event. + */ +void +WbMacroHelper::receiveEvent(Event* event) +{ + CaretAssert(event); + if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { + event->setEventProcessed(); + emit requestDialogsUpdate(); + } +} + +/** + * @return All 'active' available macro groups. + * Macros groups that are editible. Other macro + * groups are exluded. + */ +std::vector +WbMacroHelper::getActiveMacroGroups() +{ + std::vector macroGroups; + + const bool includePreferencesFlag(false); + if (includePreferencesFlag) { + CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); + CaretAssert(preferences); + macroGroups.push_back(preferences->getMacros()); + } + + EventSceneActive activeSceneEvent(EventSceneActive::MODE_GET); + EventManager::get()->sendEvent(activeSceneEvent.getPointer()); + if ( ! activeSceneEvent.isError()) { + Scene* activeScene = activeSceneEvent.getScene(); + if (activeScene != NULL) { + macroGroups.push_back(activeScene->getMacroGroup()); + } + } + + return macroGroups; +} + +/** + * @return All macro groups including those that are + * be valid (editable) at this time. + */ +std::vector +WbMacroHelper::getAllMacroGroups() const +{ + std::vector macroGroups; + + const bool includePreferencesFlag(false); + if (includePreferencesFlag) { + CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); + CaretAssert(preferences); + macroGroups.push_back(preferences->getMacros()); + } + + const auto sceneFiles = EventCaretDataFilesGet::getCaretDataFilesForType(DataFileTypeEnum::SCENE); + for (const auto dataFile : sceneFiles) { + const SceneFile* sceneFile = dynamic_cast(dataFile); + CaretAssert(sceneFile); + const int32_t numberOfScenes = sceneFile->getNumberOfScenes(); + for (int32_t i = 0; i < numberOfScenes; i++) { + macroGroups.push_back(sceneFile->getSceneAtIndex(i)->getMacroGroup()); + } + } + + return macroGroups; +} + +/** + * Is called when the given macro is modified + * + * @param macro + * Macro that is modified + */ +void +WbMacroHelper::macroWasModified(WuQMacro* macro) +{ + /* + * Need to write to preferences if macro is from preferences + */ + CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); + CaretAssert(preferences); + WuQMacroGroup* prefMacroGroup = preferences->getMacros(); + if (prefMacroGroup->containsMacro(macro)) { + preferences->writeMacros(); + } + + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} + +/** + * Is called when the given macro group is modified + * + * @param macroGroup + * Macro Group that is modified + */ +void +WbMacroHelper::macroGroupWasModified(WuQMacroGroup* macroGroup) +{ + /** + * Need to write to preferences if macro group is from preferences + */ + CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); + CaretAssert(preferences); + if (macroGroup == preferences->getMacros()) { + preferences->writeMacros(); + } + + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} + +/** + * @return Identifiers of all available windows in which macros may be run + */ +std::vector +WbMacroHelper::getMainWindowIdentifiers() +{ + std::vector identifiers; + + std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); + for (auto w : windows) { + identifiers.push_back(QString::number(w->getBrowserWindowIndex() + 1)); + } + + return identifiers; +} + +/** + * Get the main window with the given identifier + * + * @param identifier + * Window identifier + * @return + * Window with the given identifier or NULL if not available + */ +QMainWindow* +WbMacroHelper::getMainWindowWithIdentifier(const QString& identifier) +{ + const int32_t windowIndex(identifier.toInt() - 1); + QMainWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(windowIndex); + + return window; +} + +/** + * Called just before executing the macro + * + * @param macro + * Macro that is run + * @param window + * Widget for parent + * @param executorOptions + * Executor options + */ +void +WbMacroHelper::macroExecutionStarting(const WuQMacro* /*macro*/, + QWidget* /*window*/, + const WuQMacroExecutorOptions* executorOptions) +{ + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + m_savedRecordingMode = movieRecorder->getRecordingMode(); + if (executorOptions->isRecordMovieDuringExecution()) { + movieRecorder->setRecordingMode(MovieRecorderModeEnum::AUTOMATIC); + } + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); +} + +/** + * Called just after executing the macro + * + * @param macro + * Macro that is run + * @param window + * Widget for parent + * @param executorOptions + * Executor options + */ +void +WbMacroHelper::macroExecutionEnding(const WuQMacro* /*macro*/, + QWidget* window, + const WuQMacroExecutorOptions* executorOptions) +{ + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + movieRecorder->setRecordingMode(m_savedRecordingMode); + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); + + if (executorOptions->isCreateMovieAfterMacroExecution()) { + MovieRecordingDialog::createMovie(window); + } +} + +/** + * Reset the macro to its beginning state + * + * @param macro + * Macro that is run + * @param window + * Widget for parent + * @return + * Pointer to current macro. May be different than the macro + * passsed in. + */ +WuQMacro* +WbMacroHelper::resetMacroStateToBeginning(const WuQMacro* macro, + QWidget* window) +{ + CaretAssert(macro); + + WuQMacro* macroOut = const_cast(macro); + + BrainBrowserWindow* bbw = dynamic_cast(window); + + EventSceneActive sceneEvent(EventSceneActive::MODE_GET); + EventManager::get()->sendEvent(sceneEvent.getPointer()); + Scene* scene = sceneEvent.getScene(); + if (scene != NULL) { + WuQMacroGroup* macroGroup = scene->getMacroGroup(); + CaretAssert(macroGroup); + const QString macroName = macroOut->getName(); + const int32_t macroIndex = macroGroup->getIndexOfMacro(macroOut); + + /* + * Reload scene + */ + SceneFile* invalidSceneFile(NULL); + const bool showSceneDialogFlag(false); + GuiManager::get()->processShowSceneDialogAndScene(bbw, + invalidSceneFile, + scene, + showSceneDialogFlag); + + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + + macroOut = NULL; + + /* + * Find macro that was previously selected + */ + EventManager::get()->sendEvent(sceneEvent.getPointer()); + scene = sceneEvent.getScene(); + if (scene != NULL) { + macroGroup = scene->getMacroGroup(); + CaretAssert(macroGroup); + if ((macroIndex >= 0) + && (macroIndex < macroGroup->getNumberOfMacros())) { + macroOut = macroGroup->getMacroAtIndex(macroIndex); + + if (macroOut->getName() != macroName) { + for (int32_t i = 0; i < macroGroup->getNumberOfMacros(); i++) { + WuQMacro* m = macroGroup->getMacroAtIndex(i); + if (m->getName() == macroName) { + macroOut = m; + break; + } + } + } + } + } + } + + return macroOut; +} + + +/** + * Called by macro executor just after a command has completed execution + * + * @param window + * Widget for parent + * @param command + * Command that has just finished + * @param allowDelayFlagOut + * Output indicating if delay after command is enabled + */ +void +WbMacroHelper::macroCommandHasCompleted(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) +{ + bool doDelayAfterCommandFlag(false); /* change value to enable/disable delays after command */ + if (executorOptions->isIgnoreDelaysAndDurations()) { + doDelayAfterCommandFlag = false; + } + allowDelayFlagOut = doDelayAfterCommandFlag; + if (doDelayAfterCommandFlag) { + recordImagesForDelay(window, + command, + allowDelayFlagOut); + } +} + +/** + * If movie recording is on, capture images for the command's delay time + * + * @param window + * Widget for parent + * @param command + * The command + * @param executorOptions + * Executor options + * @param delay + * The delay in seconds + */ +void +WbMacroHelper::recordImagesForDelay(QWidget* window, + const WuQMacroCommand* command, + bool& allowDelayFlagOut) const +{ + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + CaretAssert(movieRecorder); + + if (command->getCommandType() != WuQMacroCommandTypeEnum::MOUSE) { + if (command->getDelayInSeconds() > 0.0) { + switch (movieRecorder->getRecordingMode()) { + case MovieRecorderModeEnum::AUTOMATIC: + { + BrainBrowserWindow* bbw = dynamic_cast(window); + const int32_t windowIndex = ((bbw != NULL) + ? bbw->getBrowserWindowIndex() + : -1); + EventMovieManualModeRecording movieEvent(windowIndex, + command->getDelayInSeconds()); + EventManager::get()->sendEvent(movieEvent.getPointer()); + + allowDelayFlagOut = false; + } + break; + case MovieRecorderModeEnum::MANUAL: + break; + } + } + } +} + +/** + * Called by macro executor just before starting execution of a command + * + * @param window + * Widget for parent + * @param command + * Command that is about to start + * @param executorOptions + * Executor options + * @param allowDelayFlagOut + * Output indicating if delay before command is enabled + */ +void +WbMacroHelper::macroCommandAboutToStart(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) +{ + bool doDelayBeforeCommandFlag(true); + if (executorOptions->isIgnoreDelaysAndDurations()) { + doDelayBeforeCommandFlag = false; + } + allowDelayFlagOut = doDelayBeforeCommandFlag; + if (doDelayBeforeCommandFlag) { + recordImagesForDelay(window, + command, + allowDelayFlagOut); + } +} + +/** + * Called by macro manager to get macro widget actions typically + * used by modal dialogs. + * + * Override to provide macro widget actions. + * + * @return Vector containing the macro widget actions. + */ +std::vector +WbMacroHelper::getMacroWidgetActions() +{ + if (m_macroWidgetActionsManager == NULL) { + m_macroWidgetActionsManager = new WbMacroWidgetActionsManager(this); + } + CaretAssert(m_macroWidgetActionsManager); + return m_macroWidgetActionsManager->getMacroWidgetActions(); +} + diff --git a/src/GuiQt/WbMacroHelper.h b/src/GuiQt/WbMacroHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..d72fd490c67d65140b387811f146ce89e5922a61 --- /dev/null +++ b/src/GuiQt/WbMacroHelper.h @@ -0,0 +1,107 @@ +#ifndef __WB_MACRO_HELPER_H__ +#define __WB_MACRO_HELPER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + +#include "EventListenerInterface.h" +#include "MovieRecorderModeEnum.h" +#include "WuQMacroHelperInterface.h" + +class QWidget; + +namespace caret { + + class WbMacroWidgetActionsManager; + + class WbMacroHelper : public WuQMacroHelperInterface, public EventListenerInterface { + Q_OBJECT + + public: + WbMacroHelper(QObject* parent); + + virtual ~WbMacroHelper(); + + WbMacroHelper(const WbMacroHelper&) = delete; + + WbMacroHelper& operator=(const WbMacroHelper&) = delete; + + void receiveEvent(Event* event) override; + + virtual std::vector getActiveMacroGroups(); + + virtual std::vector getAllMacroGroups() const; + + virtual void macroWasModified(WuQMacro* macro) override; + + virtual void macroGroupWasModified(WuQMacroGroup* macroGroup) override; + + virtual std::vector getMainWindowIdentifiers() override; + + virtual QMainWindow* getMainWindowWithIdentifier(const QString& identifier) override; + + virtual void macroExecutionStarting(const WuQMacro* macro, + QWidget* window, + const WuQMacroExecutorOptions* executorOptions) override; + + virtual void macroExecutionEnding(const WuQMacro* macro, + QWidget* window, + const WuQMacroExecutorOptions* executorOptions) override; + + virtual WuQMacro* resetMacroStateToBeginning(const WuQMacro* macro, + QWidget* window) override; + + virtual void macroCommandHasCompleted(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) override; + + virtual void macroCommandAboutToStart(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) override; + + virtual std::vector getMacroWidgetActions(); + + // ADD_NEW_METHODS_HERE + + private: + void + recordImagesForDelay(QWidget* window, + const WuQMacroCommand* command, + bool& allowDelayFlagOut) const; + + MovieRecorderModeEnum::Enum m_savedRecordingMode = MovieRecorderModeEnum::MANUAL; + + WbMacroWidgetActionsManager* m_macroWidgetActionsManager = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_HELPER_DECLARE__ + // +#endif // __WB_MACRO_HELPER_DECLARE__ + +} // namespace +#endif //__WB_MACRO_HELPER_H__ diff --git a/src/GuiQt/WbMacroWidgetActionNames.h b/src/GuiQt/WbMacroWidgetActionNames.h new file mode 100644 index 0000000000000000000000000000000000000000..a87604c3218deac49b39f9edb7a82a8c4c628324 --- /dev/null +++ b/src/GuiQt/WbMacroWidgetActionNames.h @@ -0,0 +1,67 @@ +#ifndef __WB_MACRO_WIDGET_ACTION_NAMES_H__ +#define __WB_MACRO_WIDGET_ACTION_NAMES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + +namespace caret { + + class WbMacroWidgetActionNames { + + public: + /* + * NOTE: These names are saved into scene and changing the names will break scenes + */ + + static QString getSurfacePropertiesOpacityName() { return "SurfaceProperties:surfaceOpacity"; } + + static QString getSurfacePropertiesLinkDiameterName() { return "SurfaceProperties:linkDiameter"; } + + static QString getSurfacePropertiesVertexDiameterName() { return "SurfaceProperties:vertexDiameter"; } + + static QString getSurfacePropertiesDisplayNormalVectorsName() { return "SurfaceProperties:displayNormalVectors"; } + + static QString getSurfacePropertiesDrawingTypeName() { return "SurfaceProperties:drawingType"; } + + WbMacroWidgetActionNames() = delete; + + virtual ~WbMacroWidgetActionNames() = delete; + + WbMacroWidgetActionNames(const WbMacroWidgetActionNames&) = delete; + + WbMacroWidgetActionNames& operator=(const WbMacroWidgetActionNames&) = delete; + + + // ADD_NEW_METHODS_HERE + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_WIDGET_ACTION_NAMES_DECLARE__ + // +#endif // __WB_MACRO_WIDGET_ACTION_NAMES_DECLARE__ + +} // namespace +#endif //__WB_MACRO_WIDGET_ACTION_NAMES_H__ diff --git a/src/GuiQt/WbMacroWidgetActionsManager.cxx b/src/GuiQt/WbMacroWidgetActionsManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6db1b2b49393c2edefb891744d7846e521edfa24 --- /dev/null +++ b/src/GuiQt/WbMacroWidgetActionsManager.cxx @@ -0,0 +1,253 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ +#include "WbMacroWidgetActionsManager.h" +#undef __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ + +#include + +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "Brain.h" +#include "DisplayPropertiesSurface.h" +#include "GuiManager.h" +#include "WbMacroWidgetActionNames.h" +#include "WuQMacroWidgetAction.h" + +using namespace caret; + + + +/** + * \class caret::WbMacroWidgetActionsManager + * \brief Manager for macro widget actions used by workbench + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param parent + * The parent object + */ +WbMacroWidgetActionsManager::WbMacroWidgetActionsManager(QObject* parent) +: QObject(parent) +{ + +} + +/** + * Destructor. + */ +WbMacroWidgetActionsManager::~WbMacroWidgetActionsManager() +{ +} + +/** + * @return All macro widget actions used by workbench + */ +std::vector +WbMacroWidgetActionsManager::getMacroWidgetActions() +{ + if (m_macroWidgetActions.empty()) { + m_macroWidgetActions.push_back(getSurfacePropertiesLinkDiameterWidgetAction()); + + m_macroWidgetActions.push_back(getSurfacePropertiesOpacityWidgetAction()); + + m_macroWidgetActions.push_back(getSurfacePropertiesVertexDiameterWidgetAction()); + + m_macroWidgetActions.push_back(getSurfacePropertiesDisplayNormalVectorsWidgetAction()); + + m_macroWidgetActions.push_back(getSurfacePropertiesSurfaceDrawingTypeWidgetAction()); + } + + return m_macroWidgetActions; +} + +/** + * @return The surface opacity widget action + */ +WuQMacroWidgetAction* +WbMacroWidgetActionsManager::getSurfacePropertiesOpacityWidgetAction() +{ + if (m_surfacePropertiesOpacityWidgetAction == NULL) { + m_surfacePropertiesOpacityWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::SPIN_BOX_FLOAT, + WbMacroWidgetActionNames::getSurfacePropertiesOpacityName(), + "Set the surface opacity", + this); + m_surfacePropertiesOpacityWidgetAction->setDoubleSpinBoxMinMaxStepDecimals(0.0, 1.0, 0.1, 2); + + DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); + + QObject::connect(m_surfacePropertiesOpacityWidgetAction, &WuQMacroWidgetAction::getModelValue, + this, [=](QVariant& value) { + value = dsp->getOpacity(); + }); + + QObject::connect(m_surfacePropertiesOpacityWidgetAction, &WuQMacroWidgetAction::setModelValue, + this, [=](const QVariant& value) { + dsp->setOpacity(value.toFloat()); + GuiManager::updateSurfaceColoring(); + GuiManager::updateGraphicsAllWindows(); + }); } + + CaretAssert(m_surfacePropertiesOpacityWidgetAction); + return m_surfacePropertiesOpacityWidgetAction; +} + +/** + * @return The surface link diameter widget action + */ +WuQMacroWidgetAction* +WbMacroWidgetActionsManager::getSurfacePropertiesLinkDiameterWidgetAction() +{ + if (m_surfacePropertiesLinkDiameterWidgetAction == NULL) { + m_surfacePropertiesLinkDiameterWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::SPIN_BOX_FLOAT, + WbMacroWidgetActionNames::getSurfacePropertiesLinkDiameterName(), + "Set the link (edge) diameter", + this); + m_surfacePropertiesLinkDiameterWidgetAction->setDoubleSpinBoxMinMaxStepDecimals(0.0, std::numeric_limits::max(), 1.0, 1); + + DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); + + QObject::connect(m_surfacePropertiesLinkDiameterWidgetAction, &WuQMacroWidgetAction::getModelValue, + this, [=](QVariant& value) { + value = dsp->getLinkSize(); + }); + + QObject::connect(m_surfacePropertiesLinkDiameterWidgetAction, &WuQMacroWidgetAction::setModelValue, + this, [=](const QVariant& value) { + dsp->setLinkSize(value.toFloat()); + GuiManager::updateGraphicsAllWindows(); + }); + } + + return m_surfacePropertiesLinkDiameterWidgetAction; +} + +/** + * @return The surface link diameter widget action + */ +WuQMacroWidgetAction* +WbMacroWidgetActionsManager::getSurfacePropertiesVertexDiameterWidgetAction() +{ + if (m_surfacePropertiesVertexDiameterWidgetAction == NULL) { + m_surfacePropertiesVertexDiameterWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::SPIN_BOX_FLOAT, + WbMacroWidgetActionNames::getSurfacePropertiesVertexDiameterName(), + "Set the vertex diameter", + this); + m_surfacePropertiesVertexDiameterWidgetAction->setDoubleSpinBoxMinMaxStepDecimals(0.0, std::numeric_limits::max(), 1.0, 1); + + DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); + + QObject::connect(m_surfacePropertiesVertexDiameterWidgetAction, &WuQMacroWidgetAction::getModelValue, + this, [=](QVariant& value) { + value = dsp->getNodeSize(); + }); + + QObject::connect(m_surfacePropertiesVertexDiameterWidgetAction, &WuQMacroWidgetAction::setModelValue, + this, [=](const QVariant& value) { + dsp->setNodeSize(value.toFloat()); + GuiManager::updateGraphicsAllWindows(); + }); + } + return m_surfacePropertiesVertexDiameterWidgetAction; +} + + +/** + * @return Get (and in needed create) the surface properties display normal vectors widget action + */ +WuQMacroWidgetAction* +WbMacroWidgetActionsManager::getSurfacePropertiesDisplayNormalVectorsWidgetAction() +{ + if (m_surfacePropertiesDisplayNormalVectorsWidgetAction == NULL) { + m_surfacePropertiesDisplayNormalVectorsWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::CHECK_BOX_BOOLEAN, + WbMacroWidgetActionNames::getSurfacePropertiesDisplayNormalVectorsName(), + "Display normal vectors on a surface", + this); + + DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); + + QObject::connect(m_surfacePropertiesDisplayNormalVectorsWidgetAction, &WuQMacroWidgetAction::getModelValue, + this, [=](QVariant& value) { + value = dsp->isDisplayNormalVectors(); + }); + + QObject::connect(m_surfacePropertiesDisplayNormalVectorsWidgetAction, &WuQMacroWidgetAction::setModelValue, + this, [=](const QVariant& value) { + dsp->setDisplayNormalVectors(value.toBool()); + GuiManager::updateGraphicsAllWindows(); + }); + } + + return m_surfacePropertiesDisplayNormalVectorsWidgetAction; +} + +/** + * @return Get (and in needed create) the surface properties surface drawing type widget action + */ +WuQMacroWidgetAction* +WbMacroWidgetActionsManager::getSurfacePropertiesSurfaceDrawingTypeWidgetAction() +{ + if (m_surfacePropertiesSurfaceDrawingTypeWidgetAction == NULL) { + m_surfacePropertiesSurfaceDrawingTypeWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::COMBO_BOX_STRING_LIST, + WbMacroWidgetActionNames::getSurfacePropertiesDrawingTypeName(), + "Drawing type for surface", + this); + + std::vector drawTypeNames; + const bool sortNamesFlag(false); + SurfaceDrawingTypeEnum::getAllGuiNames(drawTypeNames, + sortNamesFlag); + std::vector qsDrawTypeNames(drawTypeNames.begin(), + drawTypeNames.end()); + m_surfacePropertiesSurfaceDrawingTypeWidgetAction->setComboBoxStringList(qsDrawTypeNames); + + DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); + + QObject::connect(m_surfacePropertiesSurfaceDrawingTypeWidgetAction, &WuQMacroWidgetAction::getModelValue, + this, [=](QVariant& value) { + const SurfaceDrawingTypeEnum::Enum sdt = dsp->getSurfaceDrawingType(); + value = SurfaceDrawingTypeEnum::toGuiName(sdt); + }); + + QObject::connect(m_surfacePropertiesSurfaceDrawingTypeWidgetAction, &WuQMacroWidgetAction::setModelValue, + this, [=](const QVariant& value) { + bool validFlag(false); + const SurfaceDrawingTypeEnum::Enum std = SurfaceDrawingTypeEnum::fromGuiName(value.toString(), &validFlag); + if (validFlag) { + dsp->setSurfaceDrawingType(std); + } + else { + CaretLogSevere("Failed to convert to surface drawing type: " + + value.toString()); + } + GuiManager::updateGraphicsAllWindows(); + }); + } + + return m_surfacePropertiesSurfaceDrawingTypeWidgetAction; +} + diff --git a/src/GuiQt/WbMacroWidgetActionsManager.h b/src/GuiQt/WbMacroWidgetActionsManager.h new file mode 100644 index 0000000000000000000000000000000000000000..57a9b00f3b3398ab08f8ad9bbdb16bb69f23684b --- /dev/null +++ b/src/GuiQt/WbMacroWidgetActionsManager.h @@ -0,0 +1,86 @@ +#ifndef __WB_MACRO_WIDGET_ACTIONS_MANAGER_H__ +#define __WB_MACRO_WIDGET_ACTIONS_MANAGER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + + + +namespace caret { + + class WuQMacroWidgetAction; + + class WbMacroWidgetActionsManager : public QObject { + + Q_OBJECT + + public: + WbMacroWidgetActionsManager(QObject* parent); + + virtual ~WbMacroWidgetActionsManager(); + + + WbMacroWidgetActionsManager(const WbMacroWidgetActionsManager&) = delete; + + WbMacroWidgetActionsManager& operator=(const WbMacroWidgetActionsManager&) = delete; + + std::vector getMacroWidgetActions(); + + WuQMacroWidgetAction* getSurfacePropertiesLinkDiameterWidgetAction(); + + WuQMacroWidgetAction* getSurfacePropertiesOpacityWidgetAction(); + + WuQMacroWidgetAction* getSurfacePropertiesVertexDiameterWidgetAction(); + + WuQMacroWidgetAction* getSurfacePropertiesDisplayNormalVectorsWidgetAction(); + + WuQMacroWidgetAction* getSurfacePropertiesSurfaceDrawingTypeWidgetAction(); + + // ADD_NEW_METHODS_HERE + + private: + std::vector m_macroWidgetActions; + + WuQMacroWidgetAction* m_surfacePropertiesOpacityWidgetAction = NULL; + + WuQMacroWidgetAction* m_surfacePropertiesLinkDiameterWidgetAction = NULL; + + WuQMacroWidgetAction* m_surfacePropertiesVertexDiameterWidgetAction = NULL; + + WuQMacroWidgetAction* m_surfacePropertiesDisplayNormalVectorsWidgetAction = NULL; + + WuQMacroWidgetAction* m_surfacePropertiesSurfaceDrawingTypeWidgetAction = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ + // +#endif // __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ + +} // namespace +#endif //__WB_MACRO_WIDGET_ACTIONS_MANAGER_H__ diff --git a/src/GuiQt/WuQDataEntryDialog.cxx b/src/GuiQt/WuQDataEntryDialog.cxx index 22bcbd9bb167dc80816ac0bd56d0d35521d3ae22..714fd7e16d856f476e911007ab0a6c13aeb33315 100644 --- a/src/GuiQt/WuQDataEntryDialog.cxx +++ b/src/GuiQt/WuQDataEntryDialog.cxx @@ -587,7 +587,9 @@ WuQDataEntryDialog::addSurfaceSelectionViewController(const QString& labelText, { SurfaceSelectionViewController* surfaceSelectionViewController = new SurfaceSelectionViewController(this, - brainStructure); + brainStructure, + "DataEntryDialogSurfaceComboBox", + "Data Entry"); this->addWidget(labelText, surfaceSelectionViewController->getWidget()); diff --git a/src/GuiQt/WuQDialog.h b/src/GuiQt/WuQDialog.h index ed96020465a062e46e1f042dc2a903548ca4e4df..570dbb2aae551ac412d6cace5a8d957c1489588d 100644 --- a/src/GuiQt/WuQDialog.h +++ b/src/GuiQt/WuQDialog.h @@ -147,9 +147,6 @@ namespace caret { virtual void showEvent(QShowEvent* event); -// void setDialogSizeHint(const int32_t width, -// const int32_t height); - private slots: void clicked(QAbstractButton* button); diff --git a/src/GuiQt/WuQMacroCommandParameterWidget.cxx b/src/GuiQt/WuQMacroCommandParameterWidget.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fee97c22888455b863fb5d15a2fd2cce336010c2 --- /dev/null +++ b/src/GuiQt/WuQMacroCommandParameterWidget.cxx @@ -0,0 +1,451 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ +#include "WuQMacroCommandParameterWidget.h" +#undef __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "WbMacroCustomDataInfo.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroManager.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacroCommandParameterWidget + * \brief Widget for display and editing a macro command parameter value + * \ingroup GuiQt + */ + +/** + * Constructor for command parameter widgets + * + * @param index + * Index of the parameter + * @param gridLayout + * Layout containing the widgets + * @param parent + * The parent widget + */ +WuQMacroCommandParameterWidget::WuQMacroCommandParameterWidget(const int32_t index, + QGridLayout* gridLayout, + QWidget* parent) +: QObject(parent), +m_index(index) +{ + m_nameLabel = new QLabel(); + modifySizePolicy(m_nameLabel); + + m_booleanOnAction = new QAction("On"); + m_booleanOnAction->setCheckable(true); + QObject::connect(m_booleanOnAction, &QAction::triggered, + this, &WuQMacroCommandParameterWidget::booleanOnActionTriggered); + QToolButton* booleanOnToolButton = new QToolButton(); + booleanOnToolButton->setDefaultAction(m_booleanOnAction); + + m_booleanOffAction = new QAction("Off"); + m_booleanOffAction->setCheckable(true); + QObject::connect(m_booleanOffAction, &QAction::triggered, + this, &WuQMacroCommandParameterWidget::booleanOffActionTriggered); + QToolButton* booleanOffToolButton = new QToolButton(); + booleanOffToolButton->setDefaultAction(m_booleanOffAction); + + QActionGroup* booleanActionGroup = new QActionGroup(this); + booleanActionGroup->addAction(m_booleanOffAction); + booleanActionGroup->addAction(m_booleanOnAction); + booleanActionGroup->setExclusive(true); + + m_comboBox = new QComboBox(); + m_comboBox->setFixedHeight(m_comboBox->sizeHint().height()); + m_comboBox->setEditable(true); + QObject::connect(m_comboBox, QOverload::of(&QComboBox::activated), + this, &WuQMacroCommandParameterWidget::comboBoxActivated); + + m_doubleSpinBox = new QDoubleSpinBox(); + m_doubleSpinBox->setFixedWidth(120); + m_doubleSpinBox->setFixedHeight(m_doubleSpinBox->sizeHint().height()); + QObject::connect(m_doubleSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &WuQMacroCommandParameterWidget::doubleSpinBoxValueChanged); + + m_lineEdit = new QLineEdit(); + m_lineEdit->setFixedHeight(m_lineEdit->sizeHint().height()); + QObject::connect(m_lineEdit, &QLineEdit::textEdited, + this, &WuQMacroCommandParameterWidget::lineEditTextEdited); + + m_spinBox = new QSpinBox(); + m_spinBox->setFixedWidth(120); + m_spinBox->setFixedHeight(m_spinBox->sizeHint().height()); + QObject::connect(m_spinBox, QOverload::of(&QSpinBox::valueChanged), + this, &WuQMacroCommandParameterWidget::spinBoxValueChanged); + + m_noValueWidget = new QWidget(); + m_noValueWidget->setFixedWidth(50); + m_noValueWidget->setFixedHeight(10); + + m_booleanWidget = new QWidget(); + QHBoxLayout* booleanLayout = new QHBoxLayout(m_booleanWidget); + booleanLayout->setContentsMargins(0, 0, 0, 0); + booleanLayout->addWidget(booleanOnToolButton); + booleanLayout->addWidget(booleanOffToolButton); + booleanLayout->addStretch(); + m_booleanWidget->setFixedHeight(m_booleanWidget->sizeHint().height()); + + m_stackedWidget = new QStackedWidget(); + m_stackedWidget->addWidget(m_booleanWidget); + m_stackedWidget->addWidget(m_comboBox); + m_stackedWidget->addWidget(m_doubleSpinBox); + m_stackedWidget->addWidget(m_lineEdit); + m_stackedWidget->addWidget(m_spinBox); + m_stackedWidget->addWidget(m_noValueWidget); + + const int numWidgets = m_stackedWidget->count(); + for (int32_t i = 0; i < numWidgets; i++) { + modifySizePolicy(m_stackedWidget->widget(i)); + } + modifySizePolicy(m_stackedWidget); + + /* + * Note: A QStackedWidget aligns its current widget at the top. + * So, align the label at the top so that the label and widget + * are approximately aligned + */ + const int32_t row = gridLayout->rowCount(); + gridLayout->addWidget(m_nameLabel, row, 0, Qt::AlignTop); + gridLayout->addWidget(m_stackedWidget, row, 1); +} + +/** + * Destructor. + */ +WuQMacroCommandParameterWidget::~WuQMacroCommandParameterWidget() +{ +} + +/** + * Modify the size policy so that widget does not retain + * size when hidden + * + * @param w + * The widget + */ +void +WuQMacroCommandParameterWidget::modifySizePolicy(QWidget* w) +{ + CaretAssert(w); + QSizePolicy sp = w->sizePolicy(); + sp.setRetainSizeWhenHidden(false); + w->setSizePolicy(sp); +} + +/** + * Update content of a command parameter + * + * @param windowIndex + * Index of window + * @param macroCommand + * Macro command containing the parameter + * @param parameter + * The parameter + */ +void +WuQMacroCommandParameterWidget::updateContent(int32_t windowIndex, + WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* parameter) +{ + m_windowIndex = windowIndex; + m_macroCommand = macroCommand; + m_parameter = parameter; + + QWidget* activeWidget(m_noValueWidget); + + const bool validFlag(m_parameter != NULL); + if (validFlag) { + CaretAssert(m_macroCommand); + CaretAssert(m_parameter); + + m_nameLabel->setText(m_parameter->getName()); + + const QString customDataTypeName = parameter->getCustomDataType(); + const bool customDataFlag( ! customDataTypeName.isEmpty()); + + switch (parameter->getDataType()) { + case WuQMacroDataValueTypeEnum::AXIS: + { + m_comboBox->clear(); + m_comboBox->setEditable(false); + + std::vector axisValues { "X", "Y", "Z" }; + + int32_t defaultIndex(-1); + const QString value = m_parameter->getValue().toString(); + const int32_t numAxes = static_cast(axisValues.size()); + for (int32_t i = 0; i < numAxes; i++) { + CaretAssertVectorIndex(axisValues, i); + if (value == axisValues[i]) { + defaultIndex = i; + } + + m_comboBox->addItem(axisValues[i]); + } + + if (defaultIndex < 0) { + if ( ! value.isEmpty()) { + defaultIndex = m_comboBox->count(); + m_comboBox->addItem(value); + } + } + if (defaultIndex >= 0) { + m_comboBox->setCurrentIndex(defaultIndex); + } + + activeWidget = m_comboBox; + } + break; + case WuQMacroDataValueTypeEnum::BOOLEAN: + { + if (parameter->getValue().toBool()) { + m_booleanOnAction->setChecked(true); + } + else { + m_booleanOffAction->setChecked(true); + } + activeWidget = m_booleanWidget; + } + break; + case WuQMacroDataValueTypeEnum::FLOAT: + { + std::array floatRange { -1.0e6, 1.0e6 }; + if (customDataFlag) { + WbMacroCustomDataInfo customDataInfo(WuQMacroDataValueTypeEnum::FLOAT); + WuQMacroManager::instance()->getCustomParameterDataInfo(windowIndex, + macroCommand, + parameter, + customDataInfo); + floatRange = customDataInfo.getFloatRange(); + } + + QSignalBlocker blocker(m_doubleSpinBox); + m_doubleSpinBox->setRange(floatRange[0], floatRange[1]); + m_doubleSpinBox->setValue(m_parameter->getValue().toFloat()); + activeWidget = m_doubleSpinBox; + } + break; + case WuQMacroDataValueTypeEnum::INTEGER: + { + std::array intRange { -100000, 100000 }; + if (customDataFlag) { + WbMacroCustomDataInfo customDataInfo(WuQMacroDataValueTypeEnum::INTEGER); + WuQMacroManager::instance()->getCustomParameterDataInfo(windowIndex, + macroCommand, + parameter, + customDataInfo); + intRange = customDataInfo.getIntegerRange(); + } + + QSignalBlocker blocker(m_spinBox); + m_spinBox->setRange(intRange[0], intRange[1]); + m_spinBox->setValue(m_parameter->getValue().toInt()); + activeWidget = m_spinBox; + } + break; + case WuQMacroDataValueTypeEnum::INVALID: + break; + case WuQMacroDataValueTypeEnum::MOUSE: + break; + case WuQMacroDataValueTypeEnum::NONE: + break; + case WuQMacroDataValueTypeEnum::STRING: + m_lineEdit->setText(m_parameter->getValue().toString()); + activeWidget = m_lineEdit; + break; + case WuQMacroDataValueTypeEnum::STRING_LIST: + { + m_comboBox->clear(); + + std::vector stringValues; + + if (customDataFlag) { + WbMacroCustomDataInfo customDataInfo(WuQMacroDataValueTypeEnum::STRING_LIST); + WuQMacroManager::instance()->getCustomParameterDataInfo(windowIndex, + macroCommand, + parameter, + customDataInfo); + stringValues = customDataInfo.getStringListValues(); + } + + int32_t defaultIndex(-1); + const QString selectedValue = m_parameter->getValue().toString(); + + const int32_t numValues = static_cast(stringValues.size()); + if (numValues > 0) { + for (int32_t i = 0; i < numValues; i++) { + CaretAssertVectorIndex(stringValues, i); + if (selectedValue == stringValues[i]) { + defaultIndex = i; + } + + m_comboBox->addItem(stringValues[i]); + } + + bool editableFlag(false); + if (editableFlag) { + m_comboBox->setEditable(true); + if (defaultIndex < 0) { + if ( ! selectedValue.isEmpty()) { + defaultIndex = m_comboBox->count(); + m_comboBox->addItem(selectedValue); + } + } + } + else { + m_comboBox->setEditable(false); + } + } + else { + if ( ! selectedValue.isEmpty()) { + defaultIndex = m_comboBox->count(); + m_comboBox->addItem(selectedValue); + } + m_comboBox->setEditable(true); + } + + if (defaultIndex >= 0) { + m_comboBox->setCurrentIndex(defaultIndex); + } + + activeWidget = m_comboBox; + } + break; + } + } + + m_stackedWidget->setCurrentWidget(activeWidget); + + m_nameLabel->setVisible(validFlag); + m_stackedWidget->setVisible(validFlag); + +// std::cout << "Stacked " << m_index << " height " << m_stackedWidget->sizeHint().height() << std::endl; +// for (int32_t i = 0; i < m_stackedWidget->count(); i++) { +// QWidget* w = m_stackedWidget->widget(i); +// std::cout << " " << i << " height " << w->sizeHint().height() << " " << w->metaObject()->className() << std::endl; +// } +} + +/** + * Called when boolean OFF action is triggered + */ +void +WuQMacroCommandParameterWidget::booleanOffActionTriggered(bool) +{ + CaretAssert(m_parameter); + m_parameter->setValue(false); + + emit dataChanged(m_index); +} + +/** + * Called when boolean ON action is triggered + */ +void +WuQMacroCommandParameterWidget::booleanOnActionTriggered(bool) +{ + CaretAssert(m_parameter); + m_parameter->setValue(true); + + emit dataChanged(m_index); +} + +/** + * Called when combo box is activated + * + * @param index + * index of item selecteed + */ +void +WuQMacroCommandParameterWidget::comboBoxActivated(int /*index*/) +{ + CaretAssert(m_parameter); + m_parameter->setValue(m_comboBox->currentText()); + + emit dataChanged(m_index); +} + +/** + * Called when value of double spin box is changed + * + * @param value + * The new value + */ +void +WuQMacroCommandParameterWidget::doubleSpinBoxValueChanged(double value) +{ + CaretAssert(m_parameter); + m_parameter->setValue(static_cast(value)); + + emit dataChanged(m_index); +} + +/** + * Called when value of the line edit is changed + * + * @param text + * The new text value + */ +void +WuQMacroCommandParameterWidget::lineEditTextEdited(const QString& text) +{ + CaretAssert(m_parameter); + m_parameter->setValue(text); + + emit dataChanged(m_index); +} + +/** + * Called when value of double spin box is changed + * + * @param value + * The new value + */ +void +WuQMacroCommandParameterWidget::spinBoxValueChanged(int value) +{ + CaretAssert(m_parameter); + m_parameter->setValue(value); + + emit dataChanged(m_index); +} diff --git a/src/GuiQt/WuQMacroCommandParameterWidget.h b/src/GuiQt/WuQMacroCommandParameterWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..5b6fbc38b543fbcd9664ecbc4b652425d9ee4ca7 --- /dev/null +++ b/src/GuiQt/WuQMacroCommandParameterWidget.h @@ -0,0 +1,120 @@ +#ifndef __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_H__ +#define __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QComboBox; +class QDoubleSpinBox; +class QGridLayout; +class QLabel; +class QLineEdit; +class QSpinBox; +class QStackedWidget; + +namespace caret { + + class WuQMacroCommand; + class WuQMacroCommandParameter; + + class WuQMacroCommandParameterWidget : public QObject { + + Q_OBJECT + + public: + WuQMacroCommandParameterWidget(const int32_t index, + QGridLayout* gridLayout, + QWidget* parent); + + virtual ~WuQMacroCommandParameterWidget(); + + WuQMacroCommandParameterWidget(const WuQMacroCommandParameterWidget&) = delete; + + WuQMacroCommandParameterWidget& operator=(const WuQMacroCommandParameterWidget&) = delete; + + void updateContent(int32_t windowIndex, + WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* parameter); + + // ADD_NEW_METHODS_HERE + + signals: + void dataChanged(const int index); + + private slots: + void booleanOffActionTriggered(bool); + + void booleanOnActionTriggered(bool); + + void comboBoxActivated(int); + + void doubleSpinBoxValueChanged(double); + + void lineEditTextEdited(const QString&); + + void spinBoxValueChanged(int); + + private: + void modifySizePolicy(QWidget* w); + + QLabel* m_nameLabel; + + const int32_t m_index; + + int32_t m_windowIndex = -1; + + WuQMacroCommand* m_macroCommand = NULL; + + WuQMacroCommandParameter* m_parameter = NULL; + + QStackedWidget* m_stackedWidget; + + QAction* m_booleanOnAction; + + QAction* m_booleanOffAction; + + QWidget* m_booleanWidget; + + QComboBox* m_comboBox; + + QDoubleSpinBox* m_doubleSpinBox; + + QLineEdit* m_lineEdit; + + QSpinBox* m_spinBox; + + QWidget* m_noValueWidget; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ + // +#endif // __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_H__ diff --git a/src/GuiQt/WuQMacroCopyDialog.cxx b/src/GuiQt/WuQMacroCopyDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a6c530c8b966e33456b1a0b1605913b976fe3d18 --- /dev/null +++ b/src/GuiQt/WuQMacroCopyDialog.cxx @@ -0,0 +1,247 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_COPY_DIALOG_DECLARE__ +#include "WuQMacroCopyDialog.h" +#undef __WU_Q_MACRO_COPY_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "WuQMacro.h" +#include "WuQMacroGroup.h" +#include "WuQMacroManager.h" + +using namespace caret; + +/** + * \class caret::WuQMacroCopyDialog + * \brief Dialog for creating a new macro + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param parent + * The parent widget + */ +WuQMacroCopyDialog::WuQMacroCopyDialog(QWidget* parent) +: QDialog(parent) +{ + setWindowTitle("Copy Macro"); + + m_macroGroups = WuQMacroManager::instance()->getAllMacroGroups(); + + QLabel* nameLabel = new QLabel("Macro:"); + QLabel* descriptionLabel = new QLabel("Description:"); + QLabel* macroGroupLabel = new QLabel("Macro From:"); + + m_macroDescriptionTextEdit = new QPlainTextEdit(); + m_macroDescriptionTextEdit->setFixedHeight(100); + m_macroDescriptionTextEdit->setReadOnly(true); + + int32_t selectedMacroGroupIndex(-1); + m_macroGroupComboBox = new QComboBox(); + QObject::connect(m_macroGroupComboBox, QOverload::of(&QComboBox::activated), + this, &WuQMacroCopyDialog::macroGroupComboBoxItemActivated); + for (auto mg : m_macroGroups) { + if ( ! mg->isEmpty()) { + if (mg->getUniqueIdentifier() == s_lastSelectedMacroGroupIdentifier) { + selectedMacroGroupIndex = m_macroGroupComboBox->count(); + } + m_macroGroupComboBox->addItem(mg->getName()); + } + } + if (selectedMacroGroupIndex < 0) { + selectedMacroGroupIndex = m_macroGroupComboBox->count() - 1; + } + if ((selectedMacroGroupIndex >= 0) + && (selectedMacroGroupIndex < m_macroGroupComboBox->count())) { + m_macroGroupComboBox->setCurrentIndex(selectedMacroGroupIndex); + } + + m_macroNameComboBox = new QComboBox(); + QObject::connect(m_macroNameComboBox, QOverload::of(&QComboBox::activated), + this, &WuQMacroCopyDialog::macroComboBoxItemActivated); + + + + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnStretch(2, 0); + gridLayout->setColumnStretch(3, 100); + int row = 0; + gridLayout->addWidget(macroGroupLabel, row, 0); + gridLayout->addWidget(m_macroGroupComboBox, row, 1, 1, 3); + row++; + gridLayout->addWidget(nameLabel, row, 0); + gridLayout->addWidget(m_macroNameComboBox, row, 1, 1, 3); + row++; + gridLayout->addWidget(descriptionLabel, row, 0); + gridLayout->addWidget(m_macroDescriptionTextEdit, row, 1, 1, 3); + row++; + + m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + QObject::connect(m_dialogButtonBox, &QDialogButtonBox::accepted, + this, &WuQMacroCopyDialog::accept); + QObject::connect(m_dialogButtonBox, &QDialogButtonBox::rejected, + this, &WuQMacroCopyDialog::reject); + + QVBoxLayout* dialogLayout = new QVBoxLayout(this); + dialogLayout->addLayout(gridLayout, 100); + dialogLayout->addWidget(m_dialogButtonBox); + + setFixedHeight(sizeHint().height()); + + macroGroupComboBoxItemActivated(m_macroGroupComboBox->currentIndex()); +} + +/** + * Destructor. + */ +WuQMacroCopyDialog::~WuQMacroCopyDialog() +{ +} + +/** + * Called when macro group is selected from combo box + * + * @param index + * Index of item selected + */ +void +WuQMacroCopyDialog::macroGroupComboBoxItemActivated(int /*index*/) +{ + m_macroNameComboBox->clear(); + + const WuQMacroGroup* mg = getMacroGroup(); + if (mg != NULL) { + const int32_t numMacros = mg->getNumberOfMacros(); + for (int32_t i = 0; i < numMacros; i++) { + m_macroNameComboBox->addItem(mg->getMacroAtIndex(i)->getName()); + } + } + macroComboBoxItemActivated(m_macroNameComboBox->currentIndex()); +} + +/** + * Called when macro group is selected from combo box + * + * @param index + * Index of item selected + */ +void +WuQMacroCopyDialog::macroComboBoxItemActivated(int /*index*/) +{ + QString text; + const WuQMacro* macro = getMacroToCopy(); + if (macro != NULL) { + text = macro->getDescription(); + } + m_macroDescriptionTextEdit->setPlainText(text); +} + +/** + * Called when user clicks OK or Cancel + * + * @param r + * The dialog code (Accepted or Rejected) + */ +void +WuQMacroCopyDialog::done(int r) +{ + if (r == QDialog::Accepted) { +// const QString name(m_macroNameLineEdit->text().trimmed()); +// if (name.isEmpty()) { +// QMessageBox::critical(this, +// "Error", +// "Name is missing", +// QMessageBox::Ok, +// QMessageBox::Ok); +// return; +// } +// +// m_macro = new WuQMacro(); +// m_macro->setName(name); +// m_macro->setDescription(m_macroDescriptionTextEdit->toPlainText()); +// +// const int32_t groupIndex = m_macroGroupComboBox->currentIndex(); +// if (groupIndex >= 0) { +// WuQMacroGroup* macroGroup = m_macroGroups[groupIndex]; +// macroGroup->addMacro(m_macro); +// s_lastSelectedMacroGroupIdentifier = macroGroup->getUniqueIdentifier(); +// } + } + + QDialog::done(r); +} + +/** + * @return Pointer to selected macro group or NULL if none available + */ +const WuQMacroGroup* +WuQMacroCopyDialog::getMacroGroup() const +{ + const WuQMacroGroup* macroGroup(NULL); + const int32_t groupIndex = m_macroGroupComboBox->currentIndex(); + if ((groupIndex >= 0) + && (groupIndex < static_cast(m_macroGroups.size()))) { + CaretAssertVectorIndex(m_macroGroups, groupIndex); + macroGroup = m_macroGroups[groupIndex]; + CaretAssert(macroGroup); + } + + return macroGroup; +} + +/** + * @return Pointer to macro that was selected and should be copied. + * NULL if no macro to copy. + */ +const WuQMacro* +WuQMacroCopyDialog::getMacroToCopy() const +{ + const WuQMacro* macro(NULL); + + const WuQMacroGroup* mg = getMacroGroup(); + if (mg != NULL) { + const int32_t macroIndex = m_macroNameComboBox->currentIndex(); + if ((macroIndex >= 0) + && (macroIndex < mg->getNumberOfMacros())) { + macro = mg->getMacroAtIndex(macroIndex); + CaretAssert(macro); + } + } + + return macro; +} + diff --git a/src/GuiQt/WuQMacroCopyDialog.h b/src/GuiQt/WuQMacroCopyDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..f90bff48d29cd09738e1e87b7dc16a744d435a4a --- /dev/null +++ b/src/GuiQt/WuQMacroCopyDialog.h @@ -0,0 +1,88 @@ +#ifndef __WU_Q_MACRO_COPY_DIALOG_H__ +#define __WU_Q_MACRO_COPY_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QComboBox; +class QDialogButtonBox; +class QLineEdit; +class QPlainTextEdit; + + +namespace caret { + + class WuQMacro; + class WuQMacroGroup; + class WuQMacroShortCutKeyComboBox; + + class WuQMacroCopyDialog : public QDialog { + + Q_OBJECT + + public: + WuQMacroCopyDialog(QWidget* parent = 0); + + virtual ~WuQMacroCopyDialog(); + + WuQMacroCopyDialog(const WuQMacroCopyDialog&) = delete; + + WuQMacroCopyDialog& operator=(const WuQMacroCopyDialog&) = delete; + + const WuQMacro* getMacroToCopy() const; + + // ADD_NEW_METHODS_HERE + + public slots: + virtual void done(int r) override; + + private slots: + void macroGroupComboBoxItemActivated(int); + + void macroComboBoxItemActivated(int); + + private: + const WuQMacroGroup* getMacroGroup() const; + + std::vector m_macroGroups; + + QComboBox* m_macroGroupComboBox; + + QComboBox* m_macroNameComboBox; + + QPlainTextEdit* m_macroDescriptionTextEdit; + + QDialogButtonBox* m_dialogButtonBox; + + static QString s_lastSelectedMacroGroupIdentifier; + }; + +#ifdef __WU_Q_MACRO_COPY_DIALOG_DECLARE__ + QString WuQMacroCopyDialog::s_lastSelectedMacroGroupIdentifier = ""; +#endif // __WU_Q_MACRO_COPY_DIALOG_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_COPY_DIALOG_H__ diff --git a/src/GuiQt/WuQMacroCreateDialog.cxx b/src/GuiQt/WuQMacroCreateDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..52d730a621aa265e7eae292fbe30b7cbd981a5b2 --- /dev/null +++ b/src/GuiQt/WuQMacroCreateDialog.cxx @@ -0,0 +1,249 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ +#include "WuQMacroCreateDialog.h" +#undef __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "WuQMacro.h" +#include "WuQMacroGroup.h" +#include "WuQMacroManager.h" +#include "WuQMacroShortCutKeyComboBox.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacroCreateDialog + * \brief Dialog for creating a new macro + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param insertIntoMacroGroup + * If not NULL, do not show group selection and insert new macro + * into this group + * @param insertMacroAfter + * Used when inserting macro into a specific group + * @param parent + * The parent widget + */ +WuQMacroCreateDialog::WuQMacroCreateDialog(WuQMacroGroup* insertIntoMacroGroup, + WuQMacro* insertAfterMacro, + QWidget* parent) +: QDialog(parent), +m_insertIntoMacroGroup(insertIntoMacroGroup), +m_insertAfterMacro(insertAfterMacro) +{ + setWindowTitle("Record Macro"); + + m_macroGroups = WuQMacroManager::instance()->getActiveMacroGroups(); + + QLabel* nameLabel = new QLabel("Macro name:"); + QLabel* shortCutKeyLabel = new QLabel("Short Cut Key:"); + QLabel* shortCutKeyMaskLabel = new QLabel(WuQMacroManager::getShortCutKeysMask()); + QLabel* descriptionLabel = new QLabel("Description:"); + QLabel* macroGroupLabel = new QLabel("Store macro in:"); + + m_macroNameLineEdit = new QLineEdit(); + m_macroNameLineEdit->setText(WuQMacroManager::instance()->getNewMacroDefaultName()); + m_macroShortCutKeyComboBox = new WuQMacroShortCutKeyComboBox(this); + m_macroDescriptionTextEdit = new QPlainTextEdit(); + m_macroDescriptionTextEdit->setFixedHeight(100); + + bool insertIntoMacroGroupMatchFlag(false); + int32_t selectedMacroGroupIndex(-1); + m_macroGroupComboBox = new QComboBox(); + for (auto mg : m_macroGroups) { + if (insertIntoMacroGroup != NULL) { + if (mg == insertIntoMacroGroup) { + insertIntoMacroGroupMatchFlag = true; + selectedMacroGroupIndex = m_macroGroupComboBox->count(); + } + } + else if (mg->getUniqueIdentifier() == s_lastSelectedMacroGroupIdentifier) { + selectedMacroGroupIndex = m_macroGroupComboBox->count(); + } + m_macroGroupComboBox->addItem(mg->getName()); + } + if (selectedMacroGroupIndex < 0) { + selectedMacroGroupIndex = m_macroGroupComboBox->count() - 1; + } + if ((selectedMacroGroupIndex >= 0) + && (selectedMacroGroupIndex < m_macroGroupComboBox->count())) { + m_macroGroupComboBox->setCurrentIndex(selectedMacroGroupIndex); + } + + if (insertIntoMacroGroupMatchFlag) { + m_macroGroupComboBox->setEnabled(false); + } + + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnStretch(2, 0); + gridLayout->setColumnStretch(3, 100); + int row = 0; + gridLayout->addWidget(macroGroupLabel, row, 0); + gridLayout->addWidget(m_macroGroupComboBox, row, 1, 1, 3); + row++; + gridLayout->addWidget(nameLabel, row, 0); + gridLayout->addWidget(m_macroNameLineEdit, row, 1, 1, 3); + row++; + gridLayout->addWidget(shortCutKeyLabel, row, 0); + gridLayout->addWidget(shortCutKeyMaskLabel, row, 1); + gridLayout->addWidget(m_macroShortCutKeyComboBox->getWidget(), row, 2); + row++; + gridLayout->addWidget(descriptionLabel, row, 0); + gridLayout->addWidget(m_macroDescriptionTextEdit, row, 1, 1, 3); + row++; + + m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + QObject::connect(m_dialogButtonBox, &QDialogButtonBox::accepted, + this, &WuQMacroCreateDialog::accept); + QObject::connect(m_dialogButtonBox, &QDialogButtonBox::rejected, + this, &WuQMacroCreateDialog::reject); + + QVBoxLayout* dialogLayout = new QVBoxLayout(this); + dialogLayout->addLayout(gridLayout, 100); + dialogLayout->addWidget(m_dialogButtonBox); + + setFixedHeight(sizeHint().height()); + +} + + +/** + * Constructor. + * + * @param parent + * The parent widget + */ +WuQMacroCreateDialog::WuQMacroCreateDialog(QWidget* parent) +: WuQMacroCreateDialog(NULL, + NULL, + parent) +{ + /* delegating constructor does the work */ +} + +/** + * Destructor. + */ +WuQMacroCreateDialog::~WuQMacroCreateDialog() +{ +} + +/** + * Called when user clicks OK or Cancel + * + * @param r + * The dialog code (Accepted or Rejected) + */ +void +WuQMacroCreateDialog::done(int r) +{ + if (r == QDialog::Accepted) { + const QString name(m_macroNameLineEdit->text().trimmed()); + if (name.isEmpty()) { + QMessageBox::critical(this, + "Error", + "Name is missing", + QMessageBox::Ok, + QMessageBox::Ok); + return; + } + + m_macro = new WuQMacro(); + m_macro->setName(name); + m_macro->setShortCutKey(m_macroShortCutKeyComboBox->getSelectedShortCutKey()); + m_macro->setDescription(m_macroDescriptionTextEdit->toPlainText()); + + const int32_t groupIndex = m_macroGroupComboBox->currentIndex(); + if (groupIndex >= 0) { + WuQMacroGroup* macroGroup = m_macroGroups[groupIndex]; + if (macroGroup == m_insertIntoMacroGroup) { + int32_t insertAtIndex = 0; + if (m_insertAfterMacro != NULL) { + insertAtIndex = macroGroup->getIndexOfMacro(m_insertAfterMacro) + 1; + } + if (insertAtIndex >= 0) { + macroGroup->insertMacroAtIndex(insertAtIndex, + m_macro); + } + else { + macroGroup->addMacro(m_macro); + } + } + else { + macroGroup->addMacro(m_macro); + } + s_lastSelectedMacroGroupIdentifier = macroGroup->getUniqueIdentifier(); + } + } + + QDialog::done(r); +} + +/** + * @return Pointer to new macro. Macro has been added to a group. + * Do not delete the pointer. + */ +WuQMacro* +WuQMacroCreateDialog::getNewMacro() const +{ + return m_macro; +} + +/** + * @return Create a combo box with valid function keys. + * Method is static so that other classes may use it. + */ +QComboBox* +WuQMacroCreateDialog::createFunctionKeyComboBox() +{ + QComboBox* comboBox = new QComboBox(); + comboBox->addItem(" "); + + const char firstChar = 'A'; + const char lastChar = 'Z'; + for (char ch = firstChar; ch <= lastChar; ch++) { + comboBox->addItem(QString(ch)); + } + + return comboBox; +} + diff --git a/src/GuiQt/WuQMacroCreateDialog.h b/src/GuiQt/WuQMacroCreateDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..e26cd1c05b20fe57e0a3e019ea6a43ff208f2fa2 --- /dev/null +++ b/src/GuiQt/WuQMacroCreateDialog.h @@ -0,0 +1,95 @@ +#ifndef __WU_Q_MACRO_CREATE_DIALOG_H__ +#define __WU_Q_MACRO_CREATE_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QComboBox; +class QDialogButtonBox; +class QLineEdit; +class QPlainTextEdit; + + +namespace caret { + + class WuQMacro; + class WuQMacroGroup; + class WuQMacroShortCutKeyComboBox; + + class WuQMacroCreateDialog : public QDialog { + + Q_OBJECT + + public: + WuQMacroCreateDialog(QWidget* parent = 0); + + WuQMacroCreateDialog(WuQMacroGroup* insertIntoMacroGroup, + WuQMacro* insertAfterMacro, + QWidget* parent = 0); + + virtual ~WuQMacroCreateDialog(); + + WuQMacroCreateDialog(const WuQMacroCreateDialog&) = delete; + + WuQMacroCreateDialog& operator=(const WuQMacroCreateDialog&) = delete; + + WuQMacro* getNewMacro() const; + + // ADD_NEW_METHODS_HERE + + static QComboBox* createFunctionKeyComboBox(); + + public slots: + virtual void done(int r) override; + + private: + std::vector m_macroGroups; + + QComboBox* m_macroGroupComboBox; + + QLineEdit* m_macroNameLineEdit; + + WuQMacroShortCutKeyComboBox* m_macroShortCutKeyComboBox; + + QPlainTextEdit* m_macroDescriptionTextEdit; + + QDialogButtonBox* m_dialogButtonBox; + + WuQMacro* m_macro = NULL; + + WuQMacroGroup* m_insertIntoMacroGroup = NULL; + + WuQMacro* m_insertAfterMacro = NULL; + + static QString s_lastSelectedMacroGroupIdentifier; + }; + +#ifdef __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ + QString WuQMacroCreateDialog::s_lastSelectedMacroGroupIdentifier = ""; +#endif // __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_CREATE_DIALOG_H__ diff --git a/src/GuiQt/WuQMacroCustomOperationManagerInterface.h b/src/GuiQt/WuQMacroCustomOperationManagerInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..2a8011c0dc12625898017e3f22dcaf09f1fcf30c --- /dev/null +++ b/src/GuiQt/WuQMacroCustomOperationManagerInterface.h @@ -0,0 +1,124 @@ +#ifndef __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_H__ +#define __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +class QString; +class QWidget; + +namespace caret { + class WuQMacroCommand; + class WuQMacroCommandParameter; + class WbMacroCustomDataInfo; + class WuQMacroExecutorMonitor; + class WuQMacroExecutorOptions; + + class WuQMacroCustomOperationManagerInterface { + + public: + WuQMacroCustomOperationManagerInterface() { } + + virtual ~WuQMacroCustomOperationManagerInterface() { } + + WuQMacroCustomOperationManagerInterface(const WuQMacroCustomOperationManagerInterface&) = delete; + + WuQMacroCustomOperationManagerInterface& operator=(const WuQMacroCustomOperationManagerInterface&) = delete; + + /** + * Get info for data in a custom parameter + * + * @param browserWindowIndex + * Index of browser window + * @param macroCommand + * Macro command that contains the parameter + * @param parameter + * Parameter for info + * @param dataInfo + * Updated with data info in this method + * @return + * True if the data info is valid + */ + virtual bool getCustomParameterDataInfo(const int32_t browserWindowIndex, + WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* parameter, + WbMacroCustomDataInfo& dataInfoOut) = 0; + + /** + * Run a custom-defined macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * The executor monitor + * @param executorOptions + * Options for the executor + * @param customMacroCommand + * Custom macro command to run + * @param errorMessageOut + * Contains any error information or empty if no error + * @return + * True if command executed successfully, else false + */ + virtual bool executeCustomOperationMacroCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand, + QString& errorMessageOut) = 0; + + /** + * @return Names of custom operation defined macro commands + */ + virtual std::vector getNamesOfCustomOperationMacroCommands() = 0; + + /** + * @return All custom operation commands. Caller is responsible for deleting + * all content of the returned vector. + */ + virtual std::vector getAllCustomOperationMacroCommands() = 0; + + /** + * Get a new instance of a custom operation for the given macro command name + * + * @param customMacroCommandName + * Name of custom macro command + * @param errorMessageOut + * Contains any error information or empty if no error + * @return + * Pointer to command or NULL if not valid + */ + virtual WuQMacroCommand* newInstanceOfCustomOperationMacroCommand(const QString& customMacroCommandName, + QString& errorMessageOut) = 0; + + // ADD_NEW_METHODS_HERE + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_DECLARE__ + // +#endif // __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_H__ diff --git a/src/GuiQt/WuQMacroDialog.cxx b/src/GuiQt/WuQMacroDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..802f7aeba4da7de2c66deed1a8e32582638f0c83 --- /dev/null +++ b/src/GuiQt/WuQMacroDialog.cxx @@ -0,0 +1,2426 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_DIALOG_DECLARE__ +#include "WuQMacroDialog.h" +#undef __WU_Q_MACRO_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "ElapsedTimer.h" +#include "MovieRecorder.h" +#include "MovieRecordingDialog.h" +#include "SessionManager.h" +#include "WuQMacro.h" +#include "WuQMacroCopyDialog.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameterWidget.h" +#include "WuQMacroGroup.h" +#include "WuQMacroExecutor.h" +#include "WuQMacroExecutorMonitor.h" +#include "WuQMacroManager.h" +#include "WuQMacroMouseEventInfo.h" +#include "WuQMacroNewCommandSelectionDialog.h" +#include "WuQMacroShortCutKeyComboBox.h" +#include "WuQMacroStandardItemTypeEnum.h" +#include "WuQtUtilities.h" + +using namespace caret; + +/** + * \class caret::WuQMacroDialog + * \brief Dialog for managing macros + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param defaultMacroName + * Default name for new macro + * @param parent + * The dialog's parent widget. + */ +WuQMacroDialog::WuQMacroDialog(QWidget* parent) +: QDialog(parent) +{ + setWindowTitle("Macros"); + this->setAttribute(Qt::WA_DeleteOnClose, false); + + m_macroGroups = WuQMacroManager::instance()->getActiveMacroGroups(); + + QLabel* macroGroupLabel = new QLabel("Macros in:"); + + m_macroGroupComboBox = new QComboBox(); + QObject::connect(m_macroGroupComboBox, static_cast(&QComboBox::activated), + this, &WuQMacroDialog::macroGroupComboBoxActivated); + + m_resetMacroGroupToolButton = new QToolButton(); + m_resetMacroGroupToolButton->setText(""); + m_resetMacroGroupToolButton->setToolTip("Reload current scene"); + QPixmap resetPixmap = createEditingToolButtonPixmap(m_resetMacroGroupToolButton, + EditButton::RESET); + m_resetMacroGroupToolButton->setIcon(resetPixmap); + QObject::connect(m_resetMacroGroupToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::macroGroupResetToolButtonClicked); + + m_macroGroupToolButton = new QToolButton(); + m_macroGroupToolButton->setText("..."); + m_macroGroupToolButton->setToolTip("Export and import macro groups"); + QObject::connect(m_macroGroupToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::macroGroupToolButtonClicked); + + QSize buttonSize(std::max(m_resetMacroGroupToolButton->sizeHint().width(), + m_macroGroupToolButton->sizeHint().width()), + std::max(m_resetMacroGroupToolButton->sizeHint().height(), + m_macroGroupToolButton->sizeHint().height())); + m_resetMacroGroupToolButton->setFixedSize(buttonSize); + m_macroGroupToolButton->setFixedSize(buttonSize); + + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->setContentsMargins(0, 0, 0, 0); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 100); + gridLayout->setColumnStretch(2, 0); + gridLayout->setColumnStretch(3, 0); + int row = 0; + gridLayout->addWidget(macroGroupLabel, row, 0); + gridLayout->addWidget(m_macroGroupComboBox, row, 1); + gridLayout->addWidget(m_resetMacroGroupToolButton, row, 2); + gridLayout->addWidget(m_macroGroupToolButton, row, 3); + row++; + gridLayout->addWidget(createHorizontalLine(), row, 0, 1, 4); + row++; + gridLayout->addWidget(createMacroRunAndEditingToolButtons(), row, 0, 1, 4); + row++; + + for (int32_t iRow = 0; iRow < gridLayout->rowCount(); iRow++) { + gridLayout->setRowStretch(iRow, 0); + } + + QWidget* macroSelectionWidget = createMacroAndCommandSelectionWidget(); + m_macroWidget = createMacroDisplayWidget(); + m_commandWidget = createCommandDisplayWidget(); + m_emptyWidget = new QWidget(); + m_stackedWidget = new QStackedWidget(); + m_stackedWidget->setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); + m_stackedWidget->addWidget(m_macroWidget); + m_stackedWidget->addWidget(m_commandWidget); + m_stackedWidget->addWidget(m_emptyWidget); + m_stackedWidget->setCurrentWidget(m_emptyWidget); + QScrollArea* stackedScrollArea = new QScrollArea(); + stackedScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + stackedScrollArea->setWidget(m_stackedWidget); + stackedScrollArea->setWidgetResizable(true); + + m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Close); + QObject::connect(m_dialogButtonBox, &QDialogButtonBox::rejected, + this, &WuQMacroDialog::close); + QObject::connect(m_dialogButtonBox, &QDialogButtonBox::clicked, + this, &WuQMacroDialog::buttonBoxButtonClicked); + + const bool splitterFlag(false); + if (splitterFlag) { + /* + * Use a splitter between the list widget (macro/command selection) + * and the parameters (macro/command editing). + * Splitter allows user to allocate space between the two. + */ + QSplitter* splitter = new QSplitter(); + splitter->setOrientation(Qt::Vertical); + macroSelectionWidget->setMinimumHeight(50); + splitter->addWidget(macroSelectionWidget); + splitter->addWidget(stackedScrollArea); + splitter->setStretchFactor(0, 35); + splitter->setStretchFactor(1, 65); + + QVBoxLayout* dialogLayout = new QVBoxLayout(this); + dialogLayout->addLayout(gridLayout); + dialogLayout->addWidget(splitter); + dialogLayout->addWidget(m_dialogButtonBox); + } + else { + /* + * Stretch the list widget (macro/command selection) + * but no stretch for the parameters (macro/command editing) + */ + QVBoxLayout* dialogLayout = new QVBoxLayout(this); + dialogLayout->addLayout(gridLayout); + dialogLayout->addWidget(macroSelectionWidget, 100); + dialogLayout->addWidget(stackedScrollArea, 0); + dialogLayout->addWidget(m_dialogButtonBox, 0); + } + + updateDialogContents(); + + /* + * Disable auto default for all push buttons + */ + QList allChildPushButtons = findChildren(QRegExp(".*")); + QListIterator allChildPushButtonsIterator(allChildPushButtons); + while (allChildPushButtonsIterator.hasNext()) { + QPushButton* pushButton = allChildPushButtonsIterator.next(); + pushButton->setAutoDefault(false); + pushButton->setDefault(false); + } +} + +/** + * Destructor. + */ +WuQMacroDialog::~WuQMacroDialog() +{ +} + +/** + * Called when close event is issuedf + * + * @param event + * The close event + */ +void +WuQMacroDialog::closeEvent(QCloseEvent* event) +{ + s_previousDialogGeometry = saveGeometry(); + + QDialog::closeEvent(event); +} + +void +WuQMacroDialog::restorePositionAndSize() +{ + if ( ! s_previousDialogGeometry.isEmpty()) { + restoreGeometry(s_previousDialogGeometry); + } +} + + +/** + * @return Widget with run and editing buttons + */ +QWidget* +WuQMacroDialog::createMacroRunAndEditingToolButtons() +{ + m_runMacroToolButton = new QToolButton(); + m_runMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_runMacroToolButton->setText("Run"); + QPixmap runPixmap = createEditingToolButtonPixmap(m_runMacroToolButton, + EditButton::RUN); + m_runMacroToolButton->setIcon(runPixmap); + m_runMacroToolButton->setToolTip("Runs the selected macro. If a command is selected, " + "the macro containing the command is run."); + QObject::connect(m_runMacroToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::runMacroToolButtonClicked); + + m_pauseMacroToolButton = new QToolButton(); + m_pauseMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_pauseMacroToolButton->setText("Pause"); + QPixmap pausePixmap = createEditingToolButtonPixmap(m_pauseMacroToolButton, + EditButton::PAUSE); + m_pauseMacroToolButton->setIcon(pausePixmap); + m_pauseMacroToolButton->setToolTip("Pause or continue a macro. Button is highlighted " + "when a macro is paused."); + m_pauseMacroToolButton->setCheckable(true); + QObject::connect(m_pauseMacroToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::pauseContinueMacroToolButtonClicked); + + m_stopMacroToolButton = new QToolButton(); + m_stopMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_stopMacroToolButton->setText("Stop"); + QPixmap stopPixmap = createEditingToolButtonPixmap(m_stopMacroToolButton, + EditButton::STOP); + m_stopMacroToolButton->setIcon(stopPixmap); + m_stopMacroToolButton->setToolTip("Stop the currently running macro. Response may not be immediate."); + QObject::connect(m_stopMacroToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::stopMacroToolButtonClicked); + + m_recordMacroToolButton = new QToolButton(); + m_recordMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_recordMacroToolButton->setText("Record"); + m_recordMacroToolButtonIconOff = createEditingToolButtonPixmap(m_recordMacroToolButton, + EditButton::RECORD_OFF); + m_recordMacroToolButtonIconOn = createEditingToolButtonPixmap(m_recordMacroToolButton, + EditButton::RECORD_ON); + m_recordMacroToolButton->setIcon(m_recordMacroToolButtonIconOff); + m_recordMacroToolButton->setToolTip("Record a new macro or record new commands"); + QObject::connect(m_recordMacroToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::recordMacroToolButtonClicked); + + m_editingMoveUpToolButton = new QToolButton(); + QPixmap moveUpPixmap = createEditingToolButtonPixmap(m_editingMoveUpToolButton, + EditButton::MOVE_UP); + m_editingMoveUpToolButton->setIcon(moveUpPixmap); + m_editingMoveUpToolButton->setToolTip("Move selected macro/command up"); + QObject::connect(m_editingMoveUpToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::editingMoveUpToolButtonClicked); + + m_editingMoveDownToolButton = new QToolButton(); + QPixmap moveDownPixmap = createEditingToolButtonPixmap(m_editingMoveDownToolButton, + EditButton::MOVE_DOWN); + m_editingMoveDownToolButton->setIcon(moveDownPixmap); + m_editingMoveDownToolButton->setToolTip("Move selected macro/command down"); + QObject::connect(m_editingMoveDownToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::editingMoveDownToolButtonClicked); + + m_editingDeleteToolButton = new QToolButton(); + QPixmap deletePixmap = createEditingToolButtonPixmap(m_editingDeleteToolButton, + EditButton::DELETER); + m_editingDeleteToolButton->setIcon(deletePixmap); + m_editingDeleteToolButton->setToolTip("Delete the selected macro/command"); + QObject::connect(m_editingDeleteToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::editingDeleteToolButtonClicked); + + m_editingInsertToolButton = new QToolButton(); + QPixmap insertPixmap = createEditingToolButtonPixmap(m_editingInsertToolButton, + EditButton::INSERTER); + m_editingInsertToolButton->setIcon(insertPixmap); + m_editingInsertToolButton->setToolTip("Insert a new macro or macro command below the selected item"); + QObject::connect(m_editingInsertToolButton, &QToolButton::clicked, + this, &WuQMacroDialog::editingInsertToolButtonClicked); + + const int spaceAmount(7); + QWidget* widget = new QWidget(); + QHBoxLayout* toolButtonLayout = new QHBoxLayout(widget); + toolButtonLayout->setContentsMargins(0, 0, 0, 0); + toolButtonLayout->addWidget(m_stopMacroToolButton); + toolButtonLayout->addWidget(m_runMacroToolButton); + toolButtonLayout->addWidget(m_pauseMacroToolButton); + toolButtonLayout->addWidget(m_recordMacroToolButton); + toolButtonLayout->addSpacing(3 * spaceAmount); + toolButtonLayout->addStretch(); + toolButtonLayout->addWidget(m_editingInsertToolButton); + toolButtonLayout->addSpacing(spaceAmount); + toolButtonLayout->addWidget(m_editingMoveUpToolButton); + toolButtonLayout->addWidget(m_editingMoveDownToolButton); + toolButtonLayout->addSpacing(spaceAmount); + toolButtonLayout->addWidget(m_editingDeleteToolButton); + + return widget; +} + +/** + * @return the macro and command selection widget + */ +QWidget* +WuQMacroDialog::createMacroAndCommandSelectionWidget() +{ + m_treeView = new QTreeView(); + m_treeView->setHeaderHidden(true); + QObject::connect(m_treeView, &QTreeView::clicked, + this, &WuQMacroDialog::treeViewItemClicked); + m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); + QObject::connect(m_treeView, &QTreeView::customContextMenuRequested, + this, &WuQMacroDialog::treeViewCustomContextMenuRequested); + + return m_treeView; +} + +/** + * @return The widget displayed when a macro is selected + */ +QWidget* +WuQMacroDialog::createMacroDisplayWidget() +{ + QLabel* macroNameLabel = new QLabel("Name:"); + m_macroNameLineEdit = new QLineEdit(); + QObject::connect(m_macroNameLineEdit, &QLineEdit::textEdited, + this, &WuQMacroDialog::macroNameLineEditTextEdited); + + QLabel* shortCutKeyLabel = new QLabel("Short Cut Key:"); + QLabel* shortCutKeyMaskLabel = new QLabel(WuQMacroManager::getShortCutKeysMask()); + m_macroShortCutKeyComboBox = new WuQMacroShortCutKeyComboBox(this); + QObject::connect(m_macroShortCutKeyComboBox, &WuQMacroShortCutKeyComboBox::shortCutKeySelected, + this, &WuQMacroDialog::macroShortCutKeySelected); + + QLabel* descriptionLabel = new QLabel("Description:"); + m_macroDescriptionTextEdit = new QPlainTextEdit(); + m_macroDescriptionTextEdit->setFixedHeight(100); + QObject::connect(m_macroDescriptionTextEdit, &QPlainTextEdit::textChanged, + this, &WuQMacroDialog::macroDescriptionTextEditChanged); + + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->setContentsMargins(0, 0, 0, 0); + gridLayout->setVerticalSpacing(5); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnStretch(2, 100); + int row = 0; + gridLayout->addWidget(macroNameLabel, row, 0); + gridLayout->addWidget(m_macroNameLineEdit, row, 1, 1, 2); + row++; + gridLayout->addWidget(shortCutKeyLabel, row, 0); + gridLayout->addWidget(shortCutKeyMaskLabel, row, 1); + gridLayout->addWidget(m_macroShortCutKeyComboBox->getWidget(), row, 2, Qt::AlignLeft); + row++; + gridLayout->addWidget(descriptionLabel, row, 0, Qt::AlignTop); + gridLayout->addWidget(m_macroDescriptionTextEdit, row, 1, 1, 2); + row++; + + QHBoxLayout* titleLayout = new QHBoxLayout(); + titleLayout->setContentsMargins(0, 0, 0, 0); + titleLayout->addWidget(new QLabel("Macro ")); + titleLayout->addWidget(createHorizontalLine(), 100); + + QHBoxLayout* runOptionsTitleLayout = new QHBoxLayout(); + runOptionsTitleLayout->setContentsMargins(0, 0, 0, 0); + runOptionsTitleLayout->addWidget(new QLabel("Run Macro Options ")); + runOptionsTitleLayout->addWidget(createHorizontalLine(), 100); + + QWidget* widget = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->setSpacing(layout->spacing() / 2); + layout->addLayout(titleLayout); + layout->addLayout(gridLayout); + layout->addLayout(runOptionsTitleLayout); + layout->addWidget(createRunOptionsWidget()); + layout->addStretch(); + + return widget; +} + +/** + * Called when macro name line edit text changed + * @param text + */ +void +WuQMacroDialog::macroNameLineEditTextEdited(const QString& text) +{ + WuQMacro* macro = getSelectedMacro(); + if (macro != NULL) { + macro->setName(text); + m_macroNameLineEditBlockUpdateFlag = true; + WuQMacroManager::instance()->macroWasModified(macro); + m_macroNameLineEditBlockUpdateFlag = false; + } +} + +/** + * Called when macro short cut key is selected + * + * @param shortCutKey + * Shortcut key that was selected + */ +void +WuQMacroDialog::macroShortCutKeySelected(const WuQMacroShortCutKeyEnum::Enum shortCutKey) +{ + WuQMacro* macro = getSelectedMacro(); + if (macro != NULL) { + macro->setShortCutKey(shortCutKey); + WuQMacroManager::instance()->macroWasModified(macro); + updateMacroWidget(macro); + } +} + +/** + * Called when macro description text edit is changed + */ +void +WuQMacroDialog::macroDescriptionTextEditChanged() +{ + WuQMacro* macro = getSelectedMacro(); + if (macro != NULL) { + const QString text = m_macroDescriptionTextEdit->toPlainText(); + macro->setDescription(text); + m_macroDescriptionTextEditBlockUpdateFlag = true; + WuQMacroManager::instance()->macroWasModified(macro); + m_macroDescriptionTextEditBlockUpdateFlag = false; + } +} + +/** + * @return New instance of widget containing macro run options + */ +QWidget* +WuQMacroDialog::createRunOptionsWidget() +{ + QWidget* widget = new QWidget(); + + QLabel* windowLabel = new QLabel("Window"); + m_runOptionsWindowComboBox = new QComboBox(); + m_runOptionsWindowComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + + m_runOptionLoopCheckBox = new QCheckBox("Loop"); + m_runOptionLoopCheckBox->setChecked(false); + m_runOptionLoopCheckBox->setToolTip("Run macro in a loop until stopped by user"); + QObject::connect(m_runOptionLoopCheckBox, &QCheckBox::clicked, + this, &WuQMacroDialog::runOptionLoopCheckBoxClicked); + + m_runOptionMoveMouseCheckBox = new QCheckBox("Move mouse to to highlight controls"); + m_runOptionMoveMouseCheckBox->setChecked(true); + m_runOptionMoveMouseCheckBox->setToolTip("As macro runs, the mouse is moved to\n" + "highlight user-interface controls"); + QObject::connect(m_runOptionMoveMouseCheckBox, &QCheckBox::clicked, + this, &WuQMacroDialog::runOptionMoveMouseCheckBoxClicked); + + m_runOptionRecordMovieWhileMacroRunsCheckBox = new QCheckBox("Record movie while macro runs"); + m_runOptionRecordMovieWhileMacroRunsCheckBox->setChecked(false); + m_runOptionRecordMovieWhileMacroRunsCheckBox->setToolTip("While the macro runs, add images to Movie Recorder"); + QObject::connect(m_runOptionRecordMovieWhileMacroRunsCheckBox, &QCheckBox::clicked, + this, &WuQMacroDialog::runOptionRecordMovieCheckBoxClicked); + + m_runOptionCreateMovieAfterMacroRunsCheckBox = new QCheckBox("Create movie after macro finishes"); + m_runOptionCreateMovieAfterMacroRunsCheckBox->setChecked(false); + m_runOptionCreateMovieAfterMacroRunsCheckBox->setToolTip("After macro finishes, create the movie"); + QObject::connect(m_runOptionCreateMovieAfterMacroRunsCheckBox, &QCheckBox::clicked, + this, &WuQMacroDialog::runOptionCreateMovieCheckBoxClicked); + + m_ignoreDelaysAndDurationsCheckBox = new QCheckBox("Ignore delays and durations"); + const QString ignoreToolTip("Ignore delays and durations and minimize iterations " + "to quickly execute macro (for debugging)"); + m_ignoreDelaysAndDurationsCheckBox->setToolTip(ignoreToolTip); + QObject::connect(m_ignoreDelaysAndDurationsCheckBox, &QCheckBox::clicked, + this, &WuQMacroDialog::runOptionIgnoreDelaysAndDurationsCheckBoxClicked); + + QHBoxLayout* windowLayout = new QHBoxLayout(); + windowLayout->setContentsMargins(0, 0, 0, 0); + windowLayout->addWidget(windowLabel); + windowLayout->addWidget(m_runOptionsWindowComboBox); + windowLayout->addStretch(); + + /* + * In layout, create movie option is indented + */ + QGridLayout* runOptionsLayout = new QGridLayout(widget); + runOptionsLayout->setColumnMinimumWidth(0, 15); + runOptionsLayout->setColumnStretch(0, 0); + runOptionsLayout->setColumnStretch(1, 100); + int row = 0; + runOptionsLayout->addLayout(windowLayout, row, 0, 1, 2, Qt::AlignLeft); + row++; + runOptionsLayout->addWidget(m_runOptionLoopCheckBox, row, 0, 1, 2, Qt::AlignLeft); + row++; + runOptionsLayout->addWidget(m_ignoreDelaysAndDurationsCheckBox, row, 0, 1, 2, Qt::AlignLeft); + row++; + runOptionsLayout->addWidget(m_runOptionMoveMouseCheckBox, row, 0, 1, 2, Qt::AlignLeft); + row++; + runOptionsLayout->addWidget(m_runOptionRecordMovieWhileMacroRunsCheckBox, row, 0, 1, 2, Qt::AlignLeft); + row++; + runOptionsLayout->addWidget(m_runOptionCreateMovieAfterMacroRunsCheckBox, row, 1, Qt::AlignLeft); + row++; + + return widget; +} + +/** + * Called when run options move mouse checkbox is changed + * + * @param checked + * New checked status. + */ +void +WuQMacroDialog::runOptionMoveMouseCheckBoxClicked(bool checked) +{ + WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); + CaretAssert(options); + options->setShowMouseMovement(checked); +} + +/** + * Called when run options loop checkbox is changed + * + * @param checked + * New checked status. + */ +void +WuQMacroDialog::runOptionLoopCheckBoxClicked(bool checked) +{ + WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); + CaretAssert(options); + options->setLooping(checked); +} + +/** + * Called when run options record movie checkbox is changed + * + * @param checked + * New checked status. + */ +void +WuQMacroDialog::runOptionRecordMovieCheckBoxClicked(bool checked) +{ + WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); + CaretAssert(options); + options->setRecordMovieDuringExecution(checked); + updateCreateMovieCheckBox(); +} + +/** + * Called when run options create movie checkbox is changed + * + * @param checked + * New checked status. + */ +void +WuQMacroDialog::runOptionCreateMovieCheckBoxClicked(bool checked) +{ + WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); + CaretAssert(options); + + /* + * If transitioning from OFF to ON, verify file name + */ + if (checked + && ( ! options->isCreateMovieAfterMacroExecution())) { + MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); + const QString filename = MovieRecordingDialog::getMovieFileNameFromFileDialog(m_runOptionCreateMovieAfterMacroRunsCheckBox); + if (filename.isEmpty()) { + return; + } + movieRecorder->setMovieFileName(filename); + } + options->setCreateMovieAfterMacroExecution(checked); +} + +/** + * Called when run options ignore delays and durations checkbox is changed + * + * @param checked + * New checked status. + */ +void +WuQMacroDialog::runOptionIgnoreDelaysAndDurationsCheckBoxClicked(bool checked) +{ + WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); + CaretAssert(options); + options->setIgnoreDelaysAndDurations(checked); +} + +/** + * Called when a button in dialog is clicked + * + * @param button + * Button that was clicked. + */ +void +WuQMacroDialog::buttonBoxButtonClicked(QAbstractButton* /*button*/) +{ +} + +/** + * @return The widget displayed when a commnand is selected + */ +QWidget* +WuQMacroDialog::createCommandDisplayWidget() +{ + QLabel* titleLabel = new QLabel("Title:"); + m_commandTitleLabel = new QLabel(); + + QLabel* nameLabel = new QLabel("GUI Name:"); + m_commandNameLabel = new QLabel(); + + QLabel* typeLabel = new QLabel("GUI Type:"); + m_commandTypeLabel = new QLabel(); + + QLabel* delayLabel = new QLabel("Delay:"); + m_commandDelaySpinBox = new QDoubleSpinBox(); + m_commandDelaySpinBox->setMinimum(0.0); + m_commandDelaySpinBox->setMaximum(1000.0); + m_commandDelaySpinBox->setSingleStep(1.0); + m_commandDelaySpinBox->setDecimals(1); + m_commandDelaySpinBox->setToolTip("Delay, in seconds, before running command"); + m_commandDelaySpinBox->setSizePolicy(QSizePolicy::Fixed, + m_commandDelaySpinBox->sizePolicy().verticalPolicy()); + QObject::connect(m_commandDelaySpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &WuQMacroDialog::macroCommandDelaySpinBoxValueChanged); + QLabel* delayTwoLabel = new QLabel("seconds before command"); + + QLabel* descriptionLabel = new QLabel("Description:"); + m_commandDescriptionTextEdit = new QPlainTextEdit(); + m_commandDescriptionTextEdit->setMaximumHeight(100); + QObject::connect(m_commandDescriptionTextEdit, &QPlainTextEdit::textChanged, + this, &WuQMacroDialog::macroCommandDescriptionTextEditChanged); + + QWidget* commandInfoWidget = new QWidget(); + commandInfoWidget->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, + QSizePolicy::Fixed)); + QGridLayout* commandInfoLayout = new QGridLayout(commandInfoWidget); + commandInfoLayout->setContentsMargins(0, 0, 0, 0); + commandInfoLayout->setColumnStretch(0, 0); + commandInfoLayout->setColumnStretch(1, 0); + commandInfoLayout->setColumnStretch(2, 100); + int row = 0; + commandInfoLayout->addWidget(titleLabel, row, 0); + commandInfoLayout->addWidget(m_commandTitleLabel, row, 1, 1, 2, Qt::AlignLeft); + row++; + commandInfoLayout->addWidget(nameLabel, row, 0); + commandInfoLayout->addWidget(m_commandNameLabel, row, 1, 1, 2, Qt::AlignLeft); + row++; + commandInfoLayout->addWidget(typeLabel, row, 0); + commandInfoLayout->addWidget(m_commandTypeLabel, row, 1, 1, 2, Qt::AlignLeft); + row++; + commandInfoLayout->addWidget(delayLabel, row, 0); + commandInfoLayout->addWidget(m_commandDelaySpinBox, row, 1); + commandInfoLayout->addWidget(delayTwoLabel, row, 2, Qt::AlignLeft); + row++; + commandInfoLayout->addWidget(descriptionLabel, row, 0, (Qt::AlignLeft | Qt::AlignTop)); + commandInfoLayout->addWidget(m_commandDescriptionTextEdit, row, 1, 1, 2); + row++; + + QWidget* parametersWidget = new QWidget(); + parametersWidget->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, + QSizePolicy::Fixed)); + m_parameterWidgetsGridLayout = new QGridLayout(parametersWidget); + m_parameterWidgetsGridLayout->setContentsMargins(0, 0, 0, 0); + m_parameterWidgetsGridLayout->setVerticalSpacing(2); + m_parameterWidgetsGridLayout->setColumnStretch(0, 0); + m_parameterWidgetsGridLayout->setColumnStretch(1, 100); + + + QHBoxLayout* parametersLayout = new QHBoxLayout(); + parametersLayout->setContentsMargins(0, 0, 0, 0); + parametersLayout->addWidget(new QLabel("Parameters")); + parametersLayout->addWidget(createHorizontalLine(), 100); + + QWidget* widget = new QWidget(); + QVBoxLayout* widgetLayout = new QVBoxLayout(widget); + widgetLayout->addWidget(commandInfoWidget); + widgetLayout->addLayout(parametersLayout); + widgetLayout->addWidget(parametersWidget); + widgetLayout->addSpacing(6); + widgetLayout->addStretch(); + + return widget; +} + +/** + * Update content of the dialog + */ +void +WuQMacroDialog::updateDialogContents() +{ + QString selectedUniqueIdentifer; + const QVariant dataSelected = m_macroGroupComboBox->currentData(); + if (dataSelected.isValid()) { + if (dataSelected.type() == QVariant::String) { + selectedUniqueIdentifer = dataSelected.toString(); + } + } + + m_macroGroups = WuQMacroManager::instance()->getActiveMacroGroups(); + + m_macroGroupComboBox->clear(); + for (auto mg : m_macroGroups) { + m_macroGroupComboBox->addItem(mg->getName(), + mg->getUniqueIdentifier()); + } + + int32_t selectedIndex = m_macroGroupComboBox->findData(selectedUniqueIdentifer); + if (selectedIndex < 0) { + selectedIndex = m_macroGroupComboBox->count() - 1; + } + if ((selectedIndex >= 0) + && (selectedIndex < m_macroGroupComboBox->count())) { + m_macroGroupComboBox->setCurrentIndex(selectedIndex); + } + + m_macroGroupToolButton->setEnabled(m_macroGroupComboBox->count() > 0); + + const QString windowText = m_runOptionsWindowComboBox->currentText(); + m_runOptionsWindowComboBox->clear(); + const std::vector windowIDs = WuQMacroManager::instance()->getMainWindowIdentifiers(); + for (const auto id : windowIDs) { + m_runOptionsWindowComboBox->addItem(id); + } + m_runOptionsWindowComboBox->setCurrentText(windowText); + + const WuQMacroExecutorOptions* runOptions = WuQMacroManager::instance()->getExecutorOptions(); + CaretAssert(runOptions); + m_runOptionMoveMouseCheckBox->setChecked(runOptions->isShowMouseMovement()); + m_runOptionLoopCheckBox->setChecked(runOptions->isLooping()); + m_runOptionRecordMovieWhileMacroRunsCheckBox->setChecked(runOptions->isRecordMovieDuringExecution()); + m_ignoreDelaysAndDurationsCheckBox->setChecked(runOptions->isIgnoreDelaysAndDurations()); + + updateCreateMovieCheckBox(); + + macroGroupComboBoxActivated(selectedIndex); +} + +/** + * Update the create movie checkbox status + */ +void +WuQMacroDialog::updateCreateMovieCheckBox() +{ + const WuQMacroExecutorOptions* runOptions = WuQMacroManager::instance()->getExecutorOptions(); + CaretAssert(runOptions); + m_runOptionCreateMovieAfterMacroRunsCheckBox->setChecked(runOptions->isCreateMovieAfterMacroExecution()); + m_runOptionCreateMovieAfterMacroRunsCheckBox->setEnabled(runOptions->isRecordMovieDuringExecution()); +} + +/** + * Called when an item in the tree view is clicked by user + * + * @param modelIndex + * Model index of item selected + */ +void +WuQMacroDialog::treeViewItemClicked(const QModelIndex& /*modelIndex*/) +{ + /* + * Unused at this time. The signal only works when user + * click's an item and not when an arrow key is used + * to select an item. Replacement is for the selection + * model to connect to selectionModelRowChanged(). + */ +} + +/** + * Called to display custom context menu for the tree view + */ +void +WuQMacroDialog::treeViewCustomContextMenuRequested(const QPoint& pos) +{ + QModelIndex modelIndex = m_treeView->indexAt(pos); + if (modelIndex.isValid()) { + WuQMacroCommand* command = getSelectedMacroCommand(); + if (command != NULL) { + QMenu menu(this); + + menu.addAction("Run this Command", + this, &WuQMacroDialog::runOnlySelectedCommandMenuItemSelected); + + menu.addSeparator(); + + menu.addAction("Run Macro and Start With this Command", + this, &WuQMacroDialog::runAndStartWithSelectedCommandMenuItemSelected); + + menu.addAction("Run Macro and Start With this Command Without Delays/Durations", + this, &WuQMacroDialog::runAndStartWithNoDelayDurationSelectedCommandMenuItemSelected); + + menu.addSeparator(); + + menu.addAction("Run Macro and Stop After this Command", + this, &WuQMacroDialog::runAndStopAfterSelectedCommandMenuItemSelected); + + menu.addAction("Run Macro and Stop After this Command Without Delays/Durations", + this, &WuQMacroDialog::runAndStopAfterWithNoDelayDurationSelectedCommandMenuItemSelected); + + menu.exec(m_treeView->mapToGlobal(pos)); + } + } +} + +/** + * Called when 'run and start with...' is selected from + * context (pop-up) menu. Runs macro starting with selected command. + */ +void +WuQMacroDialog::runAndStartWithSelectedCommandMenuItemSelected() +{ + WuQMacroCommand* command = getSelectedMacroCommand(); + if (command != NULL) { + runSelectedMacro(command, + NULL); + } + else { + QMessageBox::warning(this, "Error", "No macro command is selected"); + } +} + +/** + * Called when 'run this command only...' is selected from + * context (pop-up) menu. Runs macro to selected command. + */ +void +WuQMacroDialog::runOnlySelectedCommandMenuItemSelected() +{ + WuQMacroCommand* command = getSelectedMacroCommand(); + if (command != NULL) { + runSelectedMacro(command, + command); + } + else { + QMessageBox::warning(this, "Error", "No macro command is selected"); + } +} + +/** + * Called when 'run and start with without delay duration...' is selected from + * context (pop-up) menu. Runs macro to selected command. + */ +void +WuQMacroDialog::runAndStartWithNoDelayDurationSelectedCommandMenuItemSelected() +{ + WuQMacroCommand* command = getSelectedMacroCommand(); + if (command != NULL) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + WuQMacroExecutorOptions* runOptions = macroManager->getExecutorOptions(); + const bool savedIgnoreDelaysFlag = runOptions->isIgnoreDelaysAndDurations(); + runOptions->setIgnoreDelaysAndDurations(true); + runSelectedMacro(command, + NULL); + runOptions->setIgnoreDelaysAndDurations(savedIgnoreDelaysFlag); + } + else { + QMessageBox::warning(this, "Error", "No macro command is selected"); + } +} + +/** + * Called when 'run and stop after...' is selected from + * context (pop-up) menu. Runs macro to selected command. + */ +void +WuQMacroDialog::runAndStopAfterSelectedCommandMenuItemSelected() +{ + WuQMacroCommand* command = getSelectedMacroCommand(); + if (command != NULL) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + WuQMacroExecutorOptions* runOptions = macroManager->getExecutorOptions(); + const bool savedStopAfterOptionFlag = runOptions->isStopAfterSelectedCommand(); + runOptions->setStopAfterSelectedCommand(true); + runSelectedMacro(NULL, + command); + runOptions->setStopAfterSelectedCommand(savedStopAfterOptionFlag); + } + else { + QMessageBox::warning(this, "Error", "No macro command is selected"); + } +} + +/** + * Called when 'run and stop after without delay duration...' is selected from + * context (pop-up) menu. Runs macro to selected command. + */ +void +WuQMacroDialog::runAndStopAfterWithNoDelayDurationSelectedCommandMenuItemSelected() +{ + WuQMacroCommand* command = getSelectedMacroCommand(); + if (command != NULL) { + WuQMacroManager* macroManager = WuQMacroManager::instance(); + WuQMacroExecutorOptions* runOptions = macroManager->getExecutorOptions(); + const bool savedStopAfterOptionFlag = runOptions->isStopAfterSelectedCommand(); + const bool savedIgnoreDelaysFlag = runOptions->isIgnoreDelaysAndDurations(); + runOptions->setStopAfterSelectedCommand(true); + runOptions->setIgnoreDelaysAndDurations(true); + runSelectedMacro(NULL, + command); + runOptions->setStopAfterSelectedCommand(savedStopAfterOptionFlag); + runOptions->setIgnoreDelaysAndDurations(savedIgnoreDelaysFlag); + } + else { + QMessageBox::warning(this, "Error", "No macro command is selected"); + } +} + +/** + * Called when an item in the tree is selected in some way + * (mouse click, arrow key, etc) + * + * @param modelIndex + * Model index of item selected + */ +void +WuQMacroDialog::treeItemSelected(const QModelIndex& modelIndex) +{ + QStandardItemModel* selectedModel = NULL; + if (modelIndex.isValid()) { + const QAbstractItemModel* abstractModel = modelIndex.model(); + if (abstractModel != NULL) { + const QStandardItemModel* constModel = qobject_cast(abstractModel); + if (constModel != NULL) { + selectedModel = const_cast(constModel); + } + } + } + + WuQMacro* macro(NULL); + WuQMacroCommand* macroCommand(NULL); + + if (selectedModel != NULL) { + QStandardItem* selectedItem = selectedModel->itemFromIndex(modelIndex); + bool validFlag(false); + const WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(selectedItem->type(), + &validFlag); + if (validFlag) { + switch (itemType) { + case WuQMacroStandardItemTypeEnum::INVALID: + CaretAssertMessage(0, "Type should never be invalid"); + break; + case WuQMacroStandardItemTypeEnum::MACRO: + macro = dynamic_cast(selectedItem); + CaretAssert(macro); + m_stackedWidget->setCurrentWidget(m_macroWidget); + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + macroCommand = dynamic_cast(selectedItem); + CaretAssert(macroCommand); + m_stackedWidget->setCurrentWidget(m_commandWidget); + break; + } + } + else { + m_stackedWidget->setCurrentWidget(m_emptyWidget); + CaretAssertMessage(0, + ("Invalid StandardItemModel type=" + AString::number(selectedItem->type()))); + } + } + else { + m_stackedWidget->setCurrentWidget(m_emptyWidget); + } + + updateMacroWidget(macro); + updateCommandWidget(macroCommand); + updateEditingToolButtons(); +} + +/** + * Called when macro group combo box selection is made + */ +void +WuQMacroDialog::macroGroupComboBoxActivated(int) +{ + WuQMacroGroup* selectedGroup = getSelectedMacroGroup(); + + if (selectedGroup != NULL) { + QModelIndex selectedIndex; + if (m_treeView->model() != selectedGroup) { + /* + * Model has changed, select first macro + */ + if (selectedGroup->getNumberOfMacros() > 0) { + selectedIndex = selectedGroup->indexFromItem(selectedGroup->getMacroAtIndex(0)); + } + } + else { + selectedIndex = m_treeView->currentIndex(); + } + + m_blockSelectionModelRowChangedFlag = true; + + m_treeView->setModel(selectedGroup); + + { + /* + * Need to (re)connect the selection model's row changed signal + * since setModel() was called. + * + * From the Qt Documentation for QAbstractItemView::setSelectionModel(): + * Note that, if you call setModel() after this function, the given + * selectionModel will be replaced by one created by the view. + */ + QItemSelectionModel* selectionModel = m_treeView->selectionModel(); + if (selectionModel != NULL) { + /* + * Use the option Qt::UniqueConnection to avoid creating + * a duplicate connection + */ + QObject::connect(selectionModel, &QItemSelectionModel::currentRowChanged, + this, &WuQMacroDialog::selectionModelRowChanged, + Qt::UniqueConnection); + } + } + m_blockSelectionModelRowChangedFlag = false; + + if (selectedIndex.isValid()) { + m_treeView->setCurrentIndex(selectedIndex); + } + treeItemSelected(m_treeView->currentIndex()); + } + else { + m_treeView->setModel(new QStandardItemModel()); + treeItemSelected(QModelIndex()); + } +} + +/** + * Called when selection model's row is changed + * + * @param current + * Model index of current item + * @parm previous + * Model index of previous item + */ +void +WuQMacroDialog::selectionModelRowChanged(const QModelIndex& current, + const QModelIndex& /*previous*/) +{ + if (m_blockSelectionModelRowChangedFlag) { + return; + } + + treeItemSelected(current); +} + +/** + * Update the macro widget with the given macro + * + * @param macro + * The macro (may be NULL) + */ +void +WuQMacroDialog::updateMacroWidget(WuQMacro* macro) +{ + QString name; + WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::Key_None; + QString text; + if (macro != NULL) { + name = macro->getName(); + text = macro->getDescription(); + shortCutKey = macro->getShortCutKey(); + } + + if ( ! m_macroNameLineEditBlockUpdateFlag) { + m_macroNameLineEdit->setText(name); + } + + m_macroShortCutKeyComboBox->setSelectedShortCutKey(shortCutKey); + if ( ! m_macroDescriptionTextEditBlockUpdateFlag) { + QSignalBlocker DescriptionBlocker(m_macroDescriptionTextEdit); + m_macroDescriptionTextEdit->setPlainText(text); + } +} + +/** + * Update the command widget with the given macommandcro + * + * @param command + * The command (may be NULL) + */ +void +WuQMacroDialog::updateCommandWidget(WuQMacroCommand* command) +{ + QString title; + QString name; + QString type; + QString toolTip; + float delay(0.0f); + if (command != NULL) { + title = command->text(); + name = command->getObjectName(); + switch (command->getCommandType()) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + { + const QString operationName = command->getCustomOperationTypeName(); + type = operationName; + } + break; + case WuQMacroCommandTypeEnum::MOUSE: + { + WuQMacroMouseEventInfo* mouseInfo = command->getMouseEventInfo(); + CaretAssert(mouseInfo); + WuQMacroMouseEventTypeEnum::Enum mouseEventType = mouseInfo->getMouseEventType(); + type = WuQMacroMouseEventTypeEnum::toGuiName(mouseEventType); + } + break; + case WuQMacroCommandTypeEnum::WIDGET: + type = WuQMacroWidgetTypeEnum::toGuiName(command->getWidgetType()); + break; + } + toolTip = command->getObjectToolTip(); + delay = command->getDelayInSeconds(); + } + m_commandTitleLabel->setText(title); + m_commandNameLabel->setText(name); + m_commandTypeLabel->setText(type); + + QSignalBlocker delayBlocker(m_commandDelaySpinBox); + m_commandDelaySpinBox->setValue(delay); + + if ( ! m_macroDescriptionCommandTextEditBlockUpdateFlag) { + QSignalBlocker descriptionBlocker(m_commandDescriptionTextEdit); + m_commandDescriptionTextEdit->setPlainText(toolTip); + } + + /** + * Update the parameter widgets + */ + const int32_t numParams = ((command != NULL) + ? command->getNumberOfParameters() + : 0); + int32_t numWidgets = static_cast(m_parameterWidgets.size()); + + for (int32_t i = numWidgets; i < numParams; i++) { + WuQMacroCommandParameterWidget* cpw = new WuQMacroCommandParameterWidget(i, + m_parameterWidgetsGridLayout, + this); + QObject::connect(cpw, &WuQMacroCommandParameterWidget::dataChanged, + this, &WuQMacroDialog::commandParamaterDataChanged); + m_parameterWidgets.push_back(cpw); + } + + const QString windowID = m_runOptionsWindowComboBox->currentText(); + int32_t windowIndex = windowID.toInt(); + if (windowIndex > 0) { + --windowIndex; /* Range 1..N but need 0..N-1 */ + } + for (int32_t i = 0; i < numParams; i++) { + m_parameterWidgets[i]->updateContent(windowIndex, + command, + command->getParameterAtIndex(i)); + } + + numWidgets = static_cast(m_parameterWidgets.size()); + for (int32_t i = numParams; i < numWidgets; i++) { + m_parameterWidgets[i]->updateContent(-1, + NULL, + NULL); + } +} + +/** + * Called when a command parameter is changed + * + * @param index + * Index of the parameter + */ +void +WuQMacroDialog::commandParamaterDataChanged(int) +{ + WuQMacro* macro = getSelectedMacro(); + if (macro != NULL) { + WuQMacroManager::instance()->macroWasModified(macro); + } + updateDialogContents(); +} + +/** + * @return Pointer to selected macro group or NULL if none available. + */ +WuQMacroGroup* +WuQMacroDialog::getSelectedMacroGroup() +{ + const int32_t selectedGroupIndex = m_macroGroupComboBox->currentIndex(); + if ((selectedGroupIndex >= 0) + && (selectedGroupIndex < m_macroGroupComboBox->count())) { + CaretAssertVectorIndex(m_macroGroups, selectedGroupIndex); + WuQMacroGroup* group = m_macroGroups[selectedGroupIndex]; + return group; + } + return NULL; +} + +/** + * @return Pointer to selected macro. If a macro command is selected, its parent + * macro is returned (NULL if no macro is selected) + */ +WuQMacro* +WuQMacroDialog::getSelectedMacro() +{ + WuQMacro* macro(NULL); + + QStandardItem* selectedItem = getSelectedItem(); + if (selectedItem != NULL) { + bool validFlag(false); + const WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(selectedItem->type(), + &validFlag); + if (validFlag) { + switch (itemType) { + case WuQMacroStandardItemTypeEnum::INVALID: + CaretAssertMessage(0, "Type should never be invalid"); + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + { + /* + * Parent should be WuQMacro + */ + QStandardItem* selectedItemParent = selectedItem->parent(); + CaretAssert(selectedItemParent); + macro = dynamic_cast(selectedItemParent); + CaretAssert(macro); + } + break; + case WuQMacroStandardItemTypeEnum::MACRO: + macro = dynamic_cast(selectedItem); + CaretAssert(macro); + break; + } + } + else { + CaretAssertMessage(0, + ("Invalid StandardItemModel type=" + AString::number(selectedItem->type()))); + } + } + + return macro; +} + +/** + * @return Pointer to selected macro command (NULL if no macro command is selected) + */ +WuQMacroCommand* +WuQMacroDialog::getSelectedMacroCommand() +{ + WuQMacroCommand* macroCommand(NULL); + + QStandardItem* selectedItem = getSelectedItem(); + if (selectedItem != NULL) { + bool validFlag(false); + const WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(selectedItem->type(), + &validFlag); + if (validFlag) { + switch (itemType) { + case WuQMacroStandardItemTypeEnum::INVALID: + CaretAssertMessage(0, "Type should never be invalid"); + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + macroCommand = dynamic_cast(selectedItem); + CaretAssert(macroCommand); + break; + case WuQMacroStandardItemTypeEnum::MACRO: + break; + } + } + else { + CaretAssertMessage(0, + ("Invalid StandardItemModel type=" + AString::number(selectedItem->type()))); + } + } + + return macroCommand; +} + +/** + * @return The selected item (NULL if invalid) + */ +QStandardItem* +WuQMacroDialog::getSelectedItem() const +{ + QModelIndex modelIndex = m_treeView->currentIndex(); + if (modelIndex.isValid()) { + QAbstractItemModel* abstractModel = m_treeView->model(); + if (abstractModel != NULL) { + QStandardItemModel* model = qobject_cast(abstractModel); + if (model != NULL) { + QStandardItem* item = model->itemFromIndex(modelIndex); + return item; + } + } + } + + return NULL; +} + +/** + * @return The selected item type + */ +WuQMacroStandardItemTypeEnum::Enum +WuQMacroDialog::getSelectedItemType() const +{ + WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::INVALID; + QStandardItem* item = getSelectedItem(); + if (item != NULL) { + bool validFlag(false); + itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(item->type(), + &validFlag); + } + + return itemType; +} + +/** + * Called to pause/continue a macro + */ +void +WuQMacroDialog::pauseContinueMacroToolButtonClicked() +{ + WuQMacroManager::instance()->pauseContinueMacro(); + updateEditingToolButtons(); +} + +/** + * Called when run button is clicked + */ +void +WuQMacroDialog::runMacroToolButtonClicked() +{ + runSelectedMacro(NULL, + NULL); +} +/** + * Called when run button is clicked + * + * @param macroCommandToStartAt + * Macro command at which execution should begin. If NULL, start + * with the first command in the macro + * @param macroCommandToStopAfter + * Macro command that the executor may stop after, depending upon options + */ +void +WuQMacroDialog::runSelectedMacro(const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter) +{ + switch (WuQMacroManager::instance()->getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + { + QMessageBox::critical(m_runMacroToolButton, + "Error", + "A macro is being recorded. Finish recording of macro.", + QMessageBox::Ok, + QMessageBox::NoButton); + return; + } break; + case WuQMacroModeEnum::RUNNING: + break; + } + + WuQMacro* macro = getSelectedMacro(); + if (macro == NULL) { + return; + } + if (macro->getNumberOfMacroCommands() <= 0) { + QMessageBox::critical(m_runMacroToolButton, + "Error", + "Macro does not contain any commands", + QMessageBox::Ok, + QMessageBox::NoButton); + return; + } + + QWidget* window = getWindow(); + + /* + * While macro runs, edit buttons are disabled + */ + m_macroIsRunningFlag = true; + updateEditingToolButtons(); + QApplication::processEvents(); + ElapsedTimer timer; + timer.start(); + WuQMacro* lastMacroRun = WuQMacroManager::instance()->runMacro(window, + macro, + macroCommandToStartAt, + macroCommandToStopAfter); + // may use this later when testing std::cout << "Time to run macro: " << timer.getElapsedTimeSeconds() << std::endl; + m_macroIsRunningFlag = false; + + if (lastMacroRun != getSelectedMacro()) { + QModelIndex modelIndex = macro->index(); + m_treeView->setCurrentIndex(modelIndex); + treeItemSelected(modelIndex); + } + updateEditingToolButtons(); +} + +/** + * @return the parent main window + */ +QWidget* +WuQMacroDialog::getWindow() +{ + const QString windowID = m_runOptionsWindowComboBox->currentText(); + QWidget* window = WuQMacroManager::instance()->getMainWindowWithIdentifier(windowID); + if (window == NULL) { + window = this; + while (window != NULL) { + if (qobject_cast(window) != NULL) { + break; + } + else { + window = window->parentWidget(); + } + } + if (window == NULL) { + window = parentWidget(); + } + } + + return window; +} + +/** + * Called when stop button is clicked + */ +void +WuQMacroDialog::stopMacroToolButtonClicked() +{ + /* + * If recording, STOP button stops recording + */ + switch (WuQMacroManager::instance()->getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + recordMacroToolButtonClicked(); + return; + break; + case WuQMacroModeEnum::RUNNING: + break; + } + + WuQMacroManager::instance()->stopMacro(); + updateEditingToolButtons(); +} + +/** + * Called when record button is clicked + */ +void +WuQMacroDialog::recordMacroToolButtonClicked() +{ + bool startRecordingValid(false); + bool stopRecordingValid(false); + switch (WuQMacroManager::instance()->getMode()) { + case WuQMacroModeEnum::OFF: + startRecordingValid = true; + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + stopRecordingValid = true; + break; + case WuQMacroModeEnum::RUNNING: + break; + } + + if (startRecordingValid) { + QMenu menu(m_editingInsertToolButton); + QAction* newCommandAction = menu.addAction("Record and Insert New Commands Below", + this, + &WuQMacroDialog::insertMenuRecordNewMacroCommandSelected); + newCommandAction->setEnabled(getSelectedMacro() != NULL); + + menu.addSeparator(); + + QAction* newMacroAction = menu.addAction("Record and Insert New Macro Below...", + this, + &WuQMacroDialog::recordAndInsertNewMacroSelected); + newMacroAction->setEnabled(getSelectedMacroGroup() != NULL); + + menu.exec(m_recordMacroToolButton->mapToGlobal(QPoint(0, 0))); + } + else if (stopRecordingValid) { + stopRecordingSelected(); + } +} + +/** + * Called when import item is selected + */ +void +WuQMacroDialog::importMacroGroupActionTriggered() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + if (macroGroup != NULL) { + if (WuQMacroManager::instance()->importMacros(m_macroGroupToolButton, + macroGroup)) { + updateDialogContents(); + } + } +} + +/** + * Called when export item is selected + */ +void +WuQMacroDialog::exportMacroGroupActionTriggered() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + WuQMacro* macro = getSelectedMacro(); + + if (macro != NULL) { + if (WuQMacroManager::instance()->exportMacros(m_macroGroupToolButton, + macroGroup, + macro)) { + updateDialogContents(); + } + } +} + +/** + * Called when macro command description text edit is changed + */ +void +WuQMacroDialog::macroCommandDescriptionTextEditChanged() +{ + WuQMacroCommand* command = getSelectedMacroCommand(); + if (command != NULL) { + command->setObjectToolTip(m_commandDescriptionTextEdit->toPlainText()); + m_macroDescriptionCommandTextEditBlockUpdateFlag = true; + WuQMacroManager::instance()->macroWasModified(getSelectedMacro()); + m_macroDescriptionCommandTextEditBlockUpdateFlag = false; + } +} + +/** + * Called when macro commands delay value is changed + * + * @param value + * New value + */ +void +WuQMacroDialog::macroCommandDelaySpinBoxValueChanged(double value) +{ + WuQMacroCommand* command = getSelectedMacroCommand(); + CaretAssert(command); + command->setDelayInSeconds(value); + + WuQMacro* macro = getSelectedMacro(); + if (macro != NULL) { + WuQMacroManager::instance()->macroWasModified(macro); + } +} + +/** + * @return a horizontal line + */ +QWidget* +WuQMacroDialog::createHorizontalLine() const +{ + QFrame* horizontalLine = new QFrame(); + horizontalLine->setMidLineWidth(1); + horizontalLine->setLineWidth(1); + horizontalLine->setFrameStyle(QFrame::HLine | QFrame::Sunken); + return horizontalLine; +} + +/** + * Called when macro group tool button is clicked + */ +void +WuQMacroDialog::macroGroupToolButtonClicked() +{ + QMenu* menu = new QMenu(this); + + QAction* importAction = menu->addAction("Import..."); + QObject::connect(importAction, &QAction::triggered, + this, &WuQMacroDialog::importMacroGroupActionTriggered); + + QAction* exportAction = menu->addAction("Export..."); + QObject::connect(exportAction, &QAction::triggered, + this, &WuQMacroDialog::exportMacroGroupActionTriggered); + + menu->exec(mapToGlobal(m_macroGroupToolButton->pos())); + + delete menu; +} + +/** + * Called when macro group reset tool button is clicked + */ +void +WuQMacroDialog::macroGroupResetToolButtonClicked() +{ + /* + * Save expanded status of selected macro + */ + bool expandedFlag = false; + WuQMacro* selectedMacro = getSelectedMacro(); + if (selectedMacro != NULL) { + QModelIndex modelIndex = selectedMacro->index(); + if (modelIndex.isValid()) { + expandedFlag = m_treeView->isExpanded(modelIndex); + } + } + + /* + * If expanded, a command may be selected + */ + int32_t selectedCommandIndex = -1; + if (expandedFlag) { + WuQMacroCommand* selectedCommand = getSelectedMacroCommand(); + if (selectedCommand != NULL) { + if (selectedMacro != NULL) { + selectedCommandIndex = selectedMacro->getIndexOfMacroCommand(selectedCommand); + } + } + } + + /* + * Reload the macro + */ + WuQMacro* macro = WuQMacroManager::instance()->resetMacro(getWindow(), + getSelectedMacro()); + updateDialogContents(); + + if (macro != NULL) { + /* + * Restore expanded status of macro + */ + QModelIndex modelIndex = macro->index(); + treeItemSelected(macro->index()); + m_treeView->setExpanded(modelIndex, + expandedFlag); + + /* + * May restore selection of command + */ + if (selectedCommandIndex >= 0) { + if (selectedCommandIndex < macro->getNumberOfMacroCommands()) { + modelIndex = macro->getMacroCommandAtIndex(selectedCommandIndex)->index(); + } + } + + /* + * Select macro or command that was selected before reset + */ + m_treeView->setCurrentIndex(modelIndex); + } + + updateDialogContents(); +} + +/** + * Called when editing move up button clicked + */ +void +WuQMacroDialog::editingMoveUpToolButtonClicked() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + WuQMacro* macro = getSelectedMacro(); + WuQMacroCommand* command = getSelectedMacroCommand(); + + switch (getSelectedItemType()) { + case WuQMacroStandardItemTypeEnum::INVALID: + break; + case WuQMacroStandardItemTypeEnum::MACRO: + if (macroGroup != NULL) { + if (macro != NULL) { + macroGroup->moveMacroUp(macro); + m_treeView->setCurrentIndex(macro->index()); + treeItemSelected(macro->index()); + } + } + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + if ((macro != NULL) + && (command != NULL)) { + macro->moveMacroCommandUp(command); + m_treeView->setCurrentIndex(command->index()); + treeItemSelected(command->index()); + } + break; + } +} + +/** + * Called when editing move down button clicked + */ +void +WuQMacroDialog::editingMoveDownToolButtonClicked() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + WuQMacro* macro = getSelectedMacro(); + WuQMacroCommand* command = getSelectedMacroCommand(); + + switch (getSelectedItemType()) { + case WuQMacroStandardItemTypeEnum::INVALID: + break; + case WuQMacroStandardItemTypeEnum::MACRO: + if (macroGroup != NULL) { + if (macro != NULL) { + macroGroup->moveMacroDown(macro); + m_treeView->setCurrentIndex(macro->index()); + treeItemSelected(macro->index()); + } + } + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + if ((macro != NULL) + && (command != NULL)) { + macro->moveMacroCommandDown(command); + m_treeView->setCurrentIndex(command->index()); + treeItemSelected(command->index()); + } + break; + } +} + +/** + * Called when editing delete button clicked + */ +void +WuQMacroDialog::editingDeleteToolButtonClicked() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + WuQMacro* macro = getSelectedMacro(); + WuQMacroCommand* command = getSelectedMacroCommand(); + + switch (getSelectedItemType()) { + case WuQMacroStandardItemTypeEnum::INVALID: + break; + case WuQMacroStandardItemTypeEnum::MACRO: + if ((macroGroup != NULL) + && (macro != NULL)) { + int32_t macroIndex = macroGroup->getIndexOfMacro(macro); + if (WuQMacroManager::instance()->deleteMacro(m_editingDeleteToolButton, + macroGroup, + macro)) { + + updateDialogContents(); + + CaretAssert(macroIndex >= 0); + if (macroIndex >= macroGroup->getNumberOfMacros()) { + macroIndex = macroGroup->getNumberOfMacros() - 1; + } + if ((macroIndex >= 0) + && (macroIndex < macroGroup->getNumberOfMacros())) { + QModelIndex modelIndex = macroGroup->getMacroAtIndex(macroIndex)->index(); + m_treeView->setCurrentIndex(modelIndex); + treeItemSelected(modelIndex); + } + } + } + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + if ((macro != NULL) + && (command != NULL)) { + if (WuQMacroManager::instance()->deleteMacroCommand(m_editingDeleteToolButton, + macroGroup, + macro, + command)) { + updateDialogContents(); + } + } + break; + } +} + +/** + * Called when editing insert button clicked + */ +void +WuQMacroDialog::editingInsertToolButtonClicked() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + if (macroGroup == NULL) { + return; + } + const WuQMacro* selectedMacro = getSelectedMacro(); + + WuQMacroManager* macroManager = WuQMacroManager::instance(); + + /* + * Copy is valid when there is at least one macro, in any macro group + * and the macro is not the selected macro + */ + bool copyValidFlag(false); + const std::vector allGroups = macroManager->getAllMacroGroups(); + for (const auto mg : allGroups) { + const int32_t nm = mg->getNumberOfMacros(); + for (int32_t i = 0; i < nm; i++) { + if (mg->getMacroAtIndex(i) != selectedMacro) { + copyValidFlag = true; + } + } + } + + bool insertMacroValidFlag(false); + bool insertMacroCommandValidFlag(false); + switch (getSelectedItemType()) { + case WuQMacroStandardItemTypeEnum::INVALID: + insertMacroValidFlag = true; + break; + case WuQMacroStandardItemTypeEnum::MACRO: + insertMacroValidFlag = true; + insertMacroCommandValidFlag = true; + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + insertMacroValidFlag = true; + insertMacroCommandValidFlag = true; + break; + } + + switch (macroManager->getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + insertMacroValidFlag = false; + copyValidFlag = false; + insertMacroCommandValidFlag = false; + break; + case WuQMacroModeEnum::RUNNING: + insertMacroValidFlag = false; + copyValidFlag = false; + insertMacroCommandValidFlag = false; + break; + } + + const bool showRecordItemsFlag(false); + + QMenu menu(m_editingInsertToolButton); + + /* + * Macro command items + */ + QAction* insertNewCommandAction = menu.addAction("Insert New Command Below...", + this, + &WuQMacroDialog::insertMenuNewMacroCommandSelected); + insertNewCommandAction->setEnabled(insertMacroCommandValidFlag); + + if (showRecordItemsFlag) { + QAction* insertRecordNewCommandAction = menu.addAction("Record and Insert New Commands Below", + this, + &WuQMacroDialog::insertMenuRecordNewMacroCommandSelected); + insertRecordNewCommandAction->setEnabled(insertMacroCommandValidFlag); + } + + /* + * Macro items + */ + if (menu.actions().count() > 0) { + menu.addSeparator(); + } + + QAction* copyMacroAction = menu.addAction("Copy and Insert Macro Below...", + this, + &WuQMacroDialog::insertMenuCopyMacroSelected); + copyMacroAction->setEnabled(copyValidFlag + && insertMacroValidFlag); + + QAction* insertMenuAction = menu.addAction("Insert New Macro Below...", + this, + &WuQMacroDialog::insertMenuNewMacroSelected); + insertMenuAction->setEnabled(insertMacroValidFlag); + + if (showRecordItemsFlag) { + QAction* recordNewMacroAction = menu.addAction("Record and Insert Macro Below...", + this, + &WuQMacroDialog::recordAndInsertNewMacroSelected); + recordNewMacroAction->setEnabled(insertMacroValidFlag); + } + + menu.exec(m_editingInsertToolButton->mapToGlobal(QPoint(0, 0))); +} + +/** + * Called to stop recording + */ +void +WuQMacroDialog::stopRecordingSelected() +{ + WuQMacroManager::instance()->stopRecordingNewMacro(); +} + +/** + * Called when copy and insert macro menu item is selected + */ +void +WuQMacroDialog::insertMenuCopyMacroSelected() +{ + WuQMacroCopyDialog dialog(this); + if (dialog.exec() == WuQMacroCopyDialog::Accepted) { + const WuQMacro* macro = dialog.getMacroToCopy(); + if (macro != NULL) { + WuQMacro* newMacro = new WuQMacro(*macro); + newMacro->setName("Copy of " + + macro->getName()); + insertNewMacro(newMacro); + } + } +} + +/** + * Called when copy and record and insert macro menu item is selected + */ +void +WuQMacroDialog::recordAndInsertNewMacroSelected() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + CaretAssert(macroGroup); + + WuQMacro* newMacro = WuQMacroManager::instance()->startRecordingNewMacro(m_editingInsertToolButton, + macroGroup, + getSelectedMacro()); + if (newMacro != NULL) { + const QModelIndex modelIndex = newMacro->index(); + m_treeView->setCurrentIndex(modelIndex); + treeItemSelected(modelIndex); + } +} + + +/** + * Insert a new macro + * + * @param macro + * Macro to insert, must be valid + */ +void +WuQMacroDialog::insertNewMacro(WuQMacro* macro) +{ + CaretAssert(macro); + + const WuQMacro* selectedMacro = getSelectedMacro(); + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + CaretAssert(macroGroup); + + if (selectedMacro != NULL) { + const int32_t index = macroGroup->getIndexOfMacro(selectedMacro); + macroGroup->insertMacroAtIndex(index + 1, + macro); + } + else { + macroGroup->addMacro(macro); + } + updateDialogContents(); + + QModelIndex selectedIndex = macroGroup->indexFromItem(macro); + if (selectedIndex.isValid()) { + m_treeView->setCurrentIndex(selectedIndex); + updateDialogContents(); + } + + WuQMacroManager::instance()->macroWasModified(macro); +} + +/** + * Called when insert new macro menu item selected + */ +void +WuQMacroDialog::insertMenuNewMacroSelected() +{ + bool okFlag(false); + const QString defaultName = WuQMacroManager::instance()->getNewMacroDefaultName(); + const QString macroName = QInputDialog::getText(m_editingInsertToolButton, + "Create Macro", + "New Macro Name", + QLineEdit::Normal, + defaultName, + &okFlag); + if (okFlag) { + if ( ! macroName.isEmpty()) { + WuQMacro* macro = new WuQMacro(); + macro->setName(macroName); + insertNewMacro(macro); + } + } +} + +/** + * Called when insert new macro command menu item selected + */ +void +WuQMacroDialog::insertMenuNewMacroCommandSelected() +{ + WuQMacroNewCommandSelectionDialog dialog(this); + QObject::connect(&dialog, &WuQMacroNewCommandSelectionDialog::signalNewMacroCommandCreated, + this, &WuQMacroDialog::addNewMacroCommand); + if (dialog.exec() == WuQMacroNewCommandSelectionDialog::Accepted) { + } +} + +/** + * Called when insert and record a new macro command menu item selected + */ +void +WuQMacroDialog::insertMenuRecordNewMacroCommandSelected() +{ + WuQMacro* macro = getSelectedMacro(); + if (macro == NULL) { + QMessageBox::warning(m_editingInsertToolButton, + "Error", + "No macro is selected for recording new commands"); + return; + } + + WuQMacroManager::instance()->startRecordingNewCommandInsertion(macro, + getSelectedMacroCommand()); +} + +/** + * Select the given command (if it is not NULL) or the macro (if it is not NULL) + * + * @param macro + * The macro + * @param command + * The macro command + */ +void +WuQMacroDialog::selectMacroCommand(const WuQMacro* macro, + const WuQMacroCommand* command) +{ + QModelIndex selectedIndex; + if (command != NULL) { + selectedIndex = command->index(); + } + else if (macro != NULL) { + if (macro != NULL) { + m_treeView->setExpanded(macro->index(), + true); + } + selectedIndex = macro->index(); + } + + if (selectedIndex.isValid()) { + m_treeView->setCurrentIndex(selectedIndex); + } +} + +/** + * Add a new macro command + */ +void +WuQMacroDialog::addNewMacroCommand(WuQMacroCommand* command) +{ + if (command == NULL) { + return; + } + + WuQMacro* macro(NULL); + switch (getSelectedItemType()) { + case WuQMacroStandardItemTypeEnum::INVALID: + CaretAssert(0); + break; + case WuQMacroStandardItemTypeEnum::MACRO: + { + macro = getSelectedMacro(); + CaretAssert(macro); + macro->insertMacroCommandAtIndex(0, + command); + } + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + { + macro = getSelectedMacro(); + CaretAssert(macro); + const WuQMacroCommand* selectedCommand = getSelectedMacroCommand(); + CaretAssert(selectedCommand); + const int32_t selectedIndex = macro->getIndexOfMacroCommand(selectedCommand); + macro->insertMacroCommandAtIndex(selectedIndex + 1, + command); + } + } + + WuQMacroGroup* selectedGroup = getSelectedMacroGroup(); + CaretAssert(selectedGroup); + QModelIndex selectedIndex = selectedGroup->indexFromItem(command); + m_treeView->setCurrentIndex(selectedIndex); + + updateDialogContents(); + + if (macro != NULL) { + WuQMacroManager::instance()->macroWasModified(macro); + } +} + +/** + * Update editing buttons after item selected + * in macro/command tree view + */ +void +WuQMacroDialog::updateEditingToolButtons() +{ + WuQMacroGroup* macroGroup = getSelectedMacroGroup(); + WuQMacro* macro = getSelectedMacro(); + WuQMacroCommand* command = getSelectedMacroCommand(); + + bool resetValid(false); + bool runValid(false); + bool stopValid(false); + bool insertValid(false); + bool deleteValid(false); + bool moveUpValid(false); + bool moveDownValid(false); + bool pauseValid(false); + bool pauseChecked(false); + bool recordValid(false); + + if (m_macroIsRunningFlag) { + pauseValid = true; + switch (WuQMacroManager::instance()->getMacroExecutorMonitor()->getMode()) { + case WuQMacroExecutorMonitor::Mode::PAUSE: + pauseChecked = true; + break; + case WuQMacroExecutorMonitor::Mode::RUN: + break; + case WuQMacroExecutorMonitor::Mode::STOP: + break; + } + stopValid = true; + } + else { + insertValid = (macroGroup != NULL); + recordValid = (macroGroup != NULL); + resetValid = (macroGroup != NULL); + + switch (getSelectedItemType()) { + case WuQMacroStandardItemTypeEnum::INVALID: + break; + case WuQMacroStandardItemTypeEnum::MACRO: + if (macroGroup != NULL) { + if (macro != NULL) { + const int32_t macroIndex = macroGroup->getIndexOfMacro(macro); + deleteValid = true; + moveUpValid = (macroIndex > 0); + moveDownValid = (macroIndex < (macroGroup->getNumberOfMacros() - 1)); + runValid = true; + } + } + break; + case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: + { + if ((macro != NULL) + && (command != NULL)) { + const int32_t commandIndex = macro->getIndexOfMacroCommand(command); + deleteValid = true; + moveUpValid = (commandIndex > 0); + moveDownValid = (commandIndex < (macro->getNumberOfMacroCommands() - 1)); + runValid = true; + } + } + break; + } + } + + bool recordingFlag(false); + switch (WuQMacroManager::instance()->getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + recordingFlag = true; + break; + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + recordingFlag = true; + break; + case WuQMacroModeEnum::RUNNING: + break; + } + + if (recordingFlag) { + m_recordMacroToolButton->setIcon(m_recordMacroToolButtonIconOn); + runValid = false; + stopValid = true; + } + else { + m_recordMacroToolButton->setIcon(m_recordMacroToolButtonIconOff); + } + + m_pauseMacroToolButton->setEnabled(pauseValid); + m_pauseMacroToolButton->setChecked(pauseChecked); + m_resetMacroGroupToolButton->setEnabled(resetValid); + m_macroGroupToolButton->setEnabled(resetValid); + m_runMacroToolButton->setEnabled(runValid); + m_stopMacroToolButton->setEnabled(stopValid); + m_recordMacroToolButton->setEnabled(recordValid); + m_editingDeleteToolButton->setEnabled(deleteValid); + m_editingInsertToolButton->setEnabled(insertValid); + m_editingMoveDownToolButton->setEnabled(moveDownValid); + m_editingMoveUpToolButton->setEnabled(moveUpValid); + +} + +/** + * Create a pixmap for the given editing tool button + * + * @param editButton + * The edit button identifier + * @return + * Pixmap for the given button + */ +QPixmap +WuQMacroDialog::createEditingToolButtonPixmap(const QWidget* widget, + const EditButton editButton) +{ + CaretAssert(widget); + const qreal pixmapSize = 22.0; + const qreal maxValue = pixmapSize / 2.0 - 1.0; + const qreal arrowTip = maxValue * (2.0 / 3.0); + + uint32_t pixmapOptions(static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); + switch (editButton) { + case EditButton::DELETER: + break; + case EditButton::INSERTER: + break; + case EditButton::MOVE_DOWN: + break; + case EditButton::MOVE_UP: + break; + case EditButton::PAUSE: + break; + case EditButton::RECORD_OFF: + break; + case EditButton::RECORD_ON: + /* allow background */ + pixmapOptions = 0; + break; + case EditButton::RESET: + /* allow background */ + pixmapOptions = 0; + break; + case EditButton::RUN: + /* allow background */ + pixmapOptions = 0; + break; + case EditButton::STOP: + /* allow background */ + pixmapOptions = 0; + break; + } + + QPixmap pixmap(static_cast(pixmapSize), + static_cast(pixmapSize)); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, + pixmap, + pixmapOptions); + QPen pen(painter->pen()); + pen.setWidth(3); + painter->setPen(pen); + + switch (editButton) { + case EditButton::DELETER: + /* + * 'X' symbol + */ + pen.setColor(Qt::red); + painter->setPen(pen); + painter->drawLine(QPointF(-maxValue, maxValue), QPointF(maxValue, -maxValue)); + painter->drawLine(QPointF(-maxValue, -maxValue), QPointF(maxValue, maxValue)); + break; + case EditButton::INSERTER: + /* + * Plus symbol + */ + painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); + painter->drawLine(QPointF(-maxValue, 0), QPointF(maxValue, 0)); + break; + case EditButton::MOVE_DOWN: + /* + * Down arrow + */ + painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); + painter->drawLine(QPointF(0, -maxValue), QPointF(arrowTip, -maxValue + arrowTip)); + painter->drawLine(QPointF(0, -maxValue), QPointF(-arrowTip, -maxValue + arrowTip)); + break; + case EditButton::MOVE_UP: + /* + * Up arrow + */ + painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); + painter->drawLine(QPointF(0, maxValue), QPointF(arrowTip, maxValue - arrowTip)); + painter->drawLine(QPointF(0, maxValue), QPointF(-arrowTip, maxValue - arrowTip)); + break; + case EditButton::PAUSE: + { + const qreal x = maxValue / 3; + const qreal y = maxValue * 0.667; + /* + * Parallel vertical lines + */ + painter->drawLine(QPointF(-x, y), QPointF(-x, -y)); + painter->drawLine(QPointF( x, y), QPointF( x, -y)); + } + break; + case EditButton::RECORD_OFF: + { + painter->setPen(Qt::red); + painter->drawEllipse(QPointF(0, 0), + maxValue, maxValue); + } + break; + case EditButton::RECORD_ON: + { + painter->setPen(Qt::red); + painter->setBrush(Qt::red); + painter->drawEllipse(QPointF(0, 0), + maxValue, maxValue); + } + break; + case EditButton::RESET: + { + QPen pen = painter->pen(); + pen.setWidth(2); + painter->setPen(pen); + /* + * From drawArc() documentation + * Zero is at 3 o'clock + * Units are 1/16th of a degree + * Positive is counter-clockwise + * BUT perhaps due to us transforming coordinate system positive is clockwise + */ + const int sz(4); + const int widthHeight(maxValue * 2 - sz); + QRect rectangle(-maxValue, -maxValue, widthHeight, widthHeight); + const int startAngle(0); + const int spanAngle(270 * 16); + painter->drawArc(rectangle, + startAngle, + spanAngle); + + const int ts(sz + 2); + const int x(-maxValue + widthHeight/2); + const int y(-maxValue + widthHeight); + QPoint trianglePoints[3] = { + { x, y + ts }, + { x + ts, y }, + { x, y - ts } + }; + painter->setBrush(pen.color()); + painter->drawPolygon(trianglePoints, 3); + } + break; + case EditButton::RUN: + { + /* + * Triangle + */ + const qreal y = maxValue * 0.85; + painter->setBrush(pen.color()); + const qreal p = pixmapSize / 3; + const QPointF points[3] = { + QPointF(-p, -y), + QPointF( p, 0.0), + QPointF(-p, y) + }; + painter->drawConvexPolygon(points, 3); + } + break; + case EditButton::STOP: + { + /* + * Square + */ + painter->setBrush(pen.color()); + const qreal a = maxValue * 0.85; + const QPointF points[4] = { + QPointF(-a, -a), + QPointF( a, -a), + QPointF( a, a), + QPointF(-a, a) + }; + painter->drawConvexPolygon(points, 4); + } + break; + } + + return pixmap; +} + diff --git a/src/GuiQt/WuQMacroDialog.h b/src/GuiQt/WuQMacroDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..b8224675aa02fd46403950df521495e173c4b5fd --- /dev/null +++ b/src/GuiQt/WuQMacroDialog.h @@ -0,0 +1,320 @@ +#ifndef __WU_Q_MACRO_DIALOG_H__ +#define __WU_Q_MACRO_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include +#include + +#include "WuQMacroCommandParameter.h" +#include "WuQMacroShortCutKeyEnum.h" +#include "WuQMacroStandardItemTypeEnum.h" + +class QAbstractButton; +class QCheckBox; +class QComboBox; +class QDialogButtonBox; +class QDoubleSpinBox; +class QGridLayout; +class QLabel; +class QLineEdit; +class QMenu; +class QPlainTextEdit; +class QStackedWidget; +class QStandardItem; +class QTreeView; +class QToolButton; + +namespace caret { + + class CommandParameterWidget; + class WuQMacro; + class WuQMacroCommand; + class WuQMacroCommandParameterWidget; + class WuQMacroGroup; + class WuQMacroShortCutKeyComboBox; + + class WuQMacroDialog : public QDialog { + + Q_OBJECT + + public: + WuQMacroDialog(QWidget* parent = 0); + + virtual ~WuQMacroDialog(); + + WuQMacroDialog(const WuQMacroDialog&) = delete; + + WuQMacroDialog& operator=(const WuQMacroDialog&) = delete; + + void updateDialogContents(); + + void restorePositionAndSize(); + + // ADD_NEW_METHODS_HERE + + public slots: + void selectMacroCommand(const WuQMacro* macro, + const WuQMacroCommand* command); + + private slots: + void treeViewItemClicked(const QModelIndex& modelIndex); + + void treeViewCustomContextMenuRequested(const QPoint& pos); + + void runOnlySelectedCommandMenuItemSelected(); + + void runAndStartWithSelectedCommandMenuItemSelected(); + + void runAndStartWithNoDelayDurationSelectedCommandMenuItemSelected(); + + void runAndStopAfterSelectedCommandMenuItemSelected(); + + void runAndStopAfterWithNoDelayDurationSelectedCommandMenuItemSelected(); + + void macroGroupComboBoxActivated(int); + + void buttonBoxButtonClicked(QAbstractButton* button); + + void importMacroGroupActionTriggered(); + + void exportMacroGroupActionTriggered(); + + void macroGroupToolButtonClicked(); + + void macroGroupResetToolButtonClicked(); + + void macroNameLineEditTextEdited(const QString& text); + + void macroDescriptionTextEditChanged(); + + void macroShortCutKeySelected(const WuQMacroShortCutKeyEnum::Enum); + + void runOptionMoveMouseCheckBoxClicked(bool); + + void runOptionLoopCheckBoxClicked(bool); + + void runOptionRecordMovieCheckBoxClicked(bool); + + void runOptionCreateMovieCheckBoxClicked(bool); + + void updateCreateMovieCheckBox(); + + void runOptionIgnoreDelaysAndDurationsCheckBoxClicked(bool); + + void editingMoveUpToolButtonClicked(); + + void editingMoveDownToolButtonClicked(); + + void editingDeleteToolButtonClicked(); + + void editingInsertToolButtonClicked(); + + void pauseContinueMacroToolButtonClicked(); + + void runMacroToolButtonClicked(); + + void stopMacroToolButtonClicked(); + + void recordMacroToolButtonClicked(); + + void macroCommandDelaySpinBoxValueChanged(double); + + void macroCommandDescriptionTextEditChanged(); + + void commandParamaterDataChanged(int); + + void insertMenuCopyMacroSelected(); + + void recordAndInsertNewMacroSelected(); + + void insertMenuNewMacroSelected(); + + void insertMenuNewMacroCommandSelected(); + + void insertMenuRecordNewMacroCommandSelected(); + + void stopRecordingSelected(); + + void addNewMacroCommand(WuQMacroCommand* command); + + void selectionModelRowChanged(const QModelIndex& current, const QModelIndex& previous); + + protected: + virtual void closeEvent(QCloseEvent* event) override; + + private: + enum class ValueIndex { + ONE, + TWO + }; + + enum class EditButton { + DELETER, /* "DELETE" does not compile on an operating system */ + INSERTER, + MOVE_DOWN, + MOVE_UP, + PAUSE, + RECORD_OFF, + RECORD_ON, + RESET, + RUN, + STOP + }; + + QWidget* createMacroAndCommandSelectionWidget(); + + QWidget* createRunOptionsWidget(); + + QWidget* createMacroDisplayWidget(); + + QWidget* createCommandDisplayWidget(); + + void updateMacroWidget(WuQMacro* macro); + + void updateCommandWidget(WuQMacroCommand* command); + + WuQMacroGroup* getSelectedMacroGroup(); + + WuQMacro* getSelectedMacro(); + + WuQMacroCommand* getSelectedMacroCommand(); + + WuQMacroStandardItemTypeEnum::Enum getSelectedItemType() const; + + QStandardItem* getSelectedItem() const; + + QWidget* createHorizontalLine() const; + + QWidget* createMacroRunAndEditingToolButtons(); + + QPixmap createEditingToolButtonPixmap(const QWidget* widget, + const EditButton editButton); + + void updateEditingToolButtons(); + + void treeItemSelected(const QModelIndex& modelIndex); + + void insertNewMacro(WuQMacro* macro); + + QWidget* getWindow(); + + void runSelectedMacro(const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter); + + std::vector m_macroGroups; + + QComboBox* m_macroGroupComboBox; + + QToolButton* m_resetMacroGroupToolButton; + + QToolButton* m_macroGroupToolButton; + + QTreeView* m_treeView; + + QLineEdit* m_macroNameLineEdit; + + bool m_macroNameLineEditBlockUpdateFlag = false; + + WuQMacroShortCutKeyComboBox* m_macroShortCutKeyComboBox; + + QPlainTextEdit* m_macroDescriptionTextEdit; + + bool m_macroDescriptionTextEditBlockUpdateFlag = false; + + QWidget* m_macroWidget; + + QWidget* m_commandWidget; + + QWidget* m_emptyWidget; + + QStackedWidget* m_stackedWidget; + + QDialogButtonBox* m_dialogButtonBox; + + QComboBox* m_runOptionsWindowComboBox; + + QCheckBox* m_runOptionLoopCheckBox; + + QCheckBox* m_runOptionMoveMouseCheckBox; + + QCheckBox* m_runOptionRecordMovieWhileMacroRunsCheckBox; + + QCheckBox* m_runOptionCreateMovieAfterMacroRunsCheckBox; + + QCheckBox* m_ignoreDelaysAndDurationsCheckBox; + + QLabel* m_commandTitleLabel; + + QLabel* m_commandTypeLabel; + + QLabel* m_commandNameLabel; + + QDoubleSpinBox* m_commandDelaySpinBox; + + QPlainTextEdit* m_commandDescriptionTextEdit; + + bool m_macroDescriptionCommandTextEditBlockUpdateFlag = false; + + std::vector m_parameterWidgets; + + QGridLayout* m_parameterWidgetsGridLayout; + + QToolButton* m_pauseMacroToolButton; + + QToolButton* m_runMacroToolButton; + + QToolButton* m_stopMacroToolButton; + + QToolButton* m_recordMacroToolButton; + + QIcon m_recordMacroToolButtonIconOff; + + QIcon m_recordMacroToolButtonIconOn; + + QToolButton* m_editingMoveUpToolButton; + + QToolButton* m_editingMoveDownToolButton; + + QToolButton* m_editingDeleteToolButton; + + QToolButton* m_editingInsertToolButton; + + bool m_macroIsRunningFlag = false; + + bool m_blockSelectionModelRowChangedFlag = false; + + static QByteArray s_previousDialogGeometry; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_DIALOG_DECLARE__ + QByteArray WuQMacroDialog::s_previousDialogGeometry; +#endif // __WU_Q_MACRO_DIALOG_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_DIALOG_H__ diff --git a/src/GuiQt/WuQMacroExecutor.cxx b/src/GuiQt/WuQMacroExecutor.cxx new file mode 100644 index 0000000000000000000000000000000000000000..97acdd9293eab8eaeb2f6b49dfd6ae4f88d2aece --- /dev/null +++ b/src/GuiQt/WuQMacroExecutor.cxx @@ -0,0 +1,1690 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_EXECUTOR_DECLARE__ +#include "WuQMacroExecutor.h" +#undef __WU_Q_MACRO_EXECUTOR_DECLARE__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "WuQMacro.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroExecutorMonitor.h" +#include "WuQMacroManager.h" +#include "WuQMacroMouseEventInfo.h" +#include "WuQMacroMouseEventWidgetInterface.h" +#include "WuQMacroSignalEmitter.h" +#include "WuQMacroWidgetAction.h" + +using namespace caret; + +/** + * \class caret::WuQMacroExecutor + * \brief Executes a macro + * \ingroup WuQMacro + */ + +/** + * Constructor. + */ +WuQMacroExecutor::WuQMacroExecutor() +: QObject() +{ + +} + +/** + * Destructor. + */ +WuQMacroExecutor::~WuQMacroExecutor() +{ +} + +/** + * Move the mouse to the tab bar's tab with the given tab index + * + * @param tabBar + * The tab bar + * @param tabIndex + * Index of the tab + */ +void +WuQMacroExecutor::moveMouseToTabBarTab(QTabBar* tabBar, + const int32_t tabIndex) const +{ + QRect tabRect = tabBar->tabRect(tabIndex); + if (tabRect.isNull()) { + moveMouseToWidget(tabBar); + } + else { + moveMouseToWidgetImplementation(tabBar, + -1, + -1, + &tabRect, + true); + } +} + +/** + * Move the mouse around the given widget + * + * @param moveToObject + * Object to where mouse should be moved + * @param highlightFlag + * If true, highlight mouse location by moving mouse in + * a circular orientation + */ +void +WuQMacroExecutor::moveMouseToWidget(QObject* moveToObject, + const bool highlightFlag) const +{ + moveMouseToWidgetImplementation(moveToObject, + -1, + -1, + NULL, + highlightFlag); +} + +/** + * Move the mouse to and around the given widget + * at the given X/Y + * + * @param moveToObject + * Object to where mouse should be moved + * @param x + * Move to this X in widget + * @param y + * Move to this Y in widget + * @param highlightFlag + * If true, highlight mouse location by moving mouse in + * a circular orientation + */ +void +WuQMacroExecutor::moveMouseToWidgetXY(QObject* moveToObject, + const int x, + const int y, + const bool highlightFlag) const +{ + moveMouseToWidgetImplementation(moveToObject, + x, + y, + NULL, + highlightFlag); +} + + +/** + * Move the mouse around the given widget. If the given X/Y are + * non-negative, mouse is moved to that location instead of center + * of widget + * + * @param moveToObject + * Object to where mouse should be moved + * @param x + * Move to this X in widget + * @param y + * Move to this Y in widget + * @param objectRect + * Optional, if not NULL, rectangle of object used for positioning mouse + * @param highlightFlag + * If true, highlight mouse location by moving mouse in + * a circular orientation + */ +void +WuQMacroExecutor::moveMouseToWidgetImplementation(QObject* moveToObject, + const int x, + const int y, + const QRect* objectRect, + const bool highlightFlag) const +{ + if ( ! m_runOptions.isShowMouseMovement()) { + return; + } + CaretAssert(moveToObject); + const QString objectName = moveToObject->objectName(); + + /* + * Object may not be a widget so find ancestor + * that is a widget + */ + QWidget* moveToWidget(NULL); + while ((moveToWidget == NULL) + && (moveToObject != NULL)) { + moveToWidget = qobject_cast(moveToObject); + if (moveToWidget == NULL) { + moveToObject = moveToObject->parent(); + } + } + + if (moveToWidget == NULL) { + return; + } + + /* + * Test visibility of widget. + * Note: Cannot use isHidden(), see Qt documentation. + */ + if ( ! moveToWidget->isVisible()) { + return; + } + + CaretAssert(moveToWidget); + const QRect widgetRect = ((objectRect != NULL) + ? *objectRect + : moveToWidget->rect()); + QPoint widgetPoint = widgetRect.center(); + if ((x >= 0) && (y >= 0)) { + widgetPoint.setX(x); + widgetPoint.setY(y); + } + + const QPoint windowPoint = moveToWidget->mapToGlobal(widgetPoint); + QCursor::setPos(windowPoint); + SystemUtilities::sleepSeconds(0.025); + + if (highlightFlag) { + const float radius = 15.0; + for (float angle = 0.0; angle < 6.28; angle += 0.314) { + const float x = windowPoint.x() + (std::cos(angle) * radius); + const float y = windowPoint.y() + (std::sin(angle) * radius); + QCursor::setPos(x, y); + SystemUtilities::sleepSeconds(0.025); + } + } + + QCursor::setPos(windowPoint); +} + +/** + * Find an object, by name, in the parent objects + * + * @param objectName + * Name of object + * @return + * Pointer to object with name or NULL if not found + */ +QObject* +WuQMacroExecutor::findObjectByName(const QString& objectName) const +{ + QObject* object(NULL); + + for (auto po : m_parentObjects) { + object = po->findChild(objectName); + if (object != NULL) { + break; + } + } + + return object; +} + +/** + * Run the commands in the given macro. + * + * @param macro + * Macro that is run + * @param macroCommandToStartAt + * Macro command at which execution should begin. If NULL, start + * with the first command in the macro + * @param macroCommandToStopAfter + * Macro command that the executor may stop after, depending upon options + * @param window + * Widget for parent + * @param otherObjectParents + * Additional objects that are searched for objects contained + * in the macro commands + * @param executorMonitor + * The executor monitor + * @param executorOptions + * Executor options + * @param errorMessageOut + * Output containing any error messages + * @return + * True if the macro completed without errors, else false. + */ +bool +WuQMacroExecutor::runMacro(const WuQMacro* macro, + const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter, + QWidget* window, + std::vector& otherObjectParents, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + QString& errorMessageOut) const +{ + const bool result = runMacroPrivate(macro, + macroCommandToStartAt, + macroCommandToStopAfter, + window, + otherObjectParents, + executorMonitor, + executorOptions, + errorMessageOut); + + return result; +} + +/** + * Run the commands in the given macro. + * + * @param macro + * Macro that is run + * @param macroCommandToStartAt + * Macro command at which execution should begin. If NULL, start + * with the first command in the macro + * @param macroCommandToStopAfter + * Macro command that the executor may stop after, depending upon options + * @param window + * Widget for parent + * @param otherObjectParents + * Additional objects that are searched for objects contained + * in the macro commands + * @param executorMonitor + * The executor monitor + * @param executorOptions + * Executor options + * @param errorMessageOut + * Output containing any error messages + * @return + * True if the macro completed without errors, else false. + */ +bool +WuQMacroExecutor::runMacroPrivate(const WuQMacro* macro, + const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter, + QWidget* window, + std::vector& otherObjectParents, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + QString& errorMessageOut) const +{ + CaretAssert(macro); + CaretAssert(executorOptions); + + m_parentObjects.clear(); + m_parentObjects.push_back(window); + m_parentObjects.insert(m_parentObjects.end(), + otherObjectParents.begin(), otherObjectParents.end()); + + m_runOptions = *executorOptions; + + errorMessageOut.clear(); + + int32_t startCommandIndex(0); + if (macroCommandToStartAt != NULL) { + const int32_t commandIndex = macro->getIndexOfMacroCommand(macroCommandToStartAt); + if (commandIndex < 0) { + errorMessageOut = ("Macro command to start at not found in macro \"" + + macroCommandToStartAt->getDescriptiveName() + + "\""); + return false; + } + startCommandIndex = commandIndex; + } + + const int32_t numberOfMacroCommands = macro->getNumberOfMacroCommands(); + for (int32_t i = startCommandIndex; i < numberOfMacroCommands; i++) { + const WuQMacroCommand* mc = macro->getMacroCommandAtIndex(i); + CaretAssert(mc); + + emit macroCommandStarting(macro, + mc); + + const QString objectName(mc->getObjectName()); + + bool requiresObjectFlag(false); + switch (mc->getCommandType()) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + break; + case WuQMacroCommandTypeEnum::MOUSE: + requiresObjectFlag = true; + break; + case WuQMacroCommandTypeEnum::WIDGET: + requiresObjectFlag = true; + break; + } + + QObject* object = findObjectByName(objectName); + if (requiresObjectFlag) { + if (object == NULL) { + errorMessageOut.append("Unable to find object named " + + objectName + + "\n"); + if (m_runOptions.isStopOnError()) { + return false; + } + continue; + } + + if (object->signalsBlocked()) { + errorMessageOut.append("Object named " + + objectName + + " has signals blocked"); + if (m_runOptions.isStopOnError()) { + return false; + } + continue; + } + } + + bool allowDelayBeforeCommandFlag(false); + emit macroCommandAboutToStart(window, + mc, + executorOptions, + allowDelayBeforeCommandFlag); + /* + * May get stopped by user in macroCommandAboutToStart() + */ + switch (executorMonitor->getMode()) { + case WuQMacroExecutorMonitor::Mode::PAUSE: + break; + case WuQMacroExecutorMonitor::Mode::RUN: + break; + case WuQMacroExecutorMonitor::Mode::STOP: + errorMessageOut = executorMonitor->getStoppedByUserMessage(); + return false; + break; + } + + if (executorOptions->isIgnoreDelaysAndDurations()) { + allowDelayBeforeCommandFlag = false; + } + if (allowDelayBeforeCommandFlag) { + performCommandDelay(mc); + } + + QString commandErrorMessage; + bool successFlag(false); + switch (mc->getCommandType()) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + successFlag = WuQMacroManager::instance()->executeCustomOperationMacroCommand(window, + executorMonitor, + executorOptions, + mc, + commandErrorMessage); + + break; + case WuQMacroCommandTypeEnum::MOUSE: + { + CaretAssert(object); + bool notFoundFlag(false); + successFlag = runMouseCommand(mc, + object, + commandErrorMessage, + notFoundFlag); + } + break; + case WuQMacroCommandTypeEnum::WIDGET: + CaretAssert(object); + successFlag = runMacroCommand(window, + executorMonitor, + mc, + object, + commandErrorMessage); + break; + } + + if ( ! successFlag) { + errorMessageOut.append(commandErrorMessage + "\n"); + if (m_runOptions.isStopOnError()) { + return false; + } + } + + + QGuiApplication::processEvents(); + if (m_stopFlag) { + errorMessageOut = "OBSOLETE: Macro stopped at request of user"; + return false; + } + + bool allowDelayAfterCommandFlag(false); + emit macroCommandHasCompleted(window, + mc, + executorOptions, + allowDelayAfterCommandFlag); + + QGuiApplication::processEvents(); + if (mc == macroCommandToStopAfter) { + errorMessageOut = ("Macro stopped after " + + mc->getDescriptiveName()); + return false; + } + + const bool stopFlag = executorMonitor->testForStop(); + if (stopFlag) { + errorMessageOut = executorMonitor->getStoppedByUserMessage(); + return false; + } + + if (executorOptions->isIgnoreDelaysAndDurations()) { + allowDelayAfterCommandFlag = false; + } + if (allowDelayAfterCommandFlag) { + performCommandDelay(mc); + } + + QGuiApplication::processEvents(); + } + + macroCommandStarting(macro, + NULL); + + return (errorMessageOut.isEmpty()); +} + +/** + * Perform delay for the given macro command + * + * @param mc + * The macro command + */ +void +WuQMacroExecutor::performCommandDelay(const WuQMacroCommand* mc) const +{ + if (mc->getCommandType() != WuQMacroCommandTypeEnum::MOUSE) { + if (mc->getDelayInSeconds() > 0.0) { + SystemUtilities::sleepSeconds(mc->getDelayInSeconds()); + } + } +} + +/** + * Stop the macro that is executing + */ +void +WuQMacroExecutor::stopMacro() +{ + m_stopFlag = true; +} + +/** + * Run the commands in the given macro. + * + * @param parentWidget + * Parent widget for dialogs + * @param executorMonitor + * The executor monitor + * @param macroCommand + * Macro command that is run + * @param object + * Object on which command is run + * @param errorMessageOut + * Output containing any error messages + * @return + * True if the macro completed without errors, else false. + */ +bool +WuQMacroExecutor::runMacroCommand(QWidget* /*parentWidget*/, + const WuQMacroExecutorMonitor* /*executorMonitor*/, + const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut) const +{ + errorMessageOut.clear(); + + CaretAssert(macroCommand); + CaretAssert(object); + + const WuQMacroWidgetTypeEnum::Enum classType = macroCommand->getWidgetType(); + + QString objectErrorMessage; + bool notFoundFlag(false); + switch (classType) { + case WuQMacroWidgetTypeEnum::ACTION: + runActionCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: + runActionCheckableCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::ACTION_GROUP: + runActionGroupCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::BUTTON_GROUP: + runButtonGroupCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::CHECK_BOX: + runCheckBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::COMBO_BOX: + runComboBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: + runDoubleSpinBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::INVALID: + CaretAssert(0); + break; + case WuQMacroWidgetTypeEnum::LINE_EDIT: + runLineEditCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::LIST_WIDGET: + runListWidgetCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: + runMacroWidgetActionCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::MENU: + runMenuCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON: + runPushButtonCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: + runPushButtonCheckableCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::RADIO_BUTTON: + runRadioButtonCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::SLIDER: + runSliderCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::SPIN_BOX: + runSpinBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::TAB_BAR: + runTabBarCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::TAB_WIDGET: + runTabWidgetCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON: + runToolButtonCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: + runToolButtonCheckableCommand(macroCommand, object, objectErrorMessage, notFoundFlag); + break; + } + + if (notFoundFlag) { + errorMessageOut = ("ERROR: Unable to cast object named " + + object->objectName() + + " to " + + WuQMacroWidgetTypeEnum::toGuiName(classType)); + return false; + } + else if ( ! objectErrorMessage.isEmpty()) { + errorMessageOut = objectErrorMessage; + return false; + } + + return true; +} + +/** + * Run a non-checkable QAction selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runActionCommand(const WuQMacroCommand* /*macroCommand*/, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QAction* action = qobject_cast(object); + if (action != NULL) { + moveMouseToWidget(action); + + /* + * Always emit true for a non-checkable action + */ + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQActionSignal(action, + true); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a checkable QAction selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runActionCheckableCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QAction* action = qobject_cast(object); + if (action != NULL) { + moveMouseToWidget(action); + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQActionSignal(action, + parameterOne->getValue().toBool()); + } + else { + castFailureFlagOut = true; + } +} + + +/** + * Run a action group selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runActionGroupCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const +{ + QActionGroup* actionGroup = qobject_cast(object); + if (actionGroup != NULL) { + moveMouseToWidget(actionGroup); + + CaretAssert(macroCommand->getNumberOfParameters() > 1); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); + CaretAssert(parameterTwo); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); + CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + + QAction* textAction(NULL); + QAction* indexAction(NULL); + QList actions = actionGroup->actions(); + for (int32_t i = 0; i < actions.size(); i++) { + QAction* actionAtIndex = actions.at(i); + if (actionAtIndex->text() == parameterOne->getValue().toString()) { + textAction = actionAtIndex; + } + if (parameterTwo->getValue().toInt() == i) { + indexAction = actionAtIndex; + } + } + + WuQMacroSignalEmitter signalEmitter; + if (textAction != NULL) { + signalEmitter.emitActionGroupSignal(actionGroup, + textAction->text()); + } + else if (indexAction != NULL) { + signalEmitter.emitActionGroupSignal(actionGroup, + indexAction->text()); + } + else { + errorMessageOut = ("For QActionGroup \"" + + object->objectName() + + "\", unable to find action with text \"" + + parameterOne->getValue().toString() + + "\" or index=" + + parameterTwo->getValue().toInt()); + } + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a button group selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runButtonGroupCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const +{ + QButtonGroup* buttonGroup = qobject_cast(object); + if (buttonGroup != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 1); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); + CaretAssert(parameterTwo); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); + CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + + const QVariant dataValue = parameterOne->getValue(); + const QVariant dataValueTwo = parameterTwo->getValue(); + + QAbstractButton* textButton(NULL); + QAbstractButton* indexButton(NULL); + QList buttons = buttonGroup->buttons(); + for (int32_t i = 0; i < buttons.size(); i++) { + QAbstractButton* buttonAtIndex = buttons.at(i); + if (buttonAtIndex->text() == dataValue.toString()) { + textButton = buttonAtIndex; + } + if (dataValueTwo.toInt() == i) { + indexButton = buttonAtIndex; + } + } + + WuQMacroSignalEmitter signalEmitter; + if (textButton != NULL) { + moveMouseToWidget(textButton); + signalEmitter.emitQButtonGroupSignal(buttonGroup, + textButton->text()); + } + else if (indexButton != NULL) { + moveMouseToWidget(indexButton); + signalEmitter.emitQButtonGroupSignal(buttonGroup, + indexButton->text()); + } + else { + errorMessageOut = ("For QButtonGroup \"" + + object->objectName() + + "\", unable to find button with text \"" + + dataValue.toString() + + "\" or index=" + + dataValueTwo.toInt()); + } + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a check box selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runCheckBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QCheckBox* checkBox = qobject_cast(object); + if (checkBox != NULL) { + moveMouseToWidget(checkBox); + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQCheckBoxSignal(checkBox, + parameterOne->getValue().toBool()); + } + else { + castFailureFlagOut = true; + } +} + + +/** + * Run a combo box selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runComboBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const +{ + QComboBox* comboBox = qobject_cast(object); + if (comboBox != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 1); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); + CaretAssert(parameterTwo); + + const QVariant dataValue = parameterOne->getValue(); + const QVariant dataValueTwo = parameterTwo->getValue(); + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); + CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + int textIndex(-1); + int indexIndex(-1); + for (int32_t i = 0; i < comboBox->count(); i++) { + if (comboBox->itemText(i) == dataValue.toString()) { + textIndex = i; + } + else if (i == dataValueTwo.toInt()) { + indexIndex = i; + } + } + moveMouseToWidget(comboBox); + WuQMacroSignalEmitter signalEmitter; + if (textIndex >= 0) { + signalEmitter.emitQComboBoxSignal(comboBox, + textIndex); + } + else if (indexIndex >= 0) { + signalEmitter.emitQComboBoxSignal(comboBox, + indexIndex); + } + else { + errorMessageOut = ("For ComboBox \"" + + object->objectName() + + "\", unable to find item with text \"" + + dataValue.toString() + + "\" or index=" + + dataValueTwo.toInt()); + } + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a double spin box selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runDoubleSpinBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QDoubleSpinBox* doubleSpinBox = qobject_cast(object); + if (doubleSpinBox != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::FLOAT); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(doubleSpinBox); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQDoubleSpinBoxSignal(doubleSpinBox, + dataValue.toDouble()); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a line edit selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runLineEditCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QLineEdit* lineEdit = qobject_cast(object); + if (lineEdit != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(lineEdit); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQLineEditSignal(lineEdit, + dataValue.toString()); + } + else { + castFailureFlagOut = true; + } +} + + +/** + * Run a list widget selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runListWidgetCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const +{ + QListWidget* listWidget = qobject_cast(object); + if (listWidget != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 1); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); + CaretAssert(parameterTwo); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); + CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + const QVariant dataValue = parameterOne->getValue(); + const QVariant dataValueTwo = parameterTwo->getValue(); + + QListWidgetItem* textItem(NULL); + QListWidgetItem* indexItem(NULL); + for (int32_t i = 0; i < listWidget->count(); i++) { + QListWidgetItem* itemAtIndex = listWidget->item(i); + if (itemAtIndex->text() == dataValue.toString()) { + textItem = itemAtIndex; + } + if (dataValueTwo.toInt() == i) { + indexItem = itemAtIndex; + } + } + + moveMouseToWidget(listWidget); + + WuQMacroSignalEmitter signalEmitter; + if (textItem != NULL) { + signalEmitter.emitQListWidgetSignal(listWidget, + textItem->text()); + } + else if (indexItem != NULL) { + signalEmitter.emitQListWidgetSignal(listWidget, + indexItem->text()); + } + else { + errorMessageOut = ("For QListWidget \"" + + object->objectName() + + "\", unable to find item with text \"" + + dataValue.toString() + + "\" or index=" + + dataValueTwo.toInt()); + } + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a menu selection selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runMacroWidgetActionCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + WuQMacroWidgetAction* macroWidgetAction = qobject_cast(object); + if (macroWidgetAction != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); + const QVariant dataValue = parameterOne->getValue(); + + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitMacroWidgetActionSignal(macroWidgetAction, + dataValue); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a menu selection selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runMenuCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const +{ + QMenu* menu = qobject_cast(object); + if (menu != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 1); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); + CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + const QVariant dataValue = parameterOne->getValue(); + const QVariant dataValueTwo = parameterTwo->getValue(); + + QAction* textAction(NULL); + QAction* indexAction(NULL); + QList actions = menu->actions(); + for (int32_t i = 0; i < actions.size(); i++) { + QAction* actionAtIndex = actions.at(i); + if (actionAtIndex->text() == dataValue.toString()) { + textAction = actionAtIndex; + } + if (dataValueTwo.toInt() == i) { + indexAction = actionAtIndex; + } + } + + moveMouseToWidget(menu); + + WuQMacroSignalEmitter signalEmitter; + if (textAction != NULL) { + signalEmitter.emitQMenuSignal(menu, + textAction->text()); + } + else if (indexAction != NULL) { + signalEmitter.emitQMenuSignal(menu, + indexAction->text()); + } + else { + errorMessageOut = ("For QMenu \"" + + object->objectName() + + "\", unable to find action with text \"" + + dataValue.toString() + + "\" or index=" + + dataValueTwo.toInt()); + } + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a mouse command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + * @return + * True if mouse command was successful + */ +bool +WuQMacroExecutor::runMouseCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& /*castFailureFlagOut*/) const +{ + QWidget* widget = qobject_cast(object); + if (widget != NULL) { + WuQMacroMouseEventWidgetInterface* mouseInterface = dynamic_cast(widget); + if (mouseInterface != NULL) { + const QSize currentWidgetSize = widget->size(); + const WuQMacroMouseEventInfo* mouseEventInfo = macroCommand->getMouseEventInfo(); + CaretAssert(mouseEventInfo); + + const int32_t numXY = mouseEventInfo->getNumberOfLocalXY(); + for (int32_t i = 0; i < numXY; i++) { + int32_t adjustedLocalX(0); + int32_t adjustedLocalY(0); + mouseEventInfo->getLocalPositionRescaledToWidgetSize(currentWidgetSize.width(), + currentWidgetSize.height(), + mouseEventInfo->getLocalX(i), + mouseEventInfo->getLocalY(i), + adjustedLocalX, + adjustedLocalY); + + QEvent::Type qtEventType = QEvent::None; + switch (mouseEventInfo->getMouseEventType()) { + case WuQMacroMouseEventTypeEnum::BUTTON_PRESS: + qtEventType = QEvent::MouseButtonPress; + break; + case WuQMacroMouseEventTypeEnum::BUTTON_RELEASE: + qtEventType = QEvent::MouseButtonRelease; + break; + case WuQMacroMouseEventTypeEnum::DOUBLE_CLICKED: + qtEventType = QEvent::MouseButtonDblClick; + break; + case WuQMacroMouseEventTypeEnum::MOVE: + qtEventType = QEvent::MouseMove; + break; + } + + moveMouseToWidgetXY(widget, + adjustedLocalX, + adjustedLocalY, + false); + + QMouseEvent qtMouseEvent(qtEventType, + QPointF(adjustedLocalX, + adjustedLocalY), + static_cast(mouseEventInfo->getMouseButton()), + static_cast(mouseEventInfo->getMouseButtonsMask()), + static_cast(mouseEventInfo->getKeyboardModifiersMask())); + mouseInterface->processMouseEventFromMacro(&qtMouseEvent); + QGuiApplication::processEvents(); + } + } + else { + errorMessageOut = ("ERROR: Unable to cast object named " + + object->objectName() + + " to WuQMacroMouseEventWidgetInterface"); + return false; + } + } + else { + errorMessageOut = ("ERROR: Unable to cast object named " + + object->objectName() + + " to QWidget"); + return false; + } + + return true; +} + +/** + * Run a pushbutton selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runPushButtonCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QPushButton* pushButton = qobject_cast(object); + if (pushButton != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::NONE); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(pushButton); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQPushButtonSignal(pushButton, + true); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a checkable pushbutton selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runPushButtonCheckableCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QPushButton* pushButton = qobject_cast(object); + if (pushButton != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(pushButton); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQPushButtonSignal(pushButton, + dataValue.toBool()); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a radio button selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runRadioButtonCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QRadioButton* radioButton = qobject_cast(object); + if (radioButton != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + /* Type=NONE since radio button is ALWAYS TRUE */ + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::NONE); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(radioButton); + WuQMacroSignalEmitter signalEmitter; + /* Note: Radio buttons are always exclusive so always use a true value */ + signalEmitter.emitQRadioButtonSignal(radioButton, + true); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a slider selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runSliderCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QSlider* slider = qobject_cast(object); + if (slider != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(slider); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQSliderSignal(slider, + dataValue.toInt()); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a spin box selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runSpinBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QSpinBox* spinBox = qobject_cast(object); + if (spinBox != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(spinBox); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQSpinBoxSignal(spinBox, + dataValue.toInt()); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a tab bar selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runTabBarCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const +{ + QTabBar* tabBar = qobject_cast(object); + if (tabBar != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 1); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); + + CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + const QVariant dataValue = parameterOne->getValue(); + const WuQMacroDataValueTypeEnum::Enum dataValueType = parameterOne->getDataType(); + const QVariant dataValueTwo = parameterTwo->getValue(); + + int32_t tabIndex = dataValueTwo.toInt(); + if (dataValueType == WuQMacroDataValueTypeEnum::STRING) { + /* + * Allow tab name to override tab index + */ + const QString tabName = dataValue.toString(); + if ( ! tabName.isEmpty()) { + for (int32_t i = 0; i < tabBar->count(); i++) { + if (tabName == tabBar->tabText(i)) { + tabIndex = i; + break; + } + } + } + } + if (tabBar->isTabEnabled(tabIndex)) { + moveMouseToTabBarTab(tabBar, tabIndex); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQTabBarSignal(tabBar, + tabIndex); + } + else { + errorMessageOut = ("QTabWidget \"" + + object->objectName() + + "\", tab \"" + + QString::number(tabIndex + 1) + + "\" with text \"" + + tabBar->tabText(tabIndex) + + "\" is disabled"); + } + + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a tab widget selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runTabWidgetCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const +{ + QTabWidget* tabWidget = qobject_cast(object); + if (tabWidget != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 1); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); + + CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); + const QVariant dataValue = parameterOne->getValue(); + const WuQMacroDataValueTypeEnum::Enum dataValueType = parameterOne->getDataType(); + const QVariant dataValueTwo = parameterTwo->getValue(); + + QTabBar* tabBar = tabWidget->tabBar(); + CaretAssert(tabBar); + int32_t tabIndex = dataValueTwo.toInt(); + if (dataValueType == WuQMacroDataValueTypeEnum::STRING) { + /* + * Allow tab name to override tab index + */ + const QString tabName = dataValue.toString(); + if ( ! tabName.isEmpty()) { + for (int32_t i = 0; i < tabWidget->count(); i++) { + if (tabName == tabWidget->tabText(i)) { + tabIndex = i; + break; + } + } + } + } + + if (tabWidget->isTabEnabled(tabIndex)) { + moveMouseToTabBarTab(tabBar, + tabIndex); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQTabWidgetSignal(tabWidget, + tabIndex); + } + else { + errorMessageOut = ("QTabWidget \"" + + object->objectName() + + "\", tab \"" + + QString::number(tabIndex + 1) + + "\" with text \"" + + tabWidget->tabText(tabIndex) + + "\" is disabled"); + } + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a toolbutton selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runToolButtonCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QToolButton* toolButton = qobject_cast(object); + if (toolButton != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::NONE); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(toolButton); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQToolButtonSignal(toolButton, + true); + } + else { + castFailureFlagOut = true; + } +} + +/** + * Run a checkable toolbutton selection command + * + * @param macroCommand + * Macro command that is run + * @param object + * The object that is cast to specific object/widget + * @param errorMessageOut + * Error message from execution + * @param castFailureFlagOut + * Set to true if unable to cast object to widget type + */ +void +WuQMacroExecutor::runToolButtonCheckableCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& /*errorMessageOut*/, + bool& castFailureFlagOut) const +{ + QToolButton* toolButton = qobject_cast(object); + if (toolButton != NULL) { + CaretAssert(macroCommand->getNumberOfParameters() > 0); + const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); + CaretAssert(parameterOne); + + CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); + const QVariant dataValue = parameterOne->getValue(); + + moveMouseToWidget(toolButton); + WuQMacroSignalEmitter signalEmitter; + signalEmitter.emitQToolButtonSignal(toolButton, + dataValue.toBool()); + } + else { + castFailureFlagOut = true; + } +} diff --git a/src/GuiQt/WuQMacroExecutor.h b/src/GuiQt/WuQMacroExecutor.h new file mode 100644 index 0000000000000000000000000000000000000000..7230492bbd52efd550139e1208acee04f9228726 --- /dev/null +++ b/src/GuiQt/WuQMacroExecutor.h @@ -0,0 +1,239 @@ +#ifndef __WU_Q_MACRO_EXECUTOR_H__ +#define __WU_Q_MACRO_EXECUTOR_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +#include "WuQMacroExecutorOptions.h" +class QTabBar; +class QWidget; + +namespace caret { + + class WuQMacro; + class WuQMacroCommand; + class WuQMacroExecutorMonitor; + class WuQMacroExecutorOptions; + + class WuQMacroExecutor : public QObject { + + Q_OBJECT + + public: + WuQMacroExecutor(); + + virtual ~WuQMacroExecutor(); + + WuQMacroExecutor(const WuQMacroExecutor&) = delete; + + WuQMacroExecutor& operator=(const WuQMacroExecutor&) = delete; + + bool runMacro(const WuQMacro* macro, + const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter, + QWidget* window, + std::vector& otherObjectParents, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + QString& errorMessageOut) const; + + void stopMacro(); + + // ADD_NEW_METHODS_HERE + + signals: + void macroCommandAboutToStart(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) const; + + void macroCommandHasCompleted(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) const; + + void macroCommandStarting(const WuQMacro* macro, + const WuQMacroCommand* command) const; + + + private: + void moveMouseToTabBarTab(QTabBar* tabBar, + const int32_t tabIndex) const; + + void moveMouseToWidget(QObject* moveToObject, + const bool highlightFlag = true) const; + + void moveMouseToWidgetXY(QObject* moveToObject, + const int x, + const int y, + const bool highlightFlag = true) const; + + void moveMouseToWidgetImplementation(QObject* moveToObject, + const int x, + const int y, + const QRect* objectRect = NULL, + const bool hightlightFlag = false) const; + + void performCommandDelay(const WuQMacroCommand* mc) const; + + bool runMacroPrivate(const WuQMacro* macro, + const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter, + QWidget* window, + std::vector& otherObjectParents, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + QString& errorMessageOut) const; + + bool runMacroCommand(QWidget* parentWidget, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut) const; + + QObject* findObjectByName(const QString& objectName) const; + + void runActionCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runActionCheckableCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runActionGroupCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runButtonGroupCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runCheckBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runComboBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runDoubleSpinBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runLineEditCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runListWidgetCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runMacroWidgetActionCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runMenuCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + bool runMouseCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runPushButtonCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runPushButtonCheckableCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runRadioButtonCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runSliderCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runSpinBoxCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runTabBarCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runTabWidgetCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runToolButtonCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + void runToolButtonCheckableCommand(const WuQMacroCommand* macroCommand, + QObject* object, + QString& errorMessageOut, + bool& castFailureFlagOut) const; + + mutable WuQMacroExecutorOptions m_runOptions; + + mutable std::vector m_parentObjects; + + bool m_stopFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_EXECUTOR_DECLARE__ + // +#endif // __WU_Q_MACRO_EXECUTOR_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_EXECUTOR_H__ diff --git a/src/GuiQt/WuQMacroExecutorMonitor.cxx b/src/GuiQt/WuQMacroExecutorMonitor.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6687efb579f31cb098acf6dd92240e4e9a7972d0 --- /dev/null +++ b/src/GuiQt/WuQMacroExecutorMonitor.cxx @@ -0,0 +1,155 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ +#include "WuQMacroExecutorMonitor.h" +#undef __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ + +#include + +#include +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::WuQMacroExecutorMonitor + * \brief Allows interuption to pause or stop a macro + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param parent + * The parent object + */ +WuQMacroExecutorMonitor::WuQMacroExecutorMonitor(QObject* parent) +: QObject(parent) +{ + +} + +/** + * Destructor. + */ +WuQMacroExecutorMonitor::~WuQMacroExecutorMonitor() +{ +} + +/** + * @return Error message indicating macro stopped by + * user. Use this method for error message so that it + * is consistent. + */ +QString +WuQMacroExecutorMonitor::getStoppedByUserMessage() const +{ + return "Execution stopped by user"; +} + +/** + * @return The mode + */ +WuQMacroExecutorMonitor::Mode +WuQMacroExecutorMonitor::getMode() const +{ + QMutexLocker locker(&m_modeMutex); + return m_mode; +} + +/** + * Set the mode + * + * @param mode + * New mode + */ +void +WuQMacroExecutorMonitor::setMode(const Mode mode) +{ + QMutexLocker locker(&m_modeMutex); + m_mode = mode; + switch (m_mode) { + case Mode::PAUSE: + break; + case Mode::RUN: + break; + case Mode::STOP: + break; + } +} + +/** + * @return True if execution should stop and the command + * should cleanup and return + */ +bool +WuQMacroExecutorMonitor::testForStop() const +{ + bool stopFlag(false); + switch (getMode()) { + case Mode::PAUSE: + stopFlag = doPause(); + break; + case Mode::RUN: + break; + case Mode::STOP: + stopFlag = true; + break; + } + return stopFlag; +} + +/** + * Pause execution and return when mode changes to run or stop. + * @return True if execution should stop and the command + * should cleanup and return. + */ +bool +WuQMacroExecutorMonitor::doPause() const +{ + bool stopFlag(false); + + bool waitFlag(true); + while (waitFlag) { + QApplication::processEvents(); + + switch (getMode()) { + case Mode::PAUSE: + break; + case Mode::RUN: + stopFlag = false; + waitFlag = false; + break; + case Mode::STOP: + stopFlag = true; + waitFlag = false; + break; + } + } + + return stopFlag; +} + + diff --git a/src/GuiQt/WuQMacroExecutorMonitor.h b/src/GuiQt/WuQMacroExecutorMonitor.h new file mode 100644 index 0000000000000000000000000000000000000000..b8ee0a0f34473d1037419b19e1a4156415fa9284 --- /dev/null +++ b/src/GuiQt/WuQMacroExecutorMonitor.h @@ -0,0 +1,79 @@ +#ifndef __WU_Q_MACRO_EXECUTOR_MONITOR_H__ +#define __WU_Q_MACRO_EXECUTOR_MONITOR_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include +#include + +namespace caret { + + class WuQMacroExecutorMonitor : public QObject { + Q_OBJECT + + public: + enum class Mode { + RUN, + PAUSE, + STOP + }; + + WuQMacroExecutorMonitor(QObject* parent); + + virtual ~WuQMacroExecutorMonitor(); + + WuQMacroExecutorMonitor(const WuQMacroExecutorMonitor&) = delete; + + WuQMacroExecutorMonitor& operator=(const WuQMacroExecutorMonitor&) = delete; + + QString getStoppedByUserMessage() const; + + Mode getMode() const; + + bool testForStop() const; + + void setMode(const Mode mode); + + bool doPause() const; + + mutable Mode m_mode = Mode::STOP; + + mutable QMutex m_modeMutex; + + // ADD_NEW_METHODS_HERE + + private: + // ADD_NEW_MEMBERS_HERE + + friend class WuQMacroExecutor; + friend class WuQMacroManager; + }; + +#ifdef __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ + // +#endif // __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_EXECUTOR_MONITOR_H__ diff --git a/src/GuiQt/WuQMacroExecutorOptions.cxx b/src/GuiQt/WuQMacroExecutorOptions.cxx new file mode 100644 index 0000000000000000000000000000000000000000..85e78abc3b98e5f20332db1db9bcda4f87b212f3 --- /dev/null +++ b/src/GuiQt/WuQMacroExecutorOptions.cxx @@ -0,0 +1,255 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ +#include "WuQMacroExecutorOptions.h" +#undef __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::WuQMacroExecutorOptions + * \brief Options for execution of macros + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WuQMacroExecutorOptions::WuQMacroExecutorOptions() +: CaretObject() +{ + /* members initialized in header file */ +} + +/** + * Destructor. + */ +WuQMacroExecutorOptions::~WuQMacroExecutorOptions() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +WuQMacroExecutorOptions::WuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj) +: CaretObject(obj) +{ + this->copyHelperWuQMacroExecutorOptions(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +WuQMacroExecutorOptions& +WuQMacroExecutorOptions::operator=(const WuQMacroExecutorOptions& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperWuQMacroExecutorOptions(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +WuQMacroExecutorOptions::copyHelperWuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj) +{ + m_loopingFlag = obj.m_loopingFlag; + m_stopOnErrorFlag = obj.m_stopOnErrorFlag; + m_showMouseMovementFlag = obj.m_showMouseMovementFlag; + m_recordMovieDuringExecutionFlag = obj.m_recordMovieDuringExecutionFlag; + m_createMovieAfterMacroExecutionFlag = obj.m_createMovieAfterMacroExecutionFlag; + m_stopAfterSelectedCommandFlag = obj.m_stopAfterSelectedCommandFlag; + m_ignoreDelaysAndDurationsFlag = obj.m_ignoreDelaysAndDurationsFlag; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +WuQMacroExecutorOptions::toString() const +{ + return "WuQMacroExecutorOptions"; +} + +/** + * @return Show mouse movement while running macro + */ +bool +WuQMacroExecutorOptions::isShowMouseMovement() const +{ + return m_showMouseMovementFlag; +} + +/** + * Set show mouse movement activity that was recorded in the macro + * + * @param status + * New status + */ +void +WuQMacroExecutorOptions::setShowMouseMovement(const bool status) +{ + m_showMouseMovementFlag = status; +} + +/** + * @return True if exector should stop macro if an error occurs + */ +bool +WuQMacroExecutorOptions::isStopOnError() const +{ + return m_stopOnErrorFlag; +} + +/** + * Stop runningh of macro if there is an error while running the macro + * + * @param status + * New status + */ +void +WuQMacroExecutorOptions::setStopOnError(const bool status) +{ + m_stopOnErrorFlag = status; +} + +/** + * @return True if looping is on. + */ +bool +WuQMacroExecutorOptions::isLooping() const +{ + return m_loopingFlag; +} + +/** + * Set looping on/off + * + * @param status + * New status + */ +void +WuQMacroExecutorOptions::setLooping(const bool status) +{ + m_loopingFlag = status; +} + +/** + * @return True if record movie while macro executes is on. + */ +bool +WuQMacroExecutorOptions::isRecordMovieDuringExecution() const +{ + return m_recordMovieDuringExecutionFlag; +} + +/** + * Set record movie during macro execution + * + * @param status + * New status + */ +void +WuQMacroExecutorOptions::setRecordMovieDuringExecution(const bool status) +{ + m_recordMovieDuringExecutionFlag = status; +} + +/** + * @return True if create movie after macro executes is on. + */ +bool +WuQMacroExecutorOptions::isCreateMovieAfterMacroExecution() const +{ + return m_createMovieAfterMacroExecutionFlag; +} + +/** + * Set create movie after macro execution + * + * @param status + * New status + */ +void +WuQMacroExecutorOptions::setCreateMovieAfterMacroExecution(const bool status) +{ + m_createMovieAfterMacroExecutionFlag = status; +} + +/** + * @return True if execution should stop after the command selected in macro dialog + */ +bool +WuQMacroExecutorOptions::isStopAfterSelectedCommand() const +{ + return m_stopAfterSelectedCommandFlag; +} + +/** + * Set execution should stop after selected command in macro dialog + * + * @param status + * New status + */ +void +WuQMacroExecutorOptions::setStopAfterSelectedCommand(const bool status) +{ + m_stopAfterSelectedCommandFlag = status; +} + +/** + * @return True if delays and durations should be ignored, + * usually for editing and debugging macros. + */ +bool +WuQMacroExecutorOptions::isIgnoreDelaysAndDurations() const +{ + return m_ignoreDelaysAndDurationsFlag; +} + +/** + * Set delays and durations should be ignored, + * usually for editing and debugging macros + * + * @param status + * New status + */ +void +WuQMacroExecutorOptions::setIgnoreDelaysAndDurations(const bool status) +{ + m_ignoreDelaysAndDurationsFlag = status; +} diff --git a/src/GuiQt/WuQMacroExecutorOptions.h b/src/GuiQt/WuQMacroExecutorOptions.h new file mode 100644 index 0000000000000000000000000000000000000000..de642a82ef253a8778830189df3cdf68d06d3974 --- /dev/null +++ b/src/GuiQt/WuQMacroExecutorOptions.h @@ -0,0 +1,103 @@ +#ifndef __WU_Q_MACRO_EXECUTOR_OPTIONS_H__ +#define __WU_Q_MACRO_EXECUTOR_OPTIONS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class WuQMacroExecutorOptions : public CaretObject { + + public: + WuQMacroExecutorOptions(); + + virtual ~WuQMacroExecutorOptions(); + + WuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj); + + WuQMacroExecutorOptions& operator=(const WuQMacroExecutorOptions& obj); + + bool isShowMouseMovement() const; + + void setShowMouseMovement(const bool status); + + bool isStopOnError() const; + + void setStopOnError(const bool status); + + bool isLooping() const; + + void setLooping(const bool status); + + bool isRecordMovieDuringExecution() const; + + void setRecordMovieDuringExecution(const bool status); + + bool isCreateMovieAfterMacroExecution() const; + + void setCreateMovieAfterMacroExecution(const bool status); + + bool isStopAfterSelectedCommand() const; + + void setStopAfterSelectedCommand(const bool status); + + bool isIgnoreDelaysAndDurations() const; + + void setIgnoreDelaysAndDurations(const bool status); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperWuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj); + + bool m_showMouseMovementFlag = false; + + bool m_stopOnErrorFlag = true; + + bool m_loopingFlag = false; + + bool m_recordMovieDuringExecutionFlag = false; + + bool m_createMovieAfterMacroExecutionFlag = false; + + bool m_stopAfterSelectedCommandFlag = false; + + bool m_ignoreDelaysAndDurationsFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ + // +#endif // __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_EXECUTOR_OPTIONS_H__ diff --git a/src/GuiQt/WuQMacroHelperInterface.h b/src/GuiQt/WuQMacroHelperInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..e7180fa5ce98dcff7a90765dea109dc3e5595119 --- /dev/null +++ b/src/GuiQt/WuQMacroHelperInterface.h @@ -0,0 +1,205 @@ +#ifndef __WU_Q_MACRO_HELPER_INTERFACE_H__ +#define __WU_Q_MACRO_HELPER_INTERFACE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +/** + * \class caret::WuQMacroHelperInterface + * \brief Interface that provides Macro Groups and is used by WuQMacroManager + * \ingroup GuiQt + */ + +#include +#include + +class QMainWindow; +class QWidget; + +namespace caret { + class WuQMacro; + class WuQMacroCommand; + class WuQMacroExecutorOptions; + class WuQMacroGroup; + class WuQMacroWidgetAction; + + class WuQMacroHelperInterface : public QObject { + Q_OBJECT + + public: + WuQMacroHelperInterface(QObject* parent) : QObject(parent) { } + + virtual ~WuQMacroHelperInterface() { } + + WuQMacroHelperInterface(const WuQMacroHelperInterface&) = delete; + + WuQMacroHelperInterface& operator=(const WuQMacroHelperInterface&) = delete; + + /** + * @return All 'active' available macro groups. + * Macros groups that are editible. Other macro + * groups are exluded. + */ + virtual std::vector getActiveMacroGroups() = 0; + + /** + * @return All macro groups including those that are + * be valid (editable) at this time. + */ + virtual std::vector getAllMacroGroups() const = 0; + + /** + * Is called when the given macro is modified + * + * @param macro + * Macro that is modified + */ + virtual void macroWasModified(WuQMacro* macro) = 0; + + /** + * Is called when the given macro group is modified + * + * @param macroGroup + * Macro Group that is modified + */ + virtual void macroGroupWasModified(WuQMacroGroup* macroGroup) = 0; + + /** + * @return Identifiers of all available windows in which macros may be run + */ + virtual std::vector getMainWindowIdentifiers() = 0; + + /** + * Get the main window with the given identifier + * + * @param identifier + * Window identifier + * @return + * Window with the given identifier or NULL if not available + */ + virtual QMainWindow* getMainWindowWithIdentifier(const QString& identifier) = 0; + + /** + * Called by macro executor just before executing the macro + * + * @param macro + * Macro that is run + * @param window + * Widget for parent + * @param executorOptions + * Executor options + */ + virtual void macroExecutionStarting(const WuQMacro* macro, + QWidget* window, + const WuQMacroExecutorOptions* executorOptions) = 0; + + /** + * Called by macro executor just after executing the macro + * + * @param macro + * Macro that is run + * @param window + * Widget for parent + * @param executorOptions + * Executor options + */ + virtual void macroExecutionEnding(const WuQMacro* macro, + QWidget* window, + const WuQMacroExecutorOptions* executorOptions) = 0; + + /** + * Reset the macro to its beginning state + * + * @param macro + * Macro that is run + * @param window + * Widget for parent + * @return + * Pointer to current macro. May be different than the macro + * passsed in. + */ + virtual WuQMacro* resetMacroStateToBeginning(const WuQMacro* macro, + QWidget* window) = 0; + + /** + * Called by macro executor just after a command has completed execution + * + * @param window + * Widget for parent + * @param command + * Command that has just finished + * @param executorOptions + * Executor options + * @param allowDelayFlagOut + * Output indicating if delay after command is enabled + */ + virtual void macroCommandHasCompleted(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) = 0; + + /** + * Called by macro executor just before starting execution of a command + * + * @param window + * Widget for parent + * @param command + * Command that is about to start + * @param executorOptions + * Executor options + * @param allowDelayFlagOut + * Output indicating if delay before command is enabled + */ + virtual void macroCommandAboutToStart(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) = 0; + + + /** + * Called by macro manager to get macro widget actions typically + * used by modal dialogs. + * + * Override to provide macro widget actions. + * + * @return Vector containing the macro widget actions. + */ + virtual std::vector getMacroWidgetActions() + { + std::vector emptyActions; + return emptyActions; + } + + // ADD_NEW_METHODS_HERE + + signals: + void requestDialogsUpdate(); + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_HELPER_INTERFACE_DECLARE__ + // +#endif // __WU_Q_MACRO_HELPER_INTERFACE_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_HELPER_INTERFACE_H__ diff --git a/src/GuiQt/WuQMacroManager.cxx b/src/GuiQt/WuQMacroManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..19c4c906a8881cc98d2d1c3beb81fee26186d533 --- /dev/null +++ b/src/GuiQt/WuQMacroManager.cxx @@ -0,0 +1,1637 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_MANAGER_DECLARE__ +#include "WuQMacroManager.h" +#undef __WU_Q_MACRO_MANAGER_DECLARE__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "DataFileException.h" +#include "EventManager.h" +#include "EventUserInterfaceUpdate.h" +#include "WuQMacro.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCreateDialog.h" +#include "WuQMacroCustomOperationManagerInterface.h" +#include "WuQMacroDialog.h" +#include "WuQMacroExecutor.h" +#include "WuQMacroExecutorMonitor.h" +#include "WuQMacroFile.h" +#include "WuQMacroGroup.h" +#include "WuQMacroMouseEventInfo.h" +#include "WuQMacroHelperInterface.h" +#include "WuQMacroExecutorOptions.h" +#include "WuQMacroSignalWatcher.h" +#include "WuQMacroWidgetAction.h" + +using namespace caret; + + +/** + * \class caret::WuQMacroManager + * \brief Manages the macro system. + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param name + * Name for the macro manager. + */ +WuQMacroManager::WuQMacroManager(const QString& name, + QObject* parent) +: QObject(parent), +m_name(name) +{ + setObjectName(name); + + m_macroExecutorMonitor = new WuQMacroExecutorMonitor(this); + m_executorOptions.reset(new WuQMacroExecutorOptions()); +} + +/** + * Destructor. + */ +WuQMacroManager::~WuQMacroManager() +{ + /* + * Note: Do not delete the executor monitor as it is a QObject + * with 'this' as a parent so Qt will take of of deleting it + */ + + /* + * Do not delete the WuQMacroSignalWatcher instances in + * m_signalWatchers. This WuQMacroManager is set as the + * parent object of the WuQMacroSignalWatcher's so Qt + * will destroy them. + */ + m_signalWatchers.clear(); + + if (m_customCommandManager != NULL) { + delete m_customCommandManager; + m_customCommandManager = NULL; + } + + /* + * If an instance is being deleted it MUST be the + * singleton so make it NULL. + */ + if (s_singletonMacroManager != NULL) { + s_singletonMacroManager = NULL; + } +} + +/** + * @return The instance of the Macro Manager. Before calling this method, + * the createMacroManagerSingleton() must have been called to create the + * singleton Macro Manager. If the singleton is not valid this method + * will cause the application to abort. + */ +WuQMacroManager* +WuQMacroManager::instance() +{ + if (s_singletonMacroManager == NULL) { + /* + * 'qApp' is macro in QApplication that points to the QApplication instance + */ + s_singletonMacroManager = new WuQMacroManager("MacroManager", + qApp); + } + + return s_singletonMacroManager; +} + +/** + * Set the macro helper that provides the macro groups + * + * @param macroHelper + * The macro helper. Ownership will be taken of macro helper + * and it will be destoryed when this instance is destroyed. + */ +void +WuQMacroManager::setMacroHelper(WuQMacroHelperInterface* macroHelper) +{ + m_macroHelper = macroHelper; + + if (macroHelper != NULL) { + QObject::connect(macroHelper, &WuQMacroHelperInterface::requestDialogsUpdate, + this, &WuQMacroManager::updateNonModalDialogs); + + m_macroWidgetActions = macroHelper->getMacroWidgetActions(); + + for (auto mwa : m_macroWidgetActions) { + addMacroSupportToObject(mwa, + mwa->getToolTip()); + } + } +} + +/** + * Set the custom command manager for editing custom command parameters and + * running custom commands + * + * @param customCommandManager + * Pointer to custom command manager + */ +void +WuQMacroManager::setCustomCommandManager(WuQMacroCustomOperationManagerInterface* customCommandManager) +{ + m_customCommandManager = customCommandManager; +} + +/** + * @return Name of this macro manager + */ +QString +WuQMacroManager::getName() const +{ + return m_name; +} + +/** + * @return The current macro mode. + */ +WuQMacroModeEnum::Enum +WuQMacroManager::getMode() const +{ + return m_mode; +} + +/** + * Set the macro mode + * + * @param mode + * New mode + */ +void +WuQMacroManager::setMode(const WuQMacroModeEnum::Enum mode) +{ + m_mode = mode; +} + +/** + * Add macro support to the given object. When recording, + * The object's 'value changed' signal will be monitored so + * that the new value can be part of a macro command. + * + * @param object + * Object that is monitored. + * @param descriptiveName + * Descriptive name for user + * @param toolTipTextOverride + * Override of object's tooltip. This is primarily used when + * an object of a particular class does not support a tooltip + * such as a QButtonGroup. This can also be empty to avoid + * the "no tooltip" message. + */ +bool +WuQMacroManager::addMacroSupportToObjectWithToolTip(QObject* object, + const QString& descriptiveName, + const QString& toolTipOverride) +{ + CaretAssert(object); + + const QString name = object->objectName(); + if (name.isEmpty()) { + CaretLogSevere("Object name is empty, will be ignored for macros\n" + + SystemUtilities::getBackTrace()); + return false; + } + if (descriptiveName.isEmpty()) { + CaretLogSevere("Descriptive name is empty for " + + name + + "\n" + + SystemUtilities::getBackTrace()); + } + + auto existingWatcher = m_signalWatchers.find(name); + if (existingWatcher != m_signalWatchers.end()) { + CaretLogSevere("Object named \"" + + name + + "\" has already been connected for macros\n" + + SystemUtilities::getBackTrace() + + "\n"); + return false; + } + + AString errorMessage; + WuQMacroSignalWatcher* widgetWatcher = WuQMacroSignalWatcher::newInstance(this, + object, + descriptiveName, + toolTipOverride, + errorMessage); + if (widgetWatcher != NULL) { + widgetWatcher->setParent(this); + m_signalWatchers.insert(std::make_pair(name, + widgetWatcher)); + return true; + } + else { + CaretLogWarning(errorMessage); + return false; + } +} + +/** + * Add macro support to the given object. When recording, + * The object's 'value changed' signal will be monitored so + * that the new value can be part of a macro command. + * + * @param object + * Object that is monitored. + * @param descriptiveName + * Descriptive name for user + */ +bool +WuQMacroManager::addMacroSupportToObject(QObject* object, + const QString& descriptiveName) +{ + CaretAssert(object); + + QString toolTipText; + QAction* action = qobject_cast(object); + if (action != NULL) { + toolTipText = action->toolTip(); + } + QWidget* widget = qobject_cast(object); + if (widget != NULL) { + toolTipText = widget->toolTip(); + } + WuQMacroWidgetAction* macroWidgetAction = qobject_cast(object); + if (macroWidgetAction != NULL) { + toolTipText = macroWidgetAction->getToolTip(); + } + + const bool resultFlag = addMacroSupportToObjectWithToolTip(object, + descriptiveName, + toolTipText); + if (resultFlag) { + + if (toolTipText.isEmpty()) { + CaretLogWarning("Object named \"" + + object->objectName() + + "\" is missing a tooltip"); + } + } + + return resultFlag; +} + +/** + * Adds the given macro comand to the macro that is currently being + * recorded. If no macro is being recorded, no action is taken. + * + * @param macroCommand + * Command to add to the current macro + * @return + * True if recording is on and command was added to the macro. + * Ownership of command will be by the macro + * False if recording off in which case caller is responsible + * to delete the macro command + */ +bool +WuQMacroManager::addMacroCommandToRecording(WuQMacroCommand* macroCommand) +{ + CaretAssert(macroCommand); + + switch (getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + CaretAssert(m_macroInsertCommandBeingRecorded); + m_macroInsertCommandBeingRecorded->insertRow(m_macroInsertCommandBeingRecordedOffset, + macroCommand); + m_macroInsertCommandBeingRecordedOffset++; + return true; + break; + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + CaretAssert(m_macroBeingRecorded); + m_macroBeingRecorded->appendMacroCommand(macroCommand); + return true; + break; + case WuQMacroModeEnum::RUNNING: + break; + } + + return false; +} + +/** + * Adds a mouse event to the macro that is currently being + * recorded. If no macro is being recorded, no action is taken. + * + * @param widget + * Widget where mouse event occurred + * @param descriptiveName + * Descriptive name for user + * @param me + * The Qt Mouse Event + * @return + * True if the mouse event was recorded or false if there is an error. + */ +bool +WuQMacroManager::addMouseEventToRecording(QWidget* widget, + const QString& descriptiveName, + const QMouseEvent* me) +{ + CaretAssert(widget); + CaretAssert(me); + + WuQMacro* recordingMacro(NULL); + switch (getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + CaretAssert(m_macroInsertCommandBeingRecorded); + recordingMacro = m_macroInsertCommandBeingRecorded; + break; + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + CaretAssert(m_macroBeingRecorded); + recordingMacro = m_macroBeingRecorded; + break; + case WuQMacroModeEnum::RUNNING: + break; + } + if (recordingMacro != NULL) { + const QString name(widget->objectName()); + if (name.isEmpty()) { + CaretLogSevere("Widget name is empty for recording of mouse event\n" + + SystemUtilities::getBackTrace()); + return false; + } + if (descriptiveName.isEmpty()) { + CaretLogSevere("Descriptive name is empty for " + + name + + "\n" + + SystemUtilities::getBackTrace()); + } + + bool validMouseEventFlag(true); + WuQMacroMouseEventTypeEnum::Enum mouseEventType = WuQMacroMouseEventTypeEnum::MOVE; + switch (me->type()) { + case QEvent::MouseButtonPress: + mouseEventType = WuQMacroMouseEventTypeEnum::BUTTON_PRESS; + break; + case QEvent::MouseButtonRelease: + mouseEventType = WuQMacroMouseEventTypeEnum::BUTTON_RELEASE; + break; + case QEvent::MouseButtonDblClick: + mouseEventType = WuQMacroMouseEventTypeEnum::DOUBLE_CLICKED; + break; + case QEvent::MouseMove: + mouseEventType = WuQMacroMouseEventTypeEnum::MOVE; + + /* + * Only track move events if a button is down + * Note: Use "buttons()" mask, not button() + */ + if (me->buttons() == Qt::NoButton) { + validMouseEventFlag = false; + } + break; + default: + CaretAssertMessage(0, ("Unknown mouse event type integer cast=" + + QString::number(static_cast(me->type())))); + break; + } + if (validMouseEventFlag) { + WuQMacroMouseEventInfo* mouseInfo = new WuQMacroMouseEventInfo(mouseEventType, + static_cast(me->button()), + static_cast(me->buttons()), + static_cast(me->modifiers()), + widget->width(), + widget->height()); + mouseInfo->addLocalXY(me->localPos().x(), + me->localPos().y()); + + const int32_t versionNumber(1); + QString errorMessage; + WuQMacroCommand* command = WuQMacroCommand::newInstanceMouseCommand(mouseInfo, + versionNumber, + name, + descriptiveName, + "mouse operation", + 1.0, + errorMessage); + recordingMacro->appendMacroCommand(command); + return true; + } + } + + return false; +} + + +/** + * @return All 'active' available macro groups. + * Macros groups that are editible. Other macro + * groups are exluded. + */ +std::vector +WuQMacroManager::getActiveMacroGroups() const +{ + std::vector macroGroups; + if (m_macroHelper) { + macroGroups = m_macroHelper->getActiveMacroGroups(); + } + return macroGroups; +} + +/** + * @return All macro groups including those that are + * be valid (editable) at this time. + */ +std::vector +WuQMacroManager::getAllMacroGroups() const +{ + std::vector macroGroups; + if (m_macroHelper) { + macroGroups = m_macroHelper->getAllMacroGroups(); + } + return macroGroups; +} + + +/** + * Start recording a new macro using the New Macro dialog. + * + * @param parent + * Parent for dialog. + */ +void +WuQMacroManager::startRecordingNewMacro(QWidget* parent) +{ + startRecordingNewMacro(parent, + NULL, + NULL); +} + +/** + * Start recording a new macro using the New Macro dialog. + * New macro inserted into the given macro group and after the given macro. + * + * @param parent + * Parent for dialog. + * @param insertIntoMacroGroup + * Insert new macro into this macro group + * @param insertAfterMacro + * Insert new macro after this macro (if NULL + * new macro is inserted at beginning of group) + * @return + * Pointer to new macro or NULL if user cancelled + */ +WuQMacro* +WuQMacroManager::startRecordingNewMacro(QWidget* parent, + WuQMacroGroup* insertIntoMacroGroup, + WuQMacro* insertAfterMacro) +{ + CaretAssert(m_mode == WuQMacroModeEnum::OFF); + + WuQMacroCreateDialog createMacroDialog(insertIntoMacroGroup, + insertAfterMacro, + parent); + if (createMacroDialog.exec() == WuQMacroCreateDialog::Accepted) { + m_mode = WuQMacroModeEnum::RECORDING_NEW_MACRO; + m_macroBeingRecorded = createMacroDialog.getNewMacro(); + CaretAssert(m_macroBeingRecorded); + + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + } + else { + m_macroBeingRecorded = NULL; + } + + return m_macroBeingRecorded; +} + +/** + * Start recording commands and insert them into the given macro after + * the given macro command. + * + * @param insertIntoMacro + * Macro into which new commands are inserted. + * @param insertAfterMacroCommand + * New commands are inserted after this command or at beginning + * if this command is NULL. + */ +void +WuQMacroManager::startRecordingNewCommandInsertion(WuQMacro* insertIntoMacro, + WuQMacroCommand* insertAfterMacroCommand) +{ + CaretAssert(m_mode == WuQMacroModeEnum::OFF); + CaretAssert(insertIntoMacro); + + m_mode = WuQMacroModeEnum::RECORDING_INSERT_COMMANDS; + m_macroInsertCommandBeingRecorded = insertIntoMacro; + m_macroInsertCommandBeingRecordedOffset = 0; + if (insertAfterMacroCommand != NULL) { + const int32_t index = insertIntoMacro->getIndexOfMacroCommand(insertAfterMacroCommand) + 1; + CaretAssert(index >= 0); + m_macroInsertCommandBeingRecordedOffset = index; + } + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} + +/** + * Stop recording the macro. + */ +void +WuQMacroManager::stopRecordingNewMacro() +{ + switch (m_mode) { + case WuQMacroModeEnum::OFF: + CaretAssert(0); + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + CaretAssert(m_macroInsertCommandBeingRecorded); + if (m_macroHelper) { + m_macroHelper->macroWasModified(m_macroInsertCommandBeingRecorded); + } + break; + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + CaretAssert(m_macroBeingRecorded); + if (m_macroHelper) { + m_macroHelper->macroWasModified(m_macroBeingRecorded); + } + break; + case WuQMacroModeEnum::RUNNING: + CaretAssert(0); + break; + } + m_mode = WuQMacroModeEnum::OFF; + + m_macroBeingRecorded = NULL; + m_macroInsertCommandBeingRecorded = NULL; + m_macroInsertCommandBeingRecordedOffset = -1; + + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + updateNonModalDialogs(); +} + +/** + * Show the macros dialog + * + * @param parent + * Parent for dialog + */ +void +WuQMacroManager::showMacrosDialog(QWidget* parent) +{ + if (m_macrosDialog == NULL) { + m_macrosDialog = new WuQMacroDialog(parent); + } + m_macrosDialog->updateDialogContents(); + m_macrosDialog->show(); + m_macrosDialog->raise(); + m_macrosDialog->restorePositionAndSize(); +} + +/** + * @return Vector containing all non-modal dialogs used by Macro Manager. + * This may be useful if the parent window is closed but other parent + * windows are available. + */ +std::vector +WuQMacroManager::getNonModalDialogs() +{ + std::vector nonModalDialogs; + if (m_macrosDialog != NULL) { + nonModalDialogs.push_back(m_macrosDialog); + } + return nonModalDialogs; +} + + +/** + * Update non-modal dialogs in macro manager + */ +void +WuQMacroManager::updateNonModalDialogs() +{ + if (m_macrosDialog != NULL) { + m_macrosDialog->updateDialogContents(); + } +} + +/** + * Run the given macro + * + * @param widget + * Widget used for parent of dialogs + * @param macroToRun + * Macro that is run + * @param macroCommandToStartAt + * Macro command at which execution should begin. If NULL, start + * with the first command in the macro + * @param macroCommandToStopAfter + * Macro command that the executor may stop after, depending upon options. + * If NULL, end after last command is executed. + * @return + * Pointer to macro that was last run. The selected macro could change + * when looping is enabled. + */ +WuQMacro* +WuQMacroManager::runMacro(QWidget* widget, + const WuQMacro* macroToRun, + const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter) +{ + CaretAssert(widget); + CaretAssert(macroToRun); + WuQMacro* macro(const_cast(macroToRun)); + + bool dialogWasDisplayed(false); + bool resultFlag(false); + bool loopFlag(true); + while (loopFlag) { + loopFlag = m_executorOptions->isLooping(); + QString errorMessage; + m_macroExecutor = new WuQMacroExecutor(); + QObject::connect(m_macroExecutor, &WuQMacroExecutor::macroCommandAboutToStart, + this, &WuQMacroManager::macroCommandStartingExecution); + QObject::connect(m_macroExecutor, &WuQMacroExecutor::macroCommandHasCompleted, + this, &WuQMacroManager::macroCommandCompletedExecution); + + if (m_macrosDialog != NULL) { + QObject::connect(m_macroExecutor, &WuQMacroExecutor::macroCommandStarting, + m_macrosDialog, &WuQMacroDialog::selectMacroCommand); + } + + m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::RUN); + + if (m_macroHelper != NULL) { + m_macroHelper->macroExecutionStarting(macro, + widget, + m_executorOptions.get()); + } + resultFlag = m_macroExecutor->runMacro(macro, + macroCommandToStartAt, + macroCommandToStopAfter, + widget, + m_parentObjects, + m_macroExecutorMonitor, + m_executorOptions.get(), + errorMessage); + if (m_macroHelper != NULL) { + m_macroHelper->macroExecutionEnding(macro, + widget, + m_executorOptions.get()); + } + + m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::STOP); + + if ( ! resultFlag) { + QMessageBox::information(widget, + "Macro Done", + errorMessage, + QMessageBox::Ok, + QMessageBox::NoButton); + loopFlag = false; + dialogWasDisplayed = true; + } + + /* + * Mutex needed so stop() method does not try + * to access an invalid pointer to executor. + */ + QMutexLocker locker(&m_macroExecutorMutex); + delete m_macroExecutor; + m_macroExecutor = NULL; + locker.unlock(); + + if (loopFlag) { + if (m_macroHelper != NULL) { + QMessageBox* msgBox = new QMessageBox(QMessageBox::Information, + "Wait", + "Reloading scene", + QMessageBox::Ok, + widget); + msgBox->button(QMessageBox::Ok)->setVisible(false); + msgBox->show(); + + WuQMacro* newMacro = resetMacro(widget, macro); + if (newMacro != NULL) { + macro = newMacro; + } + else { + loopFlag = false; + } + + msgBox->hide(); + msgBox->deleteLater(); + } + } + } + + if ( ! dialogWasDisplayed) { + QApplication::beep(); + } + return macro; +} + +/** + * If a macro is running, stop it + */ +void +WuQMacroManager::stopMacro() +{ + m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::STOP); +} + +/** + * Pause or continue a macro + */ +void +WuQMacroManager::pauseContinueMacro() +{ + switch (m_macroExecutorMonitor->getMode()) { + case WuQMacroExecutorMonitor::Mode::PAUSE: + m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::RUN); + break; + case WuQMacroExecutorMonitor::Mode::RUN: + m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::PAUSE); + break; + case WuQMacroExecutorMonitor::Mode::STOP: + break; + } +} + +/** + * Called by macro executor when a macro command has completed + * + * @param window + * Window in which command is running + * @param command + * Command that just finished execution + * @param allowDelayFlagOut + * Allow delay for after command has completed + */ +void +WuQMacroManager::macroCommandCompletedExecution(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) +{ + CaretAssert(command); + if (m_macroHelper != NULL) { + m_macroHelper->macroCommandHasCompleted(window, + command, + executorOptions, + allowDelayFlagOut); + } +} + +/** + * Called by macro executor when a macro command is about to start + * + * @param window + * Window in which command is running + * @param command + * Command that about to start execution + * @param allowDelayFlagOut + * Allow delay for after command has completed + */ +void +WuQMacroManager::macroCommandStartingExecution(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut) +{ + CaretAssert(command); + if (m_macroHelper != NULL) { + m_macroHelper->macroCommandAboutToStart(window, + command, + executorOptions, + allowDelayFlagOut); + } +} + +/** + * Reset the given macro + * + * @param parentg + * Parent for any dialogs + * @param macro + * Macro that is reset to beginning state + */ +WuQMacro* +WuQMacroManager::resetMacro(QWidget* parent, + WuQMacro* macro) +{ + WuQMacro* newMacro(macro); + if (m_macroHelper != NULL) { + newMacro = m_macroHelper->resetMacroStateToBeginning(macro, + parent); + } + return newMacro; +} + +/** + * Add a parent object that will be searched during macro + * execution to find objects by name that are contained + * in a macro command + * + * @param parentObject + * Object used to find objects + */ +void +WuQMacroManager::addParentObject(QObject* parentObject) +{ + CaretAssert(parentObject); + m_parentObjects.push_back(parentObject); +} + +/** + * Can be called to indicate that a macro was modified + * + * @param macro + * Macro that was modified + */ +void +WuQMacroManager::macroWasModified(WuQMacro* macro) +{ + if (m_macroHelper) { + m_macroHelper->macroWasModified(macro); + } +} + + +/** + * Delete a macro + * + * @param parent + * Parent widget for dialog + * @param macroGroup + * Group containing macro for deletion + * @param macro + * Macro to delete + * @return + * True if macro was deleted. + */ +bool +WuQMacroManager::deleteMacro(QWidget* parent, + WuQMacroGroup* macroGroup, + WuQMacro* macro) +{ + CaretAssert(macroGroup); + CaretAssert(macro); + if (QMessageBox::warning(parent, + "Warning", + ("Delete the macro: " + macro->getName()), + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok) == QMessageBox::Ok) { + macroGroup->deleteMacro(macro); + if (m_macroHelper) { + m_macroHelper->macroGroupWasModified(macroGroup); + } + return true; + } + + return false; +} + +/** + * Delete a macro command + * + * @param parent + * Parent widget for dialog + * @param macroGroup + * Group containing macro + * @param macro + * Macro containing command to be deleted + * @param macroCommand + * Macro command for deletion + * @return + * True if macro was deleted. + */ +bool +WuQMacroManager::deleteMacroCommand(QWidget* parent, + WuQMacroGroup* macroGroup, + WuQMacro* macro, + WuQMacroCommand* macroCommand) +{ + CaretAssert(macroGroup); + CaretAssert(macro); + CaretAssert(macroCommand); + bool deleteFlag(true); + const bool confirmDeleteFlag(false); + if (confirmDeleteFlag) { + deleteFlag = (QMessageBox::warning(parent, + "Warning", + ("Delete the macro command: " + macroCommand->getDescriptiveName()), + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok) == QMessageBox::Ok); + } + if (deleteFlag) { + macro->deleteMacroCommand(macroCommand); + if (m_macroHelper) { + m_macroHelper->macroGroupWasModified(macroGroup); + } + return true; + } + + return false; +} + +/** + * Import macros from a file + * + * @param parent + * Parent widget for dialog + * @param macroGroup + * Group to which macros are appended + * @return + * True if macro(s) were successfully imported + */ +bool +WuQMacroManager::importMacros(QWidget* parent, + WuQMacroGroup* appendToMacroGroup) +{ + QString fileFilterString(WuQMacroFile::getFileDialogFilter()); + const QString filename = QFileDialog::getOpenFileName(parent, + "Import Macros", + s_importExportMacroFileDirectory, + fileFilterString, + &fileFilterString, + QFileDialog::DontUseNativeDialog); + if ( ! filename.isEmpty()) { + WuQMacroFile macroFile; + try { + macroFile.readFile(filename); + + QFileInfo fileInfo(filename); + s_importExportMacroFileDirectory = fileInfo.absolutePath(); + + const WuQMacroGroup* fileMacroGroup = macroFile.getMacroGroup(); + if (fileMacroGroup->getNumberOfMacros() > 0) { + appendToMacroGroup->appendMacroGroup(fileMacroGroup); + if (m_macroHelper) { + m_macroHelper->macroGroupWasModified(appendToMacroGroup); + } + return true; + } + else { + throw DataFileException("File is empty, no macros to import"); + } + } + catch (const DataFileException& dfe) { + QMessageBox::critical(parent, + "File Error", + dfe.whatString(), + QMessageBox::Ok, + QMessageBox::Ok); + } + } + + return false; +} + +/** + * Export macro(s) + * + * @param parent + * Parent widget for dialog + * @param macroGroup + * Group for export (if non-NULL) + * @param macro + * Macro for export (if non-NULL) + * @return + * True if macro was successfully exported + */ +bool +WuQMacroManager::exportMacros(QWidget* parent, + WuQMacroGroup* macroGroup, + WuQMacro* macro) +{ + QString fileFilterString(WuQMacroFile::getFileDialogFilter()); + const QString filename = QFileDialog::getSaveFileName(parent, + "Export Macros", + s_importExportMacroFileDirectory, + fileFilterString, + &fileFilterString, + (QFileDialog::DontUseNativeDialog + | QFileDialog::DontConfirmOverwrite)); + if ( ! filename.isEmpty()) { + try { + WuQMacroFile macroFile; + + if (macroGroup != NULL) { + macroFile.appendMacroGroup(macroGroup); + } + else if (macro != NULL) { + macroFile.addMacro(new WuQMacro(*macro)); + } + else { + throw DataFileException("No macro group or macro for export"); + } + + QString filenameToWrite(filename); + if ( ! filenameToWrite.endsWith(WuQMacroFile::getFileExtension())) { + filenameToWrite.append(WuQMacroFile::getFileExtension()); + } + + macroFile.writeFile(filenameToWrite); + + QFileInfo fileInfo(filenameToWrite); + s_importExportMacroFileDirectory = fileInfo.absolutePath(); + + return true; + } + catch (const DataFileException& dfe) { + QMessageBox::critical(parent, + "File Error", + dfe.whatString(), + QMessageBox::Ok, + QMessageBox::Ok); + } + } + + return false; +} + +/** + * Get all signal watchers + * + * @param enabledItemsOnly + * Only valid signal watchers whose object currently exists are included. + * An object may cease to exists with something is closed (such as a window) + * + * @return + * All signal watchers + */ +std::vector +WuQMacroManager::getAllWidgetSignalWatchers(const bool enabledItemsOnly) const +{ + std::vector allWatchers; + allWatchers.reserve(m_signalWatchers.size()); + + for (auto iter : m_signalWatchers) { + WuQMacroSignalWatcher* watcher = iter.second; + bool validFlag(true); + if (enabledItemsOnly) { + validFlag = false; + for (auto po : m_parentObjects) { + QObject* object = po->findChild(watcher->getObjectName()); + if (object != NULL) { + validFlag = true; + break; + } + } + } + + if (validFlag) { + allWatchers.push_back(watcher); + } + } + return allWatchers; +} + +/** + * Get names of all signal watchers + * + * @param enabledItemsOnly + * Only valid signal watches are returned + * @return + * All signal watchers + */ +std::vector +WuQMacroManager::getAllWidgetSignalWatcherNames(const bool enabledItemsOnly) const +{ + std::vector allWatchers = getAllWidgetSignalWatchers(enabledItemsOnly); + + std::vector names; + names.reserve(m_signalWatchers.size()); + + for (auto iter : allWatchers) { + names.push_back(iter->getObjectName()); + } + + return names; +} + + +/** + * Get the widget signal watcher with the given name + * + * @param name + * Name of widget signal watcher + * @retrurn + * Pointer to watcher or NULL if not valid. + */ +WuQMacroSignalWatcher* +WuQMacroManager::getWidgetSignalWatcherWithName(const QString& name) +{ + auto watcher = m_signalWatchers.find(name); + if (watcher != m_signalWatchers.end()) { + return watcher->second; + } + return NULL; +} + +/** + * Print supported widgets to the terminal window. + */ +void +WuQMacroManager::printSupportedWidgetsToTerminal() +{ + std::set allList; + std::set duplicateList; + for (auto iter : m_signalWatchers) { + const QString s(iter.second->toString()); + + const auto existIter = allList.find(s); + if (existIter != allList.end()) { + duplicateList.insert(s); + } + else { + allList.insert(s); + } + } + + for (auto& iter : allList) { + std::cout << iter << std::endl; + } + + for (auto& iter : duplicateList) { + std::cout << "DUPLICTE: " << iter << std::endl; + } +} + +/** + * Print top level widgets + */ +void +WuQMacroManager::printToLevelWidgetsToTerminal() +{ + std::cout << "Top Level Widgets: " << std::endl; + QWidgetList widgetList = qApp->topLevelWidgets(); + foreach (QWidget* widget, widgetList) { + std::cout << " " << widget->objectName() + << ", " << widget->metaObject()->className() << std::endl; + } + std::cout << std::endl; +} +/** + * Get the tooltip for the object with the given name + * + * @param objectName + * Name of object + * @return + * Tooltip for object or empty if not found. + */ +QString +WuQMacroManager::getToolTipForObjectName(const QString& objectName) const +{ + QString tooltip; + + const auto existingWatcher = m_signalWatchers.find(objectName); + if (existingWatcher != m_signalWatchers.end()) { + tooltip = existingWatcher->second->getToolTip(); + } + + return tooltip; +} + +/** + * @return Pointer to the executor's run options (const method) + */ +const WuQMacroExecutorOptions* +WuQMacroManager::getExecutorOptions() const +{ + return m_executorOptions.get(); +} + +/** + * @return Pointer to the executor's run options + */ +WuQMacroExecutorOptions* +WuQMacroManager::getExecutorOptions() +{ + return m_executorOptions.get(); +} + +/** + * @return Pointer to the executor monitor. + * Always returns valid pointer, even if macro is not running. + */ +const WuQMacroExecutorMonitor* +WuQMacroManager::getMacroExecutorMonitor() const +{ + return m_macroExecutorMonitor; +} + +/** + * Process a key press event for macro shortcut + * + * @param keyEvent + * Key event information. + * @return + * True if the input process recognized the key event + * and the key event SHOULD NOT be propagated to parent + * widgets + */ +bool +WuQMacroManager::runMacroWithShortCutKeyEvent(QWidget* window, + const QKeyEvent* keyEvent) +{ + CaretAssert(keyEvent); + + /* + * On Mac, SHIFT, CONTROL, COMMANDS + * On Linux/Windows: SHIFT CTRL META + */ + Qt::KeyboardModifiers mods; +#ifdef CARET_OS_MACOSX + mods.setFlag(Qt::ShiftModifier); + mods.setFlag(Qt::MetaModifier); + mods.setFlag(Qt::ControlModifier); +#else + mods.setFlag(Qt::ShiftModifier); + mods.setFlag(Qt::ControlModifier); + mods.setFlag(Qt::AltModifier); +#endif + if (keyEvent->modifiers() == mods) { + const int qtKeyCode = keyEvent->key(); + const WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::fromQtKeyEnum(qtKeyCode); + if (shortCutKey != WuQMacroShortCutKeyEnum::Key_None) { + const WuQMacro* macro = getMacroWithShortCutKey(shortCutKey); + if (macro != NULL) { + runMacro(window, + macro, + NULL, + NULL); + return true; + } + } + } + + return false; +} + +/** + * @return the macro with the given short cut key or NULL if not found + * + * @param shortCutKey + * The short cut key + */ +WuQMacro* +WuQMacroManager::getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const +{ + WuQMacro* macro(NULL); + + const auto macroGroups = getActiveMacroGroups(); + for (const auto mg : macroGroups) { + macro = mg->getMacroWithShortCutKey(shortCutKey); + if (macro != NULL) { + break; + } + } + + return macro; +} + +QString +WuQMacroManager::getShortCutKeysMask() +{ + QString mask; +#ifdef CARET_OS_MACOSX + mask = "shift/control/command"; +#else + mask = "shift/ctrl/alt"; +#endif + + return mask; +} + +/** + * Get information about a custom parameter that may be a range or + * a list of valid values + * + * @param browserWindowIndex + * Index of window + * @param macroCommand + * Macro command that contains the parameter for editing + * @param parameter + * Parameter for editing + * @param dataInfoOut + * Information about the data + * @return + * True if the parameter was modified + */ +bool +WuQMacroManager::getCustomParameterDataInfo(const int32_t browserWindowIndex, + WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* parameter, + WbMacroCustomDataInfo& dataInfoOut) +{ + bool validFlag(false); + if (m_customCommandManager != NULL) { + validFlag = m_customCommandManager->getCustomParameterDataInfo(browserWindowIndex, + macroCommand, + parameter, + dataInfoOut); + } + else { + CaretLogSevere("No Macro Helper available for editing custom values in a macro parameter"); + } + return validFlag; +} + +/** + * Run a custom-defined macro command + * + * @param parent + * Parent widget for any dialogs + * @param executorMonitor + * The executor monitor + * @param executorOptions + * Options for the executor + * @param macroCommand + * Custom macro command to run + * @param errorMessageOut + * Contains any error information or empty if no error + */ +bool +WuQMacroManager::executeCustomOperationMacroCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand, + QString& errorMessageOut) +{ + CaretAssert(parent); + CaretAssert(macroCommand); + + errorMessageOut.clear(); + + bool successFlag(false); + if (m_customCommandManager != NULL) { + successFlag = m_customCommandManager->executeCustomOperationMacroCommand(parent, + executorMonitor, + executorOptions, + macroCommand, + errorMessageOut); + } + else { + CaretLogSevere("No Macro Helper available for running custom macro commands"); + } + + return successFlag; +} + +/** + * @return All custom operation commands. Caller is responsible for deleting + * all content of the returned vector. + */ +std::vector +WuQMacroManager::getAllCustomOperationMacroCommands() +{ + std::vector customCommands; + + if (m_customCommandManager != NULL) { + customCommands = m_customCommandManager->getAllCustomOperationMacroCommands(); + } + return customCommands; +} + +/** + * @return Names of custom operation defined macro commands + */ +std::vector +WuQMacroManager::getNamesOfCustomOperationMacroCommands() +{ + std::vector names; + + if (m_customCommandManager != NULL) { + names = m_customCommandManager->getNamesOfCustomOperationMacroCommands(); + } + + return names; +} + +/** + * Get a new instance of a custom operation for the given macro command name + * + * @param customMacroCommandName + * Name of custom macro command + * @param errorMessageOut + * Contains any error information or empty if no error + * @return + * Pointer to command or NULL if not valid + */ +WuQMacroCommand* +WuQMacroManager::newInstanceOfCustomOperationMacroCommand(const QString& macroCommandName, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + WuQMacroCommand* command(NULL); + + if (m_customCommandManager != NULL) { + command = m_customCommandManager->newInstanceOfCustomOperationMacroCommand(macroCommandName, + errorMessageOut); + } + else { + errorMessageOut = "No Custom Operation Manager is available for creating custom commands"; + } + + return command; +} + +/** + * @return Identifiers of all available windows in which macros may be run + */ +std::vector +WuQMacroManager::getMainWindowIdentifiers() +{ + std::vector identifiers; + if (m_macroHelper != NULL) { + identifiers = m_macroHelper->getMainWindowIdentifiers(); + } + return identifiers; +} + +/** + * Get the main window with the given identifier + * + * @param identifier + * Window identifier + * @return + * Window with the given identifier or NULL if not available + */ +QMainWindow* +WuQMacroManager::getMainWindowWithIdentifier(const QString& identifier) +{ + if (m_macroHelper != NULL) { + return m_macroHelper->getMainWindowWithIdentifier(identifier); + } + return NULL; +} + +/** + * @return A default name for a macro + */ +QString +WuQMacroManager::getNewMacroDefaultName() const +{ + QString name(""); + bool foundFlag(false); + static int32_t minimumIndex = 1; + + const std::vector macroGroups = getAllMacroGroups(); + for (int32_t i = minimumIndex; i < 10000; i++) { + name = ("Macro " + + QString::number(i)); + foundFlag = false; + for (auto mg : macroGroups) { + if (mg->getMacroByName(name) != NULL) { + foundFlag = true; + break; + } + } + + if ( ! foundFlag) { + /* + * If a default name was created, do not allow a "lower-numbered" + * default name. Start with same index since user may not use it. + */ + minimumIndex = i; + break; + } + } + + return name; +} + +/** + * @return The macro widget action with the given name or + * NULL if not found + * + * @param name + * Name of macro widget action + */ +WuQMacroWidgetAction* +WuQMacroManager::getMacroWidgetActionByName(const QString& name) +{ + for (auto mwa : m_macroWidgetActions) { + if (mwa->getName() == name) { + return mwa; + } + } + return NULL; +} + +/** + * Get a widget for the macro widget action with the given name + * + * @param name + * Name of the macro widget action + * @param parentWidget + * Optional parent widget for the returned widget + * @return + * Widget associated with the widget macro action or NULL if failure. + */ +QWidget* +WuQMacroManager::getWidgetForMacroWidgetActionByName(const QString& name, + QWidget* parentWidget) +{ + QWidget* widget(NULL); + WuQMacroWidgetAction* mwa = getMacroWidgetActionByName(name); + if (mwa != NULL) { + widget = mwa->requestWidget(parentWidget); + if (widget == NULL) { + const QString msg("Failed to create widget for macro widget action with name \"" + + name + + "."); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + } + } + else { + const QString msg("No macro widget action with name \"" + + name + + "\" was found."); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + } + + return widget; +} + +/** + * Release the widget from its associated macro widget action. + * Note: The widget is NOT destroyed as that is the responsibility + * of the widget owner (typically a dialog). + */ +void +WuQMacroManager::releaseWidgetFromMacroWidgetAction(QWidget* widget, + QWidget* widget2, + QWidget* widget3, + QWidget* widget4, + QWidget* widget5, + QWidget* widget6) +{ + std::vector allWidgets { widget, widget2, widget3, widget4, widget5, widget6 }; + for (auto widget : allWidgets) { + if (widget != NULL) { + for (auto mwa : m_macroWidgetActions) { + mwa->releaseWidget(widget); + } + } + } +} + +/** + * Update the value of a widget from its macro widget action. + * + * @param widget + * Widget that gets its value update + */ +void +WuQMacroManager::updateValueInWidgetFromMacroWidgetAction(QWidget* widget, + QWidget* widget2, + QWidget* widget3, + QWidget* widget4, + QWidget* widget5, + QWidget* widget6) +{ + std::vector allWidgets { widget, widget2, widget3, widget4, widget5, widget6 }; + for (auto widget : allWidgets) { + if (widget != NULL) { + for (auto mwa : m_macroWidgetActions) { + if (mwa->updateWidgetWithModelValue(widget)) { + return; + } + } + } + } +} diff --git a/src/GuiQt/WuQMacroManager.h b/src/GuiQt/WuQMacroManager.h new file mode 100644 index 0000000000000000000000000000000000000000..a1fa8df223e228830b601350d62b6a3983004bcf --- /dev/null +++ b/src/GuiQt/WuQMacroManager.h @@ -0,0 +1,275 @@ +#ifndef __WU_Q_MACRO_MANAGER_H__ +#define __WU_Q_MACRO_MANAGER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include +#include +#include + +#include +#include + +#include "WuQMacroExecutor.h" +#include "WuQMacroModeEnum.h" +#include "WuQMacroShortCutKeyEnum.h" + +class QKeyEvent; +class QMainWindow; +class QMouseEvent; +class QWidget; + +namespace caret { + + class WbMacroCustomDataInfo; + class WuQMacro; + class WuQMacroCommand; + class WuQMacroCommandParameter; + class WuQMacroCustomOperationManagerInterface; + class WuQMacroDialog; + class WuQMacroExecutor; + class WuQMacroExecutorMonitor; + class WuQMacroExecutorOptions; + class WuQMacroGroup; + class WuQMacroHelperInterface; + class WuQMacroSignalWatcher; + class WuQMacroWidgetAction; + + class WuQMacroManager : public QObject { + Q_OBJECT + + public: + static WuQMacroManager* instance(); + + virtual ~WuQMacroManager(); + + WuQMacroManager(const WuQMacroManager&) = delete; + + WuQMacroManager& operator=(const WuQMacroManager&) = delete; + + void setMacroHelper(WuQMacroHelperInterface* macroHelper); + + void setCustomCommandManager(WuQMacroCustomOperationManagerInterface* customCommandManager); + + QString getName() const; + + bool addMacroSupportToObject(QObject* object, + const QString& descriptiveName); + + bool addMacroSupportToObjectWithToolTip(QObject* object, + const QString& descriptiveName, + const QString& toolTipOverride); + + bool addMacroCommandToRecording(WuQMacroCommand* macroCommand); + + bool addMouseEventToRecording(QWidget* widget, + const QString& descriptiveName, + const QMouseEvent* me); + + WuQMacroModeEnum::Enum getMode() const; + + void setMode(const WuQMacroModeEnum::Enum mode); + + std::vector getActiveMacroGroups() const; + + std::vector getAllMacroGroups() const; + + void startRecordingNewMacro(QWidget* parent); + + WuQMacro* startRecordingNewMacro(QWidget* parent, + WuQMacroGroup* insertIntoMacroGroup, + WuQMacro* insertAfterMacro); + + void startRecordingNewCommandInsertion(WuQMacro* insertIntoMacro, + WuQMacroCommand* insertAfterMacroCommand); + + void stopRecordingNewMacro(); + + void showMacrosDialog(QWidget* parent); + + std::vector getNonModalDialogs(); + + WuQMacroExecutorOptions* getExecutorOptions(); + + const WuQMacroExecutorOptions* getExecutorOptions() const; + + const WuQMacroExecutorMonitor* getMacroExecutorMonitor() const; + + bool deleteMacro(QWidget* parent, + WuQMacroGroup* macroGroup, + WuQMacro* macro); + + bool deleteMacroCommand(QWidget* parent, + WuQMacroGroup* macroGroup, + WuQMacro* macro, + WuQMacroCommand* macroCommand); + + bool importMacros(QWidget* parent, + WuQMacroGroup* appendToMacroGroup); + + bool exportMacros(QWidget* parent, + WuQMacroGroup* macroGroup, + WuQMacro* macro); + + WuQMacro* runMacro(QWidget* window, + const WuQMacro* macro, + const WuQMacroCommand* macroCommandToStartAt, + const WuQMacroCommand* macroCommandToStopAfter); + + WuQMacro* resetMacro(QWidget* parent, + WuQMacro* macro); + + void stopMacro(); + + void pauseContinueMacro(); + + bool runMacroWithShortCutKeyEvent(QWidget* window, + const QKeyEvent* keyEvent); + + void printSupportedWidgetsToTerminal(); + + void printToLevelWidgetsToTerminal(); + + void addParentObject(QObject* parentObject); + + QString getToolTipForObjectName(const QString& objectName) const; + + WuQMacro* getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const; + + static QString getShortCutKeysMask(); + + void macroWasModified(WuQMacro* macro); + + bool getCustomParameterDataInfo(const int32_t browserWindowIndex, + WuQMacroCommand* macroCommand, + WuQMacroCommandParameter* parameter, + WbMacroCustomDataInfo& dataInfoOut); + + bool executeCustomOperationMacroCommand(QWidget* parent, + const WuQMacroExecutorMonitor* executorMonitor, + const WuQMacroExecutorOptions* executorOptions, + const WuQMacroCommand* macroCommand, + QString& errorMessageOut); + + virtual std::vector getAllCustomOperationMacroCommands(); + + virtual std::vector getNamesOfCustomOperationMacroCommands(); + + virtual WuQMacroCommand* newInstanceOfCustomOperationMacroCommand(const QString& macroCommandName, + QString& errorMessageOut); + + std::vector getMainWindowIdentifiers(); + + QMainWindow* getMainWindowWithIdentifier(const QString& identifier); + + std::vector getAllWidgetSignalWatchers(const bool enabledItemsOnly) const; + + std::vector getAllWidgetSignalWatcherNames(const bool enabledItemsOnly) const; + + WuQMacroSignalWatcher* getWidgetSignalWatcherWithName(const QString& name); + + QString getNewMacroDefaultName() const; + + WuQMacroWidgetAction* getMacroWidgetActionByName(const QString& name); + + QWidget* getWidgetForMacroWidgetActionByName(const QString& name, + QWidget* parentWidget = 0); + + void releaseWidgetFromMacroWidgetAction(QWidget* widget, + QWidget* widget2 = NULL, + QWidget* widget3 = NULL, + QWidget* widget4 = NULL, + QWidget* widget5 = NULL, + QWidget* widget6 = NULL); + + void updateValueInWidgetFromMacroWidgetAction(QWidget* widget, + QWidget* widget2 = NULL, + QWidget* widget3 = NULL, + QWidget* widget4 = NULL, + QWidget* widget5 = NULL, + QWidget* widget6 = NULL); + + // ADD_NEW_METHODS_HERE + + public slots: + void updateNonModalDialogs(); + + void macroCommandCompletedExecution(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut); + + void macroCommandStartingExecution(QWidget* window, + const WuQMacroCommand* command, + const WuQMacroExecutorOptions* executorOptions, + bool& allowDelayFlagOut); + + private: + WuQMacroManager(const QString& name, + QObject* parent = NULL); + + std::vector m_parentObjects; + + const QString m_name; + + WuQMacroModeEnum::Enum m_mode = WuQMacroModeEnum::OFF; + + std::map m_signalWatchers; + + WuQMacro* m_macroBeingRecorded = NULL; + + WuQMacro* m_macroInsertCommandBeingRecorded = NULL; + + int32_t m_macroInsertCommandBeingRecordedOffset = -1; + + WuQMacroDialog* m_macrosDialog = NULL; + + static WuQMacroManager* s_singletonMacroManager; + + std::unique_ptr m_executorOptions; + + WuQMacroHelperInterface* m_macroHelper = NULL; + + WuQMacroCustomOperationManagerInterface* m_customCommandManager = NULL; + + std::vector m_macroWidgetActions; + + WuQMacroExecutor* m_macroExecutor = NULL; + + WuQMacroExecutorMonitor* m_macroExecutorMonitor = NULL; + + QMutex m_macroExecutorMutex; + + static QString s_importExportMacroFileDirectory; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_MANAGER_DECLARE__ + WuQMacroManager* WuQMacroManager::s_singletonMacroManager = NULL; + QString WuQMacroManager::s_importExportMacroFileDirectory; +#endif // __WU_Q_MACRO_MANAGER_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_MANAGER_H__ diff --git a/src/GuiQt/WuQMacroMenu.cxx b/src/GuiQt/WuQMacroMenu.cxx new file mode 100644 index 0000000000000000000000000000000000000000..907fd3bc39e39f1dd217b32fb4d904ddeac24d4c --- /dev/null +++ b/src/GuiQt/WuQMacroMenu.cxx @@ -0,0 +1,197 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_MENU_DECLARE__ +#include "WuQMacroMenu.h" +#undef __WU_Q_MACRO_MENU_DECLARE__ + +#include "CaretAssert.h" +#include "WuQMacroManager.h" + +using namespace caret; + + + +/** + * \class caret::WuQMacroMenu + * \brief Menu for accessing and interacting with the Macro System. + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param windowParent + * Window used as parent for dialogs + * @param parent + * Parent of the menu + */ +WuQMacroMenu::WuQMacroMenu(QWidget* windowParent, + QWidget* parent) +: QMenu(parent), +m_windowParent(windowParent) +{ + CaretAssert(windowParent); + + setTitle("Macro"); + + m_macroDialogAction = addAction("Macros..."); + QObject::connect(m_macroDialogAction, &QAction::triggered, + this, &WuQMacroMenu::macroDialogSelected); + + m_recordMacroAction = addAction("Start Recording New Macro..."); + QObject::connect(m_recordMacroAction, &QAction::triggered, + this, &WuQMacroMenu::macroRecordSelected); + + m_stopMacroAction = addAction("Stop Recording New Macro"); + QObject::connect(m_stopMacroAction, &QAction::triggered, + this, &WuQMacroMenu::macroStopSelected); + + { + QMenu* developmentMenu = new QMenu("Development"); + QAction* printAction = developmentMenu->addAction("Print Supported Widgets"); + QObject::connect(printAction, &QAction::triggered, + this, &WuQMacroMenu::macroPrintAllSelected); + QAction* printTopLevelWidgetsAction = developmentMenu->addAction("Print Top-Level Widgets"); + QObject::connect(printTopLevelWidgetsAction, &QAction::triggered, + this, &WuQMacroMenu::macroPrintTopLevelWidgets); + + addSeparator(); + addMenu(developmentMenu); + } + + QObject::connect(this, &QMenu::aboutToShow, + this, &WuQMacroMenu::macroMenuAboutToShow); +} + +/** + * Destructor. + */ +WuQMacroMenu::~WuQMacroMenu() +{ +} + +/** + * Called when the macro menu is about to show. + */ +void +WuQMacroMenu::macroMenuAboutToShow() +{ + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + + const bool hasMacroGroupFlag = ( ! macroManager->getActiveMacroGroups().empty()); + bool editValidFlag(false); + bool recordValidFlag(false); + bool stopValidFlag(false); + + switch (macroManager->getMode()) { + case WuQMacroModeEnum::OFF: + editValidFlag = true; + recordValidFlag = hasMacroGroupFlag; + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + stopValidFlag = true; + break; + case WuQMacroModeEnum::RUNNING: + break; + } + + m_macroDialogAction->setEnabled(editValidFlag); + m_recordMacroAction->setEnabled(recordValidFlag); + m_stopMacroAction->setEnabled(stopValidFlag); +} + +/** + * Called to start macro recording. + */ +void +WuQMacroMenu::macroRecordSelected() +{ + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + + switch (macroManager->getMode()) { + case WuQMacroModeEnum::OFF: + macroManager->startRecordingNewMacro(m_windowParent); + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + CaretAssert(0); + break; + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + CaretAssert(0); + break; + case WuQMacroModeEnum::RUNNING: + CaretAssert(0); + break; + } +} + +/** + * Called to stop macro recording. + */ +void +WuQMacroMenu::macroStopSelected() +{ + WuQMacroManager* macroManager = WuQMacroManager::instance(); + CaretAssert(macroManager); + + switch (macroManager->getMode()) { + case WuQMacroModeEnum::OFF: + CaretAssert(0); + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + macroManager->stopRecordingNewMacro(); + break; + case WuQMacroModeEnum::RUNNING: + CaretAssert(0); + break; + } +} + +/** + * Called to display the macro editor dialog. + */ +void +WuQMacroMenu::macroDialogSelected() +{ + WuQMacroManager::instance()->showMacrosDialog(m_windowParent); +} + +/** + * Print all watched widgets to terminal + */ +void +WuQMacroMenu::macroPrintAllSelected() +{ + WuQMacroManager::instance()->printSupportedWidgetsToTerminal(); +} + +/** + * Print all top level widgets name and class name + */ +void +WuQMacroMenu::macroPrintTopLevelWidgets() +{ + WuQMacroManager::instance()->printToLevelWidgetsToTerminal(); +} diff --git a/src/GuiQt/WuQMacroMenu.h b/src/GuiQt/WuQMacroMenu.h new file mode 100644 index 0000000000000000000000000000000000000000..8cd60e93ac1596b57d10c6ffe4fe7d11e6c0dcb5 --- /dev/null +++ b/src/GuiQt/WuQMacroMenu.h @@ -0,0 +1,78 @@ +#ifndef __WU_Q_MACRO_MENU_H__ +#define __WU_Q_MACRO_MENU_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +namespace caret { + + class WuQMacroMenu : public QMenu { + + Q_OBJECT + + public: + WuQMacroMenu(QWidget* windowParent, + QWidget* parent = 0); + + virtual ~WuQMacroMenu(); + + WuQMacroMenu(const WuQMacroMenu&) = delete; + + WuQMacroMenu& operator=(const WuQMacroMenu&) = delete; + + // ADD_NEW_METHODS_HERE + + private slots: + void macroMenuAboutToShow(); + + void macroRecordSelected(); + + void macroStopSelected(); + + void macroDialogSelected(); + + void macroPrintAllSelected(); + + void macroPrintTopLevelWidgets(); + + private: + // ADD_NEW_MEMBERS_HERE + + QWidget* m_windowParent; + + QAction* m_macroDialogAction; + + QAction* m_recordMacroAction; + + QAction* m_stopMacroAction; + }; + +#ifdef __WU_Q_MACRO_MENU_DECLARE__ + // +#endif // __WU_Q_MACRO_MENU_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_MENU_H__ diff --git a/src/GuiQt/WuQMacroMouseEventWidgetInterface.h b/src/GuiQt/WuQMacroMouseEventWidgetInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..4df88fb1b010af13436412afd7cb4f8a452003e5 --- /dev/null +++ b/src/GuiQt/WuQMacroMouseEventWidgetInterface.h @@ -0,0 +1,51 @@ +#ifndef __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_H__ +#define __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +class QMouseEvent; + +namespace caret { + + class WuQMacroMouseEventWidgetInterface { + + public: + WuQMacroMouseEventWidgetInterface() { } + + virtual ~WuQMacroMouseEventWidgetInterface() { } + + WuQMacroMouseEventWidgetInterface(const WuQMacroMouseEventWidgetInterface&) = delete; + + WuQMacroMouseEventWidgetInterface& operator=(const WuQMacroMouseEventWidgetInterface&) = delete; + + virtual void processMouseEventFromMacro(QMouseEvent* me) = 0; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_DECLARE__ + // +#endif // __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_H__ diff --git a/src/GuiQt/WuQMacroNewCommandSelectionDialog.cxx b/src/GuiQt/WuQMacroNewCommandSelectionDialog.cxx new file mode 100644 index 0000000000000000000000000000000000000000..93a916f170afbcb7881d7613a806ac7fec4a7f3b --- /dev/null +++ b/src/GuiQt/WuQMacroNewCommandSelectionDialog.cxx @@ -0,0 +1,469 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ +#include "WuQMacroNewCommandSelectionDialog.h" +#undef __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EnumComboBoxTemplate.h" +#include "WuQMacro.h" +#include "WuQMacroCommand.h" +#include "WuQMacroGroup.h" +#include "WuQMacroManager.h" +#include "WuQMacroShortCutKeyComboBox.h" +#include "WuQMacroSignalWatcher.h" + +using namespace caret; + +/** + * \class caret::WuQMacroNewCommandSelectionDialog + * \brief Dialog for creating a new macro + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param parent + * The parent widget + */ +WuQMacroNewCommandSelectionDialog::WuQMacroNewCommandSelectionDialog(QWidget* parent) +: QDialog(parent) +{ + setWindowTitle("Add Macro Command"); + + QLabel* commandTypeLabel = new QLabel("Command Type:"); + QLabel* commandsLabel = new QLabel("Commands:"); + QLabel* descriptionLabel = new QLabel("Description:"); + + std::vector commandTypes; + commandTypes.push_back(WuQMacroCommandTypeEnum::CUSTOM_OPERATION); + commandTypes.push_back(WuQMacroCommandTypeEnum::WIDGET); + m_commandTypeComboBox = new EnumComboBoxTemplate(this); + m_commandTypeComboBox->setupWithItems(commandTypes); + m_commandTypeComboBox->setSelectedItem(s_lastCommandTypeSelected); + QObject::connect(m_commandTypeComboBox, &EnumComboBoxTemplate::itemActivated, + this, &WuQMacroNewCommandSelectionDialog::commandTypeComboBoxActivated); + + QWidget* typeWidget = new QWidget(); + QHBoxLayout* typeLayout = new QHBoxLayout(typeWidget); + typeLayout->setContentsMargins(0, 0, 0, 0); + typeLayout->addWidget(commandTypeLabel, 0); + typeLayout->addWidget(m_commandTypeComboBox->getWidget(), 100); + + m_customCommandListWidget = new QListWidget(); + QObject::connect(m_customCommandListWidget, &QListWidget::currentItemChanged, + this, &WuQMacroNewCommandSelectionDialog::customCommandListWidgetCurrentItemChanged); + + m_widgetCommandListWidget = new QListWidget(); + QObject::connect(m_widgetCommandListWidget, &QListWidget::currentItemChanged, + this, &WuQMacroNewCommandSelectionDialog::widgetCommandListWidgetCurrentItemChanged); + + m_stackedWidget = new QStackedWidget(); + m_stackedWidget->addWidget(m_customCommandListWidget); + m_stackedWidget->addWidget(m_widgetCommandListWidget); + + QWidget* commandsWidget = new QWidget(); + QHBoxLayout* commandsLayout = new QHBoxLayout(commandsWidget); + commandsLayout->setContentsMargins(0, 0, 0, 0); + commandsLayout->addWidget(commandsLabel, 0); + commandsLayout->addWidget(m_stackedWidget, 100); + + m_macroDescriptionTextEdit = new QPlainTextEdit(); + + QWidget* descriptionWidget = new QWidget(); + QHBoxLayout* descriptionLayout = new QHBoxLayout(descriptionWidget); + descriptionLayout->setContentsMargins(0, 0, 0, 0); + descriptionLayout->addWidget(descriptionLabel, 0); + descriptionLayout->addWidget(m_macroDescriptionTextEdit, 100); + + m_splitter = new QSplitter(); + m_splitter->setOrientation(Qt::Vertical); + m_splitter->addWidget(commandsWidget); + m_splitter->addWidget(descriptionWidget); + m_splitter->setStretchFactor(0, 75); + m_splitter->setStretchFactor(1, 25); + m_splitter->setChildrenCollapsible(false); + + m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + const bool allowApplyButtonFlag(false); + if (allowApplyButtonFlag) { + m_dialogButtonBox->addButton(QDialogButtonBox::Apply); + } + QObject::connect(m_dialogButtonBox, &QDialogButtonBox::clicked, + this, &WuQMacroNewCommandSelectionDialog::otherButtonClicked); + + QVBoxLayout* dialogLayout = new QVBoxLayout(this); + dialogLayout->addWidget(typeWidget); + dialogLayout->addWidget(m_splitter); + dialogLayout->addWidget(m_dialogButtonBox); + + loadCustomCommandListWidget(); + loadWidgetCommandListWidget(); + + commandTypeComboBoxActivated(); + + if ( ! s_previousDialogGeometry.isEmpty()) { + restoreGeometry(s_previousDialogGeometry); + } + if ( ! s_previousSplitterState.isEmpty()) { + m_splitter->restoreState(s_previousSplitterState); + } +} + +/** + * Destructor. + */ +WuQMacroNewCommandSelectionDialog::~WuQMacroNewCommandSelectionDialog() +{ + s_previousDialogGeometry = saveGeometry(); + s_previousSplitterState = m_splitter->saveState(); + + for (auto cc : m_customCommands) { + delete cc; + } + m_customCommands.clear(); +} + +/** + * Called when a selection is made from command type combo box + */ +void +WuQMacroNewCommandSelectionDialog::commandTypeComboBoxActivated() +{ + s_lastCommandTypeSelected = m_commandTypeComboBox->getSelectedItem(); + + m_macroDescriptionTextEdit->clear(); + + switch (s_lastCommandTypeSelected) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + { + m_stackedWidget->setCurrentWidget(m_customCommandListWidget); + QListWidgetItem* item = m_customCommandListWidget->currentItem(); + if (item == NULL) { + if (m_customCommandListWidget->count() > 0) { + item = m_customCommandListWidget->item(0); + } + } + if (item != NULL) { + m_customCommandListWidget->setCurrentItem(item); + customCommandListWidgetCurrentItemChanged(item); + } + } + break; + case WuQMacroCommandTypeEnum::MOUSE: + CaretAssert(0); + break; + case WuQMacroCommandTypeEnum::WIDGET: + { + m_stackedWidget->setCurrentWidget(m_widgetCommandListWidget); + QListWidgetItem* item = m_widgetCommandListWidget->currentItem(); + if (item == NULL) { + if (m_widgetCommandListWidget->count() > 0) { + item = m_widgetCommandListWidget->item(0); + } + } + if (item != NULL) { + m_widgetCommandListWidget->setCurrentItem(item); + widgetCommandListWidgetCurrentItemChanged(item); + } + } + break; + } + + m_commandSelectionChangedSinceApplyClickedFlag = true; +} + +/** + * Load the custom commands into the list widget + */ +void +WuQMacroNewCommandSelectionDialog::loadCustomCommandListWidget() +{ + m_customCommands = WuQMacroManager::instance()->getAllCustomOperationMacroCommands(); + for (auto cc : m_customCommands) { + const QString name = cc->getDescriptiveName(); + const QString customTypeName = cc->getCustomOperationTypeName(); + + QListWidgetItem* item = new QListWidgetItem(name); + item->setData(Qt::UserRole, customTypeName); + m_customCommandListWidget->addItem(item); + } +} + +/** + * Load the widget commands into the list widget + */ +void +WuQMacroNewCommandSelectionDialog::loadWidgetCommandListWidget() +{ + m_widgetCommands = WuQMacroManager::instance()->getAllWidgetSignalWatchers(false); + for (auto wc : m_widgetCommands) { + const QString name = wc->getObjectName(); + QListWidgetItem *item = new QListWidgetItem(name); + m_widgetCommandListWidget->addItem(item); + } +} + +/** + * Called when an item in the custom list widget is clicked + * + * @param item + * Item that was clicked + */ +void +WuQMacroNewCommandSelectionDialog::customCommandListWidgetCurrentItemChanged(QListWidgetItem* item) +{ + QString description; + if (item != NULL) { + const QString customTypeName = item->data(Qt::UserRole).toString(); + for (auto cc : m_customCommands) { + if (customTypeName == cc->getCustomOperationTypeName()) { + description = cc->getObjectToolTip(); + } + } + } + + m_macroDescriptionTextEdit->setPlainText(description); + m_commandSelectionChangedSinceApplyClickedFlag = true; +} + +/** + * Called when an item in the custom list widget is clicked + * + * @param item + * Item that was clicked + */ +void +WuQMacroNewCommandSelectionDialog::widgetCommandListWidgetCurrentItemChanged(QListWidgetItem* /*item*/) +{ + QString description; + const int index = m_widgetCommandListWidget->currentRow(); + if ((index >= 0) + && (index < static_cast(m_widgetCommands.size()))) { + description = m_widgetCommands[index]->getToolTip(); + } + + m_macroDescriptionTextEdit->setPlainText(description); + m_commandSelectionChangedSinceApplyClickedFlag = true; +} + +/** + * Called when a dialog button is clicked + */ +void +WuQMacroNewCommandSelectionDialog::otherButtonClicked(QAbstractButton* button) +{ + switch (m_dialogButtonBox->standardButton(button)) { + case QDialogButtonBox::Apply: + processApplyButtonClicked(false); + break; + case QDialogButtonBox::Ok: + accept(); + break; + case QDialogButtonBox::Cancel: + reject(); + break; + default: + CaretAssertMessage(0, ("Unknown button clicked with text \"" + + button->text() + + "\"")); + break; + } +} + +/** + * Called to process the apply button. + * + * @return True if apply button process was successful, else false. + */ +bool +WuQMacroNewCommandSelectionDialog::processApplyButtonClicked(const bool okButtonClicked) +{ + bool validFlag(false); + switch (s_lastCommandTypeSelected) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + validFlag = (m_customCommandListWidget->currentItem() != NULL); + break; + case WuQMacroCommandTypeEnum::MOUSE: + CaretAssert(0); + validFlag = false; + break; + case WuQMacroCommandTypeEnum::WIDGET: + validFlag = (m_widgetCommandListWidget->currentItem() != NULL); + break; + } + + if (validFlag) { + bool addCommandFlag = true; + if (okButtonClicked) { + /* + * Both Apply and Ok add a command to the macro. If the user adds a command + * using apply and then clicks Ok without changing the selected command, + * warn the user to avoid unintentionally adding the command twice. + */ + if ( ! m_commandSelectionChangedSinceApplyClickedFlag) { + const QString msg("Selected command has not changed since Apply button was clicked. " + "Add command to macro again?"); + switch (QMessageBox::warning(this, + "Warning", + msg, + (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel), + QMessageBox::No)) { + case QMessageBox::Yes: + addCommandFlag = true; + break; + case QMessageBox::No: + addCommandFlag = false; + break; + case QMessageBox::Cancel: + addCommandFlag = false; + validFlag = false; + break; + default: + break; + } + } + } + QString errorMessage; + if (addCommandFlag) { + WuQMacroCommand* command = NULL; + command = getNewInstanceOfSelectedCommand(errorMessage); + if (command != NULL) { + emit signalNewMacroCommandCreated(command); + if ( ! okButtonClicked) { + m_commandSelectionChangedSinceApplyClickedFlag = false; + } + } + else { + validFlag = false; + QMessageBox::critical(this, + "Error", + errorMessage, + QMessageBox::Ok, + QMessageBox::Ok); + } + } + } + else { + QMessageBox::critical(this, + "Error", + "No command is selected", + QMessageBox::Ok, + QMessageBox::Ok); + } + return validFlag; +} + +/** + * Called when user clicks OK or Cancel + * + * @param r + * The dialog code (Accepted or Rejected) + */ +void +WuQMacroNewCommandSelectionDialog::done(int r) +{ + if (r == QDialog::Accepted) { + const bool validFlag = processApplyButtonClicked(true); + if ( ! validFlag) { + return; + } + } + + QDialog::done(r); +} + +/** + * Get new instance of the command selected + * + * @param errorMessageOut + * Output with error information. + * @return + Pointer to new command or NULL if it failed. + */ +WuQMacroCommand* +WuQMacroNewCommandSelectionDialog::getNewInstanceOfSelectedCommand(QString& errorMessageOut) +{ + errorMessageOut.clear(); + WuQMacroCommand* commandOut(NULL); + + switch (s_lastCommandTypeSelected) { + case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: + { + QListWidgetItem* item = m_customCommandListWidget->currentItem(); + if (item != NULL) { + const QString customTypeName = item->data(Qt::UserRole).toString(); + QString errorMessage; + commandOut = WuQMacroManager::instance()->newInstanceOfCustomOperationMacroCommand(customTypeName, + errorMessage); + if (commandOut == NULL) { + errorMessageOut = ("New instance of custom command \"" + + customTypeName + + "\" failed"); + } + } + } + break; + case WuQMacroCommandTypeEnum::MOUSE: + errorMessageOut = "Mouse commands not supported for new instances"; + CaretAssert(0); + break; + case WuQMacroCommandTypeEnum::WIDGET: + { + QListWidgetItem* item = m_widgetCommandListWidget->currentItem(); + if (item != NULL) { + const QString widgetName = item->text(); + WuQMacroSignalWatcher* watcher = WuQMacroManager::instance()->getWidgetSignalWatcherWithName(widgetName); + if (watcher != NULL) { + commandOut = watcher->createMacroCommandWithDefaultParameters(errorMessageOut); + } + else { + errorMessageOut = ("Unable to find widget watcher with name \"" + + widgetName + + "\""); + } + } + } + break; + } + + return commandOut; +} + + diff --git a/src/GuiQt/WuQMacroNewCommandSelectionDialog.h b/src/GuiQt/WuQMacroNewCommandSelectionDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..dec696b60597c2acab6250f23d8d693d8b0329d1 --- /dev/null +++ b/src/GuiQt/WuQMacroNewCommandSelectionDialog.h @@ -0,0 +1,125 @@ +#ifndef __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_H__ +#define __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include + +#include "WuQMacroCommandTypeEnum.h" + +class QAbstractButton; +class QComboBox; +class QDialogButtonBox; +class QLineEdit; +class QListWidget; +class QListWidgetItem; +class QPlainTextEdit; +class QSplitter; +class QStackedWidget; + +namespace caret { + + class EnumComboBoxTemplate; + class WuQMacro; + class WuQMacroCommand; + class WuQMacroGroup; + class WuQMacroShortCutKeyComboBox; + class WuQMacroSignalWatcher; + + class WuQMacroNewCommandSelectionDialog : public QDialog { + + Q_OBJECT + + public: + WuQMacroNewCommandSelectionDialog(QWidget* parent = 0); + + virtual ~WuQMacroNewCommandSelectionDialog(); + + WuQMacroNewCommandSelectionDialog(const WuQMacroNewCommandSelectionDialog&) = delete; + + WuQMacroNewCommandSelectionDialog& operator=(const WuQMacroNewCommandSelectionDialog&) = delete; + + // ADD_NEW_METHODS_HERE + + signals: + void signalNewMacroCommandCreated(WuQMacroCommand* command); + + public slots: + void commandTypeComboBoxActivated(); + + void customCommandListWidgetCurrentItemChanged(QListWidgetItem* item); + + void widgetCommandListWidgetCurrentItemChanged(QListWidgetItem* item); + + virtual void done(int r) override; + + void otherButtonClicked(QAbstractButton* button); + + private: + WuQMacroCommand* getNewInstanceOfSelectedCommand(QString& errorMessageOut); + + void loadCustomCommandListWidget(); + + void loadWidgetCommandListWidget(); + + bool processApplyButtonClicked(const bool okButtonClicked); + + EnumComboBoxTemplate* m_commandTypeComboBox; + + QStackedWidget* m_stackedWidget; + + QSplitter* m_splitter; + + QListWidget* m_customCommandListWidget; + + QListWidget* m_widgetCommandListWidget; + + QPlainTextEdit* m_macroDescriptionTextEdit; + + QDialogButtonBox* m_dialogButtonBox; + + std::vector m_customCommands; + + std::vector m_widgetCommands; + + WuQMacroCommand* m_lastCustomCommandAdded = NULL; + + bool m_commandSelectionChangedSinceApplyClickedFlag = false; + + static WuQMacroCommandTypeEnum::Enum s_lastCommandTypeSelected; + + static QByteArray s_previousDialogGeometry; + + static QByteArray s_previousSplitterState; + }; + +#ifdef __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ + WuQMacroCommandTypeEnum::Enum WuQMacroNewCommandSelectionDialog::s_lastCommandTypeSelected = WuQMacroCommandTypeEnum::CUSTOM_OPERATION; + QByteArray WuQMacroNewCommandSelectionDialog::s_previousDialogGeometry; + QByteArray WuQMacroNewCommandSelectionDialog::s_previousSplitterState; +#endif // __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_H__ diff --git a/src/GuiQt/WuQMacroShortCutKeyComboBox.cxx b/src/GuiQt/WuQMacroShortCutKeyComboBox.cxx new file mode 100644 index 0000000000000000000000000000000000000000..748f111c76e0b24e6437a6dfdd1361d34133a3a3 --- /dev/null +++ b/src/GuiQt/WuQMacroShortCutKeyComboBox.cxx @@ -0,0 +1,132 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ +#include "WuQMacroShortCutKeyComboBox.h" +#undef __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ + +using namespace caret; + +/** + * \class caret::WuQMacroShortCutKeyComboBox + * \brief Control for selection of a macro short cut key. + * \ingroup GuiQt + */ + +/** + * Constructor. + * @param parent + * The parent. + */ +WuQMacroShortCutKeyComboBox::WuQMacroShortCutKeyComboBox(QObject* parent) +: WuQWidget(parent) +{ + std::vector allShortCutKeys; + WuQMacroShortCutKeyEnum::getAllEnums(allShortCutKeys); + const int32_t numShortCutKeys = static_cast(allShortCutKeys.size()); + + m_shortCutKeyComboBox = new QComboBox(); + for (int32_t i = 0; i < numShortCutKeys; i++) { + m_shortCutKeyComboBox->addItem(WuQMacroShortCutKeyEnum::toGuiName(allShortCutKeys[i])); + m_shortCutKeyComboBox->setItemData(i, WuQMacroShortCutKeyEnum::toIntegerCode(allShortCutKeys[i])); + } + + QObject::connect(m_shortCutKeyComboBox, SIGNAL(activated(int)), + this, SLOT(shortCutKeyComboBoxSelection(int))); + +} + +/** + * Destructor. + */ +WuQMacroShortCutKeyComboBox::~WuQMacroShortCutKeyComboBox() +{ + +} + +/** + * Called to set the selected short cut key. + * @param shortCutKey + * New value for short cut key. + */ +void +WuQMacroShortCutKeyComboBox::setSelectedShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) +{ + const int32_t shortCutIntegerCode = WuQMacroShortCutKeyEnum::toIntegerCode(shortCutKey); + + const int numShortCutKeys = m_shortCutKeyComboBox->count(); + for (int32_t i = 0; i < numShortCutKeys; i++) { + if (shortCutIntegerCode == m_shortCutKeyComboBox->itemData(i).toInt()) { + if (this->signalsBlocked()) { + m_shortCutKeyComboBox->blockSignals(true); + } + + m_shortCutKeyComboBox->setCurrentIndex(i); + + if (this->signalsBlocked()) { + m_shortCutKeyComboBox->blockSignals(false); + } + break; + } + } +} + +/** + * @return The selected short cut key. + */ +WuQMacroShortCutKeyEnum::Enum +WuQMacroShortCutKeyComboBox::getSelectedShortCutKey() const +{ + WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::Key_None; + const int32_t indx = m_shortCutKeyComboBox->currentIndex(); + if (indx >= 0) { + const int32_t integerCode = m_shortCutKeyComboBox->itemData(indx).toInt(); + shortCutKey = WuQMacroShortCutKeyEnum::fromIntegerCode(integerCode, NULL); + } + return shortCutKey; +} + +/** + * @return The widget for this control. + */ +QWidget* +WuQMacroShortCutKeyComboBox::getWidget() +{ + return m_shortCutKeyComboBox; +} + +/** + * Called when a short cut key is selected + * @param indx + * Index of selection. + */ +void +WuQMacroShortCutKeyComboBox::shortCutKeyComboBoxSelection(int indx) +{ + if (this->signalsBlocked() == false) { + if ((indx >= 0) && + (indx < m_shortCutKeyComboBox->count())) { + const int32_t integerCode = m_shortCutKeyComboBox->itemData(indx).toInt(); + WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::fromIntegerCode(integerCode, NULL); + emit shortCutKeySelected(shortCutKey); + } + } +} diff --git a/src/GuiQt/WuQMacroShortCutKeyComboBox.h b/src/GuiQt/WuQMacroShortCutKeyComboBox.h new file mode 100644 index 0000000000000000000000000000000000000000..00776b894d2af5a9cc51afbfc8ddc4e794b545ca --- /dev/null +++ b/src/GuiQt/WuQMacroShortCutKeyComboBox.h @@ -0,0 +1,71 @@ +#ifndef __WUQ_MACRO_SHORT_CUT_COMBOBOX__H_ +#define __WUQ_MACRO_SHORT_CUT_COMBOBOX__H_ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "WuQMacroShortCutKeyEnum.h" +#include "WuQWidget.h" + +namespace caret { + + class Surface; + + class WuQMacroShortCutKeyComboBox : public WuQWidget { + + Q_OBJECT + + public: + WuQMacroShortCutKeyComboBox(QObject* parent); + + virtual ~WuQMacroShortCutKeyComboBox(); + + WuQMacroShortCutKeyEnum::Enum getSelectedShortCutKey() const; + + QWidget* getWidget(); + + public slots: + void setSelectedShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey); + + signals: + void shortCutKeySelected(const WuQMacroShortCutKeyEnum::Enum); + + private slots: + void shortCutKeyComboBoxSelection(int); + + private: + WuQMacroShortCutKeyComboBox(const WuQMacroShortCutKeyComboBox&); + + WuQMacroShortCutKeyComboBox& operator=(const WuQMacroShortCutKeyComboBox&); + + QComboBox* m_shortCutKeyComboBox; + + public: + private: + }; + +#ifdef __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ + // +#endif // __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ + +} // namespace +#endif //__WUQ_MACRO_SHORT_CUT_COMBOBOX__H_ diff --git a/src/GuiQt/WuQMacroSignalEmitter.cxx b/src/GuiQt/WuQMacroSignalEmitter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b952cc0f296090443fd4181effcf23d5935ad2d1 --- /dev/null +++ b/src/GuiQt/WuQMacroSignalEmitter.cxx @@ -0,0 +1,597 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ +#include "WuQMacroSignalEmitter.h" +#undef __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "WuQMacroWidgetAction.h" + +using namespace caret; + +/** + * \class caret::WuQMacroSignalEmitter + * \brief Causes the emission of a signal from a QObject instance + * \ingroup WuQMacro + */ + +/** + * Constructor. + */ +WuQMacroSignalEmitter::WuQMacroSignalEmitter() +: QObject() +{ + +} + +/** + * Destructor. + */ +WuQMacroSignalEmitter::~WuQMacroSignalEmitter() +{ +} + +/** + * Update a QAction's checked status and cause emission + * of its triggered() signal + * + * @param action + * The QAction + * @param checked + * New checked status + */ +void +WuQMacroSignalEmitter::emitQActionSignal(QAction* action, + const bool checked) +{ + CaretAssert(action); + action->setChecked(checked); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, + action, &QAction::triggered); + + emit valueChangedSignalBool(checked); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); +} + +/** + * Update a QActionGroup's selected action and cause emission + * of its triggered() signal + * + * @param actionGroup + * The QActionGroup + * @param text + * Text of selected action + */ +void +WuQMacroSignalEmitter::emitActionGroupSignal(QActionGroup* actionGroup, + const QString& text) +{ + CaretAssert(actionGroup); + + QList actions = actionGroup->actions(); + if (actions.isEmpty()) { + CaretLogWarning("Menu " + + actionGroup->objectName() + + " does not contain any actions when trying to select menu item with text: " + + text); + return; + } + + QAction* actionSelected = NULL; + const int32_t numActions = actions.size(); + for (int32_t i = 0; i < numActions; i++) { + if (actions.at(i)->text() == text) { + actionSelected = actions.at(i); + } + } + + if (actionSelected == NULL) { + CaretLogWarning("Unable to find QAction with text \"" + + text + + "\" for menu " + + actionGroup->objectName()); + return; + } + + QSignalBlocker blocker(actionGroup); + actionSelected->trigger(); + blocker.unblock(); + + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalActionGroupAction, + actionGroup, &QActionGroup::triggered); + + emit valueChangeSignalMenuAction(actionSelected); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalActionGroupAction, 0, 0); +} + +/** + * Update a QButtonGroup and cause emission + * of its buttonClicked() signal + * + * @param buttonGroup + * The QButtonGroup + * @param text + * Text of button + */ +void +WuQMacroSignalEmitter::emitQButtonGroupSignal(QButtonGroup* buttonGroup, + const QString& text) +{ + CaretAssert(buttonGroup); + + QAbstractButton* buttonSelected = NULL; + + QList allButtons = buttonGroup->buttons(); + if (allButtons.isEmpty()) { + CaretLogWarning("ButtonGroup " + + buttonGroup->objectName() + + " does not contain any buttons when trying to select button item with text: " + + text); + return; + } + + for (auto b : allButtons) { + if (b->text() == text) { + buttonSelected = b; + break; + } + } + if (buttonSelected == NULL) { + CaretLogWarning("Unable to find QAbstactButton with text \"" + + text + + "\" for button group " + + buttonGroup->objectName()); + return; + } + + QSignalBlocker blocker(buttonGroup); + buttonSelected->click(); + blocker.unblock(); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalAbstractButton, + buttonGroup, static_cast(&QButtonGroup::buttonClicked)); + + emit valueChangedSignalAbstractButton(buttonSelected); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); +} + +/** + * Update a QCheckBox's checked status and cause emission + * of its clicked() signal + * + * @param checkBox + * The QCheckBox + * @param checked + * New checked status + */ +void +WuQMacroSignalEmitter::emitQCheckBoxSignal(QCheckBox* checkBox, + const bool checked) +{ + CaretAssert(checkBox); + checkBox->setChecked(checked); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, + checkBox, &QCheckBox::clicked); + + emit valueChangedSignalBool(checked); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); +} + +/** + * Update a QComboBox's index and cause emission + * of its triggered() signal + * + * @param comboBox + * The QComboBox + * @param index + * New index + */ +void +WuQMacroSignalEmitter::emitQComboBoxSignal(QComboBox* comboBox, + const int32_t index) +{ + CaretAssert(comboBox); + comboBox->setCurrentIndex(index); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, + comboBox, static_cast(&QComboBox::activated)); + + emit valueChangedSignalInt(index); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); +} + +/** + * Update a QDoubleSpinBox value and cause emission + * of its valueChanged() signal + * + * @param doubleSpinBox + * The QDoubleSpinBox + * @param value + * New value + */ +void +WuQMacroSignalEmitter::emitQDoubleSpinBoxSignal(QDoubleSpinBox* doubleSpinBox, + const double value) +{ + CaretAssert(doubleSpinBox); + QSignalBlocker blocker(doubleSpinBox); + doubleSpinBox->setValue(value); + blocker.unblock(); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalDouble, + doubleSpinBox, static_cast(&QDoubleSpinBox::valueChanged)); + + emit valueChangedSignalDouble(value); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalDouble, 0, 0); + +} + +/** + * Update a QListWidget's item and cause emission + * of its itemActivated() signal + * + * @param lineEdit + * The QLineEdit + * @param text + * New text + */ +void +WuQMacroSignalEmitter::emitQListWidgetSignal(QListWidget* listWidget, + const QString& text) +{ + CaretAssert(listWidget); + + QList items = listWidget->findItems(text, + Qt::MatchExactly); + if (items.isEmpty()) { + CaretLogWarning("Unable to find QListWidgetItem with text \"" + + text + + "\" for " + + listWidget->objectName()); + return; + } + + QListWidgetItem* newItem = items.at(0); + listWidget->setCurrentItem(newItem); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangeSignalListWidgetItem, + listWidget, &QListWidget::itemActivated); + + emit valueChangeSignalListWidgetItem(newItem); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangeSignalListWidgetItem, 0, 0); +} + + +/** + * Update a QLineEdit's text and cause emission + * of its textChanged() signal + * + * @param lineEdit + * The QLineEdit + * @param text + * New text + */ +void +WuQMacroSignalEmitter::emitQLineEditSignal(QLineEdit* lineEdit, + const QString& text) +{ + CaretAssert(lineEdit); + lineEdit->setText(text); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalString, + lineEdit, &QLineEdit::textChanged); + + emit valueChangedSignalString(text); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalString, 0, 0); +} + +/** + * Update a Macro Widget Action's value and cause emission + * of its valueChanged() signal + * + * @param macroWidgetAction + * The Macro Widget Action + * @param value + * New value + */ +void +WuQMacroSignalEmitter::emitMacroWidgetActionSignal(WuQMacroWidgetAction* macroWidgetAction, + const QVariant& value) +{ + CaretAssert(macroWidgetAction); + macroWidgetAction->setDataValue(value); + + QObject::connect(this, & WuQMacroSignalEmitter::valueChangedSignalVariant, + macroWidgetAction, &WuQMacroWidgetAction::setModelValue); + + emit valueChangedSignalVariant(value); + + QObject::disconnect(this, & WuQMacroSignalEmitter::valueChangedSignalVariant, 0, 0); +} + +/** + * Select an item from a menu using the item's text + * + * @param lineEdit + * The QLineEdit + * @param menuActionText + * Text of menu item for selection + */ +void +WuQMacroSignalEmitter::emitQMenuSignal(QMenu* menu, + const QString& menuActionText) +{ + CaretAssert(menu); + + QList actions = menu->actions(); + if (actions.isEmpty()) { + CaretLogWarning("Menu " + + menu->objectName() + + " does not contain any actions when trying to select menu item with text: " + + menuActionText); + return; + } + + QAction* actionSelected = NULL; + const int32_t numActions = actions.size(); + for (int32_t i = 0; i < numActions; i++) { + if (actions.at(i)->text() == menuActionText) { + actionSelected = actions.at(i); + } + } + + if (actionSelected == NULL) { + CaretLogWarning("Unable to find QAction with text \"" + + menuActionText + + "\" for menu " + + menu->objectName()); + return; + } + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangeSignalMenuAction, + menu, &QMenu::triggered); + + emit valueChangeSignalMenuAction(actionSelected); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangeSignalMenuAction, 0, 0); +} + + +/** + * Update a QPushButton's checked status and cause emission + * of its clicked() signal + * + * @param pushButton + * The QPushButton + * @param checked + * New checked status + */ +void +WuQMacroSignalEmitter::emitQPushButtonSignal(QPushButton* pushButton, + const bool checked) +{ + CaretAssert(pushButton); + pushButton->setChecked(checked); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, + pushButton, &QPushButton::clicked); + + emit valueChangedSignalBool(checked); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); +} + +/** + * Update a RadioButton's checked status and cause emission + * of its checked() signal + * + * @param radioButton + * The QRadioButton + * @param checked + * New checked status + */ +void +WuQMacroSignalEmitter::emitQRadioButtonSignal(QRadioButton* radioButton, + const bool checked) +{ + CaretAssert(radioButton); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, + radioButton, &QRadioButton::clicked); + + const bool useClickFlag(true); + if (useClickFlag) { + QSignalBlocker blocker(radioButton); + radioButton->setChecked( !checked); + blocker.unblock(); + radioButton->click(); + } + else { + /* + * This does not work for a radio button in a button group + * as either click() or animateClick() is needed for the + * button group to emit a signal + */ + radioButton->setChecked(checked); + emit valueChangedSignalBool(checked); + } + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); +} + +/** + * Update a QSlider's value and cause emission + * of its valueChanged signal + * + * @param slider + * The QSlider + * @param value + * New value + */ +void +WuQMacroSignalEmitter::emitQSliderSignal(QSlider* slider, + const int32_t value) +{ + CaretAssert(slider); + + QSignalBlocker blocker(slider); + slider->setValue(value); + blocker.unblock(); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, + slider, &QSlider::valueChanged); + + emit valueChangedSignalInt(value); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); +} + +/** + * Update a spin box's value and cause emission + * of its valueChanged signal + * + * @param spinBox + * The QSpinBox + * @param value + * New value + */ +void +WuQMacroSignalEmitter::emitQSpinBoxSignal(QSpinBox* spinBox, + const int32_t value) +{ + CaretAssert(spinBox); + + QSignalBlocker blocker(spinBox); + spinBox->setValue(value); + blocker.unblock(); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, + spinBox, static_cast(&QSpinBox::valueChanged)); + + emit valueChangedSignalInt(value); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); + +} + +/** + * Update a TabBar's index and cause emission + * of its currentChanged() signal + * + * @param tabBar + * The QTabBar + * @param index + * New index + */ +void +WuQMacroSignalEmitter::emitQTabBarSignal(QTabBar* tabBar, + const int32_t index) +{ + CaretAssert(tabBar); + + tabBar->setCurrentIndex(index); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, + tabBar, &QTabBar::currentChanged); + + emit valueChangedSignalInt(index); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); +} + +/** + * Update a TabWidget's index and cause emission + * of its currentChanged() signal + * + * @param tabWidget + * The QTabWidget + * @param index + * New index + */ +void +WuQMacroSignalEmitter::emitQTabWidgetSignal(QTabWidget* tabWidget, + const int32_t index) +{ + CaretAssert(tabWidget); + + tabWidget->setCurrentIndex(index); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, + tabWidget, &QTabWidget::currentChanged); + + emit valueChangedSignalInt(index); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); +} + +/** + * Update a QToolButton checked status and cause emission + * of its checked() signal + * + * @param toolButton + * The QToolButton + * @param checked + * New checked status + */ +void +WuQMacroSignalEmitter::emitQToolButtonSignal(QToolButton* toolButton, + const bool checked) +{ + CaretAssert(toolButton); + toolButton->setChecked(checked); + + QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, + toolButton, &QToolButton::clicked); + + emit valueChangedSignalBool(checked); + + QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); +} diff --git a/src/GuiQt/WuQMacroSignalEmitter.h b/src/GuiQt/WuQMacroSignalEmitter.h new file mode 100644 index 0000000000000000000000000000000000000000..0d58bb7d9930dc12b34fa31fc0da72dc91d496f6 --- /dev/null +++ b/src/GuiQt/WuQMacroSignalEmitter.h @@ -0,0 +1,148 @@ +#ifndef __WU_Q_MACRO_SIGNAL_EMITTER_H__ +#define __WU_Q_MACRO_SIGNAL_EMITTER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include +#include + +class QAction; +class QActionGroup; +class QAbstractButton; +class QButtonGroup; +class QCheckBox; +class QComboBox; +class QDoubleSpinBox; +class QLineEdit; +class QListWidget; +class QListWidgetItem; +class QMenu; +class QPushButton; +class QRadioButton; +class QSlider; +class QSpinBox; +class QTabBar; +class QTabWidget; +class QToolButton; + +namespace caret { + + class WuQMacroWidgetAction; + + class WuQMacroSignalEmitter : public QObject { + + Q_OBJECT + + public: + WuQMacroSignalEmitter(); + + virtual ~WuQMacroSignalEmitter(); + + WuQMacroSignalEmitter(const WuQMacroSignalEmitter&) = delete; + + WuQMacroSignalEmitter& operator=(const WuQMacroSignalEmitter&) = delete; + + void emitQActionSignal(QAction* action, + const bool checked); + + void emitActionGroupSignal(QActionGroup* actionGroup, + const QString& text); + + void emitQCheckBoxSignal(QCheckBox* checkBox, + const bool checked); + + void emitQButtonGroupSignal(QButtonGroup* buttonGroup, + const QString& text); + + void emitQComboBoxSignal(QComboBox* comboBox, + const int32_t index); + + void emitQDoubleSpinBoxSignal(QDoubleSpinBox* doubleSpinBox, + const double value); + + void emitQLineEditSignal(QLineEdit* lineEdit, + const QString& text); + + void emitQListWidgetSignal(QListWidget* listWidget, + const QString& text); + + void emitMacroWidgetActionSignal(WuQMacroWidgetAction* macroWidgetAction, + const QVariant& value); + + void emitQMenuSignal(QMenu* menu, + const QString& text); + + void emitQPushButtonSignal(QPushButton* pushButton, + const bool checked); + + void emitQRadioButtonSignal(QRadioButton* radioButton, + const bool checked); + + void emitQSliderSignal(QSlider* slider, + const int32_t value); + + void emitQSpinBoxSignal(QSpinBox* spinBox, + const int32_t value); + + void emitQTabBarSignal(QTabBar* tabBar, + const int32_t value); + + void emitQTabWidgetSignal(QTabWidget* tabWidget, + const int32_t value); + + void emitQToolButtonSignal(QToolButton* toolButton, + const bool checked); + + // ADD_NEW_METHODS_HERE + + signals: + void valueChangedSignalActionGroupAction(QAction*); + + void valueChangeSignalMenuAction(QAction*); + + void valueChangedSignalBool(bool); + + void valueChangedSignalAbstractButton(QAbstractButton* button); + + void valueChangedSignalInt(int); + + void valueChangedSignalDouble(double); + + void valueChangedSignalString(QString); + + void valueChangeSignalListWidgetItem(QListWidgetItem*); + + void valueChangedSignalVariant(QVariant); + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ + // +#endif // __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_SIGNAL_EMITTER_H__ diff --git a/src/GuiQt/WuQMacroSignalWatcher.cxx b/src/GuiQt/WuQMacroSignalWatcher.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2bfe378b8f938831bb52120fd896e5eb77091d2a --- /dev/null +++ b/src/GuiQt/WuQMacroSignalWatcher.cxx @@ -0,0 +1,1112 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ +#include "WuQMacroSignalWatcher.h" +#undef __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "WuQMacroCommand.h" +#include "WuQMacroCommandParameter.h" +#include "WuQMacroManager.h" +#include "WuQMacroWidgetAction.h" + +using namespace caret; + +/** + * \class caret::WuQMacroSignalWatcher + * \brief Watches a QObject instance to observe its "value changed" signal + * \ingroup WuQMacro + */ + +/** + * Constructor. + * + * @param parentMacroManager + * Parent macro manager. + * @param object + * Object that is watched for a "value changed" signal + * @param objectType + * The type of the object. + * @param descriptiveName + * Descriptive name shown to user in macro command + * @param toolTipTextOverride + * Used to override tool tip or for when object does not + * support a tool tip. + */ +WuQMacroSignalWatcher::WuQMacroSignalWatcher(WuQMacroManager* parentMacroManager, + QObject* object, + const WuQMacroWidgetTypeEnum::Enum objectType, + const QString& descriptiveName, + const QString& toolTipTextOverride) +: QObject(), +m_parentMacroManager(parentMacroManager), +m_object(object), +m_objectType(objectType), +m_descriptiveName(descriptiveName), +m_objectName(object->objectName()) +{ + CaretAssert(m_parentMacroManager); + CaretAssert(m_object); + + QWidget* widget = qobject_cast(m_object); + if (widget != NULL) { + m_toolTipText = widget->toolTip(); + } + + switch (m_objectType) { + case WuQMacroWidgetTypeEnum::ACTION: + { + QAction* action = qobject_cast(m_object); + CaretAssert(action); + QObject::connect(action, &QAction::triggered, + this, &WuQMacroSignalWatcher::actionTriggered); + m_toolTipText = action->toolTip(); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, + "Click/Select", + "")); + } + break; + case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: + { + QAction* action = qobject_cast(m_object); + CaretAssert(action); + QObject::connect(action, &QAction::triggered, + this, &WuQMacroSignalWatcher::actionCheckableTriggered); + m_toolTipText = action->toolTip(); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, + "On/Off", + true)); + } + break; + case WuQMacroWidgetTypeEnum::ACTION_GROUP: + { + QActionGroup* actionGroup = qobject_cast(m_object); + CaretAssert(actionGroup); + QObject::connect(actionGroup, &QActionGroup::triggered, + this, &WuQMacroSignalWatcher::actionGroupTriggered); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Select name", + "")); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Select index", + 1)); + } + break; + case WuQMacroWidgetTypeEnum::BUTTON_GROUP: + { + QButtonGroup* buttonGroup = qobject_cast(m_object); + CaretAssert(buttonGroup); + QObject::connect(buttonGroup, static_cast(&QButtonGroup::buttonClicked), + this, &WuQMacroSignalWatcher::buttonGroupButtonClicked); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Select button with name", + "")); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Select button at index", + 1)); + } + break; + case WuQMacroWidgetTypeEnum::CHECK_BOX: + { + QCheckBox* checkBox = qobject_cast(m_object); + CaretAssert(checkBox); + QObject::connect(checkBox, &QCheckBox::clicked, + this, &WuQMacroSignalWatcher::checkBoxClicked); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, + "On/Off", + true)); + } + break; + case WuQMacroWidgetTypeEnum::COMBO_BOX: + { + QComboBox* comboBox = qobject_cast(m_object); + CaretAssert(comboBox); + QObject::connect(comboBox, static_cast(&QComboBox::activated), + this, &WuQMacroSignalWatcher::comboBoxActivated); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Select item with name", + "")); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Select item at index", + 1)); + } + break; + case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: + { + QDoubleSpinBox* spinBox = qobject_cast(m_object); + CaretAssert(spinBox); + QObject::connect(spinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &WuQMacroSignalWatcher::doubleSpinBoxValueChanged); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::FLOAT, + "New value", + spinBox->minimum())); + } + break; + case WuQMacroWidgetTypeEnum::INVALID: + CaretAssert(0); + break; + case WuQMacroWidgetTypeEnum::LINE_EDIT: + { + QLineEdit* lineEdit = qobject_cast(m_object); + CaretAssert(lineEdit); + QObject::connect(lineEdit, &QLineEdit::textEdited, + this, &WuQMacroSignalWatcher::lineEditTextEdited); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "New text", + "")); + } + break; + case WuQMacroWidgetTypeEnum::LIST_WIDGET: + { + QListWidget* listWidget = qobject_cast(m_object); + CaretAssert(listWidget); + QObject::connect(listWidget, &QListWidget::itemActivated, + this, &WuQMacroSignalWatcher::listWidgetItemActivated); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Select item with name", + "")); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Select item at index", + 1)); + } + break; + case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: + { + WuQMacroWidgetAction* macroWidgetAction = qobject_cast(m_object); + CaretAssert(macroWidgetAction); + QObject::connect(macroWidgetAction, &WuQMacroWidgetAction::valueChanged, + this, &WuQMacroSignalWatcher::macroWidgetActionValueChanged); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Data Value", + "")); + } + break; + case WuQMacroWidgetTypeEnum::MENU: + { + QMenu* menu = qobject_cast(m_object); + CaretAssert(menu); + QObject::connect(menu, &QMenu::triggered, + this, &WuQMacroSignalWatcher::menuTriggered); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Select item with name", + "")); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Select item at index", + 1)); + } + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON: + { + QPushButton* pushButton = qobject_cast(m_object); + CaretAssert(pushButton); + QObject::connect(pushButton, &QPushButton::clicked, + this, &WuQMacroSignalWatcher::pushButtonClicked); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, + "Click button", + "")); + } + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: + { + QPushButton* pushButton = qobject_cast(m_object); + CaretAssert(pushButton); + QObject::connect(pushButton, &QPushButton::clicked, + this, &WuQMacroSignalWatcher::pushButtonClicked); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, + "On/Off", + true)); + } + break; + case WuQMacroWidgetTypeEnum::RADIO_BUTTON: + { + QRadioButton* radioButton = qobject_cast(m_object); + CaretAssert(radioButton); + QObject::connect(radioButton, &QRadioButton::clicked, + this, &WuQMacroSignalWatcher::radioButtonClicked); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, /* type=NONE - RADIO BUTTON ALWAYS TRUE !!! */ + "Select button", + true)); + } + break; + case WuQMacroWidgetTypeEnum::SLIDER: + { + QSlider* slider = qobject_cast(m_object); + CaretAssert(slider); + QObject::connect(slider, &QSlider::valueChanged, + this, &WuQMacroSignalWatcher::sliderValueChanged); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Move slider to", + slider->minimum())); + + } + break; + case WuQMacroWidgetTypeEnum::SPIN_BOX: + { + QSpinBox* spinBox = qobject_cast(m_object); + CaretAssert(spinBox); + QObject::connect(spinBox, static_cast(&QSpinBox::valueChanged), + this, &WuQMacroSignalWatcher::spinBoxValueChanged); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Enter value", + spinBox->minimum())); + } + break; + case WuQMacroWidgetTypeEnum::TAB_BAR: + { + QTabBar* tabBar = qobject_cast(m_object); + CaretAssert(tabBar); + QObject::connect(tabBar, &QTabBar::tabBarClicked, + this, &WuQMacroSignalWatcher::tabBarCurrentChanged); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Select tab with name", + "")); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Select tab at index", + 0)); + } + break; + case WuQMacroWidgetTypeEnum::TAB_WIDGET: + { + QTabWidget* tabWidget = qobject_cast(m_object); + CaretAssert(tabWidget); + QObject::connect(tabWidget, &QTabWidget::tabBarClicked, + this, &WuQMacroSignalWatcher::tabWidgetCurrentChanged); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, + "Select tab with name", + "")); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, + "Select tab at index", + 0)); + } + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON: + { + QToolButton* toolButton = qobject_cast(m_object); + CaretAssert(toolButton); + QObject::connect(toolButton, &QCheckBox::clicked, + this, &WuQMacroSignalWatcher::toolButtonClicked); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, + "Select button", + true)); + } + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: + { + QToolButton* toolButton = qobject_cast(m_object); + CaretAssert(toolButton); + QObject::connect(toolButton, &QCheckBox::clicked, + this, &WuQMacroSignalWatcher::toolButtonClicked); + m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, + "On/Off", + true)); + } + break; + } + + /* + * Override the tool tip text + */ + if ( ! toolTipTextOverride.isEmpty()) { + m_toolTipText = toolTipTextOverride; + } + + QObject::connect(m_object, &QObject::destroyed, + this, &WuQMacroSignalWatcher::objectWasDestroyed); + QObject::connect(m_object, &QObject::objectNameChanged, + this, &WuQMacroSignalWatcher::objectNameWasChanged); +} + +/** + * Destructor. + */ +WuQMacroSignalWatcher::~WuQMacroSignalWatcher() +{ + for (auto p : m_objectParameters) { + delete p; + } + m_objectParameters.clear(); +} + +/** + * Called if the object whose signal is being monitored is destroyed + * + * @obj + * Pointer to object that was destroyed + */ +void +WuQMacroSignalWatcher::objectWasDestroyed(QObject* /*obj*/) +{ + /* + * Log object destroyed only when NOT debug + */ +#ifndef NDEBUG + /* disable as need way to disallow this while a window is closing or application exiting */ + const bool allowMessageFlag(false); + if (allowMessageFlag) { + CaretLogWarning("Object was destroyed: " + + m_objectName); + } +#endif +} + +/** + * Called if the object whose signal is being monitored + * has its name changed + * + * @name + * New name + */ +void +WuQMacroSignalWatcher::objectNameWasChanged(const QString& name) +{ + std::cout << "Object name changed from " + << m_objectName << " to " << name << std::endl; +} + +/** + * Create an new instance of a widget signal watcher for + * the given object. + * + * @param parentMacroManager + * Parent macro manager. + * @param object + * Object that will have a widget signal watcher. + * @param descriptiveName + * Descriptive name shown to user in macro command + * @param toolTipTextOverride + * Used to override tool tip or for when object does not + * support a tool tip. + * @param errorMessageOut + * Output containing error information if failure. + * @return + * Pointer to widget watcher or NULL if there was an error. + */ +WuQMacroSignalWatcher* +WuQMacroSignalWatcher::newInstance(WuQMacroManager* parentMacroManager, + QObject* object, + const QString& descriptiveName, + const QString& toolTipTextOverride, + QString& errorMessageOut) +{ + errorMessageOut.clear(); + + QString objectClassName = object->metaObject()->className(); + + bool validFlag(false); + WuQMacroWidgetTypeEnum::Enum objectType = WuQMacroWidgetTypeEnum::fromGuiName(objectClassName, + &validFlag); + + /* + * Some Qt Widgets may have a 'checkable' state + * and the 'checkable' and 'non-checkable' states + * must be handled differently. + */ + switch (objectType) { + case WuQMacroWidgetTypeEnum::ACTION: + { + /* + * Actions may have a 'checkable' status enabled + * Actions may also be in a QActionGroup and the + * QActionGroup may have an 'exclusive' status. + * + * NOTE: For this logic to work, the actions must have + * macro support added after the actions are placed + * in an exclusive action group + */ + QAction* action = qobject_cast(object); + CaretAssert(action); + if (action->isCheckable()) { + /* + * Probably checkable + */ + objectType = WuQMacroWidgetTypeEnum::ACTION_CHECKABLE; + + const QActionGroup* actionGroup = action->actionGroup(); + if (actionGroup != NULL) { + if (actionGroup->isExclusive()) { + /* + * In an exclusive group, actions CANNOT be + * uchecked so treat as non-checkable action + */ + objectType = WuQMacroWidgetTypeEnum::ACTION; + } + } + } + } + break; + case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: + CaretAssertMessage(0, "ACTION_CHECKABLE is created by ACTION above"); + break; + case WuQMacroWidgetTypeEnum::ACTION_GROUP: + break; + case WuQMacroWidgetTypeEnum::BUTTON_GROUP: + break; + case WuQMacroWidgetTypeEnum::CHECK_BOX: + break; + case WuQMacroWidgetTypeEnum::COMBO_BOX: + break; + case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: + break; + case WuQMacroWidgetTypeEnum::INVALID: + break; + case WuQMacroWidgetTypeEnum::LINE_EDIT: + break; + case WuQMacroWidgetTypeEnum::LIST_WIDGET: + break; + case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: + break; + case WuQMacroWidgetTypeEnum::MENU: + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON: + { + /* + * Buttons may have a 'checkable' status enabled + * Buttons may also be in a QButtonGroup and the + * QButtonGroup may have an 'exclusive' status. + * + * NOTE: For this logic to work, the buttons must have + * macro support added after the buttons are placed + * in an exclusive button group + */ + QAbstractButton* button = qobject_cast(object); + CaretAssert(button); + if (button->isCheckable()) { + /* + * Probably checkable + */ + objectType = WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE; + + const QButtonGroup* buttonGroup = button->group(); + if (buttonGroup != NULL) { + if (buttonGroup->exclusive()) { + /* + * In an exclusive group, buttons CANNOT be + * uchecked so treat as non-checkable button + */ + objectType = WuQMacroWidgetTypeEnum::PUSH_BUTTON; + } + } + } + } + break; + case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: + CaretAssertMessage(0, "PUSH_BUTTON_CHECKABLE is created by PUSH_BUTTON case above"); + break; + case WuQMacroWidgetTypeEnum::RADIO_BUTTON: + break; + case WuQMacroWidgetTypeEnum::SLIDER: + break; + case WuQMacroWidgetTypeEnum::SPIN_BOX: + break; + case WuQMacroWidgetTypeEnum::TAB_BAR: + break; + case WuQMacroWidgetTypeEnum::TAB_WIDGET: + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON: + { + /* + * Buttons may have a 'checkable' status enabled + * Buttons may also be in a QButtonGroup and the + * QButtonGroup may have an 'exclusive' status. + * + * NOTE: For this logic to work, the buttons must have + * macro support added after the buttons are placed + * in an exclusive button group + */ + QAbstractButton* button = qobject_cast(object); + CaretAssert(button); + if (button->isCheckable()) { + /* + * Probably checkable + */ + objectType = WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE; + + const QButtonGroup* buttonGroup = button->group(); + if (buttonGroup != NULL) { + if (buttonGroup->exclusive()) { + /* + * In an exclusive group, buttons CANNOT be + * uchecked so treat as non-checkable button + */ + objectType = WuQMacroWidgetTypeEnum::TOOL_BUTTON; + } + } + } + } + break; + case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: + CaretAssertMessage(0, "TOOL_BUTTON_CHECKABLE is created by TOOL_BUTTON case above"); + break; + } + + if ((objectType == WuQMacroWidgetTypeEnum::INVALID) + || ( ! validFlag)) { + errorMessageOut = ("Widget named \"" + + object->objectName() + + "\" of class \"" + + object->metaObject()->className() + + "\" is not supported for macros"); + return NULL; + } + + WuQMacroSignalWatcher* ww = new WuQMacroSignalWatcher(parentMacroManager, + object, + objectType, + descriptiveName, + toolTipTextOverride); + return ww; +} + +/** + * @return Name of the object + */ +QString +WuQMacroSignalWatcher::getObjectName() const +{ + return m_objectName; +} + +/** + * @return Tooltip for this signal watcher + */ +QString +WuQMacroSignalWatcher::getToolTip() const +{ + return m_toolTipText; +} + +/** + * Create a macro command for this widget watcher with default + * (essentially unset) parameters that need to be set by user + * + * @param errorMessageOut + * Contains error information if failure. + * @return + * Pointer to new command or NULL if failure. Caller + * is responsible for destroying returned command + */ +WuQMacroCommand* +WuQMacroSignalWatcher::createMacroCommandWithDefaultParameters(QString& errorMessageOut) const +{ + const int32_t versionNumber(1); + WuQMacroCommand* mc = WuQMacroCommand::newInstanceWidgetCommand(m_objectType, + versionNumber, + m_objectName, + m_descriptiveName, + m_toolTipText, + 1.0, + errorMessageOut); + if (mc != NULL) { + std::vector parameters = getCopyOfObjectParameters(); + for (auto p : parameters) { + mc->addParameter(p); + } + } + + return mc; +} + +/** + * If recording mode is enabled, create and send a macro command + * to the macro manager. + * + * @param parameters + * Parameters for the command + */ +void +WuQMacroSignalWatcher::createAndSendMacroCommand(std::vector& parameters) +{ + bool recordingFlag(false); + switch (m_parentMacroManager->getMode()) { + case WuQMacroModeEnum::OFF: + break; + case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: + case WuQMacroModeEnum::RECORDING_NEW_MACRO: + recordingFlag = true; + break; + case WuQMacroModeEnum::RUNNING: + break; + } + if (recordingFlag) { + const int32_t versionNumber(1); + QString errorMessage; + WuQMacroCommand* mc = WuQMacroCommand::newInstanceWidgetCommand(m_objectType, + versionNumber, + m_objectName, + m_descriptiveName, + m_toolTipText, + 1.0, + errorMessage); + if (mc != NULL) { + for (auto p : parameters) { + mc->addParameter(p); + } + + if ( ! m_parentMacroManager->addMacroCommandToRecording(mc)) { + delete mc; + } + } + else { + for (auto p : parameters) { + delete p; + } + parameters.clear(); + CaretLogSevere(errorMessage); + } + } + else { + for (auto p : parameters) { + delete p; + } + parameters.clear(); + } +} + +/** + * Called when a action group has an item triggered + * + * @param action + * ActionGroup action that was triggered + */ +void +WuQMacroSignalWatcher::actionGroupTriggered(QAction* action) +{ + QActionGroup* actionGroup = qobject_cast(m_object); + CaretAssert(actionGroup); + + int actionIndex(-1); + QList actionList = actionGroup->actions(); + for (int32_t i = 0; i < actionList.size(); i++) { + if (actionList.at(i) == action) { + actionIndex = i; + break; + } + } + + const QString actionText((action != NULL) + ? action->text() + : ""); + + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 2); + params[0]->setValue(actionText); + params[1]->setValue(actionIndex); + createAndSendMacroCommand(params); +} + + +/** + * Called when an action is triggered + * + * @param checked + * New checked status + */ +void +WuQMacroSignalWatcher::actionTriggered(bool /*checked*/) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(""); + createAndSendMacroCommand(params); +} + +/** + * Called when a checkable action is triggered + * + * @param checked + * New checked status + */ +void +WuQMacroSignalWatcher::actionCheckableTriggered(bool checked) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(checked); + createAndSendMacroCommand(params); +} + +/** + * Called when a button group button is clicked + * + * @param button + * Button that was clicked + */ +void +WuQMacroSignalWatcher::buttonGroupButtonClicked(QAbstractButton* button) +{ + QButtonGroup* buttonGroup = qobject_cast(m_object); + CaretAssert(buttonGroup); + + int buttonIndex(-1); + QList buttonList = buttonGroup->buttons(); + for (int32_t i = 0; i < buttonList.size(); i++) { + if (buttonList.at(i) == button) { + buttonIndex = i; + break; + } + } + + const QString buttonText((button != NULL) + ? button->text() + : ""); + + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 2); + params[0]->setValue(buttonText); + params[1]->setValue(buttonIndex); + createAndSendMacroCommand(params); +} + + +/** + * Called when a check box is clicked + * + * @param checked + * New checked status + */ +void +WuQMacroSignalWatcher::checkBoxClicked(bool checked) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(checked); + createAndSendMacroCommand(params); +} + +/** + * Called when a combo box is activated + * + * @param index + * Index of activated item + */ +void +WuQMacroSignalWatcher::comboBoxActivated(int index) +{ + QComboBox* comboBox = qobject_cast(m_object); + CaretAssert(comboBox); + + QString text; + if ((index >= 0) + && (index < comboBox->count())) { + text = comboBox->itemText(index); + } + + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 2); + params[0]->setValue(text); + params[1]->setValue(index); + createAndSendMacroCommand(params); + +} + +/** + * Called when a spin box value is changed + * + * @param value + * New value in double spin box + */ +void +WuQMacroSignalWatcher::doubleSpinBoxValueChanged(double value) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(value); + createAndSendMacroCommand(params); +} + +/** + * Called when a line edit has text edited + * + * @param text + * New value of text in the line edit + */ +void +WuQMacroSignalWatcher::lineEditTextEdited(const QString& text) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(text); + createAndSendMacroCommand(params); +} + +/** + * Called when a macro widget action value is changed + * + * @param value + * New value + */ +void +WuQMacroSignalWatcher::macroWidgetActionValueChanged(const QVariant& value) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(value); + createAndSendMacroCommand(params); +} + +/** + * Called when a list widget item is activated + * + * @param item + * List widget item that was selected + */ +void +WuQMacroSignalWatcher::listWidgetItemActivated(QListWidgetItem* item) +{ + QListWidget* listWidget = qobject_cast(m_object); + CaretAssert(listWidget); + + const int rowIndex = listWidget->row(item); + + const QString text((item != NULL) + ? item->text() + : ""); + + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 2); + params[0]->setValue(text); + params[1]->setValue(rowIndex); + createAndSendMacroCommand(params); +} + +/** + * Called when a menu has an item triggered + * + * @param action + * Menu action that was triggered + */ +void +WuQMacroSignalWatcher::menuTriggered(QAction* action) +{ + QMenu* menu = qobject_cast(m_object); + CaretAssert(menu); + + int actionIndex(-1); + QList actionList = menu->actions(); + for (int32_t i = 0; i < actionList.size(); i++) { + if (actionList.at(i) == action) { + actionIndex = i; + break; + } + } + + const QString text((action != NULL) + ? action->text() + : ""); + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 2); + params[0]->setValue(text); + params[1]->setValue(actionIndex); + createAndSendMacroCommand(params); +} + +/** + * Called when a push button is clicked + * + * @param checked + * New checked status + */ +void +WuQMacroSignalWatcher::pushButtonClicked(bool /*checked*/) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(""); + createAndSendMacroCommand(params); +} + +/** + * Called when a checkable push button is clicked + * + * @param checked + * New checked status + */ +void +WuQMacroSignalWatcher::pushButtonCheckableClicked(bool checked) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(checked); + createAndSendMacroCommand(params); +} + + +/** + * Called when a radio button is clicked + * + * @param checked + * New checked status + */ +void +WuQMacroSignalWatcher::radioButtonClicked(bool checked) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(checked); + createAndSendMacroCommand(params); +} + +/** + * Called when a slider value is changed + * + * @param value + * New value + */ +void +WuQMacroSignalWatcher::sliderValueChanged(int value) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(value); + createAndSendMacroCommand(params); +} + +/** + * Called when a spin box value is changed + * + * @param value + * New value + */ +void +WuQMacroSignalWatcher::spinBoxValueChanged(int value) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(value); + createAndSendMacroCommand(params); +} + +/** + * Called when a tab bar current tab is changed + * + * @param index + * Index of the new selected tab + */ +void +WuQMacroSignalWatcher::tabBarCurrentChanged(int index) +{ + QTabBar* tabBar = qobject_cast(m_object); + CaretAssert(tabBar); + const QString tabText = tabBar->tabText(index); + + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 2); + params[0]->setValue(tabText); + params[1]->setValue(index); + createAndSendMacroCommand(params); +} + +/** + * Called when a tab widget current tab is changed + * + * @param index + * Index of the new selected tab + */ +void +WuQMacroSignalWatcher::tabWidgetCurrentChanged(int index) +{ + QTabWidget* tabWidget = qobject_cast(m_object); + CaretAssert(tabWidget); + const QString tabText = tabWidget->tabText(index); + + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 2); + params[0]->setValue(tabText); + params[1]->setValue(index); + createAndSendMacroCommand(params); +} + +/** + * Called when a tool button is clicked + * + * @param checked + * New check status + */ +void +WuQMacroSignalWatcher::toolButtonClicked(bool /*checked*/) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(""); + createAndSendMacroCommand(params); +} + +/** + * Called when a tool button is clicked + * + * @param checked + * New check status + */ +void +WuQMacroSignalWatcher::toolButtonCheckableClicked(bool checked) +{ + std::vector params = getCopyOfObjectParameters(); + CaretAssert(params.size() >= 1); + params[0]->setValue(checked); + createAndSendMacroCommand(params); +} + +/** + * @return String containing description of this signal watcher + */ +QString +WuQMacroSignalWatcher::toString() const +{ + QString s(m_objectName + + " type=" + + WuQMacroWidgetTypeEnum::toGuiName(m_objectType)); + return s; +} + +/** + * @return A copy of the object's parameters + */ +std::vector +WuQMacroSignalWatcher::getCopyOfObjectParameters() const +{ + std::vector paramsCopy; + for(auto p : m_objectParameters) { + paramsCopy.push_back(new WuQMacroCommandParameter(*p)); + } + + return paramsCopy; +} + + diff --git a/src/GuiQt/WuQMacroSignalWatcher.h b/src/GuiQt/WuQMacroSignalWatcher.h new file mode 100644 index 0000000000000000000000000000000000000000..695babe60a4d55ef2b853859dcb70fa733e4d9f1 --- /dev/null +++ b/src/GuiQt/WuQMacroSignalWatcher.h @@ -0,0 +1,148 @@ +#ifndef __WU_Q_MACRO_SIGNAL_WATCHER_H__ +#define __WU_Q_MACRO_SIGNAL_WATCHER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +#include "WuQMacroWidgetTypeEnum.h" + +class QAbstractButton; +class QAction; +class QListWidgetItem; + +namespace caret { + + class WuQMacroCommand; + class WuQMacroCommandParameter; + class WuQMacroManager; + + class WuQMacroSignalWatcher : public QObject { + + Q_OBJECT + + public: + static WuQMacroSignalWatcher* newInstance(WuQMacroManager* parentMacroManager, + QObject* object, + const QString& descriptiveName, + const QString& toolTipTextOverride, + QString& errorMessageOut); + + virtual ~WuQMacroSignalWatcher(); + + WuQMacroSignalWatcher(const WuQMacroSignalWatcher&) = delete; + + WuQMacroSignalWatcher& operator=(const WuQMacroSignalWatcher&) = delete; + + WuQMacroCommand* createMacroCommandWithDefaultParameters(QString& errorMessageOut) const; + + QString getObjectName() const; + + QString toString() const; + + QString getToolTip() const; + + private slots: + void actionTriggered(bool); + + void actionCheckableTriggered(bool); + + void actionGroupTriggered(QAction* action); + + void buttonGroupButtonClicked(QAbstractButton* button); + + void checkBoxClicked(bool); + + void comboBoxActivated(int); + + void doubleSpinBoxValueChanged(double); + + void lineEditTextEdited(const QString&); + + void listWidgetItemActivated(QListWidgetItem*); + + void macroWidgetActionValueChanged(const QVariant& value); + + void menuTriggered(QAction* action); + + void pushButtonClicked(bool); + + void pushButtonCheckableClicked(bool); + + void radioButtonClicked(bool); + + void sliderValueChanged(int); + + void spinBoxValueChanged(int); + + void tabBarCurrentChanged(int); + + void tabWidgetCurrentChanged(int); + + void toolButtonClicked(bool); + + void toolButtonCheckableClicked(bool); + + void objectWasDestroyed(QObject* obj); + + void objectNameWasChanged(const QString& name); + + // ADD_NEW_METHODS_HERE + + private: + WuQMacroSignalWatcher(WuQMacroManager* parentMacroManager, + QObject* object, + const WuQMacroWidgetTypeEnum::Enum objectType, + const QString& descriptiveName, + const QString& toolTipTextOverride); + + WuQMacroManager* m_parentMacroManager; + + void createAndSendMacroCommand(std::vector& parameters); + + std::vector getCopyOfObjectParameters() const; + + QObject* m_object; + + const WuQMacroWidgetTypeEnum::Enum m_objectType; + + const QString m_descriptiveName; + + const QString m_objectName; + + QString m_toolTipText; + + std::vector m_objectParameters; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ + // +#endif // __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_SIGNAL_WATCHER_H__ diff --git a/src/GuiQt/WuQMacroWidgetAction.cxx b/src/GuiQt/WuQMacroWidgetAction.cxx new file mode 100644 index 0000000000000000000000000000000000000000..01d853d1cdfaac795dc486340dc61aa94e990783 --- /dev/null +++ b/src/GuiQt/WuQMacroWidgetAction.cxx @@ -0,0 +1,428 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ +#include "WuQMacroWidgetAction.h" +#undef __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ + +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EventManager.h" +using namespace caret; + + + +/** + * \class caret::WuQMacroWidgetAction + * \brief Like QWidgetAction but for use with widgets monitored by macro system but in dialogs + * \ingroup GuiQt + * + * Widgets in modal dialogs exist only while the dialog is active. Widgets in non-modal + * dialogs do not exist until the dialog is created. This presents a problem + * when the macro executor wants to trigger the widget's signal but the widget does not + * exist. This class is used by the macro system and an instance contains a signal corresponding + * to a widget in a modal dialog. + */ + + +/** + * Constructor. + * + * @param widgetType + * Type of widget + * @param objectName + * Name of this object + * @param objectToolTip + * Tooltip for object + * @param parent + * Parent for object + */ +WuQMacroWidgetAction::WuQMacroWidgetAction(const WidgetType widgetType, + const QString& objectName, + const QString& objectToolTip, + QObject* parent) +: QObject(parent), +m_widgetType(widgetType), +m_toolTip(objectToolTip) +{ + setObjectName(objectName); + + QObject::connect(this, &WuQMacroWidgetAction::valueChanged, + this, &WuQMacroWidgetAction::setValuePrivate); + +// EventManager::get()->addEventListener(this, EventTypeEnum::); +} + +/** + * Destructor. + */ +WuQMacroWidgetAction::~WuQMacroWidgetAction() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * @return The type of data value + */ +WuQMacroWidgetAction::WidgetType +WuQMacroWidgetAction::getWidgetType() const +{ + return m_widgetType; +} + +/** + * @return A widget the represents the action with the given parent. + * Caller is responsibled for deleting the widget and must call + * releaseWidget() prior to deleting the widget. + * + * @param Parent for the returned widget + */ +QWidget* +WuQMacroWidgetAction::requestWidget(QWidget* parent) +{ + QWidget* w(NULL); + + /* + * Create widget and attach to signal + */ + switch (m_widgetType) { + case WidgetType::CHECK_BOX_BOOLEAN: + { + QCheckBox* cb = new QCheckBox(parent); + QObject::connect(cb, &QCheckBox::clicked, + this, [=](bool checked) { emit valueChanged(checked); }); + w = cb; + } + break; + case WidgetType::COMBO_BOX_STRING_LIST: + { + QComboBox* cb = new QComboBox(parent); + for (auto s : m_comboBoxStringListItems) { + cb->addItem(s); + } + QObject::connect(cb, QOverload::of(&QComboBox::activated), + this, [=](const QString& value) { emit valueChanged(value); } ); + w = cb; + } + break; + case WidgetType::LINE_EDIT_STRING: + { + QLineEdit* le = new QLineEdit(parent); + QObject::connect(le, QOverload::of(&QLineEdit::textEdited), + this, [=](const QString& value) { emit valueChanged(value); } ); + w = le; + } + break; + case WidgetType::SPIN_BOX_FLOAT: + { + QDoubleSpinBox* sb = new QDoubleSpinBox(parent); + sb->setMinimum(m_spinBoxFloatMinMaxStep.m_minValue); + sb->setMaximum(m_spinBoxFloatMinMaxStep.m_maxValue); + sb->setSingleStep(m_spinBoxFloatMinMaxStep.m_step); + sb->setDecimals(m_spinBoxFloatMinMaxStep.m_decimals); + sb->setValue(sb->minimum()); + QObject::connect(sb, QOverload::of(&QDoubleSpinBox::valueChanged), + this, [=](const double value) { emit valueChanged(static_cast(value)); } ); + w = sb; + } + break; + case WidgetType::SPIN_BOX_INTEGER: + { + QSpinBox* sb = new QSpinBox(parent); + sb->setMinimum(m_spinBoxIntegerMinMaxStep.m_minValue); + sb->setMaximum(m_spinBoxIntegerMinMaxStep.m_maxValue); + sb->setSingleStep(m_spinBoxIntegerMinMaxStep.m_step); + sb->setValue(sb->minimum()); + QObject::connect(sb, QOverload::of(&QSpinBox::valueChanged), + this, [=](const int value) { emit valueChanged(value); } ); + w = sb; + } + break; + } + + CaretAssert(w); + + w->setToolTip(m_toolTip); + w->setObjectName(objectName() + + ":" + + w->metaObject()->className()); + + m_widgets.insert(w); + + updateWidgetWithModelValue(w); + + return w; +} + +/** + * Release the specified widget. Any signals are disconnected + * and this widget is no longer updated. The caller is + * responsible for deleting the widget. + * + * It is okay to call this method with a widget + * that belongs to another macro widget action + * and in this case no action is taken. + * + * @return + * True if the widget was monitored by this + * macro widget action, otherwise false. + */ +bool +WuQMacroWidgetAction::releaseWidget(QWidget* widget) +{ + CaretAssert(widget); + + if (m_widgets.find(widget) != m_widgets.end()) { + /* + * Disconnect all signals in widget from 'this' + */ + QObject::disconnect(widget, 0, + this, 0); + + m_widgets.erase(widget); + + //std::cout << "Released widget: " << widget->objectName() << std::endl; + return true; + } + + /* + * If here, widget was not in this macro widget action + */ + return false; +} + +/** + * @return The tooltip + */ +QString +WuQMacroWidgetAction::getToolTip() const +{ + return m_toolTip; +} + +/** + * @return The name of the widget action + */ +QString +WuQMacroWidgetAction::getName() const +{ + return objectName(); +} + +/** + * Set the data value but DOES NOT emit valueChanged() signal + * + * @param value + * New data value for widget action + */ +void +WuQMacroWidgetAction::setDataValue(const QVariant& value) +{ + for (auto w : m_widgets) { + setWidgetValue(w, + value); + } +} + +/** + * Set the value and will emit the valueChanged signal + * + * @param value + * New value. + */ +void +WuQMacroWidgetAction::setValuePrivate(const QVariant& value) +{ + for (auto w : m_widgets) { + setWidgetValue(w, + value); + } + + emit setModelValue(value); +} + +/** + * Set a widget's value + * + * @param widget + * The widget + * @param value + * Value for the widget + */ +void +WuQMacroWidgetAction::setWidgetValue(QWidget* widget, + const QVariant& value) +{ + /* + * Some widgets, such as spin box, will emit a signal + * when its value is changed so block its signals + */ + QSignalBlocker sb(widget); + + switch (m_widgetType) { + case WidgetType::CHECK_BOX_BOOLEAN: + { + QCheckBox* cb = qobject_cast(widget); + CaretAssert(cb); + cb->setChecked(value.toBool()); + } + break; + case WidgetType::COMBO_BOX_STRING_LIST: + { + QComboBox* cb = qobject_cast(widget); + CaretAssert(cb); + cb->setCurrentText(value.toString()); + } + break; + case WidgetType::LINE_EDIT_STRING: + { + QLineEdit* le = qobject_cast(widget); + CaretAssert(le); + le->setText(value.toString()); + } + break; + case WidgetType::SPIN_BOX_FLOAT: + { + QDoubleSpinBox* sb = qobject_cast(widget); + CaretAssert(sb); + sb->setValue(value.toFloat()); + } + break; + case WidgetType::SPIN_BOX_INTEGER: + { + QSpinBox* sb = qobject_cast(widget); + CaretAssert(sb); + sb->setValue(value.toInt()); + } + break; + } +} + +/** + * May be called when a dialog is created or updated + * to update the model value in the given widget + * + * @param widget + * The widget + * @return + * True if widget was updated with model value + */ +bool +WuQMacroWidgetAction::updateWidgetWithModelValue(QWidget* widget) +{ + CaretAssert(widget); + if (m_widgets.find(widget) != m_widgets.end()) { + QVariant value; + emit getModelValue(value); + + if (value.isNull()) { + const QString msg("Value was not updated by model, need to connect getModelValue() signal"); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + } + else { + setWidgetValue(widget, + value); + return true; + } + } + + return false; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +WuQMacroWidgetAction::receiveEvent(Event* /*event*/) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + +/** + * Setup widget that will be provided by the macro widget action + * + * @param comboBoxTextItems + * Text items for combo box + */ +void +WuQMacroWidgetAction::setComboBoxStringList(std::vector& comboBoxTextItems) +{ + m_comboBoxStringListItems = comboBoxTextItems; +} + +/** + * Setup widget that will be provided by the macro widget action + * + * @param minValue + * Minimum value for spin box + * @param maxValue + * Maximum value for spin box + * @param step + * Step value for spin box + */ +void +WuQMacroWidgetAction::setSpinBoxMinMaxStep(const int32_t minValue, + const int32_t maxValue, + const int32_t step) +{ + m_spinBoxIntegerMinMaxStep.m_minValue = minValue; + m_spinBoxIntegerMinMaxStep.m_maxValue = maxValue; + m_spinBoxIntegerMinMaxStep.m_step = step; +} + +/** + * Setup widget that will be provided by the macro widget action + * + * @param minValue + * Minimum value for spin box + * @param maxValue + * Maximum value for spin box + * @param step + * Step value for spin box + * @param decimals + * Number of decimals right of decimal point + */ +void +WuQMacroWidgetAction::setDoubleSpinBoxMinMaxStepDecimals(const double minValue, + const double maxValue, + const double step, + const int32_t decimals) +{ + m_spinBoxFloatMinMaxStep.m_minValue = minValue; + m_spinBoxFloatMinMaxStep.m_maxValue = maxValue; + m_spinBoxFloatMinMaxStep.m_step = step; + m_spinBoxFloatMinMaxStep.m_decimals = decimals; +} diff --git a/src/GuiQt/WuQMacroWidgetAction.h b/src/GuiQt/WuQMacroWidgetAction.h new file mode 100644 index 0000000000000000000000000000000000000000..fc88716907b3260d7d73b494bd71718abd3b1c87 --- /dev/null +++ b/src/GuiQt/WuQMacroWidgetAction.h @@ -0,0 +1,168 @@ +#ifndef __WU_Q_MACRO_WIDGET_ACTION_H__ +#define __WU_Q_MACRO_WIDGET_ACTION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include + +#include + +#include "EventListenerInterface.h" +#include "WuQMacroDataValueTypeEnum.h" + +namespace caret { + +// class ModelPropertySetGet { +// public: +// virtual QVariant getValue() const = 0; +// virtual void setValue(const QVariant& value) = 0; +// }; + + class WuQMacroWidgetAction : public QObject, public EventListenerInterface { + + Q_OBJECT + + public: + /** + * Type of widget + */ + enum class WidgetType { + /** CheckBox for boolean value */ + CHECK_BOX_BOOLEAN, + /** Combo Box for string list selection */ + COMBO_BOX_STRING_LIST, + /** Line edit for text */ + LINE_EDIT_STRING, + /** Spin box for float value */ + SPIN_BOX_FLOAT, + /** Spin box for integer value */ + SPIN_BOX_INTEGER + }; + + WuQMacroWidgetAction(const WidgetType widgetType, + const QString& objectName, + const QString& objectToolTip, + QObject* parent); + + static void initialize(std::map& namesAndTypes); + + static void destroy(); + + virtual ~WuQMacroWidgetAction(); + + WuQMacroWidgetAction(const WuQMacroWidgetAction&) = delete; + + WuQMacroWidgetAction& operator=(const WuQMacroWidgetAction&) = delete; + + QWidget* requestWidget(QWidget* parent); + + bool releaseWidget(QWidget* widget); + + WidgetType getWidgetType() const; + + QString getName() const; + + QString getToolTip() const; + + // ADD_NEW_METHODS_HERE + + virtual void receiveEvent(Event* event); + + void setDataValue(const QVariant& value); + + bool updateWidgetWithModelValue(QWidget* widget); + + void setComboBoxStringList(std::vector& comboBoxTextItems); + + void setSpinBoxMinMaxStep(const int32_t minValue, + const int32_t maxValue, + const int32_t step); + + void setDoubleSpinBoxMinMaxStepDecimals(const double minValue, + const double maxValue, + const double step, + const int32_t decimals); + + signals: + /** + * Emitted when the value changes. Used by macro signal watcher. + * + * @param value + * The new value + */ + void valueChanged(const QVariant& value); + + /** + * Connect this signal to get the model's data value + * + * @param valueOut + * Reference for signal receiver to set with model's data value + */ + void getModelValue(QVariant& valueOut); + + /** + * Connect this signal to set the model's data value + * + * @param value + * New value for model + */ + void setModelValue(const QVariant& value); + + private slots: + void setValuePrivate(const QVariant& value); + + private: + void setWidgetValue(QWidget* widget, + const QVariant& value); + + const WidgetType m_widgetType; + + const QString m_toolTip; + + std::set m_widgets; + + std::vector m_comboBoxStringListItems; + + struct { + int32_t m_minValue = 0; + int32_t m_maxValue = 32000; + int32_t m_step = 1; + } m_spinBoxIntegerMinMaxStep; + + struct { + double m_minValue = 0.0; + double m_maxValue = 32000.0; + double m_step = 1.0; + int32_t m_decimals = 2; + } m_spinBoxFloatMinMaxStep; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ + // +#endif // __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ + +} // namespace +#endif //__WU_Q_MACRO_WIDGET_ACTION_H__ diff --git a/src/GuiQt/WuQSpinBox.cxx b/src/GuiQt/WuQSpinBox.cxx new file mode 100644 index 0000000000000000000000000000000000000000..80fc7365804b2c1761509ac3cbea38d29804a0f7 --- /dev/null +++ b/src/GuiQt/WuQSpinBox.cxx @@ -0,0 +1,66 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_SPIN_BOX_DECLARE__ +#include "WuQSpinBox.h" +#undef __WU_Q_SPIN_BOX_DECLARE__ + +#include + +#include "CaretAssert.h" + +using namespace caret; + +#include + + +/** + * \class caret::WuQSpinBox + * \brief Emits a signal when the return key is pressed + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WuQSpinBox::WuQSpinBox() +: QSpinBox() +{ +} + +/** + * Destructor. + */ +WuQSpinBox::~WuQSpinBox() +{ +} + +void +WuQSpinBox::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Return) { + emit signalReturnPressed(); + return; + } + + QSpinBox::keyPressEvent(event); +} + diff --git a/src/GuiQt/WuQSpinBox.h b/src/GuiQt/WuQSpinBox.h new file mode 100644 index 0000000000000000000000000000000000000000..d11858300f84f9616fd411f896f619ceb31eeca5 --- /dev/null +++ b/src/GuiQt/WuQSpinBox.h @@ -0,0 +1,66 @@ +#ifndef __WU_Q_SPIN_BOX_H__ +#define __WU_Q_SPIN_BOX_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + + + +namespace caret { + + class WuQSpinBox : public QSpinBox { + + Q_OBJECT + + public: + WuQSpinBox(); + + virtual ~WuQSpinBox(); + + WuQSpinBox(const WuQSpinBox&) = delete; + + WuQSpinBox& operator=(const WuQSpinBox&) = delete; + + + // ADD_NEW_METHODS_HERE + + signals: + void signalReturnPressed(); + + protected: + void keyPressEvent(QKeyEvent* event) override; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_SPIN_BOX_DECLARE__ + // +#endif // __WU_Q_SPIN_BOX_DECLARE__ + +} // namespace +#endif //__WU_Q_SPIN_BOX_H__ diff --git a/src/GuiQt/WuQTabBar.cxx b/src/GuiQt/WuQTabBar.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6b1a2934d8f1e4ce82806c91ec059a5ab21f333a --- /dev/null +++ b/src/GuiQt/WuQTabBar.cxx @@ -0,0 +1,80 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_TAB_BAR_DECLARE__ +#include "WuQTabBar.h" +#undef __WU_Q_TAB_BAR_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::WuQTabBar + * \brief Overrides and adds capabilities to QTabBar + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +WuQTabBar::WuQTabBar(QWidget* parent) +: QTabBar(parent) +{ + +} + +/** + * Destructor. + */ +WuQTabBar::~WuQTabBar() +{ +} + +/** + * Overrides parent widget's method to emit mousePressedSignal. + * + * @param event + * The mouse event. + */ +void +WuQTabBar::mousePressEvent(QMouseEvent* event) +{ + emit mousePressedSignal(); + + QTabBar::mousePressEvent(event); +} + +/** + * Overrides parent widget's method to emit mouseReleaseSignal. + * + * @param event + * The mouse event. + */ +void +WuQTabBar::mouseReleaseEvent(QMouseEvent* event) +{ + emit mouseReleasedSignal(); + + QTabBar::mouseReleaseEvent(event); +} + diff --git a/src/GuiQt/WuQTabBar.h b/src/GuiQt/WuQTabBar.h new file mode 100644 index 0000000000000000000000000000000000000000..84d294e2e70e021fe36194c0fcf613f3ce1be0f8 --- /dev/null +++ b/src/GuiQt/WuQTabBar.h @@ -0,0 +1,70 @@ +#ifndef __WU_Q_TAB_BAR_H__ +#define __WU_Q_TAB_BAR_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + + + +namespace caret { + + class WuQTabBar : public QTabBar { + + Q_OBJECT + + public: + WuQTabBar(QWidget* parent = 0); + + virtual ~WuQTabBar(); + + WuQTabBar(const WuQTabBar&) = delete; + + WuQTabBar& operator=(const WuQTabBar&) = delete; + + + // ADD_NEW_METHODS_HERE + + signals: + void mousePressedSignal(); + + void mouseReleasedSignal(); + + protected: + virtual void mousePressEvent(QMouseEvent* event) override; + + virtual void mouseReleaseEvent(QMouseEvent* event) override; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_TAB_BAR_DECLARE__ + // +#endif // __WU_Q_TAB_BAR_DECLARE__ + +} // namespace +#endif //__WU_Q_TAB_BAR_H__ diff --git a/src/GuiQt/WuQTabWidget.cxx b/src/GuiQt/WuQTabWidget.cxx index 6f5c69f38c2c042f1cce04428c47e03719c9d053..246169e2a1ca341e11f59138cde2750e27d3734b 100644 --- a/src/GuiQt/WuQTabWidget.cxx +++ b/src/GuiQt/WuQTabWidget.cxx @@ -116,6 +116,16 @@ WuQTabWidget::getWidget() return m_widget; } +/** + * @return The embedded tab bar + */ +QTabBar* +WuQTabWidget::getTabBar() const +{ + return m_tabBar; +} + + /** * Adds a tab with the given page and label to the tab widget, and returns * the index of the tab in the tab bar. If the tab's label contains an diff --git a/src/GuiQt/WuQTabWidget.h b/src/GuiQt/WuQTabWidget.h index f20d001dfa705a6298194079961c057b87476ae8..4d88f60699f36903c1d8df19520e1ca27108cb94 100644 --- a/src/GuiQt/WuQTabWidget.h +++ b/src/GuiQt/WuQTabWidget.h @@ -55,6 +55,8 @@ namespace caret { QWidget* currentWidget() const; + QTabBar* getTabBar() const; + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index 1acec9a6c13642c093020f8eb9b1077a4f3ea5db..d653978ce630a808942a00d7aaa0621c8957ba11 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -168,12 +168,6 @@ WuQtUtilities::createAction(const QString& text, QAction* action = WuQtUtilities::createAction(text, toolAndStatusTipText, parent); -// QAction* action = new QAction(parent); -// action->setText(text); -// if (toolAndStatusTipText.isEmpty() == false) { -// action->setStatusTip(toolAndStatusTipText); -// action->setToolTip(toolAndStatusTipText); -// } QObject::connect(action, SIGNAL(triggered(bool)), receiver, @@ -215,12 +209,55 @@ WuQtUtilities::createPushButton(const QString& text, return pb; } +/** + * Create a tool button with the specified text, icon, + * tooltip and slot. + * + * @param text + * Text for the action. + * @param iconFileName + * Name of file containing the icon. + * @param tooltip + * Tooltip for the button + * @param receiver + * Owner of method that is called when button is clicked. + * @param method + * method in receiver that is called when button is clicked. + * @return + * Toolbutton that was created. + */ +QToolButton* +WuQtUtilities::createToolButtonWithIcon(const QString& text, + const QString& iconFileName, + const QString& toolTip, + QObject* receiver, + const char* method) +{ + QIcon icon; + const bool iconValid = WuQtUtilities::loadIcon(iconFileName, + icon); + + QToolButton* toolButton = new QToolButton(); + if (iconValid) { + toolButton->setIcon(icon); + } + else { + toolButton->setText(text); + } + toolButton->setToolTip(toolTip); + + QObject::connect(toolButton, SIGNAL(clicked(bool)), + receiver, method); + + return toolButton; +} + /** * Create a horizontal line widget used as a separator. * * @return A horizontal line widget used as a separator. */ -QWidget* +QWidget* WuQtUtilities::createHorizontalLineWidget() { QFrame* frame = new QFrame(); @@ -643,7 +680,7 @@ WuQtUtilities::estimateTableWidgetSize(QTableWidget* tableWidget) if (item != NULL) { int itemWidth = 0; int itemHeight = 0; - if (item->flags() && Qt::ItemIsUserCheckable) { + if (item->flags() & Qt::ItemIsUserCheckable) { itemWidth += 12; } @@ -1296,7 +1333,8 @@ WuQtUtilities::createCaretColorEnumPixmap(const QWidget* widget, QPixmap pixmap(pixmapWidth, pixmapHeight); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, - pixmap); + pixmap, + 0); if (noneColorFlag) { /* @@ -1350,17 +1388,21 @@ WuQtUtilities::createCaretColorEnumPixmap(const QWidget* widget, * Widget used for coloring. * @param pixmap * The Pixmap must be square (width == height). + * @param pixmapOptions + * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainterOriginCenter100x100(const QWidget* widget, - QPixmap& pixmap) + QPixmap& pixmap, + const uint32_t pixmapOptions) { CaretAssert(pixmap.width() == pixmap.height()); QSharedPointer painter = createPixmapWidgetPainter(widget, - pixmap); + pixmap, + pixmapOptions); /* * Note: QPainter has its origin at the top left. @@ -1389,17 +1431,21 @@ WuQtUtilities::createPixmapWidgetPainterOriginCenter100x100(const QWidget* widge * Widget used for coloring. * @param pixmap * The Pixmap must be square (width == height). + * @param pixmapOptions + * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainterOriginCenter(const QWidget* widget, - QPixmap& pixmap) + QPixmap& pixmap, + const uint32_t pixmapOptions) { CaretAssert(pixmap.width() == pixmap.height()); - QSharedPointer painter = createPixmapWidgetPainter(widget, - pixmap); + QSharedPointer painter = createPixmapWidgetPainterPrivate(widget, + pixmap, + pixmapOptions); /* * Note: QPainter has its origin at the top left. @@ -1427,15 +1473,19 @@ WuQtUtilities::createPixmapWidgetPainterOriginCenter(const QWidget* widget, * Widget used for coloring. * @param pixmap * The Pixmap. + * @param pixmapOptions + * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(const QWidget* widget, - QPixmap& pixmap) + QPixmap& pixmap, + const uint32_t pixmapOptions) { QSharedPointer painter = createPixmapWidgetPainter(widget, - pixmap); + pixmap, + pixmapOptions); /* * Note: QPainter has its origin at the top left. @@ -1464,12 +1514,43 @@ WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(const QWidget* widget, * Widget used for coloring. * @param pixmap * The Pixmap. + * @param pixmapOptions + * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, - QPixmap& pixmap) + QPixmap& pixmap, + const uint32_t pixmapOptions) +{ + return createPixmapWidgetPainterPrivate(widget, + pixmap, + pixmapOptions); +} + +/** + * Create a painter for the given pixmap that will be placed + * into the given widget. The pixmap's background is painted + * with the widget's background color, the painter's pen is set + * to the widget's foreground color, and then the painter is + * returned. + * + * Origin of painter will be in the TOP LEFT corner. + * + * @param widget + * Widget used for coloring. + * @param pixmap + * The Pixmap. + * @param pixmapOptions + * Options for creation of the pixmap. + * @return + * Shared pointer containing QPainter for drawing to the pixmap. + */ +QSharedPointer +WuQtUtilities::createPixmapWidgetPainterPrivate(const QWidget* widget, + QPixmap& pixmap, + const uint32_t pixmapOptions) { CaretAssert(widget); CaretAssert(pixmap.width() > 0); @@ -1486,6 +1567,23 @@ WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, const QBrush foregroundBrush = palette.brush(foregroundRole); const QColor foregroundColor = foregroundBrush.color(); + const bool transparentBackgroundFlag = (pixmapOptions + & static_cast(PixMapCreationOptions::TransparentBackground)); + if (transparentBackgroundFlag) { + /* + * It is not possible to create a pixmap with alpha using Qt. + * So, create a QImage filled with alpha = 0 and then + * let the pixmap copy from the QImage. + */ + QImage image(pixmap.width(), + pixmap.height(), + QImage::Format_RGBA8888_Premultiplied); + image.fill(QColor(0, 0, 0, 0)); + const bool succssFlag = pixmap.convertFromImage(image); + if ( ! succssFlag) { + CaretLogSevere("Failed to convert image to pixmap"); + } + } /* * Create a painter and fill the pixmap with @@ -1493,9 +1591,14 @@ WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, */ QSharedPointer painter(new QPainter(&pixmap)); painter->setRenderHint(QPainter::Antialiasing, - true); - painter->setBackgroundMode(Qt::OpaqueMode); - painter->fillRect(pixmap.rect(), backgroundColor); + true); + if (transparentBackgroundFlag) { + painter->setBackgroundMode(Qt::TransparentMode); + } + else { + painter->setBackgroundMode(Qt::OpaqueMode); + painter->fillRect(pixmap.rect(), backgroundColor); + } painter->setPen(foregroundColor); diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index 73a53a6ff2339f3a760ee04c88433c0a933e9c97..13cdeb7a900260b926d2dc0c7eab5ca0108496d0 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -22,6 +22,7 @@ */ /*LICENSE_END*/ +#include #include #include @@ -52,6 +53,24 @@ namespace caret { class WuQtUtilities { public: + /* + * Options for creating pixmaps + */ + enum PixMapCreationOptions { + /* + * Create pixmap with transparent background. + * Useful for pixmaps used in toolbar toggle buttons so that selection is shaded + * in the entire button not just around the pixmap + */ + TransparentBackground = 1 + }; + + static QToolButton* createToolButtonWithIcon(const QString& text, + const QString& iconFileName, + const QString& toolTip, + QObject* receiver, + const char* method); + static QAction* createAction(const QString& text, const QString& toolAndStatusTipText, const QKeySequence& shortcut, @@ -91,16 +110,20 @@ namespace caret { const bool outlineFlag); static QSharedPointer createPixmapWidgetPainter(const QWidget* widget, - QPixmap& pixmap); + QPixmap& pixmap, + const uint32_t pixmapOptions = 0); static QSharedPointer createPixmapWidgetPainterOriginBottomLeft(const QWidget* widget, - QPixmap& pixmap); + QPixmap& pixmap, + const uint32_t pixmapOptions = 0); static QSharedPointer createPixmapWidgetPainterOriginCenter(const QWidget* widget, - QPixmap& pixmap); + QPixmap& pixmap, + const uint32_t pixmapOptions = 0); static QSharedPointer createPixmapWidgetPainterOriginCenter100x100(const QWidget* widget, - QPixmap& pixmap); + QPixmap& pixmap, + const uint32_t pixmapOptions = 0); static void moveWindowToOffset(QWidget* parentWidget, QWidget* window, @@ -206,6 +229,10 @@ namespace caret { static void setToolButtonStyleForQt5Mac(QToolButton* toolButton); private: + static QSharedPointer createPixmapWidgetPainterPrivate(const QWidget* widget, + QPixmap& pixmap, + const uint32_t pixmapOptions = 0); + WuQtUtilities(); ~WuQtUtilities(); WuQtUtilities(const WuQtUtilities&); diff --git a/src/Nifti/NiftiIO.h b/src/Nifti/NiftiIO.h index 732a8b77bfd160d0ca7904c69a86e04bcb31b691..63ba3faa68175b47e22b053f4cfdc96a1bd0b2a9 100644 --- a/src/Nifti/NiftiIO.h +++ b/src/Nifti/NiftiIO.h @@ -58,6 +58,7 @@ namespace caret void overrideDimensions(const std::vector& newDims) { m_dims = newDims; }//HACK: deal with reading/writing CIFTI-1's broken headers void close(); const NiftiHeader& getHeader() const { return m_header; } + void dropExtensions() { m_header.m_extensions.clear(); } const std::vector& getDimensions() const { return m_dims; } int getNumComponents() const; //to read/write 1 frame of a standard volume file, call with fullDims = 3, indexSelect containing indexes for any of dims 4-7 that exist @@ -289,6 +290,7 @@ namespace caret TO NiftiIO::clamp(const FROM& in) { typedef std::numeric_limits mylimits; + if (mylimits::has_infinity && std::isinf(in)) return (TO)in;//in case we use this on float types at some point if (mylimits::max() < in) return mylimits::max(); if (mylimits::lowest() > in) return mylimits::lowest(); /*if (mylimits::is_integer)//here is a c++03 solution to missing ::lowest diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt index c3f1648ada535acfd237734690a8afcad1b38f9d..bf68207bb2263d35732312e7231ef879ed40fdfd 100644 --- a/src/Operations/CMakeLists.txt +++ b/src/Operations/CMakeLists.txt @@ -55,6 +55,7 @@ OperationEstimateFiberBinghams.h OperationException.h OperationFileConvert.h OperationFileInformation.h +OperationFociCreate.h OperationFociGetProjectionVertex.h OperationFociListCoords.h OperationGiftiConvert.h @@ -145,6 +146,7 @@ OperationException.cxx OperationEstimateFiberBinghams.cxx OperationFileConvert.cxx OperationFileInformation.cxx +OperationFociCreate.cxx OperationFociGetProjectionVertex.cxx OperationFociListCoords.cxx OperationGiftiConvert.cxx diff --git a/src/Operations/OperationCiftiConvert.cxx b/src/Operations/OperationCiftiConvert.cxx index 1df9a95f756f34ce69215a6ed71d985b4a7d7c36..166daeb7f879b093ee8f0f6c6dfdb3d8687aef72 100644 --- a/src/Operations/OperationCiftiConvert.cxx +++ b/src/Operations/OperationCiftiConvert.cxx @@ -69,6 +69,7 @@ OperationParameters* OperationCiftiConvert::getParameters() OptionalParameter* fgresetTimeunitsOpt = fgresetTimeOpt->createOptionalParameter(3, "-unit", "use a unit other than time"); fgresetTimeunitsOpt->addStringParameter(1, "unit", "unit identifier (default SECOND)"); fromGiftiExt->createOptionalParameter(4, "-reset-scalars", "reset mapping along rows to scalars, taking length from the gifti file"); + fromGiftiExt->createOptionalParameter(6, "-column-reset-scalars", "reset mapping along columns to scalar (useful for changing number of series in a sdseries file)"); OptionalParameter* fromGiftiReplace = fromGiftiExt->createOptionalParameter(5, "-replace-binary", "replace data with a binary file"); fromGiftiReplace->addStringParameter(1, "binary-in", "the binary file that contains replacement data"); fromGiftiReplace->createOptionalParameter(2, "-flip-endian", "byteswap the binary file"); @@ -129,6 +130,38 @@ OperationParameters* OperationCiftiConvert::getParameters() return ret; } +namespace +{ + + bool haveWarned = false; + + float toFloat(const AString& input) + { + bool ok = false; + double converted = input.toDouble(&ok); + if (!ok) throw OperationException("failed to convert text to number: '" + input + "'"); + float ret = float(converted);//this will turn some non-inf values into +/- inf, so let's fix that + if (!std::isinf(converted) && (abs(converted) > numeric_limits::max() || abs(converted) < numeric_limits::denorm_min())) + { + if (!haveWarned) + { + CaretLogWarning("input number(s) changed to fit range of float32, first instance: '" + input + "'"); + haveWarned = true; + } + if (std::isinf(ret)) + { + if (ret > 0.0f) + { + ret = numeric_limits::max(); + } else { + ret = -numeric_limits::max(); + } + } + } + return ret; + } +} + void OperationCiftiConvert::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); @@ -194,7 +227,7 @@ void OperationCiftiConvert::useParameters(OperationParameters* myParams, Progres int64_t numRows = dataArrayRef->getNumberOfRows(); OptionalParameter* fgresetTimeOpt = fromGiftiExt->getOptionalParameter(3); if (fgresetTimeOpt->m_present) - { + {//-reset-timepoints CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::SECOND; OptionalParameter* fgresetTimeunitsOpt = fgresetTimeOpt->getOptionalParameter(3); if (fgresetTimeunitsOpt->m_present) @@ -215,12 +248,18 @@ void OperationCiftiConvert::useParameters(OperationParameters* myParams, Progres myXML.getSeriesMap(CiftiXML::ALONG_COLUMN).setLength(numRows); } if (fromGiftiExt->getOptionalParameter(4)->m_present) - { + {//-reset-scalars if (fgresetTimeOpt->m_present) throw OperationException("only one of -reset-timepoints and -reset-scalars may be specified"); CiftiScalarsMap newMap; newMap.setLength(numCols); myXML.setMap(CiftiXML::ALONG_ROW, newMap); } + if (fromGiftiExt->getOptionalParameter(6)->m_present) + {//-column-reset-scalars + CiftiScalarsMap newMap; + newMap.setLength(numRows); + myXML.setMap(CiftiXML::ALONG_COLUMN, newMap); + } if (myXML.getDimensionLength(CiftiXML::ALONG_ROW) != numCols || myXML.getDimensionLength(CiftiXML::ALONG_COLUMN) != numRows) { throw OperationException("dimensions of input gifti array (" + AString::number(numRows) + " rows, " + AString::number(numCols) + " columns)" + @@ -376,7 +415,7 @@ void OperationCiftiConvert::useParameters(OperationParameters* myParams, Progres if (outXML.getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); OptionalParameter* fnresetTimeOpt = fromNifti->getOptionalParameter(4); if (fnresetTimeOpt->m_present) - { + {//-reset-timepoints CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::SECOND; OptionalParameter* fnresetTimeunitsOpt = fnresetTimeOpt->getOptionalParameter(3); if (fnresetTimeunitsOpt->m_present) @@ -388,7 +427,7 @@ void OperationCiftiConvert::useParameters(OperationParameters* myParams, Progres outXML.setMap(CiftiXML::ALONG_ROW, CiftiSeriesMap(myDims[3], fnresetTimeOpt->getDouble(2), fnresetTimeOpt->getDouble(1), myUnit)); } if (fromNifti->getOptionalParameter(5)->m_present) - { + {//-reset-scalars if (fnresetTimeOpt->m_present) throw OperationException("only one of -reset-timepoints and -reset-scalars may be specified"); CiftiScalarsMap newMap; newMap.setLength(myDims[3]); @@ -498,11 +537,9 @@ void OperationCiftiConvert::useParameters(OperationParameters* myParams, Progres } ciftiOut->setCiftiXML(outXML); vector temprow(textRowLength); - bool ok = false; for (int i = 0; i < textRowLength; ++i) { - temprow[i] = entries[i].toFloat(&ok); - if (!ok) throw OperationException("failed to convert text to number: '" + entries[i] + "'"); + temprow[i] = toFloat(entries[i]); } ciftiOut->setRow(temprow.data(), 0); for (int64_t j = 1; j < numRows; ++j) @@ -517,8 +554,7 @@ void OperationCiftiConvert::useParameters(OperationParameters* myParams, Progres if (entries.size() != textRowLength) throw OperationException("text file has inconsistent line length"); for (int i = 0; i < textRowLength; ++i) { - temprow[i] = entries[i].toFloat(&ok); - if (!ok) throw OperationException("failed to convert text to number: '" + entries[i] + "'"); + temprow[i] = toFloat(entries[i]); } ciftiOut->setRow(temprow.data(), j); } diff --git a/src/Operations/OperationCiftiLabelImport.cxx b/src/Operations/OperationCiftiLabelImport.cxx index 44c013d4a20197af7e8a4fa8adf6cb47c48de1b4..697c72b9d8c355d0ba6605cdecb1861c92834220 100644 --- a/src/Operations/OperationCiftiLabelImport.cxx +++ b/src/Operations/OperationCiftiLabelImport.cxx @@ -67,13 +67,12 @@ OperationParameters* OperationCiftiLabelImport::getParameters() ret->setHelpText( AString("Creates a cifti label file from a cifti file with label-like values. ") + - "You may specify the empty string ('' will work on linux/mac) for , which will be treated as if it is an empty file. " + - "It is assumed that a value of 0 in the input file means \"unlabeled\", unless -unlabeled-value is specified. " + - "Do not specify the \"unlabeled\" label in the text file.\n\n" + + "You may specify the empty string (use \"\") for , which will be treated as if it is an empty file. " + "The label list file must have the following format (2 lines per label):\n\n" + "\n \n...\n\n" + "Label names are specified on a separate line from their value and color, in order to let label names contain spaces. " + "Whitespace is trimmed from both ends of the label name, but is kept if it is in the middle of a label. " + + "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + "The value of specifies what value in the imported file should be used as this label. " + "The values of , , and must be integers from 0 to 255, and will specify the color the label is drawn as " + "(alpha of 255 means fully opaque, which is probably what you want).\n\n" + diff --git a/src/Operations/OperationCiftiMerge.cxx b/src/Operations/OperationCiftiMerge.cxx index 62249a39e04d83e52482da41cfe3ca809fbcde8d..ad85df072861e8f4172f14666221b27481480a8c 100644 --- a/src/Operations/OperationCiftiMerge.cxx +++ b/src/Operations/OperationCiftiMerge.cxx @@ -47,7 +47,7 @@ OperationParameters* OperationCiftiMerge::getParameters() ret->addCiftiOutputParameter(1, "cifti-out", "output cifti file"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(2, "-cifti", "specify an input cifti file"); - ciftiOpt->addCiftiParameter(1, "cifti-in", "a cifti file to use columns from"); + ciftiOpt->addStringParameter(1, "cifti-in", "a cifti file to use columns from"); ParameterComponent* columnOpt = ciftiOpt->createRepeatableParameter(2, "-column", "select a single column to use"); columnOpt->addStringParameter(1, "column", "the column number (starting from 1) or name"); OptionalParameter* upToOpt = columnOpt->createOptionalParameter(2, "-up-to", "use an inclusive range of columns"); @@ -69,10 +69,11 @@ void OperationCiftiMerge::useParameters(OperationParameters* myParams, ProgressO LevelProgress myProgress(myProgObj); CiftiFile* ciftiOut = myParams->getOutputCifti(1); const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); - vector ciftiList; int numInputs = (int)myInputs.size(); if (numInputs == 0) throw OperationException("no inputs specified"); - const CiftiFile* firstCifti = myInputs[0]->getCifti(1); + vector ciftiList(numInputs); + ciftiList[0].openFile(myInputs[0]->getString(1)); + const CiftiFile* firstCifti = &(ciftiList[0]); const CiftiXML& baseXML = firstCifti->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2) throw OperationException("only 2D cifti are supported"); const CiftiMappingType& baseColMapping = *(baseXML.getMap(CiftiXML::ALONG_COLUMN)), &baseRowMapping = *(baseXML.getMap(CiftiXML::ALONG_ROW)); @@ -88,7 +89,11 @@ void OperationCiftiMerge::useParameters(OperationParameters* myParams, ProgressO int64_t numOutColumns = 0;//output row length for (int i = 0; i < numInputs; ++i) { - const CiftiFile* ciftiIn = myInputs[i]->getCifti(1); + if (i != 0) + { + ciftiList[i].openFile(myInputs[i]->getString(1)); + } + const CiftiFile* ciftiIn = &(ciftiList[i]); vector thisDims = ciftiIn->getDimensions(); const CiftiXML& thisXML = ciftiIn->getCiftiXML(); if (thisXML.getNumberOfDimensions() != 2) throw OperationException("only 2D cifti are supported"); @@ -116,6 +121,10 @@ void OperationCiftiMerge::useParameters(OperationParameters* myParams, ProgressO } else { numOutColumns += thisDims[0]; } + if (i != 0)//don't mess with the first file, we use its mapping for the output file + { + ciftiList[i].forgetMapping(CiftiXML::ALONG_COLUMN);//HACK: release the memory being used to store the dense or parcel mapping, to deal with thousands of inputs + } } CiftiScalarsMap outScalarMap;//we only use one of these CiftiLabelsMap outLabelMap; @@ -143,7 +152,7 @@ void OperationCiftiMerge::useParameters(OperationParameters* myParams, ProgressO int64_t curCol = 0, scratchRowLength = 0; for (int i = 0; i < numInputs; ++i) { - const CiftiFile* ciftiIn = myInputs[i]->getCifti(1); + const CiftiFile* ciftiIn = &(ciftiList[i]); vector thisDims = ciftiIn->getDimensions(); const CiftiXML& thisXML = ciftiIn->getCiftiXML(); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); @@ -262,7 +271,7 @@ void OperationCiftiMerge::useParameters(OperationParameters* myParams, ProgressO curCol = 0; for (int i = 0; i < numInputs; ++i) { - const CiftiFile* ciftiIn = myInputs[i]->getCifti(1); + const CiftiFile* ciftiIn = &(ciftiList[i]); vector thisDims = ciftiIn->getDimensions(); const CiftiXML& thisXML = ciftiIn->getCiftiXML(); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); diff --git a/src/Operations/OperationCiftiResampleDconnMemory.cxx b/src/Operations/OperationCiftiResampleDconnMemory.cxx index 2cc2b2fb356790d74b656edca1b3797e7009997e..7272b075080b954cc96668193c82dc4deb94c077 100644 --- a/src/Operations/OperationCiftiResampleDconnMemory.cxx +++ b/src/Operations/OperationCiftiResampleDconnMemory.cxx @@ -61,17 +61,19 @@ OperationParameters* OperationCiftiResampleDconnMemory::getParameters() OptionalParameter* volDilateOpt = ret->createOptionalParameter(9, "-volume-predilate", "dilate the volume components before resampling"); volDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); volDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); - OptionalParameter* volDilateWeightedOpt = volDilateOpt->createOptionalParameter(3, "-weighted", "use weighted dilation"); + OptionalParameter* volDilateWeightedOpt = volDilateOpt->createOptionalParameter(3, "-weighted", "use weighted dilation (default)"); OptionalParameter* volDilateExpOpt = volDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); - volDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 2)"); + volDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 7)"); + volDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* surfDilateOpt = ret->createOptionalParameter(10, "-surface-postdilate", "dilate the surface components after resampling"); surfDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); surfDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); surfDilateOpt->createOptionalParameter(3, "-linear", "use linear dilation"); - OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->createOptionalParameter(4, "-weighted", "use weighted dilation"); + OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->createOptionalParameter(4, "-weighted", "use weighted dilation (default)"); OptionalParameter* surfDilateExpOpt = surfDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); - surfDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 2)"); + surfDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 6)"); + surfDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* affineOpt = ret->createOptionalParameter(11, "-affine", "use an affine transformation on the volume components"); affineOpt->addStringParameter(1, "affine-file", "the affine file to use"); @@ -122,6 +124,7 @@ OperationParameters* OperationCiftiResampleDconnMemory::getParameters() "If spheres are not specified for a surface structure which exists in the cifti files, its data is copied without resampling or dilation. " + "Dilation is done with the 'nearest' method, and is done on for surface data. " + "Volume components are padded before dilation so that dilation doesn't run into the edge of the component bounding box.\n\n" + + "To get the v1.3.2 and earlier behavior of weighted dilation, specify exponent of 2 for surface and volume, and -legacy-cutoff for both surface and volume.\n\n" + "The argument must be one of the following:\n\n" + "CUBIC\nENCLOSING_VOXEL\nTRILINEAR\n\n" + "The argument must be one of the following:\n\n"; @@ -186,8 +189,9 @@ void OperationCiftiResampleDconnMemory::useParameters(OperationParameters* myPar } AlgorithmVolumeDilate::Method volDilateMethod = AlgorithmVolumeDilate::WEIGHTED; float volDilateExponent = 2.0f; - AlgorithmMetricDilate::Method surfDilateMethod = AlgorithmMetricDilate::WEIGHTED;//label dilate doesn't support multiple methods - what to do there, share the enum between them? + AlgorithmMetricDilate::Method surfDilateMethod = AlgorithmMetricDilate::WEIGHTED;//label dilate doesn't support multiple methods float surfDilateExponent = 2.0f;//label dilate currently only supports nearest, so in order to accept a default in the algorithm, it currently ignores this on label data, no warning + bool surfLegacyCutoff = false, volLegacyCutoff = false; OptionalParameter* volDilateOpt = myParams->getOptionalParameter(9); if (volDilateOpt->m_present) { @@ -210,6 +214,7 @@ void OperationCiftiResampleDconnMemory::useParameters(OperationParameters* myPar { volDilateExponent = (float)volDilateExpOpt->getDouble(1); } + volLegacyCutoff = volDilateWeightedOpt->getOptionalParameter(2)->m_present; } } OptionalParameter* surfDilateOpt = myParams->getOptionalParameter(10); @@ -242,6 +247,7 @@ void OperationCiftiResampleDconnMemory::useParameters(OperationParameters* myPar { surfDilateExponent = (float)surfDilateExpOpt->getDouble(1); } + surfLegacyCutoff = surfDilateWeightedOpt->getOptionalParameter(2)->m_present; } } OptionalParameter* affineOpt = myParams->getOptionalParameter(11); @@ -404,22 +410,22 @@ void OperationCiftiResampleDconnMemory::useParameters(OperationParameters* myPar curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, - volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent); + volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); AlgorithmCiftiResample(myProgObj, &tempCifti, CiftiXML::ALONG_ROW, myTemplate, templateDir, mySurfMethod, myVolMethod, myCiftiOut, surfLargest, voldilatemm, surfdilatemm, myWarpfield.getWarpfield(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, - volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent); + volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } else {//rely on AffineFile() being the identity transform for if neither option is specified AlgorithmCiftiResample(myProgObj, myCiftiIn, CiftiXML::ALONG_COLUMN, myTemplate, templateDir, mySurfMethod, myVolMethod, &tempCifti, surfLargest, voldilatemm, surfdilatemm, myAffine.getMatrix(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, - volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent); + volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); AlgorithmCiftiResample(myProgObj, &tempCifti, CiftiXML::ALONG_ROW, myTemplate, templateDir, mySurfMethod, myVolMethod, myCiftiOut, surfLargest, voldilatemm, surfdilatemm, myAffine.getMatrix(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, - volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent); + volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } } diff --git a/src/Operations/OperationFociCreate.cxx b/src/Operations/OperationFociCreate.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bede2dc620b6bf68a17f9c227a062dff89d5b3be --- /dev/null +++ b/src/Operations/OperationFociCreate.cxx @@ -0,0 +1,181 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "OperationFociCreate.h" +#include "OperationException.h" + +#include "CaretLogger.h" +#include "FileInformation.h" +#include "FociFile.h" +#include "Focus.h" +#include "GiftiLabel.h" +#include "GiftiLabelTable.h" +#include "SurfaceProjector.h" + +#include +#include +#include +#include +#include + +using namespace caret; +using namespace std; + +AString OperationFociCreate::getCommandSwitch() +{ + return "-foci-create"; +} + +AString OperationFociCreate::getShortDescription() +{ + return "CREATE A FOCI FILE"; +} + +OperationParameters* OperationFociCreate::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + ret->addFociOutputParameter(1, "output", "the output foci file"); + + ParameterComponent* fociOpt = ret->createRepeatableParameter(2, "-class", "specify class input data"); + fociOpt->addStringParameter(1, "class-name", "name of class"); + fociOpt->addStringParameter(2, "foci-list-file", "text file containing foci names, coordinates, and colors"); + fociOpt->addSurfaceParameter(3, "surface", "surface file for projection of foci list file"); + + ret->setHelpText( + AString("Creates a foci file from names, coordinates, and RGB values in a text file. ") + + "The text file must have the following format (2 lines per focus):\n\n" + + "\n" + " \n...\n\n" + + "Foci names are specified on a separate line from their coordinates and color, in order to let foci names contain spaces. " + + "Whitespace is trimmed from both ends of the foci name, but is kept if it is in the middle of a name. " + + "The values of , , and must be integers from 0 to 255, and will specify the color the foci is drawn as.\n\n" + + "Foci are grouped into classes and the name for the class is specified using the parameter.\n\n" + + "All foci within one text file must be associated with the structure contained in the " + "parameter and are projected to that surface." + ); + return ret; +} + +void OperationFociCreate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) +{ + LevelProgress myProgress(myProgObj); + + FociFile* outputFociFile = myParams->getOutputFoci(1); + + const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); + int numInputs = (int)myInputs.size(); + if (numInputs == 0) { + throw OperationException("no inputs specified"); + } + + for (int32_t i = 0; i < numInputs; i++) { + const AString className = myInputs[i]->getString(1).trimmed(); + if (className.isEmpty()) { + throw OperationException("Class name may not be empty"); + } + const AString listFileName = myInputs[i]->getString(2).trimmed(); + if (listFileName.isEmpty()) { + throw OperationException("Foci list (text) file name may not be empty"); + } + const SurfaceFile* surfaceFile = myInputs[i]->getSurface(3); + + SurfaceProjector projector(surfaceFile); + + FileInformation textFileInfo(listFileName); + if (!textFileInfo.exists()) + { + throw OperationException("foci list file doesn't exist: " + + listFileName); + } + fstream fociListFile(listFileName.toLocal8Bit().constData(), fstream::in); + if (!fociListFile.good()) + { + throw OperationException("error reading foci list file:" + + listFileName); + } + + string focusName; + float x, y, z; + int32_t red, green, blue; + int fociCount = 0; + while (fociListFile.good()) + { + ++fociCount;//just for error messages, so start at 1 + getline(fociListFile, focusName); + if (fociListFile.eof() && focusName == "") break;//if end of file trying to read an int, and label name is empty, its really just end of file + fociListFile >> red; + fociListFile >> green; + fociListFile >> blue; + fociListFile >> x; + fociListFile >> y; + + if (!(fociListFile >> z))//yes, that is seriously the correct way to check if input was successfully extracted...so much fail + { + throw OperationException("foci list file is malformed for entry #" + AString::number(fociCount) + ": " + AString(focusName.c_str())); + } + if (red < 0 || red > 255) + { + throw OperationException("bad value for red for entry #" + AString::number(fociCount) + ", " + AString(focusName.c_str()) + ": " + AString::number(red)); + } + if (green < 0 || green > 255) + { + throw OperationException("bad value for green for entry #" + AString::number(fociCount) + ", " + AString(focusName.c_str()) + ": " + AString::number(green)); + } + if (blue < 0 || blue > 255) + { + throw OperationException("bad value for blue for entry #" + AString::number(fociCount) + ", " + AString(focusName.c_str()) + ": " + AString::number(blue)); + } + while (isspace(fociListFile.peek())) + { + fociListFile.ignore();//drop the newline, possible carriage return or other whitespace so that getline doesn't get nothing, and cause int extraction to fail + } + + Focus* focus = new Focus(); + focus->setClassName(className); + focus->setName(AString(focusName.c_str()).trimmed()); + + const float xyz[3] = { x, y, z }; + CaretAssert(focus->getNumberOfProjections() > 0); + focus->getProjection(0)->setStereotaxicXYZ(xyz); + + const int32_t dummyFocusIndex(-1); + projector.projectFocus(dummyFocusIndex, + focus); + + const GiftiLabel* colorLabel = outputFociFile->getNameColorTable()->getLabel(focus->getName()); + if (colorLabel != NULL) { + if ((colorLabel->getRed() != red) + || (colorLabel->getGreen() != green) + || (colorLabel->getBlue() != blue)) { + CaretLogWarning("More than one color for focus named \"" + + focus->getName() + + "\". (All foci with same name use same color)"); + } + } + outputFociFile->getNameColorTable()->addLabel(focus->getName(), + red, green, blue); + outputFociFile->addFocus(focus); + } + } + + if (outputFociFile->getNumberOfFoci() <= 0) { + throw OperationException("No foci were successfully read/projected."); + } +} diff --git a/src/Operations/OperationFociCreate.h b/src/Operations/OperationFociCreate.h new file mode 100644 index 0000000000000000000000000000000000000000..c12a09290a18d71818fdad874f9eddc5602a6924 --- /dev/null +++ b/src/Operations/OperationFociCreate.h @@ -0,0 +1,41 @@ +#ifndef __OPERATION_FOCI_CREATE_H__ +#define __OPERATION_FOCI_CREATE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AbstractOperation.h" + +namespace caret { + + class OperationFociCreate : public AbstractOperation + { + public: + static OperationParameters* getParameters(); + static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); + static AString getCommandSwitch(); + static AString getShortDescription(); + }; + + typedef TemplateAutoOperation AutoOperationFociCreate; + +} + +#endif //__OPERATION_FOCI_CREATE_H__ diff --git a/src/Operations/OperationMetricLabelImport.cxx b/src/Operations/OperationMetricLabelImport.cxx index ffbfc27f4101b6c24b5be8527b6770fbdf2a829d..32209691036f88f070cd991d752dfb6aa801e9e1 100644 --- a/src/Operations/OperationMetricLabelImport.cxx +++ b/src/Operations/OperationMetricLabelImport.cxx @@ -68,17 +68,18 @@ OperationParameters* OperationMetricLabelImport::getParameters() ret->createOptionalParameter(7, "-drop-unused-labels", "remove any unused label values from the label table"); ret->setHelpText( - AString("Creates a new gifti label file from a metric file with label-like values. ") + - "You may specify the empty string ('' will work on linux/mac) for , which will be treated as if it is an empty file. " + - "The label list file must have lines of the following format:\n\n" + - "\n \n\n" + - "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + - "Label names must be on a separate line, but may contain spaces or other unusual characters (but not newline). " + + AString("Creates a gifti label file from a metric file with label-like values. ") + + "You may specify the empty string (use \"\") for , which will be treated as if it is an empty file. " + + "The label list file must have the following format (2 lines per label):\n\n" + + "\n \n...\n\n" + + "Label names are specified on a separate line from their value and color, in order to let label names contain spaces. " + "Whitespace is trimmed from both ends of the label name, but is kept if it is in the middle of a label. " + - "The values of red, green, blue and alpha must be integers from 0 to 255, and will specify the color the label is drawn as " + - "(alpha of 255 means opaque, which is probably what you want). " + - "By default, it will set new label names with names of LABEL_# for any values encountered that are not mentioned in the " + - "list file, specify -discard-others to instead set these voxels to the \"unlabeled\" key." + "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + + "The value of specifies what value in the imported file should be used as this label. " + + "The values of , , and must be integers from 0 to 255, and will specify the color the label is drawn as " + + "(alpha of 255 means fully opaque, which is probably what you want).\n\n" + + "By default, it will create new label names with names like LABEL_5 for any values encountered that are not mentioned in the " + + "list file, specify -discard-others to instead set these values to the \"unlabeled\" key." ); return ret; } diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 0c1977d885231669ff0d7ecdc314134146903fbe..19b9e499097276bc4d422d19e3b61c9b832d4255 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -107,9 +107,9 @@ OperationShowScene::getParameters() ret->addStringParameter(3, "image-file-name", "output image file name"); - ret->addIntegerParameter(4, "image-width", "width of output image(s)"); + ret->addIntegerParameter(4, "image-width", "width of output image(s), in pixels"); - ret->addIntegerParameter(5, "image-height", "height of output image(s)"); + ret->addIntegerParameter(5, "image-height", "height of output image(s), in pixels"); const QString windowSizeSwitch("-use-window-size"); ret->createOptionalParameter(6, windowSizeSwitch, "Override image size with window size"); @@ -465,9 +465,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, TileTabsConfiguration* tileTabsConfiguration = bwc->getSelectedTileTabsConfiguration(); CaretAssert(tileTabsConfiguration); - if ((tileTabsConfiguration->getMaximumNumberOfRows() > 0) - && (tileTabsConfiguration->getMaximumNumberOfColumns() > 0)) { - + const std::vector tabIndices = bwc->getSceneTabIndices(); if ( ! tabIndices.empty()) { std::vector allTabContent; @@ -508,11 +506,13 @@ OperationShowScene::useParameters(OperationParameters* myParams, bwc, gapsAndMargins, windowViewport, + windowIndex, tabIndexToHighlight); std::vector constViewports(viewports.begin(), viewports.end()); brainOpenGL->drawModels(windowIndex, + UserInputModeEnum::VIEW, brain, mesaContext, constViewports); @@ -534,10 +534,6 @@ OperationShowScene::useParameters(OperationParameters* myParams, } viewports.clear(); } - } - else { - throw OperationException("Tile tabs configuration is corrupted."); - } } else { CaretPointer brainOpenGL(createBrainOpenGL()); @@ -566,6 +562,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, viewportContents.push_back(content); brainOpenGL->drawModels(windowIndex, + UserInputModeEnum::VIEW, brain, mesaContext, viewportContents); @@ -749,6 +746,7 @@ OperationShowScene::createBrainOpenGL() */ BrainOpenGLTextRenderInterface* textRenderer = NULL; if (textRenderer == NULL) { +#ifdef HAVE_FREETYPE textRenderer = new FtglFontTextRenderer(); if (! textRenderer->isValid()) { delete textRenderer; @@ -756,6 +754,10 @@ OperationShowScene::createBrainOpenGL() CaretLogWarning("Unable to create FTGL Font Renderer.\n" "No text will be available in graphics window."); } +#else + CaretLogWarning("Unable to create FTGL Font Renderer due to FreeType not found during configuration.\n" + "No text will be available in graphics window."); +#endif } if (textRenderer == NULL) { textRenderer = new DummyFontTextRenderer(); diff --git a/src/Operations/OperationVolumeCreate.cxx b/src/Operations/OperationVolumeCreate.cxx index 9e70399502ca80b830ac0b01bb7594fdb65867ba..063316139fbe4a37d8b77f59dbf1500fe1cb3fa8 100644 --- a/src/Operations/OperationVolumeCreate.cxx +++ b/src/Operations/OperationVolumeCreate.cxx @@ -53,9 +53,9 @@ OperationParameters* OperationVolumeCreate::getParameters() plumbOpt->addDoubleParameter(2, "x-spacing", "change in x-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(3, "y-spacing", "change in y-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(4, "z-spacing", "change in z-coordinate from incrementing the relevant index"); - plumbOpt->addDoubleParameter(5, "x-offset", "the x-coordinate of the first voxel"); - plumbOpt->addDoubleParameter(6, "y-offset", "the y-coordinate of the first voxel"); - plumbOpt->addDoubleParameter(7, "z-offset", "the z-coordinate of the first voxel"); + plumbOpt->addDoubleParameter(5, "x-offset", "the x-coordinate of the center of the first voxel"); + plumbOpt->addDoubleParameter(6, "y-offset", "the y-coordinate of the center of the first voxel"); + plumbOpt->addDoubleParameter(7, "z-offset", "the z-coordinate of the center of the first voxel"); OptionalParameter* sformOpt = ret->createOptionalParameter(6, "-sform", "set via a nifti sform"); char axisNames[] = "xyz", indexNames[] = "ijk"; diff --git a/src/Operations/OperationVolumeLabelImport.cxx b/src/Operations/OperationVolumeLabelImport.cxx index 8a8e21a4e7a3bb738d2b4705a3fb9fce5e837fd5..2bf1f582d12f22ab513e76a95d74233a798fe1ed 100644 --- a/src/Operations/OperationVolumeLabelImport.cxx +++ b/src/Operations/OperationVolumeLabelImport.cxx @@ -67,18 +67,19 @@ OperationParameters* OperationVolumeLabelImport::getParameters() ret->createOptionalParameter(7, "-drop-unused-labels", "remove any unused label values from the label table"); ret->setHelpText( - AString("Creates a new label volume from an integer-valued volume file. ") + + AString("Creates a label volume from an integer-valued volume file. ") + "The label name and color information is stored in the volume header in a nifti extension, with a similar format as in caret5, see -volume-help. " + - "You may specify the empty string ('' will work on linux/mac) for , which will be treated as if it is an empty file. " + - "The label list file must have pairs of lines of the following format:\n\n" + - "\n \n\n" + - "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + - "Label names must be on a separate line, but may contain spaces or other unusual characters (but not newline). " + + "You may specify the empty string (use \"\") for , which will be treated as if it is an empty file. " + + "The label list file must have the following format (2 lines per label):\n\n" + + "\n \n...\n\n" + + "Label names are specified on a separate line from their value and color, in order to let label names contain spaces. " + "Whitespace is trimmed from both ends of the label name, but is kept if it is in the middle of a label. " + - "The values of red, green, blue and alpha must be integers from 0 to 255, and will specify the color the label is drawn as " + - "(alpha of 255 means opaque, which is probably what you want). " + - "By default, it will set new label names with names of LABEL_# for any values encountered that are not mentioned in the " + - "list file, specify -discard-others to instead set these voxels to the \"unlabeled\" key." + "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + + "The value of specifies what value in the imported file should be used as this label. " + + "The values of , , and must be integers from 0 to 255, and will specify the color the label is drawn as " + + "(alpha of 255 means fully opaque, which is probably what you want).\n\n" + + "By default, it will create new label names with names like LABEL_5 for any values encountered that are not mentioned in the " + + "list file, specify -discard-others to instead set these values to the \"unlabeled\" key." ); return ret; } diff --git a/src/Operations/OperationVolumeMerge.cxx b/src/Operations/OperationVolumeMerge.cxx index e5657749595fc7e0c2d1ea22aee06a6a991843f8..cda6f3e70dce3595f098c4bf26ee3be4ed01b5fa 100644 --- a/src/Operations/OperationVolumeMerge.cxx +++ b/src/Operations/OperationVolumeMerge.cxx @@ -114,7 +114,7 @@ void OperationVolumeMerge::useParameters(OperationParameters* myParams, Progress vector outDims = firstVol->getOriginalDimensions(); outDims.resize(4); outDims[3] = subvolCount; - volumeOut->reinitialize(outDims, firstVol->getSform(), firstDims[4], firstVol->getType()); + volumeOut->reinitialize(outDims, firstVol->getSform(), firstDims[4], firstVol->getType(), firstVol->m_header); int64_t curOutVol = 0; for (int i = 0; i < numInputs; ++i) { diff --git a/src/Operations/OperationZipSceneFile.cxx b/src/Operations/OperationZipSceneFile.cxx index f0d1891d743c878df179899eed19809f37817de0..af06d3e3a5aba48c691edfc0cb2b635d31ea9b86 100644 --- a/src/Operations/OperationZipSceneFile.cxx +++ b/src/Operations/OperationZipSceneFile.cxx @@ -64,6 +64,8 @@ OperationParameters* OperationZipSceneFile::getParameters() OptionalParameter* baseOpt = ret->createOptionalParameter(4, "-base-dir", "specify a directory that all data files are somewhere within, this will become the root of the zipfile's directory structure"); baseOpt->addStringParameter(1, "directory", "the directory"); + + ret->createOptionalParameter(5, "-skip-missing", "any missing files will generate only warnings, and the zip file will be created anyway"); ret->setHelpText("If zip-file already exists, it will be overwritten. " "If -base-dir is not specified, the base directory will be automatically set to the lowest level directory containing all files. " @@ -82,21 +84,24 @@ void OperationZipSceneFile::useParameters(OperationParameters* myParams, Progres { myBaseDir = QDir::cleanPath(QDir(baseOpt->getString(1)).absolutePath()); } + bool skipMissing = myParams->getOptionalParameter(5)->m_present; - OperationZipSceneFile::createZipFile(sceneFileName, + OperationZipSceneFile::createZipFile(myProgObj, + sceneFileName, outputSubDirectory, zipFileName, myBaseDir, PROGRESS_COMMAND_LINE, - myProgObj); + skipMissing); } -void OperationZipSceneFile::createZipFile(const AString& sceneFileName, +void OperationZipSceneFile::createZipFile(ProgressObject* myProgObj, + const AString& sceneFileName, const AString& outputSubDirectory, const AString& zipFileName, const AString& baseDirectory, const ProgressMode progressMode, - ProgressObject* myProgObj) + const bool skipMissing) { LevelProgress myProgress(myProgObj); FileInformation sceneFileInfo(sceneFileName); @@ -215,6 +220,7 @@ void OperationZipSceneFile::createZipFile(const AString& sceneFileName, EventManager::get()->sendEvent(progressEvent.getPointer()); QFile zipFileObject(zipFileName); + zipFileObject.remove();//delete it if it exists, to play better with file symlinks QuaZip zipFile(&zipFileObject); if (!zipFile.open(QuaZip::mdCreate)) { @@ -224,13 +230,20 @@ void OperationZipSceneFile::createZipFile(const AString& sceneFileName, } int32_t fileIndex = 1; static const char *myUnits[9] = {" B ", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB"}; + int goodFileCount = 0; for (set::iterator iter = allFiles.begin(); iter != allFiles.end(); ++iter, ++fileIndex) { AString dataFileName = *iter; AString unzippedDataFileName = outputSubDirectory + "/" + dataFileName.mid(myBaseDir.size());//we know the string matches to the length of myBaseDir, and is cleaned, so we can just chop the right number of characters off QFile dataFileIn(dataFileName); if (!dataFileIn.open(QFile::ReadOnly)) { - throw OperationException("Unable to open \"" + dataFileName + "\" for reading: " + dataFileIn.errorString()); + if (skipMissing) + { + CaretLogWarning("Skipping unreadable file '" + dataFileName + "'"); + continue; + } else { + throw OperationException("Unable to open \"" + dataFileName + "\" for reading: " + dataFileIn.errorString()); + } } float fileSize = (float)dataFileIn.size(); int unit = 0; @@ -292,15 +305,26 @@ void OperationZipSceneFile::createZipFile(const AString& sceneFileName, case PROGRESS_GUI_EVENT: break; } + ++goodFileCount; } zipFile.close(); switch (progressMode) { case PROGRESS_COMMAND_LINE: + if (goodFileCount != int(allFiles.size())) + { + CaretLogWarning("Zip creation skipped " + AString::number(allFiles.size() - goodFileCount) + " unreadable files"); + } break; case PROGRESS_GUI_EVENT: - progressEvent.setProgress(allFiles.size(), - "Zip created successfully"); + if (goodFileCount == int(allFiles.size())) + { + progressEvent.setProgress(allFiles.size(), + "Zip created successfully"); + } else { + progressEvent.setProgress(allFiles.size(), + "Zip creation skipped " + AString::number(allFiles.size() - goodFileCount) + " unreadable files"); + } EventManager::get()->sendEvent(progressEvent.getPointer()); break; } diff --git a/src/Operations/OperationZipSceneFile.h b/src/Operations/OperationZipSceneFile.h index 66f51cfa25009d10e012acec331b4e1a15cfccee..0630eb0149d71681e16fd19b10f1f41c1775c2cf 100644 --- a/src/Operations/OperationZipSceneFile.h +++ b/src/Operations/OperationZipSceneFile.h @@ -37,12 +37,13 @@ namespace caret { static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); - static void createZipFile(const AString& sceneFileName, + static void createZipFile(ProgressObject* myProgObj, + const AString& sceneFileName, const AString& outputSubDirectory, const AString& zipFileName, const AString& baseDirectory, const ProgressMode progressMode, - ProgressObject* myProgObj); + const bool skipMissing = false); }; typedef TemplateAutoOperation AutoOperationZipSceneFile; diff --git a/src/Operations/OperationZipSpecFile.cxx b/src/Operations/OperationZipSpecFile.cxx index d507d5998315fba56636037973b3059b6ebf5c85..11d83c27879155150cbade81f1a5e1eece7d9fb2 100644 --- a/src/Operations/OperationZipSpecFile.cxx +++ b/src/Operations/OperationZipSpecFile.cxx @@ -60,6 +60,8 @@ OperationParameters* OperationZipSpecFile::getParameters() OptionalParameter* baseOpt = ret->createOptionalParameter(4, "-base-dir", "specify a directory that all data files are somewhere within, this will become the root of the zipfile's directory structure"); baseOpt->addStringParameter(1, "directory", "the directory"); + ret->createOptionalParameter(5, "-skip-missing", "any missing files will generate only warnings, and the zip file will be created anyway"); + ret->setHelpText(AString("If zip-file already exists, it will be overwritten. ") + "If -base-dir is not specified, the directory containing the spec file is used for the base directory. " + "The spec file must contain only relative paths, and no data files may be outside the base directory. " + @@ -86,6 +88,7 @@ void OperationZipSpecFile::useParameters(OperationParameters* myParams, Progress {//this is actually because the path function strips the final "/" from the path, but not when it is just "/" myBaseDir += "/";//so, add the trailing slash to the path } + bool skipMissing = myParams->getOptionalParameter(5)->m_present; if (outputSubDirectory.isEmpty()) { throw OperationException("extract-dir must contain characters"); @@ -152,7 +155,12 @@ void OperationZipSpecFile::useParameters(OperationParameters* myParams, Progress } if (!missingDataFileNames.isEmpty()) { - throw OperationException("These data files do not exist:\n" + missingDataFileNames); + if (skipMissing) + { + CaretLogWarning("These data files do not exist and will be skipped:\n" + missingDataFileNames); + } else { + throw OperationException("These data files do not exist:\n" + missingDataFileNames); + } } if (!outsideBaseDirFiles.isEmpty()) { @@ -163,6 +171,7 @@ void OperationZipSpecFile::useParameters(OperationParameters* myParams, Progress * Create the ZIP file */ QFile zipFileObject(zipFileName); + zipFileObject.remove();//delete it if it exists, to play better with file symlinks QuaZip zipFile(&zipFileObject); if (zipFile.open(QuaZip::mdCreate) == false) { throw OperationException("Unable to open ZIP File \"" @@ -180,11 +189,16 @@ void OperationZipSpecFile::useParameters(OperationParameters* myParams, Progress AString unzippedDataFileName = outputSubDirectory + "/" + dataFileName.mid(myBaseDir.size());//we know the string matches to the length of myBaseDir, and is cleaned, so we can just chop the right number of characters off QFile dataFileIn(dataFileName); if (dataFileIn.open(QFile::ReadOnly) == false) { - errorMessage = "Unable to open \"" - + dataFileName - + "\" for reading: " - + dataFileIn.errorString(); - break; + if (skipMissing) + { + continue; + } else { + errorMessage = "Unable to open \"" + + dataFileName + + "\" for reading: " + + dataFileIn.errorString(); + break; + } } float fileSize = (float)dataFileIn.size(); int unit = 0; diff --git a/src/OperationsBase/OperationParameters.cxx b/src/OperationsBase/OperationParameters.cxx index 8f17841787f8c6f78d3237bd84fe05f97305ed51..6f3a3f27b202aac44426d6bd9ca29f775a3f2081 100644 --- a/src/OperationsBase/OperationParameters.cxx +++ b/src/OperationsBase/OperationParameters.cxx @@ -23,6 +23,7 @@ #include "CaretAssert.h" #include "CaretLogger.h" +#include "AnnotationFile.h" #include "BorderFile.h" #include "CiftiFile.h" #include "FociFile.h" @@ -291,6 +292,12 @@ void ParameterComponent::addDoubleParameter(const int32_t key, const AString& na m_paramList.push_back(new DoubleParameter(key, name, description)); } +void ParameterComponent::addAnnotationParameter(const int32_t key, const AString& name, const AString& description) +{ + CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::ANNOTATION), "input annotation parameter created with previously used key"); + m_paramList.push_back(new AnnotationParameter(key, name, description)); +} + void ParameterComponent::addMetricParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::METRIC), "input metric parameter created with previously used key"); @@ -350,6 +357,12 @@ void ParameterComponent::addBorderOutputParameter(const int32_t key, const AStri m_outputList.push_back(new BorderParameter(key, name, description)); } +void ParameterComponent::addAnnotationOutputParameter(const int32_t key, const AString& name, const AString& description) +{ + CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::ANNOTATION), "output annotation parameter created with previously used key"); + m_outputList.push_back(new AnnotationParameter(key, name, description)); +} + void ParameterComponent::addMetricOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::METRIC), "output metric parameter created with previously used key"); @@ -418,6 +431,11 @@ LabelFile* ParameterComponent::getLabel(const int32_t key) return ((LabelParameter*)getInputParameter(key, OperationParametersEnum::LABEL))->m_parameter.getPointer(); } +AnnotationFile* ParameterComponent::getAnnotation(const int32_t key) +{ + return ((AnnotationParameter*)getInputParameter(key, OperationParametersEnum::ANNOTATION))->m_parameter.getPointer(); +} + MetricFile* ParameterComponent::getMetric(const int32_t key) { return ((MetricParameter*)getInputParameter(key, OperationParametersEnum::METRIC))->m_parameter.getPointer(); @@ -468,6 +486,11 @@ VolumeFile* ParameterComponent::getOutputVolume(const int32_t key) return ((VolumeParameter*)getOutputParameter(key, OperationParametersEnum::VOLUME))->m_parameter.getPointer(); } +AnnotationFile* ParameterComponent::getOutputAnnotation(const int32_t key) +{ + return ((AnnotationParameter*)getOutputParameter(key, OperationParametersEnum::ANNOTATION))->m_parameter.getPointer(); +} + MetricFile* ParameterComponent::getOutputMetric(const int32_t key) { return ((MetricParameter*)getOutputParameter(key, OperationParametersEnum::METRIC))->m_parameter.getPointer(); diff --git a/src/OperationsBase/OperationParameters.h b/src/OperationsBase/OperationParameters.h index 0f8bd0790822a4ccf20fc21aca35af672094594e..49371127685f5212f099bdaf4d8721f41cf8c536 100644 --- a/src/OperationsBase/OperationParameters.h +++ b/src/OperationsBase/OperationParameters.h @@ -29,6 +29,7 @@ namespace caret { + class AnnotationFile; class BorderFile; class CiftiFile; class FociFile; @@ -110,6 +111,12 @@ namespace caret { ///get a volume with a key VolumeFile* getVolume(const int32_t key); + ///add a parameter to get next item as an annotation file + void addAnnotationParameter(const int32_t key, const AString& name, const AString& description); + + ///get an annotation with a key + AnnotationFile* getAnnotation(const int32_t key); + ///add a parameter to get next item as a functional file (metric) void addMetricParameter(const int32_t key, const AString& name, const AString& description); @@ -152,6 +159,12 @@ namespace caret { ///get a volume with a key VolumeFile* getOutputVolume(const int32_t key); + ///add a parameter to get next item as an annotation file + void addAnnotationOutputParameter(const int32_t key, const AString& name, const AString& description); + + ///get an annotation with a key + AnnotationFile* getOutputAnnotation(const int32_t key); + ///add a parameter to get next item as a functional file (metric) void addMetricOutputParameter(const int32_t key, const AString& name, const AString& description); @@ -327,6 +340,7 @@ namespace caret { //some friendlier names typedef PointerTemplateParameter SurfaceParameter; typedef PointerTemplateParameter VolumeParameter; + typedef PointerTemplateParameter AnnotationParameter; typedef PointerTemplateParameter MetricParameter; typedef PointerTemplateParameter LabelParameter; typedef PointerTemplateParameter CiftiParameter; diff --git a/src/OperationsBase/OperationParametersEnum.cxx b/src/OperationsBase/OperationParametersEnum.cxx index ff2b6e5d11eef18976a242ae42c391b4fe95c8eb..ef93e6b5aaef0c0d1bf8ca4522b3b602034d83b9 100644 --- a/src/OperationsBase/OperationParametersEnum.cxx +++ b/src/OperationsBase/OperationParametersEnum.cxx @@ -133,6 +133,11 @@ OperationParametersEnum::initialize() "Boolean", "Boolean")); + enumData.push_back(OperationParametersEnum(ANNOTATION, + 11, + "Annotation File", + "Annotation")); + } /** diff --git a/src/OperationsBase/OperationParametersEnum.h b/src/OperationsBase/OperationParametersEnum.h index b86acb8ba28950d24a2da4d729ca4071a9f2781a..45b8cf3d0f0906c8b0d492c9ac6a714aed896ffa 100644 --- a/src/OperationsBase/OperationParametersEnum.h +++ b/src/OperationsBase/OperationParametersEnum.h @@ -45,7 +45,8 @@ public: DOUBLE, INT, STRING, - BOOL + BOOL, + ANNOTATION }; diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index de2a3a975005428263dbe28c8c48e065c76fe5ca..102f78e4641ccc5d59e9be9f2a72f54c77c4c0d8 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -243,7 +243,7 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const void PaletteColorMapping::initializeMembersPaletteColorMapping() { - this->scaleMode = PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE; + this->scaleMode = PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE; this->autoScalePercentageNegativeMaximum = 98.0f; this->autoScalePercentageNegativeMinimum = 2.0f; this->autoScalePercentagePositiveMinimum = 2.0f; @@ -1963,7 +1963,7 @@ PaletteColorMapping::mapDataToPaletteNormalizedValues(const FastStatistics* stat { normalized = (scalar - mappingLeastPositive) / mappingPositiveDenominator + PALETTE_ZERO_COLOR_ZONE; } else { - if (scalar > mappingLeastPositive) + if (scalar >= mappingMostPositive) { normalized = 1.0f; } @@ -1979,7 +1979,7 @@ PaletteColorMapping::mapDataToPaletteNormalizedValues(const FastStatistics* stat { normalized = (scalar - mappingLeastNegative) / mappingNegativeDenominator - PALETTE_ZERO_COLOR_ZONE; } else { - if (scalar < mappingLeastNegative) + if (scalar <= mappingMostNegative) { normalized = -1.0f; } diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 2163ec0cb1b80b99e2f071aeb173516ca7ab8bbc..660d8ce42be04783f322e4f8d9114295fc4bcfb1 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -436,7 +436,7 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, << qName.toStdString() << "\" with content: " << this->elementText.toStdString(); - warning(XmlSaxParserException(AString::fromStdString(str.str()))); + CaretLogFine(AString::fromStdString(str.str())); } break; } diff --git a/src/Resources/Gui/ToolBar/icon_credits.txt b/src/Resources/Gui/ToolBar/icon_credits.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1d0195d35ca36804dce7f352136c05502fb2807 --- /dev/null +++ b/src/Resources/Gui/ToolBar/icon_credits.txt @@ -0,0 +1,10 @@ +macro.png Icon Author Credit: + +
Icons made by Webalys Freebies from www.flaticon.com is licensed by CC 3.0 BY
+ + + +movie.png Icon: + +
Icons made by Catalin Fertu from www.flaticon.com is licensed by CC 3.0 BY
+ diff --git a/src/Resources/Gui/ToolBar/macro.png b/src/Resources/Gui/ToolBar/macro.png new file mode 100644 index 0000000000000000000000000000000000000000..55d98e7b6f2cac69f134ea928781e3de098449cc Binary files /dev/null and b/src/Resources/Gui/ToolBar/macro.png differ diff --git a/src/Resources/Gui/ToolBar/movie.png b/src/Resources/Gui/ToolBar/movie.png new file mode 100644 index 0000000000000000000000000000000000000000..7118cd48e889aa5dea418f3161ff5805e16337f3 Binary files /dev/null and b/src/Resources/Gui/ToolBar/movie.png differ diff --git a/src/Resources/Gui/gui_resources.qrc b/src/Resources/Gui/gui_resources.qrc index c9a45154be84ffc6bfbb57192a9deed99b50adde..92f718a5f42836d496c5c22518d39a05d27b68e6 100644 --- a/src/Resources/Gui/gui_resources.qrc +++ b/src/Resources/Gui/gui_resources.qrc @@ -21,6 +21,8 @@ ./ToolBar/help.png ./ToolBar/identify.png ./ToolBar/info.png +./ToolBar/macro.png +./ToolBar/movie.png ./ToolBar/overlay_toolbox.png ./ToolBar/toolbar.png ./ToolBar/view-anterior.png diff --git a/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image008.png b/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image008.png index 2f6075815c9df155afe458983bc65d94265e6d78..e13dbb33f62df8f54fb5e203bce765c3c16e6779 100644 Binary files a/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image008.png and b/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image008.png differ diff --git a/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.html b/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.html index 3a6748b5c672fbe7b9f3111952682d2807a4993c..b25375eaa219b993cc3cd7aafca801a14ce69ebe 100644 --- a/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.html +++ b/src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.html @@ -228,7 +228,7 @@ style='font-size:36.0pt'>Guide to WB Annotations

style='font-size:28.0pt'>1.3.2

27 August 2018

+style='font-size:24.0pt'>01 November 2018

 

@@ -591,7 +591,7 @@ aspect ratio, padding is added to the horizontal or vertical sides of the window to limit the graphics region in a way that matches the locked aspect ratio.   For example, suppose one creates two annotations in tab coordinate space, a red oval and a fuchsia box as in Figure 3.  Now suppose one increases the width of the +style='font-size:14.0pt'>.  Now suppose one increases the width of the window while the aspect ratio is unlocked.  Notice that the annotations no longer overlay the original anatomical regions, Figure 4.  However, if one locks the aspect ratio and @@ -677,8 +677,8 @@ Figure from A multimodal parcellation of human cerebral cortex (Glasser et al) 

-

+

Figure 7: Window with Annotation ToolBar

@@ -711,6 +711,19 @@ annotation in chart data space will move.

 

+

Spacer Coordinate Space (Sp)

+ +

 

+ +

When Tile Tabs is enabled, +rows and/or columns in the Tile Tabs Configuration may contain Spacers or Tabs +(Tabs is the default).  Spacers create an empty row (or column) in a Tile +Tabs Configuration so that one has regions for displaying annotations without +underlying brain models.  Each annotation in Spacer Coordinate Space is +assigned to a specific row and column and is visible only when Tile Tabs is +enabled.  The most common use for annotations in this space is as row and +column titles.

+

Stereotaxic Coordinate Space (St)

 

@@ -852,10 +865,10 @@ and one or both may be used.

of annotations that pictorially describe the mapping of numeric data into a color palette.  Color bars are not created like other annotation types but are enabled for display by pressing the color bar button for a row in the -Overlay ToolBoxÕs Layers tab.  Positioning of color bars is performed automatically -unless the user chooses to manually position them.  Color bars are limited -to Tab and Window spaces.  Editing of color bars is described at the end -of this document.

+Overlay ToolBoxÕs Layers tab.  Positioning of color bars is performed +automatically unless the user chooses to manually position them.  Color +bars are limited to Tab and Window spaces.  Editing of color bars is +described at the end of this document.

 

@@ -901,7 +914,7 @@ coordinate and the text alignment properties control the offset of the text relative to the coordinate.  Text characters are drawn in the Font Color.  The Line color, if enabled, draws a box around the text.  The File color, if enabled, draws a background behind the text.  The height of text is -specified as a percentage of the regionÕs height containing the text.  As +specified as a percentage of the regionÕs height containing the text.  As the region changes in height, a corresponding change will occur in the size of the text.

@@ -1454,9 +1467,9 @@ Controls

 

The Annotation Line Arrow -Tips section controls the addition of arrows to the end points of a line -annotation.  The top arrow button adds an arrow to the lineÕs start and -the bottom arrow button adds an arrow to the lineÕs end.

+Tips section controls the addition of arrows to the end points of a line annotation.  +The top arrow button adds an arrow to the lineÕs start and the bottom arrow +button adds an arrow to the lineÕs end.

Annotation Text Characters

@@ -1811,8 +1824,8 @@ Selection Controls

new annotations are placed in either ÒScene AnnotationsÓ or an Annotation File stored to disk.  Scene Annotations are not saved to an annotation file but instead are added to a scene when a a new scene is created.  Note that the -user will need to save the scene file.  Disk annotation files are saved and -opened like other data files.

+user will need to save the scene file.  Disk annotation files are saved +and opened like other data files.

 

@@ -1824,19 +1837,19 @@ the user must choose the Space from the top row of buttons (the selected space is highlighted).  Third, the user must click one of the type buttons in the bottom row to choose the type of annotation that is created.  Lastly, the user moves the mouse into the graphics region at which time the mouse -pointer becomes a small ÔplusÕ symbol.  The user must either click the -mouse in the graphics region to insert a default annotation for the type or drag -the mouse to create a rectangular region that bounds the new annotation.  -If the location of the new annotation is incompatible with the selected -annotation space, a dialog pops up that allows the user to choose a different -space or to cancel creation of the annotation. When entering a text annotation, -a dialog will always pop-up for entry of the text.

+pointer becomes a small ÔplusÕ symbol.  The user must either click the mouse +in the graphics region to insert a default annotation for the type or drag the +mouse to create a rectangular region that bounds the new annotation.  If +the location of the new annotation is incompatible with the selected annotation +space, a dialog pops up that allows the user to choose a different space or to +cancel creation of the annotation. When entering a text annotation, a dialog +will always pop-up for entry of the text.

 

BEWARE that when drawing -annotations in surface space, the annotation may move a short distance from where -it was drawn.  This is caused by the surface offset attribute of the +annotations in surface space, the annotation may move a short distance from +where it was drawn.  This is caused by the surface offset attribute of the surface coordinate.  While the annotation is attached to the surface vertex closest to the mouse click, the annotation is offset by a vector.  It is this offset vector that causes the annotation to move.  Without the @@ -2094,8 +2107,8 @@ Sensitive (Pop-up) Menu.

á      -Select All Ð Selects all annotations -displayed in the window.

+Select All Ð Selects all +annotations displayed in the window.


@@ -2169,9 +2182,9 @@ deselected.  The selected annotation is highlighted in the graphics region.  The user may select multiple annotations in the features toolbox by holding down the CTRL (Apple) key or the Shift key.  If the CTRL key is held down while the mouse is clicked, the annotation under the mouse is added -to the selected annotations.  If the Shift key is held down while the -mouse is clicked, all annotation from the last selected annotation to the -annotations under the mouse are selected.

+to the selected annotations.  If the Shift key is held down while the mouse +is clicked, all annotation from the last selected annotation to the annotations +under the mouse are selected.

 

@@ -2207,8 +2220,8 @@ the annotation the annotation's ÔFill ColorÕ is enabled, the background of the icon is the fill color.  If the annotationÕs line color is enabled, the edges of the icon are drawn in the line color.  If the annotation is a text annotation, -a small square consisting of the text characterÕs color is in the center of -icon.

+a small square consisting of the text characterÕs color is in the center of icon. +

 

@@ -2354,10 +2367,11 @@ one group.  There is a group for each tab and a group for each window. To select an annotation with the mouse, the user simply clicks the mouse over an annotation.  The -annotation under the mouse is selected and any other annotations are deselected. - To select multiple annotations the user clicks the annotation with the -mouse while the Shift key is held down.  To deselect all annotations, the -user clicks the mouse in an empty region (not over an annotation).

+annotation under the mouse is selected and any other annotations are +deselected.  To select multiple annotations the user clicks the annotation +with the mouse while the Shift key is held down.  To deselect all +annotations, the user clicks the mouse in an empty region (not over an +annotation).

 

@@ -2439,8 +2453,8 @@ id="Picture 3" src="Annotations_1.3.fld/image032.png">

-

Figure 30: Overlay and Map Settings -Color Bar Controls

+

Figure 30: Overlay and Map +Settings Color Bar Controls

 

@@ -2530,8 +2544,8 @@ background:transparent'>Glasser MF, Coalson TS, Robinson EC, et al. A multi-modal parcellation of human cerebral cortex. Nature. 2016;536(7615):171-178. -doi:10.1038/nature18933.

+font-family:Arial;color:#303030;background:transparent'>. +2016;536(7615):171-178. doi:10.1038/nature18933.

 

diff --git a/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html index 7243cf78d3b9f716355b1d6f90525eb41447bf07..fe88ce268fc5001c815896268db065875b5d1d81 100644 --- a/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html +++ b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html @@ -20,6 +20,11 @@ + + + + + Tabs
in the Viewing @@ -37,6 +42,11 @@ + + + + + @@ -44,36 +54,199 @@ Area

+

Tile Tabs Configuration in Workbench Window

This section contains the tile tabs - configuration for the selected Workbench Window.  When a - scene is saved with Tile Tabs enabled, the selected configuration - is saved to the scene and is restored when the scene is displayed.
+ configuration for the selected Workbench Window. 
If a Scene is saved, the + selected Configuration is saved to the Scene and is restored + when the Scene is displayed.
+
+
Workbench Window  + + + + Selects the window for control of the window's Tile Tabs + Configuration
+
+

Layout of Tabs in a Tile Tabs Configuration

+  A Tile Tabs Configuration is a grid + layout that displays all Tabs in the Window.  Regardless of + the Configuration Type, the first tab will be in the top left + corner with subsequent tabs appearing to the right and wrapping to + the next row when a row is filled.  Rows and/or columns may + also contain 'Spacers' (typically used for text as row/column + headers) and tabs skip over these spacers.
+

+

Configuration Types
+

    -
  • Workbench Window - Selects the Window for adjusting the - Tile Tabs Configuration
    -
  • Automatic - Configuration - When selected, Workbench will adjust - the number of rows and columns so that all tabs are displayed.
  • + Configuration - This is the default selection and + Workbench will adjust the number of rows and columns so that + all tabs are displayed.  Use Custom when Automatic does not produce + the desired layout of tabs.
  • Custom Configuration - - Allows the user to set the number of rows/columns and their - stretch factors.
    + Allows the user to customize the configuration of the Tile + Tabs layout including number of rows, number of columns, + heights of the rows, and widths of the columns.  If the + Custom Configuration contains insufficient rows and columns + for the Window's Tabs, some tabs will not be displayed.  + Conversely, there will be empty space at the bottom when the + Tile Tabs Configuration contains space for more tabs than are + currently in the Window.  The user may also designate + rows or columns that contains 'Spacers'.
    +
  • +
+

Custom Configuration Rows/Columns
+

+

+
    +
  • Index - The index of the row or + column.
  • +
  • Construction Menu - Allows + the user to duplicate, move, or delete rows and columns.  +
    +
  • +
  • Content - The content of the row + or column chosen from Space or Tab.  The content of + 'Space' is limited to annotations in "Spacer Coordinate Space" + or "Window Space" Annotations.  The content of 'Tab' is + limited to display of a browser tab along with annotations in + spaces other than "Spacer Coordinate Space."
    +
  • +
  • Type - The type of 'stretching' + chosen from Percent and Weight.
  • -
  • Dimensions (Rows / Columns) - - Number of Rows and Columns in the Custom Configuration
  • -
  • Stretch Factors - The Stretch - Factors function as weights and are used to allocate space - assigned to rows and columns.  For example, a row with a - stretch factor of 2 is double the height of a row with a - stretch factor of 1.  The percentage values indicate the - height (width) that a row (column) occupies in the graphics - region.
    +
  • Stretch - The stretching + value.  When the Type is Percent this value is a + percentage and when the Type is weight it is the weight for + this row/column.
    +
  • +
+

Explanation of Stretching

+
+ The space allocated to a row is determined by a combination of the + Stretching Type and the Stretching Value.  (Note that row and + column stretching function identically but along different axes) as + described below.
+

Percentage Stretching Type

+ When a row's Type is set to Percentage, that row is allocated the + associated Percentage value of the window's height.  Thus, if + the row's Percentage Height is 20% and the Window is 1000 pixels in + height, the row is 200 pixels in height.  The Percentage value + for each row should be in the range 0% to 100%.  If the rows + that use Percentage sum to more than 100%, then part or all of the + last rows may not be displayed (likewise for columns).  If + there are no rows/columns that use Weight, then there may be blank + unused space, depending on the percentages used."
+
+
Example of Percentage Stretching
+
    +
  • Row 1: 20%
  • +
  • Row 2: 50%
  • +
  • Row 3: 30%
  • +
+

Result for a Window 1000 pixels in height:
+

+
    +
  • Row 1 Height: 200 pixels (20% of 1000)
  • +
  • Row 2 Height: 500 pixels (50% of 1000)
  • +
  • Row 3 Height: 300 pixels (30% of 1000)
    +
  • +
+


+

+

Weighted Stretching Type

+ When a row's Type is set to Weight, the Height of the row is + affected by Stretching Values of all Rows with the Stretching Type + set to Weight.  To determine the height of the a row, the + weights from all rows are summed and the row's weight is divided by + the sum.  This result (row's weight divided by sum) becomes the + percentage of the window's height allocated to the row.
+
+
Example of Weighted Stretching
+
    +
  • Row 1: 1.0
  • +
  • Row 2: 2.0
  • +
  • Row 3: 1.0
  • +
+

Result for a Window 1000 pixels in height (Note: sum of weights + is 4.0):
+

+
    +
  • Row 1 Height: 250 pixels   ((1.0 / 4.0) * 1000 = + 250)
    +
  • +
  • Row 2 Height: 500 pixels   ((2.0 / 4.0) * 1000 = 500)
  • +
  • Row 3 Height: 250 pixels   ((1.0 / 4.0) * 1000 = + 250)
  • +
+
+

Combination of Percentage and Weighted Stretching

+ When both Percentage and Weighted Stretching are used, rows with + Percentage stretching are assigned their requested height percentage + and any remaining space is allocated to rows with weighted + Stretching.
+
+
Example of Percentage and Weighted Stretching
+
    +
  • Row 1: Percentage, 20%
  • +
  • Row 2: Percentage, 30%
  • +
  • Row 3: Weighted, 1.0
  • +
  • Row 4: Weighted, 2.0
  • +
+

Result for a Window 1000 pixels in height (Note: Sum of + Percentages is 50% and Sum of Weights is 3.0):
+

+
    +
  • Row 1 Height: 200 pixels (20% of 1000)
  • +
  • Row 2 Height: 300 pixels (30% of 1000)
  • +
  • Row 3 Height: 166 pixels ((1.0 / 3.0) * 50% * 1000)
  • +
  • Row 4 Height: 334 pixels ((2.0 / 3.0) * 50% * 1000)
  • +
+ Now Suppose a 5th row is added with a Weight of 1.0 (the Sum of + Weights is 4.0).  Notice that the Percentage Type rows remain + the same height and the Weighted Type rows shrink in height to + accommodate the new row:
+
    +
  • Row 1 Height: 200 pixels (20% of 1000)
  • +
  • Row 2 Height: 300 pixels (30% of 1000)
  • +
  • Row 3 Height: 125 pixels ((1.0 / 4.0) * 50% * 1000)
  • +
  • Row 4 Height: 250 pixels ((2.0 / 4.0) * 50% * 1000)
  • +
  • Row 5 Height: 125 pixels ((1.0 / 4.0) * 50% * 1000)
+

Summary of Percentage and Weighted Stretching

+

The advantage of using Percentage stretching is that the row will + be allocated the requested percentage of the window's + height.  The disadvantage of Percentage Stretching is that if + all rows use Percentage Stretching, and a row is added or removed, + the user will need to adjust the stretching percentages to ensure + all rows are visible (when a row is added) or to remove empty + space (when a row is removed).
+

+

The advantage of Weighted stretching is that all of the vertical + space will be used and the available space is automatically + reallocated when a row is added or removed.  The disadvantage + is that if rows use different weights, calculations are required + to get the desired row heights.
+

+

In some instances using both Percentage and Weighted Stretching + may be best.   One such instance is when the first row's + Content is set to Spacer and Annotation are added to the Spacer + Row for use as Column Titles.  In this case, the + recommendation is to use Percentage for this Row and Weight for + the Rows below containing the Brain Models.  As Rows for + Brain Models are added as removed, the Column Titles will remain + the same size and the Rows containing the Brain Models will occupy + all of the remaining vertical space.
+

User Configuration

The User Configuration contains Tile Tabs Configurations that have been created by the user.  These @@ -88,21 +261,22 @@
  • Delete - Click this button to delete the selected User Configuration
  • -

    Copy and Load Push Buttons

    +

    Replace and Load Push Buttons

      -
    • Replace - Replaces the selected - User Configuration with the content of the Custom +
    • Replace - Replaces (saves) the + selected User Configuration with the content of the Custom Configuration
    • Load - Copies the selected User - Configuration into the Custom Configuration
    • + Configuration into the Custom Configuration and is used for + the layout of the window
      +


    -
    +


    diff --git a/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png index 139d6235af32ef20cc6387b8c33bc073c70b8a23..600f460c9ce2d9ee91d811d8d69f9c9d75ce6540 100644 Binary files a/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png and b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png differ diff --git a/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.html b/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.html index e06ebf8da9551548580adcc7cac65073bbc01dba..c888a5f168e4732f724f1ae769df020a300bce83 100644 --- a/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.html +++ b/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.html @@ -23,6 +23,7 @@ show up in this selector.
  • New  Creates + a new Scene File.  A new Scene File is created with no scenes within it. Add any number of scenes with the Add button.
  • @@ -34,11 +35,12 @@
  • Zip  Creates a ZIP file containing the scene file and all data files it references.
  • -
  • List Files  Lists all data - files from all scenes within the scene file
    +
  • Show Files and Folders  Displays + a hierarchy or list of all data files from all scenes within + the scene file
  • -
  • Open  Displays a file selection - dialog for selecting and opening a scene file.
    +
  • Open  Displays a file + selection dialog for selecting and opening a scene file.
  • Save As   Displays a file selection dialog for saving the scene file with a new @@ -52,29 +54,32 @@


    Show Scene Group

    +

    +
      -
        -
      • Show loads the active (highlighted in blue) - scene.  Double clicking on a scene's - title/description will also show the scene.
      • -
      • Preview... opens a separate window with an enlarged - display of the highlighted scene's thumbnail along with - the name and description.
      • -
      • Options  Use background and foreground colors - from scene when a scene is created, the foreground and - background colors are added to the scene and will be - used when the scene is displayed. Note that the - background and foreground colors are adjusted using - the Preferences Dialog. When a scene is loaded that - contains background and foreground colors, they will - override the user's Preferences colors until a - different scene is loaded, a spec file is loaded, or - this checkbox is unchecked.
      • -
      -

      +
    • Show loads the active (highlighted in blue) + scene.  Double clicking on a scene's + title/description will also show the scene.
    • +
    • Preview... opens a separate window with an enlarged + display of the highlighted scene's thumbnail along with + the name and description.
    • +
    • Options  Use background and foreground colors from + scene when a scene is created, the foreground and + background colors are added to the scene and will be + used when the scene is displayed. Note that the + background and foreground colors are adjusted using the + Preferences Dialog. When a scene is loaded that contains + background and foreground colors, they will override the + user's Preferences colors until a different scene is + loaded, a spec file is loaded, or this checkbox is + unchecked.
    • +
      +
    + +

    Create Scene Group

    @@ -102,17 +107,20 @@
  • -

    Selected Scene Group -

      -
    • Move Up moves the selected - scene up one position in the list of scenes.
    • -
    • Move Down moves the selected scene - down one position in the list of scenes.
    • -
    • Delete Deletes the highlighted - scene from the scene file.
      -
    • -
    -

    +

    Selected Scene Group

    +
      + +
    • Move Up moves the selected + scene up one position in the list of scenes.
    • +
    • Move Down moves the selected scene + down one position in the list of scenes.
    • +
    • Delete Deletes the highlighted scene + from the scene file.
      +
    • +
      +
    + +

    Testing Group

    @@ -131,8 +139,8 @@

    -
    +
    diff --git a/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.png b/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.png index 0b3848d9bc3165d25e6dd7184c0b831e96810d3a..25edd6b6b811e09b8bc7c93b2fd9c762cbbb8b0c 100644 Binary files a/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.png and b/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.png differ diff --git a/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/ToolTips_icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/ToolTips_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3d27fd70a65c8ab26ecfdea5d39355858a35ef00 Binary files /dev/null and b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/ToolTips_icon.png differ diff --git a/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html index d6e332fd440060a26c18aea5cd2db7a9e4f2929d..837eafb50728107793c4a5c4e451223fad0eaca2 100644 --- a/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html +++ b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html @@ -1,62 +1,70 @@ - - - - - Window Elements Hide/Show Buttons - - - - Window Elements Hide/Show - Buttons
    - The Hide/Show buttons for the Workbench Window - elements (Help - Window, + + + + Window Elements Hide/Show Buttons + + + + Window Elements Hide/Show + Buttons
    + The Hide/Show buttons for the
    Workbench Window + elements (Help + Window, Information - - Window, Scenes - Window, Toolbar, - Overlay - Toolbox, and
    , Scenes + Window, Toolbar, + Overlay + Toolbox, and Features - - Toolbox) are located in the upper right corner - of the Workbench Window. These buttons turn the display of these - elements on and off. The buttons are shaded gray (as in the images - below) to indicate that the element is on, and are unshaded when - the element is off. -
       Help - Window button
    -
    -
        Information - - - - - - - Window button
    -
    -     Identify Brainordinate button
    -
    -     Scenes Window button
    -
    -     Toolbar button
    -
    -     Overlay Toolbox button
    -
    -     Features Toolbox - button
    - - + + + + Toolbox
    ) are located in the upper right corner + of the Workbench Window. These buttons turn the display of these + elements on and off. The buttons are shaded gray (as in the images + below) to indicate that the element is on, and are unshaded when + the element is off. +
    tooltips icon Tool Tips button  Enables + tool tips that display information about the brainordinate under + the mouse.  To show a tooltip, move the mouse over a surface + or volume and then 'rest' (do not move) the mouse for a couple of + second.  A small amount of text will appear that is similar + to an identification (mouse click) operation.
    +
    +    Help Window + button
    +
    +
        + + Information Window button
    +
    +     Identify + Brainordinate button
    +
    +     Scenes Window button
    +
    +     Toolbar button
    +
    +     Overlay Toolbox button
    +
    +     Features + Toolbox button
    + + diff --git a/src/Resources/Help/help_resources.qrc b/src/Resources/Help/help_resources.qrc index 08e85549617450426ef29b52c7c85b893d15e154..10eebe98a0417863e3f702a77868628141f0772e 100644 --- a/src/Resources/Help/help_resources.qrc +++ b/src/Resources/Help/help_resources.qrc @@ -240,6 +240,7 @@ ./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Overlay_TB_icon.png ./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Scenes_icon.png ./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Toolbar_icon.png +./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/ToolTips_icon.png ./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html ./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/WindowForScene.tiff ./HelpFiles/Workbench_Window/Workbench_Window.html diff --git a/src/Scenes/BackgroundAndForegroundColorsSceneHelper.cxx b/src/Scenes/BackgroundAndForegroundColorsSceneHelper.cxx index 0b7d3215a0c160c884fb7c71a76fd12a2561dcc4..089d948ac7ba437e79c8bdbc708f3f0c47102e28 100644 --- a/src/Scenes/BackgroundAndForegroundColorsSceneHelper.cxx +++ b/src/Scenes/BackgroundAndForegroundColorsSceneHelper.cxx @@ -49,6 +49,11 @@ m_wasRestoredFromSceneFlag(false) m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->addArray("m_colorForegroundWindow", + m_colors.m_colorForegroundWindow, 3, 255); + m_sceneAssistant->addArray("m_colorBackgroundWindow", + m_colors.m_colorBackgroundWindow, 3, 0); + m_sceneAssistant->addArray("m_colorForegroundAll", m_colors.m_colorForegroundAll, 3, 255); m_sceneAssistant->addArray("m_colorBackgroundAll", @@ -71,6 +76,8 @@ m_wasRestoredFromSceneFlag(false) m_sceneAssistant->addArray("m_colorChartMatrixGridLines", m_colors.m_colorChartMatrixGridLines, 3, 0); + m_sceneAssistant->addArray("m_colorChartHistogramThreshold", + m_colors.m_colorChartHistogramThreshold, 3, 0); } /** @@ -117,9 +124,12 @@ BackgroundAndForegroundColorsSceneHelper::saveToScene(const SceneAttributes* sce { m_wasRestoredFromSceneFlag = false; + /* + * Version 2: Added window foreground and background colors + */ SceneClass* sceneClass = new SceneClass(instanceName, "BackgroundAndForegroundColorsSceneHelper", - 1); + 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -159,6 +169,19 @@ BackgroundAndForegroundColorsSceneHelper::restoreFromScene(const SceneAttributes m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + if (sceneClass->getVersionNumber() <= 1) { + /* + * Version 1 did not have window foreground and background colors so + * use the surface background colors + */ + uint8_t rgb[3]; + m_colors.getColorBackgroundSurfaceView(rgb); + m_colors.setColorBackgroundWindow(rgb); + + m_colors.getColorForegroundSurfaceView(rgb); + m_colors.setColorForegroundWindow(rgb); + } + m_wasRestoredFromSceneFlag = true; //Uncomment if sub-classes must restore from scene diff --git a/src/Scenes/CMakeLists.txt b/src/Scenes/CMakeLists.txt index ae9c8040434ffd7131e632301c8431491183db5a..abc7defabeb0d923a867f7257fce7d17a0414d51 100644 --- a/src/Scenes/CMakeLists.txt +++ b/src/Scenes/CMakeLists.txt @@ -20,6 +20,7 @@ PROJECT (Scenes) SET(CARET_QT_LINK_MODULES "") if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Gui_INCLUDE_DIRS}) #include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Xml_INCLUDE_DIRS}) SET(CARET_QT_LINK_MODULES "Qt5::Core") @@ -49,10 +50,14 @@ SceneFloat.h SceneFloatArray.h SceneInfo.h SceneInfoSaxReader.h +SceneInfoXmlStreamBase.h +SceneInfoXmlStreamReader.h +SceneInfoXmlStreamWriter.h SceneInteger.h SceneIntegerArray.h SceneObject.h SceneObjectArray.h +SceneObjectContainerTypeEnum.h SceneObjectDataTypeEnum.h SceneObjectMapIntegerKey.h ScenePathName.h @@ -68,6 +73,9 @@ SceneUnsignedByteArray.h SceneWriterInterface.h SceneWriterXml.h SceneXmlElements.h +SceneXmlStreamBase.h +SceneXmlStreamReader.h +SceneXmlStreamWriter.h SceneableInterface.h BackgroundAndForegroundColorsSceneHelper.cxx @@ -86,10 +94,14 @@ SceneFloat.cxx SceneFloatArray.cxx SceneInfo.cxx SceneInfoSaxReader.cxx +SceneInfoXmlStreamBase.cxx +SceneInfoXmlStreamReader.cxx +SceneInfoXmlStreamWriter.cxx SceneInteger.cxx SceneIntegerArray.cxx SceneObject.cxx SceneObjectArray.cxx +SceneObjectContainerTypeEnum.cxx SceneObjectDataTypeEnum.cxx SceneObjectMapIntegerKey.cxx ScenePathName.cxx @@ -103,6 +115,9 @@ SceneTypeEnum.cxx SceneUnsignedByte.cxx SceneUnsignedByteArray.cxx SceneWriterXml.cxx +SceneXmlStreamBase.cxx +SceneXmlStreamReader.cxx +SceneXmlStreamWriter.cxx ) TARGET_LINK_LIBRARIES(Scenes ${CARET_QT5_LINK}) diff --git a/src/Scenes/DisplayGroupAndTabItemHelper.cxx b/src/Scenes/DisplayGroupAndTabItemHelper.cxx index a17a8a24b42cac257da0bdc7d79c3cce25be10b5..261c71b2bad915d3bd7f27ce575b4212d64640c9 100644 --- a/src/Scenes/DisplayGroupAndTabItemHelper.cxx +++ b/src/Scenes/DisplayGroupAndTabItemHelper.cxx @@ -121,13 +121,15 @@ DisplayGroupAndTabItemHelper::copyHelperDisplayGroupAndTabItemHelper(const Displ m_expandedStatusInDisplayGroup[i] = obj.m_expandedStatusInDisplayGroup[i]; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_selectedInTab[i] = m_selectedInTab[i]; - m_expandedStatusInTab[i] = m_expandedStatusInTab[i]; + m_selectedInTab[i] = obj.m_selectedInTab[i]; + m_expandedStatusInTab[i] = obj.m_expandedStatusInTab[i]; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { - m_selectedInWindow[i] = m_selectedInWindow[i]; - m_expandedInWindow[i] = m_expandedInWindow[i]; + m_selectedInWindow[i] = obj.m_selectedInWindow[i]; + m_expandedInWindow[i] = obj.m_expandedInWindow[i]; } + + m_selectedInSpacerTab = obj.m_selectedInSpacerTab; } /** @@ -151,6 +153,8 @@ DisplayGroupAndTabItemHelper::clearPrivate() m_selectedInWindow[i] = TriStateSelectionStatusEnum::SELECTED; m_expandedInWindow[i] = defaultExpandStatus; } + + m_selectedInSpacerTab = TriStateSelectionStatusEnum::SELECTED; } /** @@ -191,6 +195,9 @@ DisplayGroupAndTabItemHelper::initializeNewInstance() m_expandedInWindow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, m_expandedInWindow[0]); + + m_sceneAssistant->add("m_selectedInSpacerTab", + &m_selectedInSpacerTab); } /** @@ -315,6 +322,32 @@ DisplayGroupAndTabItemHelper::setExpandedInWindow(const int32_t windowIndex, } +/** + * Get the selected status of this item in a spacer tab. + * + * @param windowIndex + * Index of browser window in which item is controlled/viewed. + * @return + * The selection status. + */ +TriStateSelectionStatusEnum::Enum +DisplayGroupAndTabItemHelper::getSelectedInSpacerTab() const +{ + return m_selectedInSpacerTab; +} + +/** + * Set the selected status of this item in a spacer tab. + * + * @param status + * New selection status. +*/ +void +DisplayGroupAndTabItemHelper::setSelectedInSpacerTab(const TriStateSelectionStatusEnum::Enum status) +{ + m_selectedInSpacerTab = status; +} + /** * Is this item expanded to display its children in the * selection controls? diff --git a/src/Scenes/DisplayGroupAndTabItemHelper.h b/src/Scenes/DisplayGroupAndTabItemHelper.h index edcaf24ed66f7c1dd704aa1c58876925901b9cba..e2db6bf66bb18abe7d86f81ed309c0a89f40eda4 100644 --- a/src/Scenes/DisplayGroupAndTabItemHelper.h +++ b/src/Scenes/DisplayGroupAndTabItemHelper.h @@ -72,6 +72,10 @@ namespace caret { void setExpandedInWindow(const int32_t windowIndex, const bool status); + TriStateSelectionStatusEnum::Enum getSelectedInSpacerTab() const; + + void setSelectedInSpacerTab(const TriStateSelectionStatusEnum::Enum status); + // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, @@ -123,6 +127,9 @@ namespace caret { /** Expanded (collapsed) status in window */ bool m_expandedInWindow[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; + /** Selected in Spacer Window/Row/Column */ + TriStateSelectionStatusEnum::Enum m_selectedInSpacerTab; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Scenes/Scene.cxx b/src/Scenes/Scene.cxx index 9f29f260d114918011cbdf002b28794e3a3e6d90..58e1a76e7f251f15ab736078c07b0cf442a2733c 100644 --- a/src/Scenes/Scene.cxx +++ b/src/Scenes/Scene.cxx @@ -27,6 +27,7 @@ #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneInfo.h" +#include "WuQMacroGroup.h" using namespace caret; @@ -237,6 +238,12 @@ Scene::Scene(const SceneTypeEnum::Enum sceneType) this); m_hasFilesWithRemotePaths = false; m_sceneInfo = new SceneInfo(); + + static int counter = 1; + const AString macroGroupName("SceneFile_" + + AString::number(counter)); + m_macroGroup.reset(new WuQMacroGroup(macroGroupName)); + m_macroGroup->clearModified(); } Scene::Scene(const Scene& rhs) @@ -378,6 +385,8 @@ void Scene::setName(const AString& sceneName) { m_sceneInfo->setName(sceneName); + m_macroGroup->setName("Scene: " + + sceneName); } /** @@ -490,7 +499,9 @@ Scene::getSceneInfo() const void Scene::setSceneInfo(SceneInfo* sceneInfo) { - CaretAssert(sceneInfo); + if (sceneInfo == NULL) { + return;//TSC: SceneFileXmlStreamReader will call this with NULL argument when reading ancient scene files + } if (m_sceneInfo != NULL) { delete m_sceneInfo; @@ -512,6 +523,10 @@ Scene::isModified() const return true; } + if (m_macroGroup->isModified()) { + return true; + } + return false; } @@ -523,6 +538,64 @@ Scene::clearModified() { CaretObjectTracksModification::clearModified(); m_sceneInfo->clearModified(); + m_macroGroup->clearModified(); +} + +/** + * @return The macro group + */ +WuQMacroGroup* +Scene::getMacroGroup() +{ + return m_macroGroup.get(); +} + +/** + * @return The macro group (const method) + */ +const WuQMacroGroup* +Scene::getMacroGroup() const +{ + return m_macroGroup.get(); +} + +/** + * Move any macros in the given scene to this scene + * + * @param scene + * Scene whose macros are moved to this scene. + */ +void +Scene::moveMacrosFromScene(Scene* scene) +{ + CaretAssert(scene); + std::vector macros = scene->getMacroGroup()->takeAllMacros(); + if ( ! macros.empty()) { + for (auto m : macros) { + getMacroGroup()->addMacro(m); + } + } + setModified(); +} + +/** + * Copy any macros in the given scene to this scene + * + * @param scene + * Scene whose macros are copied to this scene. + */ +void +Scene::copyMacrosFromScene(const Scene* scene) +{ + CaretAssert(scene); + + const WuQMacroGroup* macroGroup = scene->getMacroGroup(); + if (macroGroup != NULL) { + if ( ! macroGroup->isEmpty()) { + getMacroGroup()->appendMacroGroup(macroGroup); + } + } } + diff --git a/src/Scenes/Scene.h b/src/Scenes/Scene.h index 939edc7d24d1d92f29abc02d5b064473c4fcd14e..9f3cb430c19b599378d867db86e8dfc199b93485 100644 --- a/src/Scenes/Scene.h +++ b/src/Scenes/Scene.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include "CaretObjectTracksModification.h" #include "SceneTypeEnum.h" @@ -30,6 +31,7 @@ namespace caret { class SceneClass; class SceneInfo; class SceneObject; + class WuQMacroGroup; class Scene : public CaretObjectTracksModification { @@ -91,6 +93,14 @@ namespace caret { static void setSceneBeingCreatedHasFilesWithRemotePaths(); + WuQMacroGroup* getMacroGroup(); + + const WuQMacroGroup* getMacroGroup() const; + + void copyMacrosFromScene(const Scene* scene); + + void moveMacrosFromScene(Scene* scene); + private: /** Attributes of the scene*/ @@ -105,6 +115,8 @@ namespace caret { /** True if it found a ScenePathName with a remote file */ bool m_hasFilesWithRemotePaths; + std::unique_ptr m_macroGroup; + /** When a scene is being created, this will be set */ static Scene* s_sceneBeingCreated; diff --git a/src/Scenes/SceneClass.cxx b/src/Scenes/SceneClass.cxx index 36a60414ea82fecda1e720255289ec89f6eb177e..053cbed417217175616814fdf46ea59bed09f646 100644 --- a/src/Scenes/SceneClass.cxx +++ b/src/Scenes/SceneClass.cxx @@ -70,6 +70,7 @@ SceneClass::SceneClass(const AString& name, const AString& className, const int32_t versionNumber) : SceneObject(name, + SceneObjectContainerTypeEnum::SINGLE, SceneObjectDataTypeEnum::SCENE_CLASS), m_className(className), m_versionNumber(versionNumber) @@ -77,7 +78,10 @@ SceneClass::SceneClass(const AString& name, } -SceneClass::SceneClass(const SceneClass& rhs): SceneObject(rhs.getName(), SceneObjectDataTypeEnum::SCENE_CLASS), +SceneClass::SceneClass(const SceneClass& rhs) +: SceneObject(rhs.getName(), + SceneObjectContainerTypeEnum::SINGLE, + SceneObjectDataTypeEnum::SCENE_CLASS), m_className(rhs.m_className), m_versionNumber(rhs.m_versionNumber) { @@ -105,6 +109,30 @@ SceneClass::~SceneClass() m_childObjects.clear(); } +/** + * Cast an instance of SceneObject to a SceneClass. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const SceneClass* +SceneClass::castToSceneClass() const +{ + return this; +} + +/** + * Cast an instance of SceneObject to a SceneClass. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +SceneClass* +SceneClass::castToSceneClass() +{ + return this; +} + /** * @return Name of the class (NOT the instance). */ diff --git a/src/Scenes/SceneClass.h b/src/Scenes/SceneClass.h index 758cd4c5a86963a7c4fd137872ae94835a291be4..7c62fde9a4af5c3152b016e0372a5ac48ab5c39b 100644 --- a/src/Scenes/SceneClass.h +++ b/src/Scenes/SceneClass.h @@ -46,6 +46,10 @@ namespace caret { virtual ~SceneClass(); + virtual const SceneClass* castToSceneClass() const; + + virtual SceneClass* castToSceneClass(); + AString getClassName() const; int32_t getVersionNumber() const; diff --git a/src/Scenes/SceneClassArray.cxx b/src/Scenes/SceneClassArray.cxx index 6af530ff8673f4a60c0846874686803970f371e4..d80dd96a4fbfbd38dc85f3d6d8c3f95847556b51 100644 --- a/src/Scenes/SceneClassArray.cxx +++ b/src/Scenes/SceneClassArray.cxx @@ -116,6 +116,30 @@ SceneClassArray::~SceneClassArray() m_values.clear(); } +/** + * Cast an instance of SceneObjectArray to a SceneClassArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +SceneClassArray* +SceneClassArray::castToSceneClassArray() +{ + return this; +} + +/** + * Cast an instance of SceneObjectArray to a SceneClassArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const SceneClassArray* +SceneClassArray::castToSceneClassArray() const +{ + return this; +} + /** * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. */ diff --git a/src/Scenes/SceneClassArray.h b/src/Scenes/SceneClassArray.h index 3ee4bb0ea54fc11e5b4589238c0c9089d6d05f02..cc930e1289509347bdfcf60e468db2ffdf16c78c 100644 --- a/src/Scenes/SceneClassArray.h +++ b/src/Scenes/SceneClassArray.h @@ -45,6 +45,10 @@ namespace caret { virtual ~SceneClassArray(); + virtual SceneClassArray* castToSceneClassArray(); + + virtual const SceneClassArray* castToSceneClassArray() const; + void setClassAtIndex(const int32_t arrayIndex, SceneClass* sceneClass); diff --git a/src/Scenes/SceneEnumeratedType.cxx b/src/Scenes/SceneEnumeratedType.cxx index 47aff4439fc36062ec4d75a170e70213c7234386..8fd2ba97e03cafea257a15448276b5d2fe3231a1 100644 --- a/src/Scenes/SceneEnumeratedType.cxx +++ b/src/Scenes/SceneEnumeratedType.cxx @@ -41,6 +41,7 @@ using namespace caret; SceneEnumeratedType::SceneEnumeratedType(const AString& name, const AString& enumeratedValueAsString) : SceneObject(name, + SceneObjectContainerTypeEnum::SINGLE, SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE) { m_enumeratedValueAsString = enumeratedValueAsString; @@ -54,6 +55,31 @@ SceneEnumeratedType::~SceneEnumeratedType() } +/** + * Cast an instance of SceneObject to a SceneEnumeratedType. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneEnumeratedType + */ +SceneEnumeratedType* +SceneEnumeratedType::castToSceneEnumeratedType() +{ + return this; +} + +/** + * Cast an instance of SceneObject to a SceneEnumeratedType. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneEnumeratedType + */ +const SceneEnumeratedType* +SceneEnumeratedType::castToSceneEnumeratedType() const +{ + return this; +} + + /** * @param enumeratedValueAsString * New value. diff --git a/src/Scenes/SceneEnumeratedType.h b/src/Scenes/SceneEnumeratedType.h index f1602b08578b4eb0d9389bd41cb7b3d541b9693d..be0c24f40d1381b42a938ab263e24bba57757549 100644 --- a/src/Scenes/SceneEnumeratedType.h +++ b/src/Scenes/SceneEnumeratedType.h @@ -34,6 +34,10 @@ namespace caret { virtual ~SceneEnumeratedType(); + virtual SceneEnumeratedType* castToSceneEnumeratedType(); + + virtual const SceneEnumeratedType* castToSceneEnumeratedType() const; + void setValue(const AString& enumeratedValueAsString); AString stringValue() const; diff --git a/src/Scenes/SceneEnumeratedTypeArray.cxx b/src/Scenes/SceneEnumeratedTypeArray.cxx index 6fc829deb7f59c14aa2090791ebdd6cff27dc733..b551fa41206c38c1859d7cd1961049ea69387e93 100644 --- a/src/Scenes/SceneEnumeratedTypeArray.cxx +++ b/src/Scenes/SceneEnumeratedTypeArray.cxx @@ -109,6 +109,29 @@ SceneEnumeratedTypeArray::~SceneEnumeratedTypeArray() } +/** + * Cast an instance of SceneObjectArray to a SceneEnumeratedTypeArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +SceneEnumeratedTypeArray* +SceneEnumeratedTypeArray::castToSceneEnumeratedTypeArray() +{ + return this; +} + +/** + * Cast an instance of SceneObjectArray to a SceneEnumeratedTypeArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const SceneEnumeratedTypeArray* +SceneEnumeratedTypeArray::castToSceneEnumeratedTypeArray() const +{ + return this; +} /** * Set a value. diff --git a/src/Scenes/SceneEnumeratedTypeArray.h b/src/Scenes/SceneEnumeratedTypeArray.h index b088cccf84a6600b64496bf294e78a56287b5fac..0578d99daafa37f7e24e654fbe8c430f22947d13 100644 --- a/src/Scenes/SceneEnumeratedTypeArray.h +++ b/src/Scenes/SceneEnumeratedTypeArray.h @@ -43,6 +43,10 @@ namespace caret { virtual ~SceneEnumeratedTypeArray(); + virtual SceneEnumeratedTypeArray* castToSceneEnumeratedTypeArray(); + + virtual const SceneEnumeratedTypeArray* castToSceneEnumeratedTypeArray() const; + void setValue(const int32_t arrayIndex, const AString enumeratedValueAsString); diff --git a/src/Scenes/SceneInfo.cxx b/src/Scenes/SceneInfo.cxx index a5e3cfbe4d8114270341d9491ee5e4e10f7af2ba..0c3de6da4a865ce92ada04619ed6fb404c597841 100644 --- a/src/Scenes/SceneInfo.cxx +++ b/src/Scenes/SceneInfo.cxx @@ -27,11 +27,11 @@ #include "CaretLogger.h" #include "SceneXmlElements.h" #include "XmlAttributes.h" +#include "XmlUtilities.h" #include "XmlWriter.h" -using namespace caret; +using namespace caret; - /** * \class caret::SceneInfo * \brief Contains information about a scene. @@ -44,7 +44,6 @@ using namespace caret; SceneInfo::SceneInfo() : CaretObjectTracksModification() { - } SceneInfo::SceneInfo(const SceneInfo& rhs) : CaretObjectTracksModification() @@ -63,6 +62,28 @@ SceneInfo::~SceneInfo() { } +/** + * @return True if this scene info is modified + */ +bool +SceneInfo::isModified() const +{ + if (CaretObjectTracksModification::isModified()) { + return true; + } + + return false; +} + +/** + * @return Is this instance modified? + */ +void +SceneInfo::clearModified() +{ + CaretObjectTracksModification::clearModified(); +} + /** * @return name of scene */ @@ -140,8 +161,8 @@ void SceneInfo::getImageBytes(QByteArray& imageBytesOut, AString& imageFormatOut) const { - imageBytesOut = m_imageBytes; - imageFormatOut = m_imageFormat; + imageBytesOut = m_imageBytes; + imageFormatOut = m_imageFormat; } /** diff --git a/src/Scenes/SceneInfo.h b/src/Scenes/SceneInfo.h index b4358c77e4811392f42ae39ec0a5867fd27b6f18..7fb9326f781ff0ece09b91d9d2c0b27947a2d7fa 100644 --- a/src/Scenes/SceneInfo.h +++ b/src/Scenes/SceneInfo.h @@ -38,9 +38,11 @@ namespace caret { virtual ~SceneInfo(); - AString getName() const; + bool isModified() const override; - void setName(const AString& sceneName); + void clearModified() override; + + AString getName() const; AString getDescription() const; @@ -71,6 +73,12 @@ namespace caret { const AString& imageFormat) const; private: + /* + * setName() is private as users should call Scene::setName() + * but the XML readers are allowed to call setName() + */ + void setName(const AString& sceneName); + SceneInfo& operator=(const SceneInfo&); /** name of scene*/ @@ -90,6 +98,9 @@ namespace caret { // ADD_NEW_MEMBERS_HERE + friend class Scene; + friend class SceneInfoSaxReader; + friend class SceneInfoXmlStreamReader; }; #ifdef __SCENE_INFO_DECLARE__ diff --git a/src/Scenes/SceneInfoSaxReader.cxx b/src/Scenes/SceneInfoSaxReader.cxx index 7f5d35adf0d152c2de7c82aa442a6c75597e0a44..04ac99f2bd02436f486710496ac740cbab13bcab 100644 --- a/src/Scenes/SceneInfoSaxReader.cxx +++ b/src/Scenes/SceneInfoSaxReader.cxx @@ -24,7 +24,6 @@ #include "SceneInfo.h" #include "SceneInfoSaxReader.h" #include "SceneXmlElements.h" - #include "XmlAttributes.h" #include "XmlException.h" #include "XmlUtilities.h" @@ -104,6 +103,10 @@ SceneInfoSaxReader::startElement(const AString& /* namespaceURI */, else if (qName == SceneXmlElements::SCENE_INFO_BALSA_SCENE_ID_TAG) { m_state = STATE_SCENE_INFO_BALSA_ID; } + else if (qName == SceneXmlElements::SCENE_INFO_MACRO_GROUP) { + m_state = STATE_SCENE_INFO_MACRO_GROUP; + break; + } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(SceneXmlElements::SCENE_INFO_TAG, qName); @@ -112,6 +115,8 @@ SceneInfoSaxReader::startElement(const AString& /* namespaceURI */, m_state = STATE_SCENE_INFO_UNRECOGNIZED; } break; + case STATE_SCENE_INFO_MACRO_GROUP: + break; case STATE_SCENE_INFO_NAME: break; case STATE_SCENE_INFO_DESCRIPTION: @@ -170,6 +175,10 @@ SceneInfoSaxReader::endElement(const AString& /* namspaceURI */, break; case STATE_SCENE_INFO_UNRECOGNIZED: break; + case STATE_SCENE_INFO_MACRO_GROUP: + /* Should skip over macro group */ + CaretLogSevere("Encountered WuQMacroGroup while reading. Need to use newer stream reader."); + break; } /* diff --git a/src/Scenes/SceneInfoSaxReader.h b/src/Scenes/SceneInfoSaxReader.h index aae2479c99a68d5ed265bf4179cf7aa586a8d786..4a14f0b2ae79522bc4b522d0f3375fb9cc4e09da 100644 --- a/src/Scenes/SceneInfoSaxReader.h +++ b/src/Scenes/SceneInfoSaxReader.h @@ -81,6 +81,8 @@ namespace caret { STATE_SCENE_INFO_DESCRIPTION, /// processing Scene Info thumbnail tag STATE_SCENE_INFO_IMAGE_THUMBNAIL, + /// processing Scene Info macro group tag + STATE_SCENE_INFO_MACRO_GROUP, /// process an unrecognized element in Scene Info STATE_SCENE_INFO_UNRECOGNIZED }; diff --git a/src/Scenes/SceneInfoXmlStreamBase.cxx b/src/Scenes/SceneInfoXmlStreamBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4f587d99cee962ca5360a94cc110ae89ed569031 --- /dev/null +++ b/src/Scenes/SceneInfoXmlStreamBase.cxx @@ -0,0 +1,62 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_INFO_XML_STREAM_BASE_DECLARE__ +#include "SceneInfoXmlStreamBase.h" +#undef __SCENE_INFO_XML_STREAM_BASE_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SceneInfoXmlStreamBase + * \brief Base class for SceneInfo XML Stream Reader and Writer + * \ingroup Scenes + */ + +/** + * Constructor. + */ +SceneInfoXmlStreamBase::SceneInfoXmlStreamBase() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +SceneInfoXmlStreamBase::~SceneInfoXmlStreamBase() +{ +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +SceneInfoXmlStreamBase::toString() const +{ + return "SceneInfoXmlStreamBase"; +} + diff --git a/src/Scenes/SceneInfoXmlStreamBase.h b/src/Scenes/SceneInfoXmlStreamBase.h new file mode 100644 index 0000000000000000000000000000000000000000..30859e1000365e7ffcfe4d2c7f81249b2953ef62 --- /dev/null +++ b/src/Scenes/SceneInfoXmlStreamBase.h @@ -0,0 +1,81 @@ +#ifndef __SCENE_INFO_XML_STREAM_BASE_H__ +#define __SCENE_INFO_XML_STREAM_BASE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class SceneInfoXmlStreamBase : public CaretObject { + + public: + SceneInfoXmlStreamBase(); + + virtual ~SceneInfoXmlStreamBase(); + + SceneInfoXmlStreamBase(const SceneInfoXmlStreamBase&) = delete; + + SceneInfoXmlStreamBase& operator=(const SceneInfoXmlStreamBase&) = delete; + + static const AString ELEMENT_BALSA_SCENE_ID; + static const AString ELEMENT_DESCRIPTION; + static const AString ELEMENT_IMAGE; + static const AString ELEMENT_NAME; + static const AString ELEMENT_SCENE_INFO; + + static const AString ATTRIBUTE_IMAGE_ENCODING; + static const AString ATTRIBUTE_IMAGE_FORMAT; + static const AString ATTRIBUTE_SCENE_INDEX; + + static const AString VALUE_ENCODING_BASE64; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_INFO_XML_STREAM_BASE_DECLARE__ + const AString SceneInfoXmlStreamBase::ELEMENT_BALSA_SCENE_ID = "BalsaSceneID"; + const AString SceneInfoXmlStreamBase::ELEMENT_DESCRIPTION = "Description"; + const AString SceneInfoXmlStreamBase::ELEMENT_IMAGE = "Image"; + const AString SceneInfoXmlStreamBase::ELEMENT_NAME = "Name"; + const AString SceneInfoXmlStreamBase::ELEMENT_SCENE_INFO = "SceneInfo"; + + const AString SceneInfoXmlStreamBase::ATTRIBUTE_IMAGE_ENCODING = "Encoding"; + const AString SceneInfoXmlStreamBase::ATTRIBUTE_IMAGE_FORMAT = "Format"; + const AString SceneInfoXmlStreamBase::ATTRIBUTE_SCENE_INDEX = "Index"; + + const AString SceneInfoXmlStreamBase::VALUE_ENCODING_BASE64 = "Base64"; +#endif // __SCENE_INFO_XML_STREAM_BASE_DECLARE__ + +} // namespace +#endif //__SCENE_INFO_XML_STREAM_BASE_H__ diff --git a/src/Scenes/SceneInfoXmlStreamReader.cxx b/src/Scenes/SceneInfoXmlStreamReader.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3bed9a3ac4b2f8a7493a6423a4544e4f05071608 --- /dev/null +++ b/src/Scenes/SceneInfoXmlStreamReader.cxx @@ -0,0 +1,136 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_INFO_XML_STREAM_READER_DECLARE__ +#include "SceneInfoXmlStreamReader.h" +#undef __SCENE_INFO_XML_STREAM_READER_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +#include "SceneInfo.h" + +using namespace caret; + + + +/** + * \class caret::SceneInfoXmlStreamReader + * \brief XML Stream Reader for SceneInfo + * \ingroup Scenes + */ + +/** + * Constructor. + */ +SceneInfoXmlStreamReader::SceneInfoXmlStreamReader() +: SceneInfoXmlStreamBase() +{ + +} + +/** + * Destructor. + */ +SceneInfoXmlStreamReader::~SceneInfoXmlStreamReader() +{ +} + +/** + * Read the scene info. + * If, after calling this method, xmlReader.hasError() return true, + * there was an error reading the SceneInfo. + * + * @param xmlReader + * The XML stream reader + * @param sceneInfo + * Read into this sceneInfo + */ +void +SceneInfoXmlStreamReader::readSceneInfo(QXmlStreamReader& xmlReader, + SceneInfo* sceneInfo) +{ + CaretAssert(sceneInfo); + if (sceneInfo == NULL) { + return; + } + + if (xmlReader.name() != ELEMENT_SCENE_INFO) { + xmlReader.raiseError("First element is \"" + + xmlReader.name().toString() + + "\" but should be " + + ELEMENT_SCENE_INFO); + return; + } + + /* + * Gets set when ending scene info directory element is read + */ + bool endElementFound(false); + + while ( (! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + switch (xmlReader.tokenType()) { + case QXmlStreamReader::StartElement: + if (xmlReader.name() == ELEMENT_NAME) { + sceneInfo->setName(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_BALSA_SCENE_ID) { + sceneInfo->setBalsaSceneID(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_DESCRIPTION) { + sceneInfo->setDescription(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_IMAGE) { + const QXmlStreamAttributes atts = xmlReader.attributes(); + const QString encodingName = atts.value(ATTRIBUTE_IMAGE_ENCODING).toString(); + const QString formatName = atts.value(ATTRIBUTE_IMAGE_FORMAT).toString(); + sceneInfo->setImageFromText(xmlReader.readElementText(), + encodingName, + formatName); + } + else { + m_unexpectedXmlElements.insert(xmlReader.name().toString()); + xmlReader.skipCurrentElement(); + } + break; + case QXmlStreamReader::EndElement: + if (xmlReader.name() == ELEMENT_SCENE_INFO) { + endElementFound = true; + } + break; + default: + break; + } + } +} + +/** + * @return Any unexpected elements that were found, + * and ignored, while reading the SceneInfo XML. + */ +std::set +SceneInfoXmlStreamReader::getUnexpectedElements() const +{ + return m_unexpectedXmlElements; +} diff --git a/src/Scenes/SceneInfoXmlStreamReader.h b/src/Scenes/SceneInfoXmlStreamReader.h new file mode 100644 index 0000000000000000000000000000000000000000..e619a2c662ce159eef313313d5cf296054c4b4af --- /dev/null +++ b/src/Scenes/SceneInfoXmlStreamReader.h @@ -0,0 +1,66 @@ +#ifndef __SCENE_INFO_XML_STREAM_READER_H__ +#define __SCENE_INFO_XML_STREAM_READER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include +#include + +#include "SceneInfoXmlStreamBase.h" + +class QXmlStreamReader; + +namespace caret { + + class SceneInfo; + + class SceneInfoXmlStreamReader : public SceneInfoXmlStreamBase { + + public: + SceneInfoXmlStreamReader(); + + virtual ~SceneInfoXmlStreamReader(); + + SceneInfoXmlStreamReader(const SceneInfoXmlStreamReader&) = delete; + + SceneInfoXmlStreamReader& operator=(const SceneInfoXmlStreamReader&) = delete; + + void readSceneInfo(QXmlStreamReader& xmlReader, + SceneInfo* sceneInfo); + + std::set getUnexpectedElements() const; + + // ADD_NEW_METHODS_HERE + + private: + std::set m_unexpectedXmlElements; + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_INFO_XML_STREAM_READER_DECLARE__ + // +#endif // __SCENE_INFO_XML_STREAM_READER_DECLARE__ + +} // namespace +#endif //__SCENE_INFO_XML_STREAM_READER_H__ diff --git a/src/Scenes/SceneInfoXmlStreamWriter.cxx b/src/Scenes/SceneInfoXmlStreamWriter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..47159fb40949b52c4044769ebcb405a74533f5e6 --- /dev/null +++ b/src/Scenes/SceneInfoXmlStreamWriter.cxx @@ -0,0 +1,121 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_INFO_XML_STREAM_WRITER_DECLARE__ +#include "SceneInfoXmlStreamWriter.h" +#undef __SCENE_INFO_XML_STREAM_WRITER_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "SceneInfo.h" +#include "WuQMacroGroupXmlStreamWriter.h" + +using namespace caret; + +/** + * \class caret::SceneInfoXmlStreamWriter + * \brief XML stream writer for SceneInfo + * \ingroup Scenes + */ + +/** + * Constructor. + */ +SceneInfoXmlStreamWriter::SceneInfoXmlStreamWriter() +: SceneInfoXmlStreamBase() +{ + +} + +/** + * Destructor. + */ +SceneInfoXmlStreamWriter::~SceneInfoXmlStreamWriter() +{ +} + +/** + * Write the given SceneInfo to the given xml stream writer + * + * @param xmlWriter + * The XML stream writer + * @param sceneInfo + * The scene info + * @param sceneInfoIndex + * Index of scene associated with the sceneInfo + */ +void +SceneInfoXmlStreamWriter::writeXML(QXmlStreamWriter* xmlWriter, + const SceneInfo* sceneInfo, + const int32_t sceneInfoIndex) +{ + CaretAssert(xmlWriter); + CaretAssert(sceneInfo); + CaretAssert(sceneInfoIndex >= 0); + + m_xmlWriter = xmlWriter; + + m_xmlWriter->writeStartElement(ELEMENT_SCENE_INFO); + m_xmlWriter->writeAttribute(ATTRIBUTE_SCENE_INDEX, + QString::number(sceneInfoIndex)); + + m_xmlWriter->writeTextElement(ELEMENT_NAME, + sceneInfo->getName()); + + m_xmlWriter->writeTextElement(ELEMENT_BALSA_SCENE_ID, + sceneInfo->getBalsaSceneID()); + + m_xmlWriter->writeTextElement(ELEMENT_DESCRIPTION, + sceneInfo->getDescription()); + + writeImageElement(sceneInfo); + + m_xmlWriter->writeEndElement(); + + m_xmlWriter = NULL; +} + +/** + * Write the image element + * + * @param sceneInfo + * The scene information + */ +void +SceneInfoXmlStreamWriter::writeImageElement(const SceneInfo* sceneInfo) +{ + QByteArray imageBytes; + AString imageFormat; + sceneInfo->getImageBytes(imageBytes, + imageFormat); + if (! imageBytes.isEmpty()) { + const QByteArray base64ByteArray(imageBytes.toBase64()); + QString base64String = QString::fromLatin1(base64ByteArray.constData(), + base64ByteArray.size()); + m_xmlWriter->writeStartElement(ELEMENT_IMAGE); + m_xmlWriter->writeAttribute(ATTRIBUTE_IMAGE_ENCODING, VALUE_ENCODING_BASE64); + m_xmlWriter->writeAttribute(ATTRIBUTE_IMAGE_FORMAT, imageFormat); + m_xmlWriter->writeCharacters(base64String); + m_xmlWriter->writeEndElement(); + } +} + diff --git a/src/Scenes/SceneInfoXmlStreamWriter.h b/src/Scenes/SceneInfoXmlStreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..be089568fdcc5462a176d2ca79c39aa835e7ce19 --- /dev/null +++ b/src/Scenes/SceneInfoXmlStreamWriter.h @@ -0,0 +1,68 @@ +#ifndef __SCENE_INFO_XML_STREAM_WRITER_H__ +#define __SCENE_INFO_XML_STREAM_WRITER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "SceneInfoXmlStreamBase.h" + +class QXmlStreamWriter; + +namespace caret { + + class SceneInfo; + + class SceneInfoXmlStreamWriter : public SceneInfoXmlStreamBase { + + public: + SceneInfoXmlStreamWriter(); + + virtual ~SceneInfoXmlStreamWriter(); + + void writeXML(QXmlStreamWriter* xmlWriter, + const SceneInfo* sceneInfo, + const int32_t sceneInfoIndex); + + SceneInfoXmlStreamWriter(const SceneInfoXmlStreamWriter&) = delete; + + SceneInfoXmlStreamWriter& operator=(const SceneInfoXmlStreamWriter&) = delete; + + + // ADD_NEW_METHODS_HERE + + private: + void writeImageElement(const SceneInfo* sceneInfo); + + QXmlStreamWriter* m_xmlWriter = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_INFO_XML_STREAM_WRITER_DECLARE__ + // +#endif // __SCENE_INFO_XML_STREAM_WRITER_DECLARE__ + +} // namespace +#endif //__SCENE_INFO_XML_STREAM_WRITER_H__ diff --git a/src/Scenes/SceneObject.cxx b/src/Scenes/SceneObject.cxx index f1b085d567f43bf055fbc6528689d55fbe32dd53..15ec970be0ce3b50abc96d5517ff63541fc9c358 100644 --- a/src/Scenes/SceneObject.cxx +++ b/src/Scenes/SceneObject.cxx @@ -42,15 +42,18 @@ using namespace caret; * Constructor. * @param name * Name of the item. + * @param containerType + * Type of container of object (array, map, single). * @param dataType * Data type of the primitive. */ SceneObject::SceneObject(const QString& name, + const SceneObjectContainerTypeEnum::Enum containerType, const SceneObjectDataTypeEnum::Enum dataType) #ifdef CARET_SCENE_DEBUG -: CaretObject(), m_name(name), m_dataType(dataType), m_restoredFlag(false) +: CaretObject(), m_name(name), m_containerType(containerType), m_dataType(dataType), m_restoredFlag(false) #else // CARET_SCENE_DEBUG -: m_name(name), m_dataType(dataType), m_restoredFlag(false) +: m_name(name), m_containerType(containerType), m_dataType(dataType), m_restoredFlag(false) #endif // CARET_SCENE_DEBUG { CaretAssert(name.isEmpty() == false); @@ -73,6 +76,15 @@ SceneObject::getName() const return m_name; } +/** + * @return Type of container of object (array, map, single) + */ +SceneObjectContainerTypeEnum::Enum +SceneObject::getContainerType() const +{ + return m_containerType; +} + /** * @return Data type of the object. */ @@ -203,3 +215,148 @@ SceneObject::toString() const + m_name); return objectInfo; } + +/** + * Cast an instance of SceneObject to a SceneClass. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const SceneClass* +SceneObject::castToSceneClass() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a SceneClass. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +SceneClass* +SceneObject::castToSceneClass() +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a SceneEnumeratedType. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneEnumeratedType + */ +const SceneEnumeratedType* +SceneObject::castToSceneEnumeratedType() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a SceneEnumeratedType. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneEnumeratedType + */ +SceneEnumeratedType* +SceneObject::castToSceneEnumeratedType() +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a SceneObjectArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectArray + */ +const SceneObjectArray* +SceneObject::castToSceneObjectArray() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a SceneObjectArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectArray + */ +SceneObjectArray* +SceneObject::castToSceneObjectArray() +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a SceneObjectMapIntegerKey. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectMapIntegerKey + */ +SceneObjectMapIntegerKey* +SceneObject::castToSceneObjectMapIntegerKey() +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a SceneObjectMapIntegerKey. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectMapIntegerKey + */ +const SceneObjectMapIntegerKey* +SceneObject::castToSceneObjectMapIntegerKey() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a ScenePathName. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePathName + */ +ScenePathName* +SceneObject::castToScenePathName() +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a ScenePathName. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePathName + */ +const ScenePathName* +SceneObject::castToScenePathName() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a ScenePrimitive. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePrimitive + */ +ScenePrimitive* +SceneObject::castToScenePrimitive() +{ + return NULL; +} + +/** + * Cast an instance of SceneObject to a ScenePrimitive. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePrimitive + */ +const ScenePrimitive* +SceneObject::castToScenePrimitive() const +{ + return NULL; +} + diff --git a/src/Scenes/SceneObject.h b/src/Scenes/SceneObject.h index bd4b0070931802e3eae2005d47260611866ea286..3f27164425c68fb76570055948d76e434e944a32 100644 --- a/src/Scenes/SceneObject.h +++ b/src/Scenes/SceneObject.h @@ -23,10 +23,18 @@ #include "CaretObject.h" +#include "SceneObjectContainerTypeEnum.h" #include "SceneObjectDataTypeEnum.h" namespace caret { + class SceneClass; + class SceneEnumeratedType; + class SceneObjectArray; + class SceneObjectMapIntegerKey; + class ScenePathName; + class ScenePrimitive; + #ifdef CARET_SCENE_DEBUG class SceneObject : public CaretObject { #else // CARET_SCENE_DEBUG @@ -38,6 +46,8 @@ namespace caret { QString getName() const; + SceneObjectContainerTypeEnum::Enum getContainerType() const; + SceneObjectDataTypeEnum::Enum getDataType() const; bool isRestored() const; @@ -55,8 +65,33 @@ namespace caret { /// Should be overridden by any sub-classes that have children virtual std::vector getDescendants() const; + virtual SceneClass* castToSceneClass(); + + virtual const SceneClass* castToSceneClass() const; + + virtual SceneEnumeratedType* castToSceneEnumeratedType(); + + virtual const SceneEnumeratedType* castToSceneEnumeratedType() const; + + virtual SceneObjectArray* castToSceneObjectArray(); + + virtual const SceneObjectArray* castToSceneObjectArray() const; + + virtual SceneObjectMapIntegerKey* castToSceneObjectMapIntegerKey(); + + virtual const SceneObjectMapIntegerKey* castToSceneObjectMapIntegerKey() const; + + virtual ScenePathName* castToScenePathName(); + + virtual const ScenePathName* castToScenePathName() const; + + virtual ScenePrimitive* castToScenePrimitive(); + + virtual const ScenePrimitive* castToScenePrimitive() const; + protected: SceneObject(const QString& name, + const SceneObjectContainerTypeEnum::Enum containerType, const SceneObjectDataTypeEnum::Enum dataType); private: @@ -78,6 +113,9 @@ namespace caret { /** Name of the item*/ const QString m_name; + /** Container type of object */ + const SceneObjectContainerTypeEnum::Enum m_containerType; + /** Type of object */ const SceneObjectDataTypeEnum::Enum m_dataType; diff --git a/src/Scenes/SceneObjectArray.cxx b/src/Scenes/SceneObjectArray.cxx index 7ef2a8d0f23ba37bda3972c7ff19bc70ab5dc61e..da8d48dd2d6a53e722e8e52dc22782f33f727e61 100644 --- a/src/Scenes/SceneObjectArray.cxx +++ b/src/Scenes/SceneObjectArray.cxx @@ -47,6 +47,7 @@ using namespace caret; SceneObjectArray::SceneObjectArray(const QString& name, const SceneObjectDataTypeEnum::Enum dataType) : SceneObject(name, + SceneObjectContainerTypeEnum::ARRAY, dataType) { @@ -60,3 +61,122 @@ SceneObjectArray::~SceneObjectArray() } +/** + * Cast an instance of SceneObject to a SceneObjectArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectArray + */ +SceneObjectArray* +SceneObjectArray::castToSceneObjectArray() +{ + return this; +} + +/** + * Cast an instance of SceneObject to a SceneObjectArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectArray + */ +const SceneObjectArray* +SceneObjectArray::castToSceneObjectArray() const +{ + return this; +} + +/** + * Cast an instance of SceneObjectArray to a SceneClassArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +SceneClassArray* +SceneObjectArray::castToSceneClassArray() +{ + return NULL; +} + +/** + * Cast an instance of SceneObjectArray to a SceneClassArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const SceneClassArray* +SceneObjectArray::castToSceneClassArray() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObjectArray to a SceneEnumeratedTypeArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +SceneEnumeratedTypeArray* +SceneObjectArray::castToSceneEnumeratedTypeArray() +{ + return NULL; +} + +/** + * Cast an instance of SceneObjectArray to a SceneEnumeratedTypeArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const SceneEnumeratedTypeArray* +SceneObjectArray::castToSceneEnumeratedTypeArray() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObjectArray to a ScenePathNameArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +ScenePathNameArray* +SceneObjectArray::castToScenePathNameArray() +{ + return NULL; +} + +/** + * Cast an instance of SceneObjectArray to a ScenePathNameArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const ScenePathNameArray* +SceneObjectArray::castToScenePathNameArray() const +{ + return NULL; +} + +/** + * Cast an instance of SceneObjectArray to a ScenePrimitiveArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +ScenePrimitiveArray* +SceneObjectArray::castToScenePrimitiveArray() +{ + return NULL; +} + +/** + * Cast an instance of SceneObjectArray to a ScenePrimitiveArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const ScenePrimitiveArray* +SceneObjectArray::castToScenePrimitiveArray() const +{ + return NULL; +} diff --git a/src/Scenes/SceneObjectArray.h b/src/Scenes/SceneObjectArray.h index 206e0d549453621518f6bbd8c5fcf6b17a63635f..8470059477923b73ffe802482d41e972381bbf12 100644 --- a/src/Scenes/SceneObjectArray.h +++ b/src/Scenes/SceneObjectArray.h @@ -25,6 +25,10 @@ #include "SceneObject.h" namespace caret { + class SceneClassArray; + class SceneEnumeratedTypeArray; + class ScenePathNameArray; + class ScenePrimitiveArray; class SceneObjectArray : public SceneObject { @@ -34,6 +38,26 @@ namespace caret { virtual ~SceneObjectArray(); + virtual SceneObjectArray* castToSceneObjectArray(); + + virtual const SceneObjectArray* castToSceneObjectArray() const; + + virtual SceneClassArray* castToSceneClassArray(); + + virtual const SceneClassArray* castToSceneClassArray() const; + + virtual SceneEnumeratedTypeArray* castToSceneEnumeratedTypeArray(); + + virtual const SceneEnumeratedTypeArray* castToSceneEnumeratedTypeArray() const; + + virtual ScenePathNameArray* castToScenePathNameArray(); + + virtual const ScenePathNameArray* castToScenePathNameArray() const; + + virtual ScenePrimitiveArray* castToScenePrimitiveArray(); + + virtual const ScenePrimitiveArray* castToScenePrimitiveArray() const; + private: SceneObjectArray(const SceneObjectArray&); diff --git a/src/Scenes/SceneObjectContainerTypeEnum.cxx b/src/Scenes/SceneObjectContainerTypeEnum.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b183638cc6a04e111c03b4ca99d879f2b44a6522 --- /dev/null +++ b/src/Scenes/SceneObjectContainerTypeEnum.cxx @@ -0,0 +1,377 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __SCENE_OBJECT_CONTAINER_TYPE_ENUM_DECLARE__ +#include "SceneObjectContainerTypeEnum.h" +#undef __SCENE_OBJECT_CONTAINER_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::SceneObjectContainerTypeEnum + * \brief Type of container for a scene object class instance + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_sceneObjectContainerTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void sceneObjectContainerTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "SceneObjectContainerTypeEnum.h" + * + * Instatiate: + * m_sceneObjectContainerTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_sceneObjectContainerTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_sceneObjectContainerTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(sceneObjectContainerTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_sceneObjectContainerTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const SceneObjectContainerTypeEnum::Enum VARIABLE = m_sceneObjectContainerTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +SceneObjectContainerTypeEnum::SceneObjectContainerTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +SceneObjectContainerTypeEnum::~SceneObjectContainerTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +SceneObjectContainerTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(SceneObjectContainerTypeEnum(ARRAY, + "ARRAY", + "Array")); + + enumData.push_back(SceneObjectContainerTypeEnum(MAP, + "MAP", + "Map")); + + enumData.push_back(SceneObjectContainerTypeEnum(SINGLE, + "SINGLE", + "Single")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const SceneObjectContainerTypeEnum* +SceneObjectContainerTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const SceneObjectContainerTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +SceneObjectContainerTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const SceneObjectContainerTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +SceneObjectContainerTypeEnum::Enum +SceneObjectContainerTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = SceneObjectContainerTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const SceneObjectContainerTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SceneObjectContainerTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +SceneObjectContainerTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const SceneObjectContainerTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +SceneObjectContainerTypeEnum::Enum +SceneObjectContainerTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = SceneObjectContainerTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const SceneObjectContainerTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SceneObjectContainerTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +SceneObjectContainerTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const SceneObjectContainerTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +SceneObjectContainerTypeEnum::Enum +SceneObjectContainerTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = SceneObjectContainerTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const SceneObjectContainerTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SceneObjectContainerTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +SceneObjectContainerTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +SceneObjectContainerTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(SceneObjectContainerTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +SceneObjectContainerTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(SceneObjectContainerTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Scenes/SceneObjectContainerTypeEnum.h b/src/Scenes/SceneObjectContainerTypeEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..e8e85948e1949a5df2d4e05480269748383f028f --- /dev/null +++ b/src/Scenes/SceneObjectContainerTypeEnum.h @@ -0,0 +1,106 @@ +#ifndef __SCENE_OBJECT_CONTAINER_TYPE_ENUM_H__ +#define __SCENE_OBJECT_CONTAINER_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class SceneObjectContainerTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Array */ + ARRAY, + /** Map */ + MAP, + /** Single (one value) */ + SINGLE + }; + + + ~SceneObjectContainerTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + SceneObjectContainerTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const SceneObjectContainerTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __SCENE_OBJECT_CONTAINER_TYPE_ENUM_DECLARE__ +std::vector SceneObjectContainerTypeEnum::enumData; +bool SceneObjectContainerTypeEnum::initializedFlag = false; +int32_t SceneObjectContainerTypeEnum::integerCodeCounter = 0; +#endif // __SCENE_OBJECT_CONTAINER_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__SCENE_OBJECT_CONTAINER_TYPE_ENUM_H__ diff --git a/src/Scenes/SceneObjectMapIntegerKey.cxx b/src/Scenes/SceneObjectMapIntegerKey.cxx index 362a439369bac07ad7f075900f83fd3a9711405d..c87302582f3401f98f484c8ffed272b8b2ca54a3 100644 --- a/src/Scenes/SceneObjectMapIntegerKey.cxx +++ b/src/Scenes/SceneObjectMapIntegerKey.cxx @@ -60,7 +60,8 @@ using namespace caret; */ SceneObjectMapIntegerKey::SceneObjectMapIntegerKey(const QString& name, const SceneObjectDataTypeEnum::Enum valueDataType) -: SceneObject(name, +: SceneObject(name, + SceneObjectContainerTypeEnum::MAP, valueDataType) { @@ -78,6 +79,30 @@ SceneObjectMapIntegerKey::~SceneObjectMapIntegerKey() } } +/** + * Cast an instance of SceneObject to a SceneObjectMapIntegerKey. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectMapIntegerKey + */ +SceneObjectMapIntegerKey* +SceneObjectMapIntegerKey::castToSceneObjectMapIntegerKey() +{ + return this; +} + +/** + * Cast an instance of SceneObject to a SceneObjectMapIntegerKey. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneObjectMapIntegerKey + */ +const SceneObjectMapIntegerKey* +SceneObjectMapIntegerKey::castToSceneObjectMapIntegerKey() const +{ + return this; +} + /** * @return True if this map's content is empty, else false. */ diff --git a/src/Scenes/SceneObjectMapIntegerKey.h b/src/Scenes/SceneObjectMapIntegerKey.h index 9c430d16e338ac75cbce62319e8bc25fa1d97812..74a91fb3faab58e8d75e341128a46cae74322feb 100644 --- a/src/Scenes/SceneObjectMapIntegerKey.h +++ b/src/Scenes/SceneObjectMapIntegerKey.h @@ -37,6 +37,10 @@ namespace caret { SceneObjectMapIntegerKey(const QString& name, const SceneObjectDataTypeEnum::Enum valueDataType); + virtual SceneObjectMapIntegerKey* castToSceneObjectMapIntegerKey(); + + virtual const SceneObjectMapIntegerKey* castToSceneObjectMapIntegerKey() const; + virtual std::vector getDescendants() const; private: diff --git a/src/Scenes/ScenePathName.cxx b/src/Scenes/ScenePathName.cxx index aa1627b1fbb31c5eac900f8d14387a9768ffd42b..c646731e71b6ccc0ff8782bd43cc26c148222669 100644 --- a/src/Scenes/ScenePathName.cxx +++ b/src/Scenes/ScenePathName.cxx @@ -62,12 +62,16 @@ using namespace caret; ScenePathName::ScenePathName(const AString& name, const AString& value) : SceneObject(name, + SceneObjectContainerTypeEnum::SINGLE, SceneObjectDataTypeEnum::SCENE_PATH_NAME) { setValue(value); } -ScenePathName::ScenePathName(const ScenePathName& rhs): SceneObject(rhs.getName(), SceneObjectDataTypeEnum::SCENE_PATH_NAME) +ScenePathName::ScenePathName(const ScenePathName& rhs) +: SceneObject(rhs.getName(), + SceneObjectContainerTypeEnum::SINGLE, + SceneObjectDataTypeEnum::SCENE_PATH_NAME) { m_value = rhs.m_value; } @@ -85,6 +89,30 @@ ScenePathName::~ScenePathName() } +/** + * Cast an instance of SceneObject to a ScenePathName. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePathName + */ +ScenePathName* +ScenePathName::castToScenePathName() +{ + return this; +} + +/** + * Cast an instance of SceneObject to a ScenePathName. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePathName + */ +const ScenePathName* +ScenePathName::castToScenePathName() const +{ + return this; +} + /** * Set the value. * @param value diff --git a/src/Scenes/ScenePathName.h b/src/Scenes/ScenePathName.h index 3bd205c4430afd5298486a01db4fd7c758e6faf3..0a9a7eee1ae41d0fc755fc9c0a8514cd0b2d4f5f 100644 --- a/src/Scenes/ScenePathName.h +++ b/src/Scenes/ScenePathName.h @@ -36,6 +36,10 @@ namespace caret { virtual ~ScenePathName(); + virtual ScenePathName* castToScenePathName(); + + virtual const ScenePathName* castToScenePathName() const; + void setValue(const AString& value); virtual AString stringValue() const; diff --git a/src/Scenes/ScenePathNameArray.cxx b/src/Scenes/ScenePathNameArray.cxx index 4a53446f5215cd63e9abc417fca394e1b89acee0..ad6f5f09e46cc0a38272fcd51199218ab6ec1d28 100644 --- a/src/Scenes/ScenePathNameArray.cxx +++ b/src/Scenes/ScenePathNameArray.cxx @@ -122,6 +122,30 @@ ScenePathNameArray::~ScenePathNameArray() m_values.clear(); } +/** + * Cast an instance of SceneObjectArray to a ScenePathNameArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +ScenePathNameArray* +ScenePathNameArray::castToScenePathNameArray() +{ + return this; +} + +/** + * Cast an instance of SceneObjectArray to a ScenePathNameArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const ScenePathNameArray* +ScenePathNameArray::castToScenePathNameArray() const +{ + return this; +} + /** * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. */ diff --git a/src/Scenes/ScenePathNameArray.h b/src/Scenes/ScenePathNameArray.h index dcc6d16ac193b9ee620e6c5548013c0cc1c9592d..d639a15a09b288a73cbd290516f153ee82443d84 100644 --- a/src/Scenes/ScenePathNameArray.h +++ b/src/Scenes/ScenePathNameArray.h @@ -45,6 +45,10 @@ namespace caret { virtual ~ScenePathNameArray(); + virtual ScenePathNameArray* castToScenePathNameArray(); + + virtual const ScenePathNameArray* castToScenePathNameArray() const; + void setScenePathNameAtIndex(const int32_t arrayIndex, const AString& sceneFileName, const AString& pathNameValue); diff --git a/src/Scenes/ScenePrimitive.cxx b/src/Scenes/ScenePrimitive.cxx index 70b707b98f87664e0831c9c84cfba536391f392c..fa29bcd6c520f032947b80245ebaea1e92946dca 100644 --- a/src/Scenes/ScenePrimitive.cxx +++ b/src/Scenes/ScenePrimitive.cxx @@ -47,7 +47,9 @@ using namespace caret; */ ScenePrimitive::ScenePrimitive(const QString& name, const SceneObjectDataTypeEnum::Enum dataType) -: SceneObject(name, dataType) +: SceneObject(name, + SceneObjectContainerTypeEnum::SINGLE, + dataType) { } @@ -60,6 +62,30 @@ ScenePrimitive::~ScenePrimitive() } +/** + * Cast an instance of SceneObject to a ScenePrimitive. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePrimitive + */ +ScenePrimitive* +ScenePrimitive::castToScenePrimitive() +{ + return this; +} + +/** + * Cast an instance of SceneObject to a ScenePrimitive. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is ScenePrimitive + */ +const ScenePrimitive* +ScenePrimitive::castToScenePrimitive() const +{ + return this; +} + /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Scenes/ScenePrimitive.h b/src/Scenes/ScenePrimitive.h index e64c158dfc70e4fd22ccfd97645902da1a53bb3a..cbe27681b0362e8e6e5b8cf20435dbf1519a92f3 100644 --- a/src/Scenes/ScenePrimitive.h +++ b/src/Scenes/ScenePrimitive.h @@ -31,6 +31,10 @@ namespace caret { public: virtual ~ScenePrimitive(); + virtual ScenePrimitive* castToScenePrimitive(); + + virtual const ScenePrimitive* castToScenePrimitive() const; + protected: ScenePrimitive(const QString& name, const SceneObjectDataTypeEnum::Enum dataType); diff --git a/src/Scenes/ScenePrimitiveArray.cxx b/src/Scenes/ScenePrimitiveArray.cxx index c8959fb0a63ba92e3d6c54ddf52e26f9de81a865..56b3084ad3dc84efc3ce368d6b844a13a496b9b5 100644 --- a/src/Scenes/ScenePrimitiveArray.cxx +++ b/src/Scenes/ScenePrimitiveArray.cxx @@ -61,6 +61,30 @@ ScenePrimitiveArray::~ScenePrimitiveArray() } +/** + * Cast an instance of SceneObjectArray to a ScenePrimitiveArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +ScenePrimitiveArray* +ScenePrimitiveArray::castToScenePrimitiveArray() +{ + return this; +} + +/** + * Cast an instance of SceneObjectArray to a ScenePrimitiveArray. + * Is used to avoid dynamic casting and overridden by the class. + * + * @return Valid pointer (non-NULL) this is SceneClass + */ +const ScenePrimitiveArray* +ScenePrimitiveArray::castToScenePrimitiveArray() const +{ + return this; +} + /** * Load the array with boolean values. * @param valuesOut diff --git a/src/Scenes/ScenePrimitiveArray.h b/src/Scenes/ScenePrimitiveArray.h index 2424815efd4140f893edd2569ba5d5b72dca4970..80596884ba113c9baa7113f6bfaf722c66fe0a81 100644 --- a/src/Scenes/ScenePrimitiveArray.h +++ b/src/Scenes/ScenePrimitiveArray.h @@ -31,6 +31,10 @@ namespace caret { public: virtual ~ScenePrimitiveArray(); + virtual ScenePrimitiveArray* castToScenePrimitiveArray(); + + virtual const ScenePrimitiveArray* castToScenePrimitiveArray() const; + protected: ScenePrimitiveArray(const QString& name, const SceneObjectDataTypeEnum::Enum dataType); diff --git a/src/Scenes/SceneXmlElements.h b/src/Scenes/SceneXmlElements.h index 5ea4d3423ebb470e10e7798c7a5610ace2d8c173..3ae40f593676ce7deab87f9bc459cf419368af4f 100644 --- a/src/Scenes/SceneXmlElements.h +++ b/src/Scenes/SceneXmlElements.h @@ -177,6 +177,11 @@ namespace caret { */ static const AString SCENE_INFO_BASE_PATH_TYPE = "BasePathType"; + /** + * XML Tag for Macros in Scene Info + */ + static const AString SCENE_INFO_MACRO_GROUP = "SceneFileMacroGroup"; + } // namespace SceneXmlElements } // namespace caret diff --git a/src/Scenes/SceneXmlStreamBase.cxx b/src/Scenes/SceneXmlStreamBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2df1811eeded142dadc5a05ca1a0b11f653ca5d6 --- /dev/null +++ b/src/Scenes/SceneXmlStreamBase.cxx @@ -0,0 +1,62 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_XML_STREAM_BASE_DECLARE__ +#include "SceneXmlStreamBase.h" +#undef __SCENE_XML_STREAM_BASE_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SceneXmlStreamBase + * \brief Base class for Scene XML Stream Reader and Writer + * \ingroup Scenes + */ + +/** + * Constructor. + */ +SceneXmlStreamBase::SceneXmlStreamBase() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +SceneXmlStreamBase::~SceneXmlStreamBase() +{ +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +SceneXmlStreamBase::toString() const +{ + return "SceneXmlStreamBase"; +} + diff --git a/src/Scenes/SceneXmlStreamBase.h b/src/Scenes/SceneXmlStreamBase.h new file mode 100644 index 0000000000000000000000000000000000000000..3619ed544d3703c749079b2c613b5d4532fa4276 --- /dev/null +++ b/src/Scenes/SceneXmlStreamBase.h @@ -0,0 +1,125 @@ +#ifndef __SCENE_XML_STREAM_BASE_H__ +#define __SCENE_XML_STREAM_BASE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class SceneXmlStreamBase : public CaretObject { + + public: + SceneXmlStreamBase(); + + virtual ~SceneXmlStreamBase(); + + SceneXmlStreamBase(const SceneXmlStreamBase&) = delete; + + SceneXmlStreamBase& operator=(const SceneXmlStreamBase&) = delete; + + static const AString ELEMENT_SCENE; + static const AString ELEMENT_SCENE_DESCRIPTION; + static const AString ELEMENT_SCENE_NAME; + + static const AString ATTRIBUTE_SCENE_INDEX; + static const AString ATTRIBUTE_SCENE_TYPE; + + static const AString ELEMENT_OBJECT; + + static const AString ATTRIBUTE_OBJECT_CLASS; + static const AString ATTRIBUTE_OBJECT_NAME; + static const AString ATTRIBUTE_OBJECT_TYPE; + static const AString ATTRIBUTE_OBJECT_VERSION; + + + static const AString ELEMENT_OBJECT_ARRAY; + + static const AString ATTRIBUTE_OBJECT_ARRAY_NAME; + static const AString ATTRIBUTE_OBJECT_ARRAY_LENGTH; + static const AString ATTRIBUTE_OBJECT_ARRAY_TYPE; + + static const AString ELEMENT_OBJECT_ARRAY_ELEMENT; + + static const AString ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX; + + static const AString ELEMENT_OBJECT_MAP; + + static const AString ATTRIBUTE_OBJECT_MAP_NAME; + static const AString ATTRIBUTE_OBJECT_MAP_TYPE; + + static const AString ELEMENT_OBJECT_MAP_VALUE; + + static const AString ATTRIBUTE_OBJECT_MAP_VALUE_KEY; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_XML_STREAM_BASE_DECLARE__ + const AString SceneXmlStreamBase::ELEMENT_SCENE = "Scene"; + const AString SceneXmlStreamBase::ELEMENT_SCENE_DESCRIPTION = "Description"; + const AString SceneXmlStreamBase::ELEMENT_SCENE_NAME = "Name"; + + const AString SceneXmlStreamBase::ATTRIBUTE_SCENE_INDEX = "Index"; + const AString SceneXmlStreamBase::ATTRIBUTE_SCENE_TYPE = "Type"; + + const AString SceneXmlStreamBase::ELEMENT_OBJECT = "Object"; + + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_CLASS = "Class"; + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_NAME = "Name"; + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_TYPE = "Type"; + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_VERSION = "Version"; + + + const AString SceneXmlStreamBase::ELEMENT_OBJECT_ARRAY = "ObjectArray"; + + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_ARRAY_NAME = "Name"; + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_ARRAY_LENGTH = "Length"; + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_ARRAY_TYPE = "Type"; + + const AString SceneXmlStreamBase::ELEMENT_OBJECT_ARRAY_ELEMENT = "Element"; + + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX = "Index"; + + const AString SceneXmlStreamBase::ELEMENT_OBJECT_MAP = "ObjectMap"; + + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_MAP_NAME = "Name"; + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_MAP_TYPE = "Type"; + + const AString SceneXmlStreamBase::ELEMENT_OBJECT_MAP_VALUE = "Value"; + + const AString SceneXmlStreamBase::ATTRIBUTE_OBJECT_MAP_VALUE_KEY = "Key"; +#endif // __SCENE_XML_STREAM_BASE_DECLARE__ + +} // namespace +#endif //__SCENE_XML_STREAM_BASE_H__ diff --git a/src/Scenes/SceneXmlStreamReader.cxx b/src/Scenes/SceneXmlStreamReader.cxx new file mode 100644 index 0000000000000000000000000000000000000000..33e3bcb938dcb86144d96d61aa4547afffd2b26a --- /dev/null +++ b/src/Scenes/SceneXmlStreamReader.cxx @@ -0,0 +1,828 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_XML_STREAM_READER_DECLARE__ +#include "SceneXmlStreamReader.h" +#undef __SCENE_XML_STREAM_READER_DECLARE__ + +#include +#include + +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "DataFile.h" +#include "Scene.h" +#include "SceneBoolean.h" +#include "SceneBooleanArray.h" +#include "SceneClass.h" +#include "SceneClassArray.h" +#include "SceneEnumeratedType.h" +#include "SceneEnumeratedTypeArray.h" +#include "SceneFloat.h" +#include "SceneFloatArray.h" +#include "SceneInteger.h" +#include "SceneIntegerArray.h" +#include "SceneObjectMapIntegerKey.h" +#include "ScenePathName.h" +#include "ScenePathNameArray.h" +#include "SceneSaxReader.h" +#include "SceneString.h" +#include "SceneStringArray.h" +#include "SceneUnsignedByte.h" +#include "SceneUnsignedByteArray.h" +#include "SceneXmlElements.h" +#include "WuQMacroGroup.h" +#include "WuQMacroGroupXmlStreamReader.h" + +using namespace caret; + + + +/** + * \class caret::SceneXmlStreamReader + * \brief XML stream reader for Scene + * \ingroup Scenes + */ + +/** + * Constructor. + */ +SceneXmlStreamReader::SceneXmlStreamReader() +: SceneXmlStreamBase() +{ + +} + +/** + * Destructor. + */ +SceneXmlStreamReader::~SceneXmlStreamReader() +{ +} + +/** + * Read a scene from the given XML stream reader. It assumes that + * the start element for the scene has already been read and is + * the current element. If xmlReader.hasError() is set after this + * method is called, there was an error reading the scene. + * + * @param xmlReader + * The XML stream reader + * @param scene + * The scene + * @param sceneFileName + * Name of the scene file + */ +void +SceneXmlStreamReader::readScene(QXmlStreamReader& xmlReader, + Scene* scene, + const AString& sceneFileName) +{ + CaretAssert(scene); + if (scene == NULL) { + return; + } + + m_filename = sceneFileName; + + if (xmlReader.name() == ELEMENT_SCENE) { + /* + * Set when ending scene element is found + */ + bool endElementFound(false); + + while ( ( ! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + + switch (xmlReader.tokenType()) { + case QXmlStreamReader::StartElement: + { + if (xmlReader.name() == ELEMENT_SCENE_NAME) { + scene->setName(xmlReader.readElementText()); + } + else if (xmlReader.name() == ELEMENT_SCENE_DESCRIPTION) { + scene->setDescription(xmlReader.readElementText()); + } + else if (xmlReader.name() == WuQMacroGroupXmlStreamReader::ELEMENT_MACRO_GROUP) { + WuQMacroGroupXmlStreamReader macroGroupReader; + macroGroupReader.readMacroGroup(xmlReader, + scene->getMacroGroup()); + } + else if (xmlReader.name() == ELEMENT_OBJECT) { + SceneObject* object = readSceneObject(xmlReader); + if (object != NULL) { + if (object->castToSceneClass()) { + scene->addClass(object->castToSceneClass()); + } + else { + delete object; + xmlReader.raiseError("Child of Scene is not a SceneClass"); + } + } + } + else { + m_unrecognizedElements.insert(xmlReader.name().toString()); + xmlReader.skipCurrentElement(); + } + } + break; + case QXmlStreamReader::EndElement: + if (xmlReader.name() == ELEMENT_SCENE) { + endElementFound = true; + } + break; + default: + break; + } + } + + if ( ! xmlReader.hasError()) { + /* + * This will cause update of the macro's name + * using the scene's name that is actually + * inside of SceneInfo. + */ + scene->setName(scene->getName()); + } + } + else { + xmlReader.raiseError("Element should be \"" + + ELEMENT_SCENE + + "\" but is \"" + + xmlReader.name().toString() + + "\" while reading Scene"); + } +} + +/** + * Read any of the scene object sub-classes + * + * @param xmlReader + * The XML stream reader + * @return + * Pointer to object read or NULL if not valid + */ +SceneObject* +SceneXmlStreamReader::readSceneObject(QXmlStreamReader& xmlReader) +{ + SceneObject* sceneObject(NULL); + + if (xmlReader.name() == ELEMENT_OBJECT) { + sceneObject = readSceneObjectSingle(xmlReader); + } + else if (xmlReader.name() == ELEMENT_OBJECT_ARRAY) { + sceneObject = readSceneObjectArray(xmlReader); + } + else if (xmlReader.name() == ELEMENT_OBJECT_MAP) { + sceneObject = readSceneObjectMap(xmlReader); + } + else { + xmlReader.raiseError("Unexpected element \"" + + xmlReader.name().toString() + + "\" that is none of " + + ELEMENT_OBJECT + + ", " + + ELEMENT_OBJECT_ARRAY + + ", " + + ELEMENT_OBJECT_MAP); + } + return sceneObject; +} + +/** + * Read any of the 'single' scene object sub-classes. + * 'Single' is one item (not an array nor a map) + * + * @param xmlReader + * The XML stream reader + * @return + * Pointer to object read or NULL if not valid + */ +SceneObject* +SceneXmlStreamReader::readSceneObjectSingle(QXmlStreamReader& xmlReader) +{ + if (xmlReader.name() != ELEMENT_OBJECT) { + xmlReader.raiseError("Current element should be " + + ELEMENT_OBJECT + + " at beginning of readSceneObjectSingle" + + " but is \"" + + xmlReader.name().toString()); + return NULL; + } + + const QXmlStreamAttributes attributes = xmlReader.attributes(); + const QString typeString = attributes.value(ATTRIBUTE_OBJECT_TYPE).toString(); + const QString className = attributes.value(ATTRIBUTE_OBJECT_CLASS).toString(); + const QString name = attributes.value(ATTRIBUTE_OBJECT_NAME).toString(); + const QString versionString = attributes.value(ATTRIBUTE_OBJECT_VERSION).toString(); + + SceneObjectDataTypeEnum::Enum dataType = SceneObjectDataTypeEnum::SCENE_INVALID; + + AString errorString; + if (typeString.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_TYPE + + " is missing on " + + ELEMENT_OBJECT); + } + else { + bool typeStringValid(false); + dataType = SceneObjectDataTypeEnum::fromXmlName(typeString, + &typeStringValid); + if ( ! typeStringValid) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_TYPE + + " \"" + + typeString + + "\" is invalid on " + + ELEMENT_OBJECT); + } + } + + if (name.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_NAME + + " is missing on " + + ELEMENT_OBJECT); + } + if (dataType == SceneObjectDataTypeEnum::SCENE_CLASS) { + if (className.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_CLASS + + " is missing on " + + ELEMENT_OBJECT); + } + if (versionString.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_VERSION + + " is missing on " + + ELEMENT_OBJECT); + } + } + if ( ! errorString.isEmpty()) { + xmlReader.raiseError(errorString); + return NULL; + } + + SceneObject* sceneObject(NULL); + + SceneClass* sceneClass(NULL); + switch (dataType) { + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + sceneObject = new SceneBoolean(name, + AString(xmlReader.readElementText()).toBool()); + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + { + sceneClass = new SceneClass(name, + className, + versionString.toInt()); + sceneObject = sceneClass; + } + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + sceneObject = new SceneEnumeratedType(name, + xmlReader.readElementText()); + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + sceneObject = new SceneFloat(name, + xmlReader.readElementText().toFloat()); + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + sceneObject = new SceneInteger(name, + xmlReader.readElementText().toInt()); + break; + case SceneObjectDataTypeEnum::SCENE_INVALID: + CaretAssert(0); + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + { + ScenePathName* pathName = new ScenePathName(name, + ""); + pathName->setValueToAbsolutePath(m_filename, + xmlReader.readElementText()); + sceneObject = pathName; + } + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + sceneObject = new SceneString(name, + xmlReader.readElementText()); + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + { + uint32_t value = xmlReader.readElementText().toUInt(); + if (value > std::numeric_limits::max()) { + value = std::numeric_limits::max(); + } + const uint8_t byteValue = static_cast(value); + sceneObject = new SceneUnsignedByte(name, + byteValue); + } + break; + } + + /* + * Note: The 'primitive' values are read using QXmlStreamReader::readElementText() + * which reads throught the end element. Only a 'class' needs to continue until + * the end element is found + */ + if (sceneClass != NULL) { + /* + * Set when ending scene element is found + */ + bool endElementFound(false); + + while ( ( ! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + + switch (xmlReader.tokenType()) { + case QXmlStreamReader::StartElement: + if (sceneClass != NULL) { + SceneObject* child = readSceneObject(xmlReader); + if (child != NULL) { + sceneClass->addChild(child); + } + } + else { + AString msg("Should not find a start element when reading a primitive type (not a class).." + "Element name \"" + + xmlReader.name().toString() + + "\" at line " + + AString::number(xmlReader.lineNumber()) + + " column " + + AString::number(xmlReader.columnNumber())); + CaretAssertMessage(0, msg); + } + break; + case QXmlStreamReader::EndElement: + if (xmlReader.name() == ELEMENT_OBJECT) { + endElementFound = true; + } + break; + default: + break; + } + } + } + + return sceneObject; +} + +/** + * Read an array. + * + * @param xmlReader + * The XML stream reader + * @return + * Pointer to array read or NULL if not valid + */ +SceneObjectArray* +SceneXmlStreamReader::readSceneObjectArray(QXmlStreamReader& xmlReader) +{ + if (xmlReader.name() != ELEMENT_OBJECT_ARRAY) { + xmlReader.raiseError("Current element should be " + + ELEMENT_OBJECT_ARRAY + + " at beginning of readSceneObjectArray" + + " but is \"" + + xmlReader.name().toString()); + return NULL; + } + + const QXmlStreamAttributes arrayAttributes = xmlReader.attributes(); + const QString typeString = arrayAttributes.value(ATTRIBUTE_OBJECT_ARRAY_TYPE).toString(); + const QString name = arrayAttributes.value(ATTRIBUTE_OBJECT_ARRAY_NAME).toString(); + const QString lengthString = arrayAttributes.value(ATTRIBUTE_OBJECT_ARRAY_LENGTH).toString(); + + SceneObjectDataTypeEnum::Enum dataType = SceneObjectDataTypeEnum::SCENE_INVALID; + + AString errorString; + if (typeString.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_ARRAY_TYPE + + " is missing on " + + ELEMENT_OBJECT_ARRAY); + } + else { + bool typeStringValid(false); + dataType = SceneObjectDataTypeEnum::fromXmlName(typeString, + &typeStringValid); + if ( ! typeStringValid) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_ARRAY_TYPE + + " \"" + + typeString + + "\" is invalid on " + + ELEMENT_OBJECT_ARRAY); + } + } + if (name.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_ARRAY_NAME + + " is missing on " + + ELEMENT_OBJECT_ARRAY); + } + + int32_t arrayLength(0); + if (lengthString.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_ARRAY_LENGTH + + " is missing on " + + ELEMENT_OBJECT_ARRAY); + } + else { + arrayLength = lengthString.toInt(); + if (arrayLength < 0) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_ARRAY_LENGTH + + "=" + + lengthString + + " is invalid on " + + ELEMENT_OBJECT_ARRAY); + } +// else if (arrayLength == 0) { +// return NULL; +// } + } + + if ( ! errorString.isEmpty()) { + xmlReader.raiseError(errorString); + return NULL; + } + + SceneObjectArray* sceneArray(NULL); + SceneClassArray* classArray(NULL); + SceneEnumeratedTypeArray* enumeratedTypeArray(NULL); + ScenePathNameArray* pathNameArray(NULL); + SceneBooleanArray* booleanArray(NULL); + SceneFloatArray* floatArray(NULL); + SceneIntegerArray* integerArray(NULL); + SceneStringArray* stringArray(NULL); + SceneUnsignedByteArray* unsignedByteArray(NULL); + switch (dataType) { + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + booleanArray = new SceneBooleanArray(name, + arrayLength); + sceneArray = booleanArray; + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + classArray = new SceneClassArray(name, + arrayLength); + sceneArray = classArray; + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + enumeratedTypeArray = new SceneEnumeratedTypeArray(name, + arrayLength); + sceneArray = enumeratedTypeArray; + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + floatArray = new SceneFloatArray(name, + arrayLength); + sceneArray = floatArray; + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + integerArray = new SceneIntegerArray(name, + arrayLength); + sceneArray = integerArray; + break; + case SceneObjectDataTypeEnum::SCENE_INVALID: + CaretAssert(0); + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + pathNameArray = new ScenePathNameArray(name, + arrayLength); + sceneArray = pathNameArray; + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + stringArray = new SceneStringArray(name, + arrayLength); + sceneArray = stringArray; + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + unsignedByteArray = new SceneUnsignedByteArray(name, + arrayLength); + sceneArray = unsignedByteArray; + break; + } + CaretAssert(sceneArray); + + /* + * Set when ending scene element is found + */ + bool endElementFound(false); + + int32_t sceneArrayElementIndex = -1; + while ( ( ! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + + switch (xmlReader.tokenType()) { + case QXmlStreamReader::StartElement: + if (xmlReader.name() == ELEMENT_OBJECT_ARRAY_ELEMENT) { + const QXmlStreamAttributes elementAttributes = xmlReader.attributes(); + + int32_t elementIndex(-1); + const QString elementIndexString = elementAttributes.value(ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX).toString(); + if (elementIndexString.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX + + " is missing on " + + ELEMENT_OBJECT_ARRAY_ELEMENT); + } + else { + elementIndex = elementIndexString.toInt(); + if (elementIndex < 0) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX + + "=" + + elementIndexString + + " is invalid on " + + ELEMENT_OBJECT_ARRAY_ELEMENT); + } + } + if ( ! errorString.isEmpty()) { + xmlReader.raiseError(errorString); + if (sceneArray != NULL) { + delete sceneArray; + } + return NULL; + } + + switch (dataType) { + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + CaretAssert(booleanArray); + booleanArray->setValue(elementIndex, + AString(xmlReader.readElementText()).toBool()); + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + /* + * Child class is handled when start element is found + */ + sceneArrayElementIndex = elementIndex; + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + CaretAssert(enumeratedTypeArray); + enumeratedTypeArray->setValue(elementIndex, + xmlReader.readElementText()); + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + CaretAssert(floatArray); + floatArray->setValue(elementIndex, + xmlReader.readElementText().toFloat()); + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + CaretAssert(integerArray); + integerArray->setValue(elementIndex, + xmlReader.readElementText().toInt()); + break; + case SceneObjectDataTypeEnum::SCENE_INVALID: + CaretAssert(0); + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + CaretAssert(pathNameArray); + pathNameArray->setScenePathNameAtIndex(elementIndex, + m_filename, + xmlReader.readElementText()); + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + CaretAssert(stringArray); + stringArray->setValue(elementIndex, + xmlReader.readElementText()); + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + { + CaretAssert(unsignedByteArray); + uint32_t value = xmlReader.readElementText().toUInt(); + if (value > std::numeric_limits::max()) { + value = std::numeric_limits::max(); + } + const uint8_t byteValue = static_cast(value); + unsignedByteArray->setValue(elementIndex, + byteValue); + } + break; + } + } + else if (sceneArrayElementIndex >= 0) { + /* + * Must be child of a scene class + */ + CaretAssert(classArray); + SceneObject* elementObject = readSceneObject(xmlReader); + if (elementObject != NULL) { + SceneClass* elementClass = elementObject->castToSceneClass(); + CaretAssert(elementClass); + classArray->setClassAtIndex(sceneArrayElementIndex, elementClass); + } + } + else { + + } + + break; + case QXmlStreamReader::EndElement: + if (xmlReader.name() == ELEMENT_OBJECT_ARRAY) { + endElementFound = true; + } + else if (xmlReader.name() == ELEMENT_OBJECT_ARRAY_ELEMENT) { + sceneArrayElementIndex = -1; + } + break; + default: + break; + } + } + + return sceneArray; +} + +/** + * Read a map. + * + * @param xmlReader + * The XML stream reader + * @return + * Pointer to map read or NULL if not valid + */ +SceneObjectMapIntegerKey* +SceneXmlStreamReader::readSceneObjectMap(QXmlStreamReader& xmlReader) +{ + if (xmlReader.name() != ELEMENT_OBJECT_MAP) { + xmlReader.raiseError("Current element should be " + + ELEMENT_OBJECT_MAP + + " at beginning of readSceneObjectMap" + + " but is \"" + + xmlReader.name().toString()); + return NULL; + } + + const QXmlStreamAttributes mapAttributes = xmlReader.attributes(); + const QString typeString = mapAttributes.value(ATTRIBUTE_OBJECT_MAP_TYPE).toString(); + const QString name = mapAttributes.value(ATTRIBUTE_OBJECT_MAP_NAME).toString(); + + SceneObjectDataTypeEnum::Enum dataType = SceneObjectDataTypeEnum::SCENE_INVALID; + + AString errorString; + if (typeString.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_MAP_TYPE + + " is missing on " + + ELEMENT_OBJECT_MAP); + } + else { + bool typeStringValid(false); + dataType = SceneObjectDataTypeEnum::fromXmlName(typeString, + &typeStringValid); + if ( ! typeStringValid) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_MAP_TYPE + + " \"" + + typeString + + "\" is invalid on " + + ELEMENT_OBJECT_MAP); + } + } + if (name.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_MAP_NAME + + " is missing on " + + ELEMENT_OBJECT_MAP); + } + + if ( ! errorString.isEmpty()) { + xmlReader.raiseError(errorString); + return NULL; + } + + SceneObjectMapIntegerKey* sceneMap = new SceneObjectMapIntegerKey(name, + dataType); + + /* + * Set when ending scene element is found + */ + bool endElementFound(false); + + int32_t sceneKeyIndex = -1; + while ( ( ! xmlReader.atEnd()) + && ( ! endElementFound)) { + xmlReader.readNext(); + + switch (xmlReader.tokenType()) { + case QXmlStreamReader::StartElement: + if (xmlReader.name() == ELEMENT_OBJECT_MAP_VALUE) { + const QXmlStreamAttributes valueAttributes = xmlReader.attributes(); + int32_t keyIndex(-1); + const QString keyString = valueAttributes.value(ATTRIBUTE_OBJECT_MAP_VALUE_KEY).toString(); + if (keyString.isEmpty()) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_MAP_VALUE_KEY + + " is missing on " + + ELEMENT_OBJECT_MAP_VALUE); + } + else { + keyIndex = keyString.toInt(); + if (keyIndex < 0) { + errorString.appendWithNewLine(ATTRIBUTE_OBJECT_MAP_VALUE_KEY + + "=" + + keyIndex + + " is invalid on " + + ELEMENT_OBJECT_MAP_VALUE); + } + } + if ( ! errorString.isEmpty()) { + xmlReader.raiseError(); + if (sceneMap != NULL) { + delete sceneMap; + } + return NULL; + } + + switch (dataType) { + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + sceneMap->addBoolean(keyIndex, + AString(xmlReader.readElementText()).toBool()); + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + /* + * Child class is handled when start element is found + */ + sceneKeyIndex = keyIndex; + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + sceneMap->addEnumeratedType(keyIndex, + xmlReader.readElementText()); + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + sceneMap->addFloat(keyIndex, + xmlReader.readElementText().toFloat()); + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + sceneMap->addInteger(keyIndex, + xmlReader.readElementText().toInt()); + break; + case SceneObjectDataTypeEnum::SCENE_INVALID: + CaretAssert(0); + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + { + ScenePathName spn("spn", ""); + spn.setValueToAbsolutePath(m_filename, + xmlReader.readElementText()); + sceneMap->addPathName(keyIndex, + spn.toString()); + } + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + sceneMap->addString(keyIndex, + xmlReader.readElementText()); + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + { + uint32_t value = xmlReader.readElementText().toUInt(); + if (value > std::numeric_limits::max()) { + value = std::numeric_limits::max(); + } + const uint8_t byteValue = static_cast(value); + sceneMap->addUnsignedByte(keyIndex, + byteValue); + } + break; + } + } + else if (sceneKeyIndex >= 0) { + /* + * Must be child of a scene class + */ + SceneObject* elementObject = readSceneObject(xmlReader); + if (elementObject != NULL) { + SceneClass* elementClass = elementObject->castToSceneClass(); + CaretAssert(elementClass); + sceneMap->addClass(sceneKeyIndex, + elementClass); + } + } + else { + + } + + break; + case QXmlStreamReader::EndElement: + if (xmlReader.name() == ELEMENT_OBJECT_MAP) { + endElementFound = true; + } + else if (xmlReader.name() == ELEMENT_OBJECT_MAP_VALUE) { + sceneKeyIndex = -1; + } + break; + default: + break; + } + } + + return sceneMap; +} diff --git a/src/Scenes/SceneXmlStreamReader.h b/src/Scenes/SceneXmlStreamReader.h new file mode 100644 index 0000000000000000000000000000000000000000..78fb4ac1753086cfda0ffff61569fc77b7db0990 --- /dev/null +++ b/src/Scenes/SceneXmlStreamReader.h @@ -0,0 +1,79 @@ +#ifndef __SCENE_XML_STREAM_READER_H__ +#define __SCENE_XML_STREAM_READER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include +#include + +#include "SceneXmlStreamBase.h" + +class QXmlStreamReader; + +namespace caret { + + class Scene; + class SceneObject; + class SceneObjectArray; + class SceneObjectMapIntegerKey; + + class SceneXmlStreamReader : public SceneXmlStreamBase { + + public: + SceneXmlStreamReader(); + + virtual ~SceneXmlStreamReader(); + + SceneXmlStreamReader(const SceneXmlStreamReader&) = delete; + + SceneXmlStreamReader& operator=(const SceneXmlStreamReader&) = delete; + + void readScene(QXmlStreamReader& xmlReader, + Scene* scene, + const AString& sceneFileName); + + // ADD_NEW_METHODS_HERE + + private: + SceneObject* readSceneObject(QXmlStreamReader& xmlReader); + + SceneObject* readSceneObjectSingle(QXmlStreamReader& xmlReader); + + SceneObjectArray* readSceneObjectArray(QXmlStreamReader& xmlReader); + + SceneObjectMapIntegerKey* readSceneObjectMap(QXmlStreamReader& xmlReader); + + std::set m_unrecognizedElements; + + AString m_filename; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_XML_STREAM_READER_DECLARE__ + // +#endif // __SCENE_XML_STREAM_READER_DECLARE__ + +} // namespace +#endif //__SCENE_XML_STREAM_READER_H__ diff --git a/src/Scenes/SceneXmlStreamWriter.cxx b/src/Scenes/SceneXmlStreamWriter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ef5d2b77e608350364aff1ba310ddc4adb794be6 --- /dev/null +++ b/src/Scenes/SceneXmlStreamWriter.cxx @@ -0,0 +1,603 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_XML_STREAM_WRITER_DECLARE__ +#include "SceneXmlStreamWriter.h" +#undef __SCENE_XML_STREAM_WRITER_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "FileInformation.h" +#include "Scene.h" +#include "SceneAttributes.h" +#include "SceneClass.h" +#include "SceneClassArray.h" +#include "SceneEnumeratedType.h" +#include "SceneEnumeratedTypeArray.h" +#include "SceneInfo.h" +#include "SceneObjectMapIntegerKey.h" +#include "ScenePathName.h" +#include "ScenePathNameArray.h" +#include "ScenePrimitive.h" +#include "ScenePrimitiveArray.h" +#include "SceneXmlElements.h" +#include "WuQMacroGroup.h" +#include "WuQMacroGroupXmlStreamWriter.h" + +using namespace caret; + + + +/** + * \class caret::SceneXmlStreamWriter + * \brief XML stream writer for Scene + * \ingroup Scenes + */ + +/** + * Constructor. + */ +SceneXmlStreamWriter::SceneXmlStreamWriter() +: SceneXmlStreamBase() +{ + +} + +/** + * Destructor. + */ +SceneXmlStreamWriter::~SceneXmlStreamWriter() +{ +} + +/** + * Write the given scene using the given xml stream writer + * + * @param xmlWriter + * The XML writer + * @param scene + * The scene + * @param sceneIndex + * Index of the scene + * @param sceneFileName + * Name of the scene file + */ +void +SceneXmlStreamWriter::writeXML(QXmlStreamWriter* xmlWriter, + const Scene* scene, + const int32_t sceneIndex, + const AString& sceneFileName) +{ + CaretAssert(xmlWriter); + CaretAssert(scene); + CaretAssert(sceneIndex >= 0); + CaretAssert( ! sceneFileName.isEmpty()); + + m_xmlWriter = xmlWriter; + m_sceneFileName = sceneFileName; + + const SceneAttributes* sceneAttributes = scene->getAttributes(); + const AString sceneTypeName = SceneTypeEnum::toName(sceneAttributes->getSceneType()); + + m_xmlWriter->writeStartElement(ELEMENT_SCENE); + m_xmlWriter->writeAttribute(ATTRIBUTE_SCENE_INDEX, + QString::number(sceneIndex)); + m_xmlWriter->writeAttribute(ATTRIBUTE_SCENE_TYPE, + sceneTypeName); + + m_xmlWriter->writeTextElement(ELEMENT_SCENE_NAME, + scene->getName()); + m_xmlWriter->writeTextElement(ELEMENT_SCENE_DESCRIPTION, + scene->getDescription()); + + if (scene->getMacroGroup()->getNumberOfMacros() > 0) { + WuQMacroGroupXmlStreamWriter macroGroupXmlWriter; + macroGroupXmlWriter.writeXml(xmlWriter, + scene->getMacroGroup()); + } + + const int32_t numClasses = scene->getNumberOfClasses(); + for (int32_t i = 0; i < numClasses; i++) { + writeSceneClass(scene->getClassAtIndex(i)); + } + + m_xmlWriter->writeEndElement(); + + m_xmlWriter = NULL; +} + +/** + * Write the given scene class using the xml stream writer + * + * @param sceneClass + * Scene class to write + */ +void +SceneXmlStreamWriter::writeSceneClass(const SceneClass* sceneClass) +{ + CaretAssert(sceneClass); + if (sceneClass == NULL) { + return; + } + + const AString& objectTypeName = SceneObjectDataTypeEnum::toXmlName(sceneClass->getDataType()); + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_TYPE, + objectTypeName); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_CLASS, + sceneClass->getClassName()); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_NAME, + sceneClass->getName()); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_VERSION, + AString::number(sceneClass->getVersionNumber())); + + const int32_t numberOfObjects = sceneClass->getNumberOfObjects(); + for (int32_t i = 0; i < numberOfObjects; i++) { + writeSceneObject(sceneClass->getObjectAtIndex(i)); + } + m_xmlWriter->writeEndElement(); +} + +/** + * Write the given scene object using the xml stream writer + * + * @param sceneObject + * Scene object to write + */ +void +SceneXmlStreamWriter::writeSceneObject(const SceneObject* sceneObject) +{ + CaretAssert(sceneObject); + + switch (sceneObject->getContainerType()) { + case SceneObjectContainerTypeEnum::ARRAY: + writeArrayObject(sceneObject->castToSceneObjectArray()); + break; + case SceneObjectContainerTypeEnum::MAP: + writeMapObject(sceneObject->castToSceneObjectMapIntegerKey()); + break; + case SceneObjectContainerTypeEnum::SINGLE: + writeSingleObject(sceneObject); + break; + } + + switch (sceneObject->getDataType()) { + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + break; + case SceneObjectDataTypeEnum::SCENE_INVALID: + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + break; + } +} + +/** + * Write an object array + * + * @param objectArray + * The object array + */ +void +SceneXmlStreamWriter::writeArrayObject(const SceneObjectArray* objectArray) +{ + CaretAssert(objectArray); + if (objectArray == NULL) { + return; + } + + switch (objectArray->getDataType()) { + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + writeArrayPrimitiveType(objectArray->castToScenePrimitiveArray()); + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + writeArrayClass(objectArray->castToSceneClassArray()); + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + writeArrayEnumeratedType(objectArray->castToSceneEnumeratedTypeArray()); + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + writeArrayPrimitiveType(objectArray->castToScenePrimitiveArray()); + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + writeArrayPrimitiveType(objectArray->castToScenePrimitiveArray()); + break; + case SceneObjectDataTypeEnum::SCENE_INVALID: + CaretAssert(0); + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + writeArrayPathName(objectArray->castToScenePathNameArray()); + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + writeArrayPrimitiveType(objectArray->castToScenePrimitiveArray()); + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + writeArrayPrimitiveType(objectArray->castToScenePrimitiveArray()); + break; + } +} + +/** + * Write an object map + * + * @param objectMap + * The object map + */ +void +SceneXmlStreamWriter::writeMapObject(const SceneObjectMapIntegerKey* objectMap) +{ + CaretAssert(objectMap); + if (objectMap == NULL) { + return; + } + + const SceneObjectDataTypeEnum::Enum dataType = objectMap->getDataType(); + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_MAP); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_MAP_TYPE, + SceneObjectDataTypeEnum::toXmlName(dataType)); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_MAP_NAME, + objectMap->getName()); + + const std::map& sceneMap = objectMap->getMap(); + for (const auto iter : sceneMap) { + const int32_t key = iter.first; + const QString keyString(QString::number(key)); + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_MAP_VALUE); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_MAP_VALUE_KEY, + keyString); + + const SceneObject* valueObject = iter.second; + switch (dataType) { + case SceneObjectDataTypeEnum::SCENE_INVALID: + CaretAssert(0); + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + { + const SceneClass* value = valueObject->castToSceneClass(); + CaretAssert(value); + writeSceneClass(value); + } + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + { + const SceneEnumeratedType* value = valueObject->castToSceneEnumeratedType(); + CaretAssert(value); + m_xmlWriter->writeCharacters(value->stringValue()); + } + break; + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + { + const ScenePrimitive* value = valueObject->castToScenePrimitive(); + CaretAssert(value); + m_xmlWriter->writeCharacters(value->stringValue()); + } + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + { + const ScenePrimitive* value = valueObject->castToScenePrimitive(); + CaretAssert(value); + m_xmlWriter->writeCharacters(value->stringValue()); + } + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + { + const ScenePrimitive* value = valueObject->castToScenePrimitive(); + CaretAssert(value); + m_xmlWriter->writeCharacters(value->stringValue()); + } + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + { + const ScenePathName* pathName = valueObject->castToScenePathName(); + CaretAssert(pathName); + const AString path = pathName->getRelativePathToSceneFile(m_sceneFileName); + m_xmlWriter->writeCharacters(path); + } + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + { + const ScenePrimitive* value = valueObject->castToScenePrimitive(); + CaretAssert(value); + m_xmlWriter->writeCharacters(value->stringValue()); + } + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + { + const ScenePrimitive* value = valueObject->castToScenePrimitive(); + CaretAssert(value); + m_xmlWriter->writeCharacters(value->stringValue()); + } + break; + } + + m_xmlWriter->writeEndElement(); + } + + + m_xmlWriter->writeEndElement(); +} + +/** + * Write a single object (not an array nor map) + * + * @param sceneObject + * The single object + */ +void +SceneXmlStreamWriter::writeSingleObject(const SceneObject* sceneObject) +{ + CaretAssert(sceneObject); + if (sceneObject == NULL) { + return; + } + + switch (sceneObject->getDataType()) { + case SceneObjectDataTypeEnum::SCENE_BOOLEAN: + writePrimitive(sceneObject->castToScenePrimitive()); + break; + case SceneObjectDataTypeEnum::SCENE_CLASS: + writeSceneClass(sceneObject->castToSceneClass()); + break; + case SceneObjectDataTypeEnum::SCENE_ENUMERATED_TYPE: + writeEnumeratedType(sceneObject->castToSceneEnumeratedType()); + break; + case SceneObjectDataTypeEnum::SCENE_FLOAT: + writePrimitive(sceneObject->castToScenePrimitive()); + break; + case SceneObjectDataTypeEnum::SCENE_INTEGER: + writePrimitive(sceneObject->castToScenePrimitive()); + break; + case SceneObjectDataTypeEnum::SCENE_INVALID: + CaretAssert(0); + break; + case SceneObjectDataTypeEnum::SCENE_PATH_NAME: + writePathName(sceneObject->castToScenePathName()); + break; + case SceneObjectDataTypeEnum::SCENE_STRING: + writePrimitive(sceneObject->castToScenePrimitive()); + break; + case SceneObjectDataTypeEnum::SCENE_UNSIGNED_BYTE: + writePrimitive(sceneObject->castToScenePrimitive()); + break; + } +} + +/** + * Write an enumerated type + * + * @param sceneEnumeratedType + * The object map + */ +void +SceneXmlStreamWriter::writeEnumeratedType(const SceneEnumeratedType* sceneEnumeratedType) +{ + CaretAssert(sceneEnumeratedType); + if (sceneEnumeratedType == NULL) { + return; + } + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_TYPE, + SceneObjectDataTypeEnum::toXmlName(sceneEnumeratedType->getDataType())); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_NAME, + sceneEnumeratedType->getName()); + m_xmlWriter->writeCharacters(sceneEnumeratedType->stringValue()); + m_xmlWriter->writeEndElement(); +} + +/** + * Write a path name + * + * @param scenePathName + * The path name + */ +void +SceneXmlStreamWriter::writePathName(const ScenePathName* scenePathName) +{ + CaretAssert(scenePathName); + if (scenePathName == NULL) { + return; + } + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_TYPE, + SceneObjectDataTypeEnum::toXmlName(scenePathName->getDataType())); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_NAME, + scenePathName->getName()); + m_xmlWriter->writeCharacters(scenePathName->getRelativePathToSceneFile(m_sceneFileName)); + m_xmlWriter->writeEndElement(); +} + +/** + * Write a primitive + * + * @param scenePrimitive + * The primitive + */ +void +SceneXmlStreamWriter::writePrimitive(const ScenePrimitive* scenePrimitive) +{ + CaretAssert(scenePrimitive); + if (scenePrimitive == NULL) { + return; + } + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_TYPE, + SceneObjectDataTypeEnum::toXmlName(scenePrimitive->getDataType())); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_NAME, + scenePrimitive->getName()); + m_xmlWriter->writeCharacters(scenePrimitive->stringValue()); + m_xmlWriter->writeEndElement(); +} + +/** + * Write an enumerated array + * + * @param enumeratedArray + * The enumerated array + */ +void +SceneXmlStreamWriter::writeArrayEnumeratedType(const SceneEnumeratedTypeArray* enumeratedArray) +{ + CaretAssert(enumeratedArray); + if (enumeratedArray == NULL) { + return; + } + + const int32_t numberOfElements = enumeratedArray->getNumberOfArrayElements(); + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_TYPE, + SceneObjectDataTypeEnum::toXmlName(enumeratedArray->getDataType())); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_NAME, + enumeratedArray->getName()); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_LENGTH, + QString::number(numberOfElements)); + + for (int32_t i = 0; i < numberOfElements; i++) { + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY_ELEMENT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX, + QString::number(i)); + m_xmlWriter->writeCharacters(enumeratedArray->stringValue(i)); + m_xmlWriter->writeEndElement(); + } + m_xmlWriter->writeEndElement(); +} + +/** + * Write a primitive array + * + * @param primitiveArray + * The primitive array + */ +void +SceneXmlStreamWriter::writeArrayPrimitiveType(const ScenePrimitiveArray* primitiveArray) +{ + CaretAssert(primitiveArray); + if (primitiveArray == NULL) { + return; + } + + const int32_t numberOfElements = primitiveArray->getNumberOfArrayElements(); + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_TYPE, + SceneObjectDataTypeEnum::toXmlName(primitiveArray->getDataType())); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_NAME, + primitiveArray->getName()); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_LENGTH, + QString::number(numberOfElements)); + + for (int32_t i = 0; i < numberOfElements; i++) { + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY_ELEMENT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX, + QString::number(i)); + m_xmlWriter->writeCharacters(primitiveArray->stringValue(i)); + m_xmlWriter->writeEndElement(); + } + m_xmlWriter->writeEndElement(); +} + +/** + * Write a class array + * + * @param classArray + * The class array + */ +void +SceneXmlStreamWriter::writeArrayClass(const SceneClassArray* classArray) +{ + CaretAssert(classArray); + if (classArray == NULL) { + return; + } + + const int32_t numberOfElements = classArray->getNumberOfArrayElements(); + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_TYPE, + SceneObjectDataTypeEnum::toXmlName(classArray->getDataType())); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_NAME, + classArray->getName()); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_LENGTH, + QString::number(numberOfElements)); + + for (int32_t i = 0; i < numberOfElements; i++) { + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY_ELEMENT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX, + QString::number(i)); + writeSceneClass(classArray->getClassAtIndex(i)); + m_xmlWriter->writeEndElement(); + } + m_xmlWriter->writeEndElement(); +} + +/** + * Write a path name array + * + * @param pathNameArray + * The path name array + */ +void +SceneXmlStreamWriter::writeArrayPathName(const ScenePathNameArray* pathNameArray) +{ + CaretAssert(pathNameArray); + if (pathNameArray == NULL) { + return; + } + + const int32_t numberOfElements = pathNameArray->getNumberOfArrayElements(); + + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_TYPE, + SceneObjectDataTypeEnum::toXmlName(pathNameArray->getDataType())); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_NAME, + pathNameArray->getName()); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_LENGTH, + QString::number(numberOfElements)); + + for (int32_t i = 0; i < numberOfElements; i++) { + m_xmlWriter->writeStartElement(ELEMENT_OBJECT_ARRAY_ELEMENT); + m_xmlWriter->writeAttribute(ATTRIBUTE_OBJECT_ARRAY_ELEMENT_INDEX, + QString::number(i)); + const ScenePathName* scenePathName = pathNameArray->getScenePathNameAtIndex(i); + const QString path = scenePathName->getRelativePathToSceneFile(m_sceneFileName); + m_xmlWriter->writeCharacters(path); + m_xmlWriter->writeEndElement(); + } + m_xmlWriter->writeEndElement(); +} diff --git a/src/Scenes/SceneXmlStreamWriter.h b/src/Scenes/SceneXmlStreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..80084b6f5dbf950e0b0b264f0ef19f227216d6d8 --- /dev/null +++ b/src/Scenes/SceneXmlStreamWriter.h @@ -0,0 +1,103 @@ +#ifndef __SCENE_XML_STREAM_WRITER_H__ +#define __SCENE_XML_STREAM_WRITER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "SceneXmlStreamBase.h" + +class QXmlStreamWriter; + +namespace caret { + + class Scene; + class SceneClass; + class SceneClassArray; + class SceneEnumeratedType; + class SceneEnumeratedTypeArray; + class SceneObject; + class SceneObjectArray; + class SceneObjectMapIntegerKey; + class ScenePathName; + class ScenePathNameArray; + class ScenePrimitive; + class ScenePrimitiveArray; + + class SceneXmlStreamWriter : public SceneXmlStreamBase { + + public: + SceneXmlStreamWriter(); + + virtual ~SceneXmlStreamWriter(); + + SceneXmlStreamWriter(const SceneXmlStreamWriter&) = delete; + + SceneXmlStreamWriter& operator=(const SceneXmlStreamWriter&) = delete; + + void writeXML(QXmlStreamWriter* xmlWriter, + const Scene* scene, + const int32_t sceneIndex, + const AString& sceneFileName); + + // ADD_NEW_METHODS_HERE + + private: + void writeSceneClass(const SceneClass* sceneClass); + + void writeSceneObject(const SceneObject* sceneObject); + + void writeArrayObject(const SceneObjectArray* objectArray); + + void writeMapObject(const SceneObjectMapIntegerKey* objectMap); + + void writeSingleObject(const SceneObject* sceneObject); + + void writeEnumeratedType(const SceneEnumeratedType* sceneEnumeratedType); + + void writePathName(const ScenePathName* scenePathName); + + void writePrimitive(const ScenePrimitive* scenePrimitive); + + void writeArrayEnumeratedType(const SceneEnumeratedTypeArray* enumeratedArray); + + void writeArrayPrimitiveType(const ScenePrimitiveArray* primitiveArray); + + void writeArrayClass(const SceneClassArray* classArray); + + void writeArrayPathName(const ScenePathNameArray* pathNameArray); + + QXmlStreamWriter* m_xmlWriter = NULL; + + AString m_sceneFileName; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_XML_STREAM_WRITER_DECLARE__ + // +#endif // __SCENE_XML_STREAM_WRITER_DECLARE__ + +} // namespace +#endif //__SCENE_XML_STREAM_WRITER_H__