Adding pixel manipulators to canvas::Image

This commit is contained in:
James Turner
2019-11-25 11:35:30 +00:00
parent c39a5fd8c0
commit da45c26e7d
5 changed files with 132 additions and 2 deletions

View File

@@ -838,5 +838,98 @@ namespace canvas
return false;
}
void Image::fillRect(const SGRect<int>& 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<int> intersectRect(const SGRect<int>& a, const SGRect<int>& b)
{
SGVec2<int> m1 = max(a.getMin(), b.getMin());
SGVec2<int> m2 = min(a.getMax(), b.getMax());
return SGRect<int>(m1, m2);
}
void Image::fillRect(const SGRect<int>& rect, const osg::Vec4& color)
{
osg::ref_ptr<osg::Image> image = _texture->getImage();
const auto format = image->getInternalTextureFormat();
auto clippedRect = intersectRect(rect, SGRect<int>(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<GLubyte*>(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<GLubyte*>(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<osg::Image> 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

View File

@@ -101,6 +101,22 @@ namespace canvas
*/
void setSourceRect(const SGRect<float>& sourceRect);
/**
* fill the specified rectangle of the image, with an RGB value
*/
void fillRect(const SGRect<int>& rect, const std::string& color);
/**
* fill the specified rectangle of the image, with an RGB value
*/
void fillRect(const SGRect<int>& 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
{

View File

@@ -193,8 +193,8 @@ min(S s, SGVec2<T> v)
template<typename T>
inline
SGVec2<T>
max(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ v1 = simd4::max(v1.simd2(), v2.simd2()); return v1; }
max(SGVec2<T> v1, const SGVec2<T>& v2)
{ v1.simd2() = simd4::max(v1.simd2(), v2.simd2()); return v1; }
template<typename S, typename T>
inline
SGVec2<T>

View File

@@ -207,6 +207,15 @@ namespace nasal
return Vec2(vec[0], vec[1]);
}
template<class Vec4>
std::enable_if_t<is_vec4<Vec4>::value, Vec4>
from_nasal_helper(naContext c, naRef ref, const Vec4*)
{
auto vec = from_nasal_helper(c, ref, static_cast<std::array<double, 4>*>(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
*/

View File

@@ -28,6 +28,7 @@ class SGWeakReferenced;
template<class T> class SGSharedPtr;
template<class T> class SGWeakPtr;
template<class T> class SGVec2;
template<class T> 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<class T>
struct is_vec2: public std::false_type {};
template<class T>
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(<class T>, SGVec4<T>, is_vec4)
SG_MAKE_TRAIT(<>, osg::Vec4d, is_vec4)
SG_MAKE_TRAIT(<>, osg::Vec4f, is_vec4)
#undef SG_MAKE_TRAIT
template<class T>