diff --git a/simgear/canvas/elements/CanvasImage.cxx b/simgear/canvas/elements/CanvasImage.cxx index fbd2cf9f..c13f25ab 100644 --- a/simgear/canvas/elements/CanvasImage.cxx +++ b/simgear/canvas/elements/CanvasImage.cxx @@ -838,5 +838,98 @@ namespace canvas return false; } + void Image::fillRect(const SGRect& rect, const std::string& c) + { + osg::Vec4 color(1,1,1,1); + if(!c.empty() && !parseColor(c, color)) + return; + + fillRect(rect, color); + } + +void fillRow(GLubyte* row, GLuint pixel, GLuint width, GLuint pixelBytes) +{ + GLubyte* dst = row; + for (int x = 0; x < width; ++x) { + memcpy(dst, &pixel, pixelBytes); + dst += pixelBytes; + } +} + +SGRect intersectRect(const SGRect& a, const SGRect& b) +{ + SGVec2 m1 = max(a.getMin(), b.getMin()); + SGVec2 m2 = min(a.getMax(), b.getMax()); + return SGRect(m1, m2); +} + + void Image::fillRect(const SGRect& rect, const osg::Vec4& color) + { + osg::ref_ptr image = _texture->getImage(); + const auto format = image->getInternalTextureFormat(); + + auto clippedRect = intersectRect(rect, SGRect(0, 0, image->s(), image->t())); + if ((clippedRect.width() == 0) || (clippedRect.height() == 0)) { + return; + } + + GLubyte* rowData = nullptr; + size_t rowByteSize = 0; + GLuint pixelWidth = clippedRect.width(); + GLuint pixel = 0; + GLuint pixelBytes = 0; + + switch (format) { + case GL_RGBA8: + rowByteSize = pixelWidth * 4; + rowData = static_cast(alloca(rowByteSize)); + + // assume litte-endian, so read out backwards, hence when we memcpy + // the data, it ends up in RGBA order + pixel = color.asABGR(); + pixelBytes = 4; + fillRow(rowData, pixel, pixelWidth, pixelBytes); + break; + + case GL_RGB8: + rowByteSize = pixelWidth * 3; + rowData = static_cast(alloca(rowByteSize)); + pixel = color.asABGR(); + pixelBytes = 3; + fillRow(rowData, pixel, pixelWidth, pixelBytes); + break; + + default: + SG_LOG(SG_IO, SG_WARN, __PRETTY_FUNCTION__ << ": unsupported internal image format:" << format); + return; + } + + for (int row=clippedRect.t(); row < clippedRect.b(); ++row) { + GLubyte* imageData = image->data(clippedRect.l(), row); + memcpy(imageData, rowData, rowByteSize); + } + + setImage(image); + } + + void Image::setPixel(int x, int y, const std::string& c) + { + osg::Vec4 color(1,1,1,1); + if(!c.empty() && !parseColor(c, color)) + return; + + setPixel(x, y, color); + } + + void Image::setPixel(int x, int y, const osg::Vec4& color) + { + osg::ref_ptr image = _texture->getImage(); + image->setColor(color, x, y); + + // is this needed, or does OSG track modifications to the data + // automatically? + setImage(image); + } + } // namespace canvas } // namespace simgear diff --git a/simgear/canvas/elements/CanvasImage.hxx b/simgear/canvas/elements/CanvasImage.hxx index 9641c489..dedcaf01 100644 --- a/simgear/canvas/elements/CanvasImage.hxx +++ b/simgear/canvas/elements/CanvasImage.hxx @@ -101,6 +101,22 @@ namespace canvas */ void setSourceRect(const SGRect& sourceRect); + /** + * fill the specified rectangle of the image, with an RGB value + */ + void fillRect(const SGRect& rect, const std::string& color); + + /** + * fill the specified rectangle of the image, with an RGB value + */ + void fillRect(const SGRect& rect, const osg::Vec4& color); + + void setPixel(int x, int y, const std::string& color); + + void setPixel(int x, int y, const osg::Vec4& color); + + + // void setRow(int row, int offset, ) protected: enum ImageAttributes { diff --git a/simgear/math/SGVec2.hxx b/simgear/math/SGVec2.hxx index c0c6cb62..d9e4439f 100644 --- a/simgear/math/SGVec2.hxx +++ b/simgear/math/SGVec2.hxx @@ -193,8 +193,8 @@ min(S s, SGVec2 v) template inline SGVec2 -max(const SGVec2& v1, const SGVec2& v2) -{ v1 = simd4::max(v1.simd2(), v2.simd2()); return v1; } +max(SGVec2 v1, const SGVec2& v2) +{ v1.simd2() = simd4::max(v1.simd2(), v2.simd2()); return v1; } template inline SGVec2 diff --git a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx index a582bfe6..afda9f24 100644 --- a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx @@ -207,6 +207,15 @@ namespace nasal return Vec2(vec[0], vec[1]); } + template + std::enable_if_t::value, Vec4> + from_nasal_helper(naContext c, naRef ref, const Vec4*) + { + auto vec = from_nasal_helper(c, ref, static_cast*>(0)); + return Vec4(vec[0], vec[1], vec[2], vec[3]); + } + + /** * Convert a Nasal vector with 4 elements ([x, y, w, h]) to an SGRect */ diff --git a/simgear/nasal/cppbind/detail/nasal_traits.hxx b/simgear/nasal/cppbind/detail/nasal_traits.hxx index 17e18ecd..228b2556 100644 --- a/simgear/nasal/cppbind/detail/nasal_traits.hxx +++ b/simgear/nasal/cppbind/detail/nasal_traits.hxx @@ -28,6 +28,7 @@ class SGWeakReferenced; template class SGSharedPtr; template class SGWeakPtr; template class SGVec2; +template class SGVec4; namespace boost { @@ -47,6 +48,9 @@ namespace osg class Vec2d; class Vec2f; class Vec2s; + + class Vec4f; + class Vec4d; } // The actual traits... @@ -55,6 +59,10 @@ namespace nasal template struct is_vec2: public std::false_type {}; + template + struct is_vec4: public std::false_type {}; + + #define SG_MAKE_TRAIT(templ,type,attr)\ template templ\ struct attr< type >: public std::true_type {}; @@ -65,6 +73,10 @@ SG_MAKE_TRAIT(<>, osg::Vec2d, is_vec2) SG_MAKE_TRAIT(<>, osg::Vec2f, is_vec2) SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) +SG_MAKE_TRAIT(, SGVec4, is_vec4) +SG_MAKE_TRAIT(<>, osg::Vec4d, is_vec4) +SG_MAKE_TRAIT(<>, osg::Vec4f, is_vec4) + #undef SG_MAKE_TRAIT template