mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-21 20:39:08 -06:00
Merge branch 'feature/globe-generalization' of github.com:OpenSpace/OpenSpace into feature/globe-generalization
This commit is contained in:
@@ -74,17 +74,25 @@ return {
|
||||
Name = "Temporal VIIRS SNPP",
|
||||
Type = "TemporalTileLayer",
|
||||
FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml",
|
||||
PadTiles = false,
|
||||
}
|
||||
},
|
||||
{
|
||||
MaxLevel = 22,
|
||||
TileProvider = {
|
||||
Name = "ESRI Imagery World 2D",
|
||||
FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms"
|
||||
FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms",
|
||||
PadTiles = false,
|
||||
}
|
||||
},
|
||||
},
|
||||
Enabled = true,
|
||||
PadTiles = false,
|
||||
Fallback = {
|
||||
Name = "Blue Marble",
|
||||
FilePath = "textures/earth_bluemarble.jpg",
|
||||
Enabled = true,
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = "ESRI Imagery World 2D",
|
||||
@@ -139,6 +147,16 @@ return {
|
||||
Gamma = 1.5,
|
||||
Multiplier = 15.0,
|
||||
},
|
||||
Fallback = {
|
||||
Name = "Earth Night",
|
||||
FilePath = "textures/earth_night.jpg",
|
||||
Enabled = true,
|
||||
Settings = {
|
||||
Opacity = 1.0,
|
||||
Gamma = 1.5,
|
||||
Multiplier = 15.0,
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = "Temporal Earth at Night",
|
||||
@@ -186,6 +204,11 @@ return {
|
||||
FilePath = "map_service_configs/ESRI/TERRAIN.wms",
|
||||
Enabled = true,
|
||||
TilePixelSize = 64,
|
||||
Fallback = {
|
||||
Name = "Earth Bluemarble Height",
|
||||
FilePath = "textures/earth_bluemarble_height.jpg",
|
||||
Enabled = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ return {
|
||||
Name = "Viking",
|
||||
FilePath = "map_service_configs/MARS_Viking_MDIM21.xml",
|
||||
Enabled = true,
|
||||
Fallback = {
|
||||
Name = "Mars Texture",
|
||||
FilePath = "textures/mars.jpg",
|
||||
Enabled = true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name = "MOLA Pseudo Color",
|
||||
|
||||
@@ -143,7 +143,7 @@ void MemoryAwareTileCache::clear() {
|
||||
void MemoryAwareTileCache::createDefaultTextureContainers() {
|
||||
for (int id = 0; id < layergroupid::NUM_LAYER_GROUPS; id++) {
|
||||
TileTextureInitData initData =
|
||||
LayerManager::getTileTextureInitData(layergroupid::GroupID(id));
|
||||
LayerManager::getTileTextureInitData(layergroupid::GroupID(id), true);
|
||||
assureTextureContainerExists(initData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ void TextureContainer::reset() {
|
||||
for (size_t i = 0; i < _numTextures; ++i)
|
||||
{
|
||||
auto tex = std::make_unique<ghoul::opengl::Texture>(
|
||||
_initData.dimensionsWithPadding(),
|
||||
_initData.dimensions(),
|
||||
_initData.ghoulTextureFormat(),
|
||||
_initData.glTextureFormat(),
|
||||
_initData.glType(),
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <modules/globebrowsing/globebrowsingmodule.h>
|
||||
|
||||
#include <modules/globebrowsing/cache/memoryawaretilecache.h>
|
||||
#include <modules/globebrowsing/geometry/angle.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/geometry/geodeticpatch.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
@@ -162,8 +163,15 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
|
||||
{
|
||||
"goToGeo",
|
||||
&globebrowsing::luascriptfunctions::goToGeo,
|
||||
"void",
|
||||
"number, number, number",
|
||||
"Go to geographic coordinates latitude and longitude"
|
||||
},
|
||||
{
|
||||
"getGeoPosition",
|
||||
&globebrowsing::luascriptfunctions::getGeoPosition,
|
||||
"void",
|
||||
"Get geographic coordinates of the camera poosition in latitude, "
|
||||
"longitude, and altitude"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -184,7 +192,9 @@ void GlobeBrowsingModule::goToChunk(int x, int y, int level) {
|
||||
void GlobeBrowsingModule::goToGeo(double latitude, double longitude) {
|
||||
using namespace globebrowsing;
|
||||
Camera* cam = OsEng.navigationHandler().camera();
|
||||
goToGeodetic2(*cam, Geodetic2(latitude, longitude) / 180 * glm::pi<double>(), true);
|
||||
goToGeodetic2(*cam, Geodetic2(
|
||||
Angle<double>::fromDegrees(latitude).asRadians(),
|
||||
Angle<double>::fromDegrees(longitude).asRadians()), true);
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToGeo(double latitude, double longitude,
|
||||
@@ -196,7 +206,9 @@ void GlobeBrowsingModule::goToGeo(double latitude, double longitude,
|
||||
goToGeodetic3(
|
||||
*cam,
|
||||
{
|
||||
Geodetic2(latitude, longitude) / 180 * glm::pi<double>(),
|
||||
Geodetic2(
|
||||
Angle<double>::fromDegrees(latitude).asRadians(),
|
||||
Angle<double>::fromDegrees(longitude).asRadians()),
|
||||
altitude
|
||||
},
|
||||
true
|
||||
@@ -246,16 +258,18 @@ void GlobeBrowsingModule::goToGeodetic2(Camera& camera,
|
||||
return;
|
||||
}
|
||||
|
||||
// Camera position in model space
|
||||
glm::dvec3 camPos = camera.positionVec3();
|
||||
glm::dmat4 inverseModelTransform = globe->inverseModelTransform();
|
||||
glm::dvec3 cameraPosition = OsEng.navigationHandler().camera()->positionVec3();
|
||||
glm::dmat4 inverseModelTransform =
|
||||
OsEng.navigationHandler().focusNode()->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
glm::dvec3 positionOnEllipsoid =
|
||||
globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace);
|
||||
double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid);
|
||||
|
||||
inverseModelTransform * glm::dvec4(cameraPosition, 1.0);
|
||||
SurfacePositionHandle posHandle = globe->calculateSurfacePositionHandle(
|
||||
cameraPositionModelSpace);
|
||||
|
||||
glm::dvec3 centerToActualSurface = posHandle.centerToReferenceSurface +
|
||||
posHandle.referenceSurfaceOutDirection * posHandle.heightToSurface;
|
||||
double altitude = glm::length(cameraPositionModelSpace - centerToActualSurface);
|
||||
|
||||
goToGeodetic3(camera, {geo2, altitude}, resetCameraDirection);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
|
||||
globebrowsing::cache::MemoryAwareTileCache* tileCache();
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe();
|
||||
|
||||
protected:
|
||||
void internalInitialize() override;
|
||||
|
||||
@@ -66,7 +68,6 @@ private:
|
||||
void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3,
|
||||
bool resetCameraDirection);
|
||||
void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2);
|
||||
globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe();
|
||||
|
||||
/**
|
||||
\return a comma separated list of layer group names.
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/angle.h>
|
||||
#include <modules/globebrowsing/rendering/layer/layermanager.h>
|
||||
#include <modules/globebrowsing/rendering/layer/layer.h>
|
||||
|
||||
@@ -158,8 +159,8 @@ int goToGeo(lua_State* L) {
|
||||
return luaL_error(L, "Expected 2 or 3 arguments.");
|
||||
}
|
||||
|
||||
double latitude = static_cast<int>(lua_tonumber(L, 1));
|
||||
double longitude = static_cast<int>(lua_tonumber(L, 2));
|
||||
double latitude = static_cast<double>(lua_tonumber(L, 1));
|
||||
double longitude = static_cast<double>(lua_tonumber(L, 2));
|
||||
|
||||
if (nArguments == 2) {
|
||||
OsEng.moduleEngine().module<GlobeBrowsingModule>()->goToGeo(latitude, longitude);
|
||||
@@ -173,4 +174,34 @@ int goToGeo(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getGeoPosition(lua_State* L) {
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 0) {
|
||||
return luaL_error(L, "Expected 0 arguments.");
|
||||
}
|
||||
|
||||
RenderableGlobe* globe =
|
||||
OsEng.moduleEngine().module<GlobeBrowsingModule>()->castFocusNodeRenderableToGlobe();
|
||||
if (!globe) {
|
||||
return luaL_error(L, "Focus node must be a RenderableGlobe");
|
||||
}
|
||||
|
||||
glm::dvec3 cameraPosition = OsEng.navigationHandler().camera()->positionVec3();
|
||||
glm::dmat4 inverseModelTransform =
|
||||
OsEng.navigationHandler().focusNode()->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
inverseModelTransform * glm::dvec4(cameraPosition, 1.0);
|
||||
SurfacePositionHandle posHandle = globe->calculateSurfacePositionHandle(
|
||||
cameraPositionModelSpace);
|
||||
|
||||
Geodetic2 geo2 = globe->ellipsoid().cartesianToGeodetic2(posHandle.centerToReferenceSurface);
|
||||
double altitude = glm::length(cameraPositionModelSpace - posHandle.centerToReferenceSurface);
|
||||
|
||||
lua_pushnumber(L, Angle<double>::fromRadians(geo2.lat).asDegrees());
|
||||
lua_pushnumber(L, Angle<double>::fromRadians(geo2.lon).asDegrees());
|
||||
lua_pushnumber(L, altitude);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
} // namespace openspace::globebrowsing::luascriptfunctions
|
||||
|
||||
@@ -187,7 +187,7 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition(
|
||||
glm::vec2 transformedUv = layer->TileUvToTextureSamplePosition(
|
||||
uvTransform,
|
||||
patchUV,
|
||||
glm::uvec2(tileTexture->dimensions())
|
||||
@@ -271,6 +271,11 @@ void ChunkedLodGlobe::notifyShaderRecompilation() {
|
||||
_shadersNeedRecompilation = true;
|
||||
}
|
||||
|
||||
void ChunkedLodGlobe::recompileShaders() {
|
||||
_renderer->recompileShaders(_owner);
|
||||
_shadersNeedRecompilation = false;
|
||||
}
|
||||
|
||||
void ChunkedLodGlobe::render(const RenderData& data, RendererTasks&) {
|
||||
stats.startNewRecord();
|
||||
if (_shadersNeedRecompilation) {
|
||||
|
||||
@@ -100,8 +100,18 @@ public:
|
||||
*/
|
||||
float getHeight(glm::dvec3 position) const;
|
||||
|
||||
/**
|
||||
* Notifies the renderer to recompile its shaders the next time the render function is
|
||||
* called. The actual shader recompilation takes place in the render function because
|
||||
* properties that the shader depends on need to be properly synced.
|
||||
*/
|
||||
void notifyShaderRecompilation();
|
||||
|
||||
/**
|
||||
* Directly recompile the shaders of the renderer.
|
||||
*/
|
||||
void recompileShaders();
|
||||
|
||||
const int minSplitDepth;
|
||||
const int maxSplitDepth;
|
||||
|
||||
|
||||
@@ -258,6 +258,10 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
addPropertySubOwner(_debugPropertyOwner);
|
||||
addPropertySubOwner(_layerManager.get());
|
||||
//addPropertySubOwner(_pointGlobe.get());
|
||||
|
||||
// Recompile the shaders directly so that it is not done the first time the render
|
||||
// function is called.
|
||||
_chunkedLodGlobe->recompileShaders();
|
||||
}
|
||||
|
||||
void RenderableGlobe::initialize() {
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace openspace::globebrowsing {
|
||||
void GPULayer::setValue(ghoul::opengl::ProgramObject* programObject, const Layer& layer,
|
||||
const TileIndex& tileIndex, int pileSize)
|
||||
{
|
||||
ChunkTilePile chunkTilePile = layer.getChunkTilePile(tileIndex, pileSize);
|
||||
gpuRenderSettings.setValue(programObject, layer.renderSettings());
|
||||
gpuLayerAdjustment.setValue(programObject, layer.layerAdjustment());
|
||||
|
||||
@@ -43,9 +42,13 @@ void GPULayer::setValue(ghoul::opengl::ProgramObject* programObject, const Layer
|
||||
case layergroupid::TypeID::TemporalTileLayer:
|
||||
case layergroupid::TypeID::TileIndexTileLayer:
|
||||
case layergroupid::TypeID::ByIndexTileLayer:
|
||||
case layergroupid::TypeID::ByLevelTileLayer:
|
||||
case layergroupid::TypeID::ByLevelTileLayer: {
|
||||
ChunkTilePile chunkTilePile = layer.getChunkTilePile(tileIndex, pileSize);
|
||||
gpuChunkTilePile.setValue(programObject, chunkTilePile);
|
||||
paddingStartOffset.setValue(programObject, layer.tilePixelStartOffset());
|
||||
paddingSizeDifference.setValue(programObject, layer.tilePixelSizeDifference());
|
||||
break;
|
||||
}
|
||||
case layergroupid::TypeID::SolidColor:
|
||||
gpuColor.setValue(programObject, layer.otherTypesProperties().color.value());
|
||||
break;
|
||||
@@ -68,9 +71,12 @@ void GPULayer::bind(ghoul::opengl::ProgramObject* programObject, const Layer& la
|
||||
case layergroupid::TypeID::TemporalTileLayer:
|
||||
case layergroupid::TypeID::TileIndexTileLayer:
|
||||
case layergroupid::TypeID::ByIndexTileLayer:
|
||||
case layergroupid::TypeID::ByLevelTileLayer:
|
||||
case layergroupid::TypeID::ByLevelTileLayer: {
|
||||
gpuChunkTilePile.bind(programObject, nameBase + "pile.", pileSize);
|
||||
paddingStartOffset.bind(programObject, nameBase + "padding.startOffset");
|
||||
paddingSizeDifference.bind(programObject, nameBase + "padding.sizeDifference");
|
||||
break;
|
||||
}
|
||||
case layergroupid::TypeID::SolidColor:
|
||||
gpuColor.bind(programObject, nameBase + "color");
|
||||
break;
|
||||
|
||||
@@ -73,6 +73,8 @@ private:
|
||||
GPULayerRenderSettings gpuRenderSettings;
|
||||
GPULayerAdjustment gpuLayerAdjustment;
|
||||
|
||||
GPUData<glm::ivec2> paddingStartOffset;
|
||||
GPUData<glm::ivec2> paddingSizeDifference;
|
||||
// Adjustment layer stuff
|
||||
GPUData<glm::vec3> gpuColor;
|
||||
};
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
#include <modules/globebrowsing/rendering/layer/layer.h>
|
||||
|
||||
#include <modules/globebrowsing/rendering/layer/layermanager.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tiletextureinitdata.h>
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
@@ -38,6 +40,7 @@ namespace {
|
||||
const char* keySettings = "Settings";
|
||||
const char* keyAdjustment = "Adjustment";
|
||||
const char* KeyBlendMode = "BlendMode";
|
||||
const char* KeyPadTiles = "PadTiles";
|
||||
|
||||
static const openspace::properties::Property::PropertyInfo TypeInfo = {
|
||||
"Type",
|
||||
@@ -102,6 +105,14 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict)
|
||||
layerDict.getValue(keyEnabled, enabled);
|
||||
_enabled.setValue(enabled);
|
||||
|
||||
bool padTiles = true;
|
||||
layerDict.getValue<bool>(KeyPadTiles, padTiles);
|
||||
|
||||
TileTextureInitData initData = LayerManager::getTileTextureInitData(_layerGroupId,
|
||||
padTiles);
|
||||
_padTilePixelStartOffset = initData.tilePixelStartOffset();
|
||||
_padTilePixelSizeDifference = initData.tilePixelSizeDifference();
|
||||
|
||||
// Initialize settings
|
||||
ghoul::Dictionary settingsDict;
|
||||
if (layerDict.getValue(keySettings, settingsDict)) {
|
||||
@@ -260,6 +271,36 @@ void Layer::update() {
|
||||
}
|
||||
}
|
||||
|
||||
glm::ivec2 Layer::tilePixelStartOffset() const {
|
||||
return _padTilePixelStartOffset;
|
||||
}
|
||||
|
||||
glm::ivec2 Layer::tilePixelSizeDifference() const {
|
||||
return _padTilePixelSizeDifference;
|
||||
}
|
||||
|
||||
glm::vec2 Layer::compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff,
|
||||
glm::uvec2 resolution, glm::vec2 tileUV)
|
||||
{
|
||||
glm::vec2 sourceSize = glm::vec2(resolution) + sizeDiff;
|
||||
glm::vec2 currentSize = glm::vec2(resolution);
|
||||
glm::vec2 sourceToCurrentSize = currentSize / sourceSize;
|
||||
tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize);
|
||||
return tileUV;
|
||||
}
|
||||
|
||||
glm::vec2 Layer::TileUvToTextureSamplePosition(const TileUvTransform& uvTransform,
|
||||
glm::vec2 tileUV, glm::uvec2 resolution)
|
||||
{
|
||||
glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV;
|
||||
uv = compensateSourceTextureSampling(
|
||||
tilePixelStartOffset(),
|
||||
tilePixelSizeDifference(),
|
||||
resolution,
|
||||
uv);
|
||||
return uv;
|
||||
}
|
||||
|
||||
layergroupid::TypeID Layer::parseTypeIdFromDictionary(
|
||||
const ghoul::Dictionary& initDict) const
|
||||
{
|
||||
|
||||
@@ -69,6 +69,13 @@ public:
|
||||
|
||||
void update();
|
||||
|
||||
glm::ivec2 tilePixelStartOffset() const;
|
||||
glm::ivec2 tilePixelSizeDifference() const;
|
||||
glm::vec2 compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff,
|
||||
glm::uvec2 resolution, glm::vec2 tileUV);
|
||||
glm::vec2 TileUvToTextureSamplePosition(const TileUvTransform& uvTransform,
|
||||
glm::vec2 tileUV, glm::uvec2 resolution);
|
||||
|
||||
private:
|
||||
layergroupid::TypeID parseTypeIdFromDictionary(const ghoul::Dictionary& initDict) const;
|
||||
void initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict);
|
||||
@@ -86,6 +93,9 @@ private:
|
||||
LayerRenderSettings _renderSettings;
|
||||
LayerAdjustment _layerAdjustment;
|
||||
|
||||
glm::ivec2 _padTilePixelStartOffset;
|
||||
glm::ivec2 _padTilePixelSizeDifference;
|
||||
|
||||
const layergroupid::GroupID _layerGroupId;
|
||||
|
||||
std::function<void(void)> _onChangeCallback;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "LayerGroup";
|
||||
|
||||
const char* KeyFallback = "Fallback";
|
||||
static const openspace::properties::Property::PropertyInfo BlendTileInfo = {
|
||||
"BlendTileLevels",
|
||||
"Blend between levels",
|
||||
@@ -37,7 +37,6 @@ namespace {
|
||||
"and more visually pleasing.",
|
||||
openspace::properties::Property::Visibility::Hidden
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
@@ -62,6 +61,19 @@ LayerGroup::LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict)
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
|
||||
if (layerDict.hasKeyAndValue<ghoul::Dictionary>(KeyFallback)) {
|
||||
LWARNING("Unable to create layer. Initializing fallback layer.");
|
||||
ghoul::Dictionary fallbackLayerDict =
|
||||
layerDict.value<ghoul::Dictionary>(KeyFallback);
|
||||
try {
|
||||
addLayer(fallbackLayerDict);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ void LayerManager::reset(bool includeDisabled) {
|
||||
}
|
||||
|
||||
TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::GroupID id,
|
||||
bool padTiles,
|
||||
size_t preferredTileSize)
|
||||
{
|
||||
switch (id) {
|
||||
@@ -124,33 +125,34 @@ TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::GroupID i
|
||||
size_t tileSize = preferredTileSize ? preferredTileSize : 64;
|
||||
return TileTextureInitData(tileSize, tileSize, GL_FLOAT,
|
||||
ghoul::opengl::Texture::Format::Red,
|
||||
padTiles,
|
||||
TileTextureInitData::ShouldAllocateDataOnCPU::Yes);
|
||||
}
|
||||
case layergroupid::GroupID::ColorLayers: {
|
||||
size_t tileSize = preferredTileSize ? preferredTileSize : 512;
|
||||
return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE,
|
||||
ghoul::opengl::Texture::Format::BGRA);
|
||||
ghoul::opengl::Texture::Format::BGRA, padTiles);
|
||||
}
|
||||
case layergroupid::GroupID::Overlays: {
|
||||
size_t tileSize = preferredTileSize ? preferredTileSize : 512;
|
||||
return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE,
|
||||
ghoul::opengl::Texture::Format::BGRA);
|
||||
ghoul::opengl::Texture::Format::BGRA, padTiles);
|
||||
}
|
||||
case layergroupid::GroupID::NightLayers: {
|
||||
size_t tileSize = preferredTileSize ? preferredTileSize : 512;
|
||||
return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE,
|
||||
ghoul::opengl::Texture::Format::BGRA);
|
||||
ghoul::opengl::Texture::Format::BGRA, padTiles);
|
||||
}
|
||||
case layergroupid::GroupID::WaterMasks: {
|
||||
size_t tileSize = preferredTileSize ? preferredTileSize : 512;
|
||||
return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE,
|
||||
ghoul::opengl::Texture::Format::BGRA);
|
||||
ghoul::opengl::Texture::Format::BGRA, padTiles);
|
||||
}
|
||||
default: {
|
||||
ghoul_assert(false, "Unknown layer group ID");
|
||||
size_t tileSize = preferredTileSize ? preferredTileSize : 512;
|
||||
return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE,
|
||||
ghoul::opengl::Texture::Format::BGRA);
|
||||
ghoul::opengl::Texture::Format::BGRA, padTiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ public:
|
||||
void reset(bool includingDisabled = false);
|
||||
|
||||
static TileTextureInitData getTileTextureInitData(layergroupid::GroupID id,
|
||||
size_t preferredTileSize = 0);
|
||||
bool padTiles,
|
||||
size_t preferredTileSize = 0);
|
||||
|
||||
static bool shouldPerformPreProcessingOnLayergroup(layergroupid::GroupID id);
|
||||
void onChange(std::function<void(void)> callback);
|
||||
|
||||
@@ -116,17 +116,6 @@ LayerShaderManager::LayerShaderPreprocessingData
|
||||
);
|
||||
pairs.emplace_back("defaultHeight", std::to_string(Chunk::DEFAULT_HEIGHT));
|
||||
|
||||
pairs.emplace_back("tilePaddingStart",
|
||||
"ivec2(" +
|
||||
std::to_string(RawTileDataReader::padding.start.x) + "," +
|
||||
std::to_string(RawTileDataReader::padding.start.y) + ")"
|
||||
);
|
||||
pairs.emplace_back("tilePaddingSizeDiff",
|
||||
"ivec2(" +
|
||||
std::to_string(RawTileDataReader::padding.numPixels.x) + "," +
|
||||
std::to_string(RawTileDataReader::padding.numPixels.y) + ")"
|
||||
);
|
||||
|
||||
return preprocessingData;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,19 +119,19 @@ vec4 getSample#{layerGroup}#{i}(vec2 uv, LevelWeights levelWeights,
|
||||
|
||||
// All tile layers are the same. Sample from texture
|
||||
#if (#{#{layerGroup}#{i}LayerType} == 0) // DefaultTileLayer
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv);
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding);
|
||||
#elif (#{#{layerGroup}#{i}LayerType} == 1) // SingleImageTileLayer
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv);
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding);
|
||||
#elif (#{#{layerGroup}#{i}LayerType} == 2) // SizeReferenceTileLayer
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv);
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding);
|
||||
#elif (#{#{layerGroup}#{i}LayerType} == 3) // TemporalTileLayer
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv);
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding);
|
||||
#elif (#{#{layerGroup}#{i}LayerType} == 4) // TileIndexTileLayer
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv);
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding);
|
||||
#elif (#{#{layerGroup}#{i}LayerType} == 5) // ByIndexTileLayer
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv);
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding);
|
||||
#elif (#{#{layerGroup}#{i}LayerType} == 6) // ByLevelTileLayer
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv);
|
||||
color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding);
|
||||
#elif (#{#{layerGroup}#{i}LayerType} == 7) // SolidColor
|
||||
color.rgb = #{layerGroup}[#{i}].color;
|
||||
#endif
|
||||
@@ -296,8 +296,12 @@ vec4 calculateDebugColor(vec2 uv, vec4 fragPos, vec2 vertexResolution) {
|
||||
}
|
||||
|
||||
float tileResolution(vec2 tileUV, ChunkTile chunkTile) {
|
||||
PixelPadding padding;
|
||||
padding.startOffset = ivec2(0);
|
||||
padding.sizeDifference = ivec2(0);
|
||||
|
||||
vec2 heightResolution = textureSize(chunkTile.textureSampler, 0);
|
||||
vec2 uv = TileUVToTextureSamplePosition(chunkTile, tileUV);
|
||||
vec2 uv = TileUVToTextureSamplePosition(chunkTile, tileUV, padding);
|
||||
return gridDots(uv, heightResolution);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,90 +25,25 @@
|
||||
#ifndef TEXTURETILE_HGLSL
|
||||
#define TEXTURETILE_HGLSL
|
||||
|
||||
// Must match the values in tiledataset.cpp
|
||||
// (could be set as shader preprocessing data so that multiple definitions
|
||||
// are not needed)
|
||||
#define TILE_PIXEL_START_OFFSET #{tilePaddingStart}
|
||||
#define TILE_PIXEL_SIZE_DIFFERENCE #{tilePaddingSizeDiff}
|
||||
|
||||
vec4 patchBorderOverlay(vec2 uv, vec3 borderColor, float borderSize) {
|
||||
vec2 uvOffset = uv - vec2(0.5);
|
||||
float thres = 0.5 - borderSize/2;
|
||||
bool isBorder = abs(uvOffset.x) > thres || abs(uvOffset.y) > thres;
|
||||
vec3 color = isBorder ? borderColor : vec3(0);
|
||||
return vec4(color, 0);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// ChunkTile Depth Transform //
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TileDepthTransform {
|
||||
float depthScale;
|
||||
float depthOffset;
|
||||
};
|
||||
|
||||
float getTransformedTexVal(TileDepthTransform transform, float val) {
|
||||
return transform.depthOffset + transform.depthScale * val;
|
||||
}
|
||||
|
||||
vec4 getTransformedTexVal(TileDepthTransform transform, vec4 val) {
|
||||
return transform.depthOffset + transform.depthScale * val;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// ChunkTile UV Transform //
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TileUvTransform {
|
||||
vec2 uvOffset;
|
||||
vec2 uvScale;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// ChunkTile //
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct ChunkTile {
|
||||
sampler2D textureSampler;
|
||||
TileUvTransform uvTransform;
|
||||
};
|
||||
|
||||
vec2 compensateSourceTextureSampling(vec2 startOffset, vec2 sizeDiff, ChunkTile chunkTile,
|
||||
vec2 tileUV)
|
||||
{
|
||||
ivec2 resolution = textureSize(chunkTile.textureSampler, 0);
|
||||
|
||||
vec2 sourceSize = vec2(resolution) + sizeDiff;
|
||||
vec2 currentSize = vec2(resolution);
|
||||
vec2 sourceToCurrentSize = currentSize / sourceSize;
|
||||
return sourceToCurrentSize * (tileUV - startOffset / sourceSize);
|
||||
}
|
||||
|
||||
vec2 TileUVToTextureSamplePosition(ChunkTile chunkTile, vec2 tileUV) {
|
||||
vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV;
|
||||
return compensateSourceTextureSampling(
|
||||
TILE_PIXEL_START_OFFSET,
|
||||
TILE_PIXEL_SIZE_DIFFERENCE,
|
||||
chunkTile,
|
||||
uv
|
||||
);
|
||||
}
|
||||
|
||||
vec4 getTexVal(ChunkTile chunkTile, vec2 tileUV) {
|
||||
return texture(
|
||||
chunkTile.textureSampler,
|
||||
TileUVToTextureSamplePosition(chunkTile, tileUV)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Chunk Tile Pile //
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
struct PixelPadding {
|
||||
ivec2 startOffset;
|
||||
ivec2 sizeDifference;
|
||||
};
|
||||
|
||||
struct ChunkTilePile {
|
||||
ChunkTile chunkTile0;
|
||||
@@ -134,6 +69,7 @@ struct Layer {
|
||||
TileDepthTransform depthTransform;
|
||||
LayerSettings settings;
|
||||
LayerAdjustment adjustment;
|
||||
PixelPadding padding;
|
||||
|
||||
// Other layer type properties stuff
|
||||
vec3 color;
|
||||
@@ -145,6 +81,52 @@ struct LevelWeights {
|
||||
float w3;
|
||||
};
|
||||
|
||||
vec4 patchBorderOverlay(vec2 uv, vec3 borderColor, float borderSize) {
|
||||
vec2 uvOffset = uv - vec2(0.5);
|
||||
float thres = 0.5 - borderSize/2;
|
||||
bool isBorder = abs(uvOffset.x) > thres || abs(uvOffset.y) > thres;
|
||||
vec3 color = isBorder ? borderColor : vec3(0);
|
||||
return vec4(color, 0);
|
||||
}
|
||||
|
||||
float getTransformedTexVal(TileDepthTransform transform, float val) {
|
||||
return transform.depthOffset + transform.depthScale * val;
|
||||
}
|
||||
|
||||
vec4 getTransformedTexVal(TileDepthTransform transform, vec4 val) {
|
||||
return transform.depthOffset + transform.depthScale * val;
|
||||
}
|
||||
|
||||
vec2 compensateSourceTextureSampling(vec2 startOffset, vec2 sizeDiff, ChunkTile chunkTile,
|
||||
vec2 tileUV)
|
||||
{
|
||||
ivec2 resolution = textureSize(chunkTile.textureSampler, 0);
|
||||
|
||||
vec2 sourceSize = vec2(resolution) + sizeDiff;
|
||||
vec2 currentSize = vec2(resolution);
|
||||
vec2 sourceToCurrentSize = currentSize / sourceSize;
|
||||
return sourceToCurrentSize * (tileUV - startOffset / sourceSize);
|
||||
}
|
||||
|
||||
vec2 TileUVToTextureSamplePosition(ChunkTile chunkTile, vec2 tileUV,
|
||||
PixelPadding padding)
|
||||
{
|
||||
vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV;
|
||||
return compensateSourceTextureSampling(
|
||||
padding.startOffset,
|
||||
padding.sizeDifference,
|
||||
chunkTile,
|
||||
uv
|
||||
);
|
||||
}
|
||||
|
||||
vec4 getTexVal(ChunkTile chunkTile, vec2 tileUV, PixelPadding padding) {
|
||||
return texture(
|
||||
chunkTile.textureSampler,
|
||||
TileUVToTextureSamplePosition(chunkTile, tileUV, padding)
|
||||
);
|
||||
}
|
||||
|
||||
float getLevelInterpolationParameter(int chunkLevel, float distanceScaleFactor,
|
||||
float distToVertexOnEllipsoid)
|
||||
{
|
||||
@@ -172,10 +154,12 @@ LevelWeights getDefaultLevelWeights() {
|
||||
return levelWeights;
|
||||
}
|
||||
|
||||
vec4 getTexVal(ChunkTilePile chunkTilePile, LevelWeights w, vec2 uv) {
|
||||
return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv) +
|
||||
w.w2 * getTexVal(chunkTilePile.chunkTile1, uv) +
|
||||
w.w3 * getTexVal(chunkTilePile.chunkTile2, uv);
|
||||
vec4 getTexVal(ChunkTilePile chunkTilePile, LevelWeights w, vec2 uv,
|
||||
PixelPadding padding)
|
||||
{
|
||||
return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv, padding) +
|
||||
w.w2 * getTexVal(chunkTilePile.chunkTile1, uv, padding) +
|
||||
w.w3 * getTexVal(chunkTilePile.chunkTile2, uv, padding);
|
||||
}
|
||||
|
||||
#endif // TEXTURETILE_HGLSL
|
||||
|
||||
@@ -97,8 +97,6 @@ vec3 getTileNormal(vec2 uv, LevelWeights levelWeights, vec3 ellipsoidNormalCamer
|
||||
vec3 ellipsoidTangentThetaCameraSpace,
|
||||
vec3 ellipsoidTangentPhiCameraSpace)
|
||||
{
|
||||
return ellipsoidNormalCameraSpace;
|
||||
|
||||
#if USE_ACCURATE_NORMALS
|
||||
float deltaPhi = mix(deltaPhi0, deltaPhi1, uv.x);
|
||||
float deltaTheta = mix(deltaTheta0, deltaTheta1, uv.y);
|
||||
@@ -114,7 +112,9 @@ vec3 getTileNormal(vec2 uv, LevelWeights levelWeights, vec3 ellipsoidNormalCamer
|
||||
vec3 diffPhi = deltaPhiVec + ellipsoidNormalCameraSpace * (height01 - height00);
|
||||
|
||||
return normalize(cross(diffTheta, diffPhi));
|
||||
#endif // USE_ACCURATE_NORMALS
|
||||
#else // USE_ACCURATE_NORMALS
|
||||
return ellipsoidNormalCameraSpace;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // TILE_HEIGHT_HGLSL
|
||||
|
||||
@@ -106,6 +106,10 @@ int GdalRawTileDataReader::rasterYSize() const {
|
||||
return _gdalDatasetMetaDataCached.rasterYSize;
|
||||
}
|
||||
|
||||
int GdalRawTileDataReader::dataSourceNumRasters() const {
|
||||
return _gdalDatasetMetaDataCached.rasterCount;
|
||||
}
|
||||
|
||||
float GdalRawTileDataReader::depthOffset() const {
|
||||
return _gdalDatasetMetaDataCached.offset;
|
||||
}
|
||||
@@ -118,38 +122,6 @@ std::array<double, 6> GdalRawTileDataReader::getGeoTransform() const {
|
||||
return _gdalDatasetMetaDataCached.padfTransform;
|
||||
}
|
||||
|
||||
IODescription GdalRawTileDataReader::getIODescription(const TileIndex& tileIndex) const {
|
||||
IODescription io;
|
||||
io.read.region = highestResPixelRegion(tileIndex);
|
||||
|
||||
// write region starts in origin
|
||||
io.write.region.start = PixelRegion::PixelCoordinate(0, 0);
|
||||
io.write.region.numPixels = PixelRegion::PixelCoordinate(
|
||||
_initData.dimensionsWithoutPadding().x, _initData.dimensionsWithoutPadding().y);
|
||||
|
||||
io.read.overview = 0;
|
||||
io.read.fullRegion = fullPixelRegion();
|
||||
// For correct sampling in dataset, we need to pad the texture tile
|
||||
|
||||
PixelRegion scaledPadding = padding;
|
||||
double scale =
|
||||
io.read.region.numPixels.x / static_cast<double>(io.write.region.numPixels.x);
|
||||
scaledPadding.numPixels *= scale;
|
||||
scaledPadding.start *= scale;
|
||||
|
||||
io.read.region.pad(scaledPadding);
|
||||
io.write.region.pad(padding);
|
||||
io.write.region.start = PixelRegion::PixelCoordinate(0, 0);
|
||||
|
||||
io.write.bytesPerLine = _initData.bytesPerLine();
|
||||
io.write.totalNumBytes = _initData.totalNumBytes();
|
||||
|
||||
ghoul_assert(io.write.region.numPixels.x == io.write.region.numPixels.y, "");
|
||||
ghoul_assert(io.write.region.numPixels.x == _initData.dimensionsWithPadding().x, "");
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
void GdalRawTileDataReader::initialize() {
|
||||
if (_datasetFilePath.empty()) {
|
||||
throw ghoul::RuntimeError("File path must not be empty");
|
||||
@@ -172,7 +144,7 @@ void GdalRawTileDataReader::initialize() {
|
||||
|
||||
_depthTransform = calculateTileDepthTransform();
|
||||
_cached._tileLevelDifference =
|
||||
calculateTileLevelDifference(_initData.dimensionsWithoutPadding().x);
|
||||
calculateTileLevelDifference(_initData.dimensions().x);
|
||||
|
||||
int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount();
|
||||
_cached._maxLevel = -_cached._tileLevelDifference;
|
||||
@@ -182,134 +154,6 @@ void GdalRawTileDataReader::initialize() {
|
||||
_cached._maxLevel = std::max(_cached._maxLevel, 2);
|
||||
}
|
||||
|
||||
void GdalRawTileDataReader::readImageData(
|
||||
IODescription& io, RawTile::ReadError& worstError, char* imageDataDest) const {
|
||||
|
||||
// Only read the minimum number of rasters
|
||||
int nRastersToRead = std::min(_gdalDatasetMetaDataCached.rasterCount,
|
||||
static_cast<int>(_initData.nRasters()));
|
||||
|
||||
switch (_initData.ghoulTextureFormat()) {
|
||||
case ghoul::opengl::Texture::Format::Red:
|
||||
if (nRastersToRead == 1) { // One channel
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + _initData.bytesPerDatum();
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
break;
|
||||
case ghoul::opengl::Texture::Format::RG:
|
||||
case ghoul::opengl::Texture::Format::RGB:
|
||||
case ghoul::opengl::Texture::Format::RGBA: {
|
||||
if (nRastersToRead == 1) { // Grayscale
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
else if (nRastersToRead == 2) { // Grayscale + alpha
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
// Last read is the alpha channel
|
||||
char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum());
|
||||
RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
else { // Three or more rasters
|
||||
for (int i = 0; i < nRastersToRead; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ghoul::opengl::Texture::Format::BGR:
|
||||
case ghoul::opengl::Texture::Format::BGRA: {
|
||||
if (nRastersToRead == 1) { // Grayscale
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
else if (nRastersToRead == 2) { // Grayscale + alpha
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
// Last read is the alpha channel
|
||||
char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum());
|
||||
RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
else { // Three or more rasters
|
||||
for (int i = 0; i < 3 && i < nRastersToRead; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
if (nRastersToRead > 3) { // Alpha channel exists
|
||||
// Last read is the alpha channel
|
||||
char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum());
|
||||
RawTile::ReadError err = repeatedRasterRead(4, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ghoul_assert(false, "Texture format not supported for tiles");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RawTile::ReadError GdalRawTileDataReader::rasterRead(
|
||||
int rasterBand, const IODescription& io, char* dataDestination) const
|
||||
{
|
||||
|
||||
@@ -63,11 +63,10 @@ public:
|
||||
* \param baseDirectory, the base directory to use in future loading operations
|
||||
*/
|
||||
GdalRawTileDataReader(const std::string& filePath,
|
||||
const TileTextureInitData& initData,
|
||||
const std::string& baseDirectory = "",
|
||||
RawTileDataReader::PerformPreprocessing preprocess =
|
||||
RawTileDataReader::PerformPreprocessing::No
|
||||
);
|
||||
const TileTextureInitData& initData,
|
||||
const std::string& baseDirectory = "",
|
||||
RawTileDataReader::PerformPreprocessing preprocess =
|
||||
RawTileDataReader::PerformPreprocessing::No);
|
||||
|
||||
|
||||
virtual ~GdalRawTileDataReader() override;
|
||||
@@ -78,6 +77,7 @@ public:
|
||||
virtual float noDataValueAsFloat() const override;
|
||||
virtual int rasterXSize() const override;
|
||||
virtual int rasterYSize() const override;
|
||||
virtual int dataSourceNumRasters() const;
|
||||
virtual float depthOffset() const override;
|
||||
virtual float depthScale() const override;
|
||||
|
||||
@@ -90,15 +90,12 @@ protected:
|
||||
* the pixel coordinates to cover the whole geodetic lat long space.
|
||||
*/
|
||||
virtual std::array<double, 6> getGeoTransform() const override;
|
||||
virtual IODescription getIODescription(const TileIndex& tileIndex) const override;
|
||||
|
||||
private:
|
||||
// Private virtual function overloading
|
||||
virtual void initialize() override;
|
||||
virtual void readImageData(IODescription& io, RawTile::ReadError& worstError,
|
||||
char* dataDestination) const override;
|
||||
virtual RawTile::ReadError rasterRead(
|
||||
int rasterBand, const IODescription& io, char* dst) const override;
|
||||
virtual RawTile::ReadError rasterRead(int rasterBand, const IODescription& io,
|
||||
char* dst) const override;
|
||||
|
||||
// GDAL Helper methods
|
||||
GDALDataset* openGdalDataset(const std::string& filePath);
|
||||
|
||||
@@ -54,18 +54,13 @@
|
||||
#include <math.h>
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
const PixelRegion RawTileDataReader::padding = PixelRegion(
|
||||
TileTextureInitData::tilePixelStartOffset,
|
||||
TileTextureInitData::tilePixelSizeDifference
|
||||
);
|
||||
|
||||
|
||||
RawTileDataReader::RawTileDataReader(const TileTextureInitData& initData,
|
||||
PerformPreprocessing preprocess)
|
||||
PerformPreprocessing preprocess)
|
||||
: _initData(initData)
|
||||
, _preprocess(preprocess)
|
||||
, _hasBeenInitialized(false)
|
||||
{}
|
||||
{ }
|
||||
|
||||
std::shared_ptr<RawTile> RawTileDataReader::defaultTileData() const {
|
||||
return std::make_shared<RawTile>(RawTile::createDefault(_initData));
|
||||
@@ -115,6 +110,173 @@ std::shared_ptr<RawTile> RawTileDataReader::readTileData(TileIndex tileIndex,
|
||||
return rawTile;
|
||||
}
|
||||
|
||||
void RawTileDataReader::readImageData(IODescription& io, RawTile::ReadError& worstError,
|
||||
char* imageDataDest) const
|
||||
{
|
||||
io = adjustIODescription(io);
|
||||
|
||||
// Only read the minimum number of rasters
|
||||
int nRastersToRead = std::min(dataSourceNumRasters(),
|
||||
static_cast<int>(_initData.nRasters()));
|
||||
|
||||
switch (_initData.ghoulTextureFormat()) {
|
||||
case ghoul::opengl::Texture::Format::Red: {
|
||||
char* dataDestination = imageDataDest;
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
worstError = std::max(worstError, err);
|
||||
break;
|
||||
}
|
||||
case ghoul::opengl::Texture::Format::RG:
|
||||
case ghoul::opengl::Texture::Format::RGB:
|
||||
case ghoul::opengl::Texture::Format::RGBA: {
|
||||
if (nRastersToRead == 1) { // Grayscale
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
else if (nRastersToRead == 2) { // Grayscale + alpha
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
// Last read is the alpha channel
|
||||
char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum());
|
||||
RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
else { // Three or more rasters
|
||||
for (int i = 0; i < nRastersToRead; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ghoul::opengl::Texture::Format::BGR:
|
||||
case ghoul::opengl::Texture::Format::BGRA: {
|
||||
if (nRastersToRead == 1) { // Grayscale
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
else if (nRastersToRead == 2) { // Grayscale + alpha
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
// Last read is the alpha channel
|
||||
char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum());
|
||||
RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
else { // Three or more rasters
|
||||
for (int i = 0; i < 3 && i < nRastersToRead; i++) {
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum());
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
}
|
||||
if (nRastersToRead > 3) { // Alpha channel exists
|
||||
// Last read is the alpha channel
|
||||
char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum());
|
||||
RawTile::ReadError err = repeatedRasterRead(4, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ghoul_assert(false, "Texture format not supported for tiles");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IODescription RawTileDataReader::adjustIODescription(const IODescription& io) const {
|
||||
return io;
|
||||
}
|
||||
|
||||
IODescription RawTileDataReader::getIODescription(const TileIndex& tileIndex) const {
|
||||
IODescription io;
|
||||
io.read.region = highestResPixelRegion(tileIndex);
|
||||
|
||||
// write region starts in origin
|
||||
io.write.region.start = PixelRegion::PixelCoordinate(0, 0);
|
||||
io.write.region.numPixels = PixelRegion::PixelCoordinate(
|
||||
_initData.dimensions().x, _initData.dimensions().y);
|
||||
|
||||
io.read.overview = 0;
|
||||
io.read.fullRegion = fullPixelRegion();
|
||||
// For correct sampling in dataset, we need to pad the texture tile
|
||||
|
||||
PixelRegion padding = PixelRegion(
|
||||
_initData.tilePixelStartOffset(),
|
||||
_initData.tilePixelSizeDifference()
|
||||
);
|
||||
|
||||
PixelRegion scaledPadding = padding;
|
||||
double scale =
|
||||
io.read.region.numPixels.x / static_cast<double>(io.write.region.numPixels.x);
|
||||
scaledPadding.numPixels *= scale;
|
||||
scaledPadding.start *= scale;
|
||||
|
||||
io.read.region.pad(scaledPadding);
|
||||
//io.write.region.pad(padding);
|
||||
//io.write.region.start = PixelRegion::PixelCoordinate(0, 0);
|
||||
|
||||
io.write.bytesPerLine = _initData.bytesPerLine();
|
||||
io.write.totalNumBytes = _initData.totalNumBytes();
|
||||
|
||||
ghoul_assert(io.write.region.numPixels.x == io.write.region.numPixels.y,
|
||||
"Write region must be square");
|
||||
ghoul_assert(io.write.region.numPixels.x == _initData.dimensions().x,
|
||||
"Write region must match tile it writes to.");
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
TileDepthTransform RawTileDataReader::getDepthTransform() const {
|
||||
return _depthTransform;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
using PerformPreprocessing = ghoul::Boolean;
|
||||
|
||||
RawTileDataReader(const TileTextureInitData& initData,
|
||||
PerformPreprocessing preprocess = PerformPreprocessing::No);
|
||||
PerformPreprocessing preprocess = PerformPreprocessing::No);
|
||||
virtual ~RawTileDataReader() = default;
|
||||
|
||||
/**
|
||||
@@ -75,6 +75,7 @@ public:
|
||||
virtual float noDataValueAsFloat() const = 0;
|
||||
virtual int rasterXSize() const = 0;
|
||||
virtual int rasterYSize() const = 0;
|
||||
virtual int dataSourceNumRasters() const = 0;
|
||||
virtual float depthOffset() const;
|
||||
virtual float depthScale() const;
|
||||
PixelRegion fullPixelRegion() const;
|
||||
@@ -83,9 +84,6 @@ public:
|
||||
* Returns a single channeled empty <code>RawTile</code> of size 16 * 16 pixels.
|
||||
*/
|
||||
std::shared_ptr<RawTile> defaultTileData() const;
|
||||
|
||||
/// Padding around all tiles to read to make sure edge blending works.
|
||||
const static PixelRegion padding; // same as the two above
|
||||
|
||||
protected:
|
||||
|
||||
@@ -95,11 +93,6 @@ protected:
|
||||
*/
|
||||
virtual void initialize() = 0;
|
||||
|
||||
/**
|
||||
* Call this in the constructor of the class extending <code>RawTileDataReader</code>
|
||||
*/
|
||||
//void ensureInitialized();
|
||||
|
||||
/**
|
||||
* The function returns a transform to map
|
||||
* the pixel coordinates to cover the whole geodetic lat long space.
|
||||
@@ -112,13 +105,19 @@ protected:
|
||||
* \param <code>worstError</code> should be set to the error code returned when
|
||||
* reading the data.
|
||||
*/
|
||||
virtual void readImageData(
|
||||
IODescription& io, RawTile::ReadError& worstError, char* dataDestination) const = 0;
|
||||
void readImageData(
|
||||
IODescription& io, RawTile::ReadError& worstError, char* dataDestination) const;
|
||||
|
||||
/**
|
||||
* The default does not affect the IODescription but this function can be used for
|
||||
* example to flip the y axis.
|
||||
*/
|
||||
virtual IODescription adjustIODescription(const IODescription& io) const;
|
||||
|
||||
virtual RawTile::ReadError rasterRead(
|
||||
int rasterBand, const IODescription& io, char* dst) const = 0;
|
||||
|
||||
virtual IODescription getIODescription(const TileIndex& tileIndex) const = 0;
|
||||
IODescription getIODescription(const TileIndex& tileIndex) const;
|
||||
|
||||
/**
|
||||
* Get the pixel corresponding to a specific position on the globe defined by the
|
||||
|
||||
@@ -57,7 +57,8 @@ void SimpleRawTileDataReader::reset() {
|
||||
}
|
||||
|
||||
int SimpleRawTileDataReader::maxChunkLevel() const {
|
||||
return 2;
|
||||
float ratio = static_cast<float>(rasterYSize()) / _initData.dimensions().y;
|
||||
return glm::max(2, 1 + static_cast<int>(glm::log2(ratio)));
|
||||
}
|
||||
|
||||
float SimpleRawTileDataReader::noDataValueAsFloat() const {
|
||||
@@ -72,6 +73,10 @@ int SimpleRawTileDataReader::rasterYSize() const {
|
||||
return _dataTexture->dimensions().y;
|
||||
}
|
||||
|
||||
int SimpleRawTileDataReader::dataSourceNumRasters() const {
|
||||
return _dataTexture->numberOfChannels();
|
||||
}
|
||||
|
||||
float SimpleRawTileDataReader::depthOffset() const {
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -80,18 +85,6 @@ float SimpleRawTileDataReader::depthScale() const {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
IODescription SimpleRawTileDataReader::getIODescription(const TileIndex& tileIndex) const {
|
||||
IODescription io;
|
||||
io.read.overview = 0;
|
||||
io.read.region = highestResPixelRegion(tileIndex);
|
||||
io.read.fullRegion = PixelRegion({0, 0}, {rasterXSize(), rasterYSize()});
|
||||
io.write.region = PixelRegion({0, 0}, io.read.region.numPixels);
|
||||
io.write.bytesPerLine = _dataTexture->bytesPerPixel() * io.write.region.numPixels.x;
|
||||
io.write.totalNumBytes = io.write.bytesPerLine * io.write.region.numPixels.y;
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
void SimpleRawTileDataReader::initialize() {
|
||||
_dataTexture = ghoul::io::TextureReader::ref().loadTexture(_datasetFilePath);
|
||||
if (_dataTexture == nullptr) {
|
||||
@@ -101,62 +94,112 @@ void SimpleRawTileDataReader::initialize() {
|
||||
"formats."
|
||||
);
|
||||
}
|
||||
float exponentX = log2(_dataTexture->dimensions().x);
|
||||
float exponentY = log2(_dataTexture->dimensions().y);
|
||||
if ( (exponentX - static_cast<int>(exponentX)) > 0.0001 ||
|
||||
(exponentY - static_cast<int>(exponentY)) > 0.0001 ) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Unable to read dataset: " + _datasetFilePath +
|
||||
".\nCurrently only supporting power of 2 textures."
|
||||
);
|
||||
}
|
||||
|
||||
_depthTransform = {depthScale(), depthOffset()};
|
||||
}
|
||||
|
||||
void SimpleRawTileDataReader::readImageData(
|
||||
IODescription& io, RawTile::ReadError& worstError, char* dataDestination) const {
|
||||
|
||||
// Modify to match OpenGL texture layout:
|
||||
IODescription modifiedIO = io;
|
||||
modifiedIO.read.region.start.y = modifiedIO.read.fullRegion.numPixels.y - modifiedIO.read.region.numPixels.y - modifiedIO.read.region.start.y;
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(0, modifiedIO, dataDestination);
|
||||
|
||||
// None = 0, Debug = 1, Warning = 2, Failure = 3, Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
|
||||
RawTile::ReadError SimpleRawTileDataReader::rasterRead(
|
||||
int rasterBand, const IODescription& io, char* dataDestination) const
|
||||
{
|
||||
ghoul_assert(static_cast<unsigned int>(io.read.fullRegion.numPixels.x) == _dataTexture->dimensions().x,
|
||||
ghoul_assert(static_cast<unsigned int>(
|
||||
io.read.fullRegion.numPixels.x) == _dataTexture->dimensions().x,
|
||||
"IODescription does not match data texture.");
|
||||
ghoul_assert(static_cast<unsigned int>(io.read.fullRegion.numPixels.y) == _dataTexture->dimensions().y,
|
||||
"IODescription does not match data texture.");
|
||||
ghoul_assert(io.read.region.numPixels.x == io.write.region.numPixels.x,
|
||||
"IODescription does not match data texture.");
|
||||
ghoul_assert(io.read.region.numPixels.y == io.write.region.numPixels.y,
|
||||
ghoul_assert(static_cast<unsigned int>(
|
||||
io.read.fullRegion.numPixels.y) == _dataTexture->dimensions().y,
|
||||
"IODescription does not match data texture.");
|
||||
|
||||
char* pixelWriteRow = dataDestination;
|
||||
try {
|
||||
// For each row
|
||||
for (int y = 0; y < io.read.region.numPixels.y; y++) {
|
||||
int bytesPerLineDataTexture =
|
||||
_dataTexture->bytesPerPixel() * _dataTexture->dimensions().x;
|
||||
const char* textureRow = (static_cast<const char*>(_dataTexture->pixelData())
|
||||
+ io.read.region.start.x * _dataTexture->bytesPerPixel())
|
||||
+ io.read.region.start.y * bytesPerLineDataTexture
|
||||
+ y * bytesPerLineDataTexture;
|
||||
memcpy(pixelWriteRow, textureRow, io.write.bytesPerLine);
|
||||
pixelWriteRow += io.write.bytesPerLine;
|
||||
char* writeDataStart =
|
||||
dataDestination +
|
||||
_initData.bytesPerLine() * io.write.region.start.y +
|
||||
_initData.bytesPerPixel() * io.write.region.start.x;
|
||||
|
||||
for (int y = 0; y < io.write.region.numPixels.y; ++y) {
|
||||
for (int x = 0; x < io.write.region.numPixels.x; ++x) {
|
||||
char* pixelWriteDestination =
|
||||
writeDataStart +
|
||||
y * _initData.bytesPerLine() +
|
||||
x * _initData.bytesPerPixel();
|
||||
|
||||
int xInSource =
|
||||
io.read.region.start.x +
|
||||
static_cast<float>(x) / io.write.region.numPixels.x *
|
||||
io.read.region.numPixels.x;
|
||||
int yInSource =
|
||||
io.read.region.start.y +
|
||||
static_cast<float>(y) / io.write.region.numPixels.y *
|
||||
io.read.region.numPixels.y;
|
||||
|
||||
glm::vec4 sourceTexel = _dataTexture->texelAsFloat(xInSource, yInSource);
|
||||
|
||||
// Different type reinterpreting depending on the type of the target texture
|
||||
// the _initData.glType() does not necessarily have to be the same type as
|
||||
// the type of the source texture. Therefore the value is cast to float first.
|
||||
switch (_initData.glType()) {
|
||||
case GL_UNSIGNED_BYTE: {
|
||||
unsigned char value = static_cast<unsigned char>(
|
||||
sourceTexel[rasterBand - 1] * 255
|
||||
);
|
||||
*reinterpret_cast<unsigned char*>(pixelWriteDestination) = value;
|
||||
break;
|
||||
}
|
||||
case GL_BYTE: {
|
||||
char value = static_cast<char>(
|
||||
sourceTexel[rasterBand - 1] * 255
|
||||
);
|
||||
*reinterpret_cast<char*>(pixelWriteDestination) = value;
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_SHORT: {
|
||||
unsigned short value = static_cast<unsigned short>(
|
||||
sourceTexel[rasterBand - 1] * 65535
|
||||
);
|
||||
*reinterpret_cast<unsigned short*>(pixelWriteDestination) = value;
|
||||
break;
|
||||
}
|
||||
case GL_SHORT: {
|
||||
short value = static_cast<short>(
|
||||
sourceTexel[rasterBand - 1] * 65535
|
||||
);
|
||||
*reinterpret_cast<short*>(pixelWriteDestination) = value;
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_INT: {
|
||||
unsigned int value = static_cast<unsigned int>(
|
||||
sourceTexel[rasterBand - 1] * 4294967295
|
||||
);
|
||||
*reinterpret_cast<unsigned int*>(pixelWriteDestination) = value;
|
||||
break;
|
||||
}
|
||||
case GL_INT: {
|
||||
int value = static_cast<int>(
|
||||
sourceTexel[rasterBand - 1] * 4294967295
|
||||
);
|
||||
*reinterpret_cast<int*>(pixelWriteDestination) = value;
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT: {
|
||||
float value = sourceTexel[rasterBand - 1];
|
||||
*reinterpret_cast<float*>(pixelWriteDestination) = value;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ghoul_assert(false, "Unknown texture type");
|
||||
return RawTile::ReadError::Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
return RawTile::ReadError::Failure;
|
||||
}
|
||||
return RawTile::ReadError::None;
|
||||
}
|
||||
|
||||
IODescription SimpleRawTileDataReader::adjustIODescription(const IODescription& io) const {
|
||||
// Modify to match OpenGL texture layout
|
||||
IODescription modifiedIO = io;
|
||||
modifiedIO.read.region.start.y =
|
||||
modifiedIO.read.fullRegion.numPixels.y -
|
||||
modifiedIO.read.region.numPixels.y -
|
||||
modifiedIO.read.region.start.y;
|
||||
|
||||
return modifiedIO;
|
||||
}
|
||||
|
||||
} // namespace openspace::globebrowsing
|
||||
|
||||
@@ -57,18 +57,16 @@ public:
|
||||
virtual float noDataValueAsFloat() const override;
|
||||
virtual int rasterXSize() const override;
|
||||
virtual int rasterYSize() const override;
|
||||
virtual int dataSourceNumRasters() const;
|
||||
virtual float depthOffset() const override;
|
||||
virtual float depthScale() const override;
|
||||
|
||||
protected:
|
||||
|
||||
virtual IODescription getIODescription(const TileIndex& tileIndex) const override;
|
||||
virtual IODescription adjustIODescription(const IODescription& io) const;
|
||||
|
||||
private:
|
||||
// Private virtual function overloading
|
||||
virtual void initialize() override;
|
||||
virtual void readImageData(
|
||||
IODescription& io, RawTile::ReadError& worstError, char* dataDestination) const override;
|
||||
virtual RawTile::ReadError rasterRead(
|
||||
int rasterBand, const IODescription& io, char* dst) const override;
|
||||
|
||||
|
||||
@@ -38,26 +38,4 @@ Tile::Tile(ghoul::opengl::Texture* texture,
|
||||
, _status(status)
|
||||
{ }
|
||||
|
||||
glm::vec2 Tile::compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff,
|
||||
glm::uvec2 resolution, glm::vec2 tileUV)
|
||||
{
|
||||
glm::vec2 sourceSize = glm::vec2(resolution) + sizeDiff;
|
||||
glm::vec2 currentSize = glm::vec2(resolution);
|
||||
glm::vec2 sourceToCurrentSize = currentSize / sourceSize;
|
||||
tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize);
|
||||
return tileUV;
|
||||
}
|
||||
|
||||
glm::vec2 Tile::TileUvToTextureSamplePosition(const TileUvTransform& uvTransform,
|
||||
glm::vec2 tileUV, glm::uvec2 resolution)
|
||||
{
|
||||
glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV;
|
||||
uv = compensateSourceTextureSampling(
|
||||
TileTextureInitData::tilePixelStartOffset,
|
||||
TileTextureInitData::tilePixelSizeDifference,
|
||||
resolution,
|
||||
uv);
|
||||
return uv;
|
||||
}
|
||||
|
||||
} // namespace openspace::globebrowsing
|
||||
|
||||
@@ -85,10 +85,6 @@ public:
|
||||
return _texture;
|
||||
};
|
||||
|
||||
static glm::vec2 compensateSourceTextureSampling(glm::vec2 startOffset,
|
||||
glm::vec2 sizeDiff, glm::uvec2 resolution, glm::vec2 tileUV);
|
||||
static glm::vec2 TileUvToTextureSamplePosition(const TileUvTransform& uvTransform,
|
||||
glm::vec2 tileUV, glm::uvec2 resolution);
|
||||
/**
|
||||
* A tile with status unavailable that any user can return to
|
||||
* indicate that a tile was unavailable.
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace {
|
||||
const char* KeyFilePath = "FilePath";
|
||||
const char* KeyBasePath = "BasePath";
|
||||
const char* KeyPreCacheLevel = "PreCacheLevel";
|
||||
const char* KeyPadTiles = "PadTiles";
|
||||
|
||||
static const openspace::properties::Property::PropertyInfo FilePathInfo = {
|
||||
"FilePath",
|
||||
@@ -98,9 +99,13 @@ DefaultTileProvider::DefaultTileProvider(const ghoul::Dictionary& dictionary)
|
||||
LDEBUG("Default pixel size overridden: " << pixelSize);
|
||||
tilePixelSize = static_cast<int>(pixelSize);
|
||||
}
|
||||
|
||||
_padTiles = true;
|
||||
dictionary.getValue<bool>(KeyPadTiles, _padTiles);
|
||||
|
||||
TileTextureInitData initData(LayerManager::getTileTextureInitData(
|
||||
_layerGroupID, tilePixelSize));
|
||||
_tilePixelSize.setValue(initData.dimensionsWithoutPadding().x);
|
||||
_layerGroupID, _padTiles, tilePixelSize));
|
||||
_tilePixelSize.setValue(initData.dimensions().x);
|
||||
|
||||
_performPreProcessing =
|
||||
LayerManager::shouldPerformPreProcessingOnLayergroup(_layerGroupID);
|
||||
@@ -135,8 +140,10 @@ void DefaultTileProvider::update() {
|
||||
initTexturesFromLoadedData();
|
||||
if (_asyncTextureDataProvider->shouldBeDeleted()) {
|
||||
_asyncTextureDataProvider = nullptr;
|
||||
TileTextureInitData initData(LayerManager::getTileTextureInitData(
|
||||
_layerGroupID, _tilePixelSize));
|
||||
TileTextureInitData initData(
|
||||
LayerManager::getTileTextureInitData(_layerGroupID, _padTiles,
|
||||
_tilePixelSize)
|
||||
);
|
||||
initAsyncTileDataReader(initData);
|
||||
}
|
||||
}
|
||||
@@ -148,8 +155,10 @@ void DefaultTileProvider::reset() {
|
||||
_asyncTextureDataProvider->prepairToBeDeleted();
|
||||
}
|
||||
else {
|
||||
TileTextureInitData initData(LayerManager::getTileTextureInitData(
|
||||
_layerGroupID, _tilePixelSize));
|
||||
TileTextureInitData initData(
|
||||
LayerManager::getTileTextureInitData(_layerGroupID, _padTiles,
|
||||
_tilePixelSize)
|
||||
);
|
||||
initAsyncTileDataReader(initData);
|
||||
}
|
||||
}
|
||||
@@ -224,7 +233,8 @@ void DefaultTileProvider::initAsyncTileDataReader(TileTextureInitData initData)
|
||||
|
||||
_asyncTextureDataProvider = std::make_shared<AsyncTileDataProvider>(_name, tileDataset);
|
||||
|
||||
if (_preCacheLevel > -1) {
|
||||
// Tiles are only available for levels 2 and higher.
|
||||
if (_preCacheLevel >= 2) {
|
||||
LDEBUG("Precaching '" << _filePath << "' with level '" << _preCacheLevel << "'");
|
||||
for (int level = 0; level <= _preCacheLevel; ++level) {
|
||||
for (int x = 0; x <= level * 2; ++x) {
|
||||
|
||||
@@ -86,6 +86,7 @@ private:
|
||||
std::string _basePath;
|
||||
int _preCacheLevel;
|
||||
bool _performPreProcessing;
|
||||
bool _padTiles;
|
||||
};
|
||||
|
||||
} // namespace openspace::globebrowsing::tileprovider
|
||||
|
||||
@@ -43,7 +43,8 @@ namespace {
|
||||
namespace openspace::globebrowsing::tileprovider {
|
||||
|
||||
SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary)
|
||||
: TextTileProvider(LayerManager::getTileTextureInitData(layergroupid::GroupID::ColorLayers))
|
||||
: TextTileProvider(
|
||||
LayerManager::getTileTextureInitData(layergroupid::GroupID::ColorLayers, false))
|
||||
, _backgroundTile(Tile::TileUnavailable)
|
||||
{
|
||||
_fontSize = 50;
|
||||
@@ -73,7 +74,7 @@ void SizeReferenceTileProvider::renderText(const ghoul::fontrendering::FontRende
|
||||
textPosition.x = 0;
|
||||
textPosition.y = aboveEquator ?
|
||||
_fontSize / 2.f :
|
||||
_initData.dimensionsWithPadding().y - 3.f * _fontSize / 2.f;
|
||||
_initData.dimensions().y - 3.f * _fontSize / 2.f;
|
||||
glm::vec4 color(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
fontRenderer.render(
|
||||
|
||||
@@ -50,7 +50,7 @@ TextTileProvider::TextTileProvider(const TileTextureInitData& initData, size_t f
|
||||
_font = OsEng.fontManager().font("Mono", static_cast<float>(_fontSize));
|
||||
|
||||
_fontRenderer = std::unique_ptr<FontRenderer>(FontRenderer::createDefault());
|
||||
_fontRenderer->setFramebufferSize(_initData.dimensionsWithPadding());
|
||||
_fontRenderer->setFramebufferSize(_initData.dimensions());
|
||||
|
||||
glGenFramebuffers(1, &_fbo);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace openspace::globebrowsing::tileprovider {
|
||||
|
||||
TileIndexTileProvider::TileIndexTileProvider(const ghoul::Dictionary&)
|
||||
: TextTileProvider(LayerManager::getTileTextureInitData(
|
||||
layergroupid::GroupID::ColorLayers
|
||||
layergroupid::GroupID::ColorLayers,
|
||||
false
|
||||
))
|
||||
{}
|
||||
|
||||
@@ -42,9 +43,9 @@ void TileIndexTileProvider::renderText(const ghoul::fontrendering::FontRenderer&
|
||||
fontRenderer.render(
|
||||
*_font,
|
||||
glm::vec2(
|
||||
_initData.dimensionsWithPadding().x / 4 -
|
||||
(_initData.dimensionsWithPadding().x / 32) * log10(1 << tileIndex.level),
|
||||
_initData.dimensionsWithPadding().y / 2 + _fontSize),
|
||||
_initData.dimensions().x / 4 -
|
||||
(_initData.dimensions().x / 32) * log10(1 << tileIndex.level),
|
||||
_initData.dimensions().y / 2 + _fontSize),
|
||||
glm::vec4(1.0, 1.0, 1.0, 1.0),
|
||||
glm::vec4(1.0, 1.0, 1.0, 1.0),
|
||||
"level: %i \nx: %i \ny: %i",
|
||||
|
||||
@@ -162,13 +162,14 @@ void TileProvider::initializeDefaultTile() {
|
||||
|
||||
// Create pixel data
|
||||
TileTextureInitData initData(8, 8, GL_UNSIGNED_BYTE, Texture::Format::RGBA,
|
||||
false,
|
||||
TileTextureInitData::ShouldAllocateDataOnCPU::Yes);
|
||||
int numBytes = initData.totalNumBytes();
|
||||
char* pixels = new char[numBytes];
|
||||
memset(pixels, 0, numBytes);
|
||||
|
||||
// Create ghoul texture
|
||||
_defaultTileTexture = std::make_unique<Texture>(initData.dimensionsWithPadding());
|
||||
_defaultTileTexture = std::make_unique<Texture>(initData.dimensions());
|
||||
_defaultTileTexture->setDataOwnership(Texture::TakeOwnership::Yes);
|
||||
_defaultTileTexture->setPixelData(pixels);
|
||||
_defaultTileTexture->uploadTexture();
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "TileProviderByLevel";
|
||||
|
||||
const char* KeyProviders = "LevelTileProviders";
|
||||
const char* KeyMaxLevel = "MaxLevel";
|
||||
const char* KeyTileProvider = "TileProvider";
|
||||
@@ -52,66 +50,61 @@ TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) {
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < providers.size(); i++) {
|
||||
try {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary levelProviderDict = providers.value<ghoul::Dictionary>(
|
||||
dictKey
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary levelProviderDict = providers.value<ghoul::Dictionary>(
|
||||
dictKey
|
||||
);
|
||||
double floatMaxLevel;
|
||||
int maxLevel = 0;
|
||||
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyMaxLevel) + "'"
|
||||
);
|
||||
double floatMaxLevel;
|
||||
int maxLevel = 0;
|
||||
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyMaxLevel) + "'"
|
||||
);
|
||||
}
|
||||
maxLevel = std::round(floatMaxLevel);
|
||||
|
||||
ghoul::Dictionary providerDict;
|
||||
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyTileProvider) + "'"
|
||||
);
|
||||
}
|
||||
providerDict.setValue(KeyLayerGroupID, layerGroupID);
|
||||
|
||||
std::string typeString;
|
||||
providerDict.getValue("Type", typeString);
|
||||
layergroupid::TypeID typeID = layergroupid::TypeID::Unknown;
|
||||
if (typeString.empty()) {
|
||||
typeID = layergroupid::TypeID::DefaultTileLayer;
|
||||
}
|
||||
else {
|
||||
typeID = layergroupid::getTypeIDFromTypeString(typeString);
|
||||
}
|
||||
|
||||
if (typeID == layergroupid::TypeID::Unknown) {
|
||||
throw ghoul::RuntimeError("Unknown layer type: " + typeString);
|
||||
}
|
||||
|
||||
_levelTileProviders.push_back(
|
||||
std::shared_ptr<TileProvider>(TileProvider::createFromDictionary(typeID, providerDict))
|
||||
);
|
||||
|
||||
std::string providerName;
|
||||
providerDict.getValue("Name", providerName);
|
||||
_levelTileProviders.back()->setName(providerName);
|
||||
addPropertySubOwner(_levelTileProviders.back().get());
|
||||
|
||||
// Ensure we can represent the max level
|
||||
if(static_cast<int>(_providerIndices.size()) < maxLevel){
|
||||
_providerIndices.resize(maxLevel+1, -1);
|
||||
}
|
||||
|
||||
// map this level to the tile provider index
|
||||
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LWARNING("Unable to create tile provider: " + std::string(e.what()));
|
||||
}
|
||||
maxLevel = std::round(floatMaxLevel);
|
||||
|
||||
ghoul::Dictionary providerDict;
|
||||
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyTileProvider) + "'"
|
||||
);
|
||||
}
|
||||
providerDict.setValue(KeyLayerGroupID, layerGroupID);
|
||||
|
||||
std::string typeString;
|
||||
providerDict.getValue("Type", typeString);
|
||||
layergroupid::TypeID typeID = layergroupid::TypeID::Unknown;
|
||||
if (typeString.empty()) {
|
||||
typeID = layergroupid::TypeID::DefaultTileLayer;
|
||||
}
|
||||
else {
|
||||
typeID = layergroupid::getTypeIDFromTypeString(typeString);
|
||||
}
|
||||
|
||||
if (typeID == layergroupid::TypeID::Unknown) {
|
||||
throw ghoul::RuntimeError("Unknown layer type: " + typeString);
|
||||
}
|
||||
|
||||
_levelTileProviders.push_back(
|
||||
std::shared_ptr<TileProvider>(TileProvider::createFromDictionary(typeID, providerDict))
|
||||
);
|
||||
|
||||
std::string providerName;
|
||||
providerDict.getValue("Name", providerName);
|
||||
_levelTileProviders.back()->setName(providerName);
|
||||
addPropertySubOwner(_levelTileProviders.back().get());
|
||||
|
||||
// Ensure we can represent the max level
|
||||
if (static_cast<int>(_providerIndices.size()) < maxLevel) {
|
||||
_providerIndices.resize(maxLevel+1, -1);
|
||||
}
|
||||
|
||||
// map this level to the tile provider index
|
||||
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
|
||||
}
|
||||
|
||||
// Fill in the gaps (value -1) in provider indices, from back to end
|
||||
for(int i = _providerIndices.size() - 2; i >= 0; --i){
|
||||
for (int i = _providerIndices.size() - 2; i >= 0; --i) {
|
||||
if(_providerIndices[i] == -1){
|
||||
_providerIndices[i] = _providerIndices[i+1];
|
||||
}
|
||||
|
||||
@@ -23,27 +23,31 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/globebrowsing/tile/tiletextureinitdata.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h>
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
const glm::ivec2 TileTextureInitData::tilePixelStartOffset = glm::ivec2(-2);
|
||||
const glm::ivec2 TileTextureInitData::tilePixelSizeDifference = glm::ivec2(4);
|
||||
const glm::ivec2 TileTextureInitData::TilePixelStartOffset = glm::ivec2(-2);
|
||||
const glm::ivec2 TileTextureInitData::TilePixelSizeDifference = glm::ivec2(4);
|
||||
|
||||
TileTextureInitData::TileTextureInitData(size_t width, size_t height, GLenum glType,
|
||||
Format textureFormat, ShouldAllocateDataOnCPU shouldAllocateDataOnCPU)
|
||||
Format textureFormat, bool padTiles,
|
||||
ShouldAllocateDataOnCPU shouldAllocateDataOnCPU)
|
||||
: _glType(glType)
|
||||
, _ghoulTextureFormat(textureFormat)
|
||||
, _padTiles(padTiles)
|
||||
, _shouldAllocateDataOnCPU(shouldAllocateDataOnCPU)
|
||||
{
|
||||
_dimensionsWithoutPadding = glm::ivec3(width, height, 1);
|
||||
_dimensionsWithPadding = glm::ivec3(
|
||||
width + tilePixelSizeDifference.x, height + tilePixelSizeDifference.y, 1);
|
||||
_tilePixelStartOffset = padTiles ? TilePixelStartOffset : glm::ivec2(0);
|
||||
_tilePixelSizeDifference = padTiles ? TilePixelSizeDifference : glm::ivec2(0);
|
||||
|
||||
_dimensions = glm::ivec3(width, height, 1);
|
||||
_nRasters = tiledatatype::numberOfRasters(_ghoulTextureFormat);
|
||||
_bytesPerDatum = tiledatatype::numberOfBytes(glType);
|
||||
_bytesPerPixel = _nRasters * _bytesPerDatum;
|
||||
_bytesPerLine = _bytesPerPixel * _dimensionsWithPadding.x;
|
||||
_totalNumBytes = _bytesPerLine * _dimensionsWithPadding.y;
|
||||
_bytesPerLine = _bytesPerPixel * _dimensions.x;
|
||||
_totalNumBytes = _bytesPerLine * _dimensions.y;
|
||||
_glTextureFormat = tiledatatype::glTextureFormat(_glType,
|
||||
_ghoulTextureFormat);
|
||||
calculateHashKey();
|
||||
@@ -51,19 +55,24 @@ TileTextureInitData::TileTextureInitData(size_t width, size_t height, GLenum glT
|
||||
|
||||
TileTextureInitData::TileTextureInitData(const TileTextureInitData& original)
|
||||
: TileTextureInitData(
|
||||
original.dimensionsWithoutPadding().x,
|
||||
original.dimensionsWithoutPadding().y,
|
||||
original.dimensions().x,
|
||||
original.dimensions().y,
|
||||
original.glType(),
|
||||
original.ghoulTextureFormat(),
|
||||
original._padTiles,
|
||||
original.shouldAllocateDataOnCPU() ? ShouldAllocateDataOnCPU::Yes : ShouldAllocateDataOnCPU::No)
|
||||
{}
|
||||
|
||||
glm::ivec3 TileTextureInitData::dimensionsWithPadding() const {
|
||||
return _dimensionsWithPadding;
|
||||
glm::ivec3 TileTextureInitData::dimensions() const {
|
||||
return _dimensions;
|
||||
}
|
||||
|
||||
glm::ivec3 TileTextureInitData::dimensionsWithoutPadding() const {
|
||||
return _dimensionsWithoutPadding;
|
||||
glm::ivec2 TileTextureInitData::tilePixelStartOffset() const {
|
||||
return _tilePixelStartOffset;
|
||||
}
|
||||
|
||||
glm::ivec2 TileTextureInitData::tilePixelSizeDifference() const {
|
||||
return _tilePixelSizeDifference;
|
||||
}
|
||||
|
||||
size_t TileTextureInitData::nRasters() const {
|
||||
@@ -107,18 +116,18 @@ TileTextureInitData::HashKey TileTextureInitData::hashKey() const {
|
||||
}
|
||||
|
||||
void TileTextureInitData::calculateHashKey() {
|
||||
ghoul_assert(_dimensionsWithoutPadding.x > 0, "Incorrect dimension");
|
||||
ghoul_assert(_dimensionsWithoutPadding.y > 0, "Incorrect dimension");
|
||||
ghoul_assert(_dimensionsWithoutPadding.x <= 1024, "Incorrect dimension");
|
||||
ghoul_assert(_dimensionsWithoutPadding.y <= 1024, "Incorrect dimension");
|
||||
ghoul_assert(_dimensionsWithoutPadding.z == 1, "Incorrect dimension");
|
||||
ghoul_assert(_dimensions.x > 0, "Incorrect dimension");
|
||||
ghoul_assert(_dimensions.y > 0, "Incorrect dimension");
|
||||
ghoul_assert(_dimensions.x <= 1024, "Incorrect dimension");
|
||||
ghoul_assert(_dimensions.y <= 1024, "Incorrect dimension");
|
||||
ghoul_assert(_dimensions.z == 1, "Incorrect dimension");
|
||||
unsigned int format = getUniqueIdFromTextureFormat(_ghoulTextureFormat);
|
||||
ghoul_assert(format < 256, "Incorrect format");
|
||||
|
||||
_hashKey = 0LL;
|
||||
|
||||
_hashKey |= _dimensionsWithoutPadding.x;
|
||||
_hashKey |= _dimensionsWithoutPadding.y << 10;
|
||||
_hashKey |= _dimensions.x;
|
||||
_hashKey |= _dimensions.y << 10;
|
||||
_hashKey |= static_cast<std::underlying_type_t<GLenum>>(_glType) << (10 + 16);
|
||||
_hashKey |= format << (10 + 16 + 4);
|
||||
}
|
||||
|
||||
@@ -43,14 +43,16 @@ public:
|
||||
using Format = ghoul::opengl::Texture::Format;
|
||||
|
||||
TileTextureInitData(size_t width, size_t height, GLenum glType, Format textureFormat,
|
||||
ShouldAllocateDataOnCPU shouldAllocateDataOnCPU = ShouldAllocateDataOnCPU::No);
|
||||
bool padTiles,
|
||||
ShouldAllocateDataOnCPU shouldAllocateDataOnCPU = ShouldAllocateDataOnCPU::No);
|
||||
|
||||
TileTextureInitData(const TileTextureInitData& original);
|
||||
|
||||
~TileTextureInitData() = default;
|
||||
|
||||
glm::ivec3 dimensionsWithPadding() const;
|
||||
glm::ivec3 dimensionsWithoutPadding() const;
|
||||
glm::ivec3 dimensions() const;
|
||||
glm::ivec2 tilePixelStartOffset() const;
|
||||
glm::ivec2 tilePixelSizeDifference() const;
|
||||
size_t nRasters() const;
|
||||
size_t bytesPerDatum() const;
|
||||
size_t bytesPerPixel() const;
|
||||
@@ -62,16 +64,18 @@ public:
|
||||
bool shouldAllocateDataOnCPU() const;
|
||||
HashKey hashKey() const;
|
||||
|
||||
const static glm::ivec2 tilePixelStartOffset;
|
||||
const static glm::ivec2 tilePixelSizeDifference;
|
||||
const static glm::ivec2 TilePixelStartOffset;
|
||||
const static glm::ivec2 TilePixelSizeDifference;
|
||||
|
||||
private:
|
||||
|
||||
void calculateHashKey();
|
||||
unsigned int getUniqueIdFromTextureFormat(Format textureFormat) const;
|
||||
|
||||
HashKey _hashKey;
|
||||
glm::ivec3 _dimensionsWithPadding;
|
||||
glm::ivec3 _dimensionsWithoutPadding;
|
||||
glm::ivec3 _dimensions;
|
||||
glm::ivec2 _tilePixelStartOffset;
|
||||
glm::ivec2 _tilePixelSizeDifference;
|
||||
GLenum _glType;
|
||||
Format _ghoulTextureFormat;
|
||||
GLenum _glTextureFormat;
|
||||
@@ -81,6 +85,7 @@ private:
|
||||
size_t _bytesPerLine;
|
||||
size_t _totalNumBytes;
|
||||
bool _shouldAllocateDataOnCPU;
|
||||
bool _padTiles;
|
||||
};
|
||||
|
||||
} // namespace openspace::globebrowsing
|
||||
|
||||
Reference in New Issue
Block a user