# HG changeset patch # User Benjamin Golinvaux # Date 1560260481 -7200 # Node ID 266e2b0b9abc6dd611d4caf28f0af3486aa10117 # Parent 47fc7919977dff84099b67c10c687372817655b4 better error reporting in DicomStructureSetLoader + fixed POST request logic in WebAssemblyOracle + support for LookupTableTextureSceneLayer in OpenGL (NOT using shaders!) (2 new files) + a few small non-functional changes diff -r 47fc7919977d -r 266e2b0b9abc Framework/Loaders/DicomStructureSetLoader.cpp --- a/Framework/Loaders/DicomStructureSetLoader.cpp Sun Jun 09 18:47:34 2019 +0200 +++ b/Framework/Loaders/DicomStructureSetLoader.cpp Tue Jun 11 15:41:21 2019 +0200 @@ -92,6 +92,14 @@ lookup[0]["ID"].type() != Json::stringValue || lookup[0]["Type"].asString() != "Instance") { + std::stringstream msg; + msg << "Unknown resource! message.GetAnswer() = " << message.GetAnswer() << " message.GetAnswerHeaders() = "; + for (const auto& it : message.GetAnswerHeaders()) + { + msg << "\nkey: \"" << it.first << "\" value: \"" << it.second << "\"\n"; + } + auto msgStr = msg.str(); + LOG(ERROR) << msgStr; throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); } @@ -138,6 +146,7 @@ command->SetMethod(Orthanc::HttpMethod_Post); command->SetBody(*it); command->SetPayload(new LookupInstance(loader, *it)); + //LOG(TRACE) << "About to schedule a /tools/lookup POST request. URI = " << command->GetUri() << " Body size = " << (*it).size() << " Body = " << (*it) << "\n"; Schedule(command.release()); } } diff -r 47fc7919977d -r 266e2b0b9abc Framework/Oracle/WebAssemblyOracle.cpp --- a/Framework/Oracle/WebAssemblyOracle.cpp Sun Jun 09 18:47:34 2019 +0200 +++ b/Framework/Oracle/WebAssemblyOracle.cpp Tue Jun 11 15:41:21 2019 +0200 @@ -284,7 +284,12 @@ void SetBody(std::string& body /* will be swapped */) { + if (body != "") + { + LOG(ERROR) << "Setting non-empty body. body size = " << body.size() << " body = " << body; + } body_.swap(body); + LOG(ERROR) << "After setting non-empty body. body_ size = " << body_.size() << " body_ = " << body_; } void SetHttpHeaders(const HttpHeaders& headers) @@ -365,19 +370,32 @@ attr.requestHeaders = &headers[0]; + char* requestData = NULL; if (!body_.empty()) + requestData = reinterpret_cast(malloc(body_.size())); + + try { - attr.requestDataSize = body_.size(); - attr.requestData = body_.c_str(); - } + if (!body_.empty()) + { + memcpy(requestData, &(body_[0]), body_.size()); + attr.requestDataSize = body_.size(); + attr.requestData = requestData; + } + attr.userData = new FetchContext(oracle_, receiver_, command_.release(), expectedContentType); - // Must be the last call to prevent memory leak on error - attr.userData = new FetchContext(oracle_, receiver_, command_.release(), expectedContentType); - emscripten_fetch(&attr, uri_.c_str()); - } + // Must be the last call to prevent memory leak on error + emscripten_fetch(&attr, uri_.c_str()); + } + catch(...) + { + if(requestData != NULL) + free(requestData); + throw; + } + } }; - void WebAssemblyOracle::Execute(const IObserver& receiver, OrthancRestApiCommand* command) { @@ -388,14 +406,14 @@ fetch.SetHttpHeaders(command->GetHttpHeaders()); fetch.SetTimeout(command->GetTimeout()); - if (command->GetMethod() == Orthanc::HttpMethod_Put || + if (command->GetMethod() == Orthanc::HttpMethod_Post || command->GetMethod() == Orthanc::HttpMethod_Put) { std::string body; command->SwapBody(body); fetch.SetBody(body); } - + fetch.Execute(); } diff -r 47fc7919977d -r 266e2b0b9abc Framework/Scene2D/Internals/CompositorHelper.h --- a/Framework/Scene2D/Internals/CompositorHelper.h Sun Jun 09 18:47:34 2019 +0200 +++ b/Framework/Scene2D/Internals/CompositorHelper.h Tue Jun 11 15:41:21 2019 +0200 @@ -23,6 +23,10 @@ #include "../Scene2D.h" +#include + +#include + namespace OrthancStone { namespace Internals diff -r 47fc7919977d -r 266e2b0b9abc Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp Tue Jun 11 15:41:21 2019 +0200 @@ -0,0 +1,140 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "OpenGLLookupTableTextureRenderer.h" + +namespace OrthancStone +{ + namespace Internals + { + void OpenGLLookupTableTextureRenderer::LoadTexture( + const LookupTableTextureSceneLayer& layer) + { + const Orthanc::ImageAccessor& source = layer.GetTexture(); + const unsigned int width = source.GetWidth(); + const unsigned int height = source.GetHeight(); + + if ((texture_.get() == NULL) || + (texture_->GetWidth() != width) || + (texture_->GetHeight() != height)) + { + + texture_.reset(new Orthanc::Image( + Orthanc::PixelFormat_RGBA32, + width, + height, + false)); + } + + { + + const float a = layer.GetMinValue(); + float slope = 0; + + if (layer.GetMinValue() >= layer.GetMaxValue()) + { + slope = 0; + } + else + { + slope = 256.0f / (layer.GetMaxValue() - layer.GetMinValue()); + } + + Orthanc::ImageAccessor target; + texture_->GetWriteableAccessor(target); + + const std::vector& lut = layer.GetLookupTable(); + if (lut.size() != 4 * 256) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + assert(source.GetFormat() == Orthanc::PixelFormat_Float32 && + target.GetFormat() == Orthanc::PixelFormat_RGBA32 && + sizeof(float) == 4); + + for (unsigned int y = 0; y < height; y++) + { + const float* p = reinterpret_cast(source.GetConstRow(y)); + uint8_t* q = reinterpret_cast(target.GetRow(y)); + + for (unsigned int x = 0; x < width; x++) + { + float v = (*p - a) * slope; + if (v <= 0) + { + v = 0; + } + else if (v >= 255) + { + v = 255; + } + + uint8_t vv = static_cast(v); + + q[0] = lut[4 * vv + 0]; // R + q[1] = lut[4 * vv + 1]; // G + q[2] = lut[4 * vv + 2]; // B + q[3] = lut[4 * vv + 3]; // A + + p++; + q += 4; + } + } + } + + context_.MakeCurrent(); + glTexture_.reset(new OpenGL::OpenGLTexture); + glTexture_->Load(*texture_, layer.IsLinearInterpolation()); + layerTransform_ = layer.GetTransform(); + } + + + OpenGLLookupTableTextureRenderer::OpenGLLookupTableTextureRenderer( + OpenGL::IOpenGLContext& context, + OpenGLColorTextureProgram& program, + const LookupTableTextureSceneLayer& layer) + : context_(context) + , program_(program) + { + LoadTexture(layer); + } + + + void OpenGLLookupTableTextureRenderer::Render(const AffineTransform2D& transform) + { + if (glTexture_.get() != NULL) + { + program_.Apply( + *glTexture_, + AffineTransform2D::Combine(transform, layerTransform_), + true); + } + } + + + void OpenGLLookupTableTextureRenderer::Update(const ISceneLayer& layer) + { + // Should never happen (no revisions in color textures) + LoadTexture(dynamic_cast(layer)); + } + } +} diff -r 47fc7919977d -r 266e2b0b9abc Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.h Tue Jun 11 15:41:21 2019 +0200 @@ -0,0 +1,56 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "OpenGLColorTextureProgram.h" +#include "CompositorHelper.h" +#include "../LookupTableTextureSceneLayer.h" + +#include + +namespace OrthancStone +{ + namespace Internals + { + class OpenGLLookupTableTextureRenderer : public CompositorHelper::ILayerRenderer + { + private: + OpenGL::IOpenGLContext& context_; + OpenGLColorTextureProgram& program_; + std::auto_ptr glTexture_; + std::auto_ptr texture_; + AffineTransform2D layerTransform_; + + void LoadTexture(const LookupTableTextureSceneLayer& layer); + + public: + OpenGLLookupTableTextureRenderer( + OpenGL::IOpenGLContext& context, + OpenGLColorTextureProgram& program, + const LookupTableTextureSceneLayer& layer); + + virtual void Render(const AffineTransform2D& transform); + + virtual void Update(const ISceneLayer& layer); + }; + } +} diff -r 47fc7919977d -r 266e2b0b9abc Framework/Scene2D/OpenGLCompositor.cpp --- a/Framework/Scene2D/OpenGLCompositor.cpp Sun Jun 09 18:47:34 2019 +0200 +++ b/Framework/Scene2D/OpenGLCompositor.cpp Tue Jun 11 15:41:21 2019 +0200 @@ -26,6 +26,7 @@ #include "Internals/OpenGLColorTextureRenderer.h" #include "Internals/OpenGLFloatTextureRenderer.h" #include "Internals/OpenGLInfoPanelRenderer.h" +#include "Internals/OpenGLLookupTableTextureRenderer.h" #include "Internals/OpenGLTextRenderer.h" namespace OrthancStone @@ -92,6 +93,10 @@ return new Internals::OpenGLFloatTextureRenderer (context_, floatTextureProgram_, dynamic_cast(layer)); + case ISceneLayer::Type_LookupTableTexture: + return new Internals::OpenGLLookupTableTextureRenderer + (context_, colorTextureProgram_, dynamic_cast(layer)); + case ISceneLayer::Type_Polyline: return new Internals::OpenGLAdvancedPolylineRenderer (context_, linesProgram_, dynamic_cast(layer)); diff -r 47fc7919977d -r 266e2b0b9abc Framework/Scene2D/RotateSceneTracker.h --- a/Framework/Scene2D/RotateSceneTracker.h Sun Jun 09 18:47:34 2019 +0200 +++ b/Framework/Scene2D/RotateSceneTracker.h Tue Jun 11 15:41:21 2019 +0200 @@ -23,6 +23,7 @@ #include "../Scene2DViewport/OneGesturePointerTracker.h" #include "Internals/FixedPointAligner.h" +#include namespace OrthancStone { diff -r 47fc7919977d -r 266e2b0b9abc Framework/Toolbox/DicomStructureSet.cpp --- a/Framework/Toolbox/DicomStructureSet.cpp Sun Jun 09 18:47:34 2019 +0200 +++ b/Framework/Toolbox/DicomStructureSet.cpp Tue Jun 11 15:41:21 2019 +0200 @@ -413,7 +413,7 @@ countSlices = 0; } - LOG(WARNING) << "New RT structure: \"" << structures_[i].name_ + LOG(INFO) << "New RT structure: \"" << structures_[i].name_ << "\" with interpretation \"" << structures_[i].interpretation_ << "\" containing " << countSlices << " slices (color: " << static_cast(structures_[i].red_) << "," diff -r 47fc7919977d -r 266e2b0b9abc Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Sun Jun 09 18:47:34 2019 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Tue Jun 11 15:41:21 2019 +0200 @@ -535,21 +535,39 @@ if (ENABLE_OPENGL) list(APPEND ORTHANC_STONE_SOURCES + ${ORTHANC_STONE_ROOT}/Framework/Fonts/OpenGLTextCoordinates.h ${ORTHANC_STONE_ROOT}/Framework/Fonts/OpenGLTextCoordinates.cpp + ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLProgram.h ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLProgram.cpp + ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLShader.h ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLShader.cpp + ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLTexture.h ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLTexture.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/OpenGLCompositor.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/OpenGLCompositor.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLAdvancedPolylineRenderer.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLAdvancedPolylineRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLBasicPolylineRenderer.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLBasicPolylineRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLColorTextureProgram.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLColorTextureProgram.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLColorTextureRenderer.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLColorTextureRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLFloatTextureProgram.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLFloatTextureProgram.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLFloatTextureRenderer.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLFloatTextureRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLInfoPanelRenderer.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLInfoPanelRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLLinesProgram.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLLinesProgram.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.h + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLTextProgram.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLTextProgram.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLTextRenderer.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLTextRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLTextureProgram.h ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLTextureProgram.cpp ) diff -r 47fc7919977d -r 266e2b0b9abc Samples/Sdl/FusionMprSdl.cpp --- a/Samples/Sdl/FusionMprSdl.cpp Sun Jun 09 18:47:34 2019 +0200 +++ b/Samples/Sdl/FusionMprSdl.cpp Tue Jun 11 15:41:21 2019 +0200 @@ -715,6 +715,11 @@ window.GetWindow().ToggleMaximize(); break; + case SDLK_s: + controller_->FitContent( + window.GetCanvasWidth(), window.GetCanvasHeight()); + break; + case SDLK_q: g_stopApplication = true; break; @@ -733,7 +738,7 @@ //// from loader - Orthanc::SystemToolbox::ServerBarrier(); + //Orthanc::SystemToolbox::ServerBarrier(); /** * WARNING => The oracle must be stopped BEFORE the objects using