Skip to content

Instantly share code, notes, and snippets.

@jasonbeverage
Created August 21, 2020 17:19
Show Gist options
  • Save jasonbeverage/3d1439fe936d9307a8aab76c9a5e5a31 to your computer and use it in GitHub Desktop.
Save jasonbeverage/3d1439fe936d9307a8aab76c9a5e5a31 to your computer and use it in GitHub Desktop.
Playing with blend2d in osg
#include <blend2d.h>
#include <osgDB/WriteFile>
#include <osg/Image>
#include <osg/Texture2D>
#include <osgEarth/VirtualProgram>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osg/BlendEquation>
#include <osg/BlendFunc>
class Blend2DImage : public osg::Image
{
public:
Blend2DImage(unsigned int width, unsigned int height) :
osg::Image()
{
setOrigin(osg::Image::TOP_LEFT);
_img = new BLImage(width, height, BL_FORMAT_PRGB32);
copyImageData();
}
~Blend2DImage()
{
if (_img)
{
delete _img;
}
}
virtual bool requiresUpdateCall() const { return true; }
/** update method for osg::Image subclasses that update themselves during the update traversal.*/
virtual void update(osg::NodeVisitor* nv)
{
if (frame(*nv->getFrameStamp()))
{
copyImageData();
}
}
virtual bool frame(const osg::FrameStamp& fs)
{
BLContext ctx(*_img);
ctx.setCompOp(BL_COMP_OP_SRC_COPY);
ctx.setFillStyle(BLRgba32(0x00000000u));
//ctx.setFillStyle(BLRgba32(0x00000000u));
//ctx.setFillStyle(BLRgba(1.0, 0.0, 0.0, 1.0));
ctx.fillAll();
ctx.setCompOp(BL_COMP_OP_SRC_OVER);
//ctx.setFillStyle(BLRgba(0.0, 1.0, 0.0, 0.3));
ctx.setFillStyle(BLRgba(0.0, 1.0, 0.0, 1.0));
ctx.fillCircle(_img->width() / 2.0, _img->height() / 2.0, _radius);
ctx.end();
double dt = fs.getSimulationTime() - _lastTime;
_radius += _radiusDir * dt * _rate;
// Flip directions
if (_radius >= _maxRadius)
{
_radiusDir *= -1.0;
_radius = _maxRadius;
}
else if (_radius <= _minRadius)
{
_radiusDir *= -1.0;
_radius = _minRadius;
}
_lastTime = fs.getSimulationTime();
return true;
}
void copyImageData()
{
// If the image has changed update the image data.
BLImageData imageData;
BLResult result = _img->getData(&imageData);
if (result == BL_SUCCESS)
{
#if 0
unsigned int totalBytes = imageData.size.w * imageData.size.h * 4;
unsigned char * data = new unsigned char[totalBytes];
memcpy(data, imageData.pixelData, totalBytes);
//osgImage->setImage(imageData.size.w, imageData.size.h, 1, GL_RGB8, GL_BGRA, GL_UNSIGNED_BYTE, (unsigned char*)imageData.pixelData, osg::Image::NO_DELETE);
setImage(imageData.size.w, imageData.size.h, 1, GL_RGB8, GL_BGRA, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
flipVertical();
#endif
setImage(imageData.size.w, imageData.size.h, 1, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, (unsigned char*)imageData.pixelData, osg::Image::NO_DELETE);
}
}
double _radius = 0.0;
double _minRadius = 0.0;
double _maxRadius = 50.0;
double _radiusDir = 1.0;
double _lastTime = 0.0;
double _rate = 10.0;
BLImage* _img;
};
std::string vertSrc =
R""(
#version 330
out vec4 texCoord0;
void main()
{
texCoord0 = gl_MultiTexCoord0;
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
}
)"";
std::string fragSrc =
R""(
#version 330
in vec4 texCoord0;
uniform sampler2D texture_unit;
void main()
{
vec4 color = texture2D(texture_unit, texCoord0.st);
gl_FragColor = color;
}
)"";
osg::Node* makeTexturedQuad(osg::Texture* texture)
{
osg::Geometry* geometry = new osg::Geometry;
osg::Vec3Array* verts = new osg::Vec3Array;
geometry->setVertexArray(verts);
verts->push_back(osg::Vec3(0.0, 0.0, 0.0));
verts->push_back(osg::Vec3(1.0, 0.0, 0.0));
verts->push_back(osg::Vec3(1.0, 1.0, 0.0));
verts->push_back(osg::Vec3(0.0, 1.0, 0.0));
osg::Vec2Array* texCoords = new osg::Vec2Array;
bool flip = texture->getImage(0)->getOrigin() == osg::Image::TOP_LEFT;
texCoords->push_back(osg::Vec2(0.0f, flip ? 1.0f : 0.0f));
texCoords->push_back(osg::Vec2(1.0f, flip ? 1.0f : 0.0f));
texCoords->push_back(osg::Vec2(1.0f, flip ? 0.0f : 1.0f));
texCoords->push_back(osg::Vec2(0.0f, flip ? 0.0f : 1.0f));
geometry->setTexCoordArray(0, texCoords);
osg::Vec4Array* colors = new osg::Vec4Array();
colors->push_back(osg::Vec4(1, 1, 1, 1.0));
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
geometry->getOrCreateStateSet()->setTextureAttribute(0, texture);
osg::DrawElementsUByte* de = new osg::DrawElementsUByte(GL_TRIANGLES);
de->addElement(0); de->addElement(1); de->addElement(3);
de->addElement(1); de->addElement(2); de->addElement(3);
geometry->addPrimitiveSet(de);
osg::Program *program = new osg::Program;
program->addShader(new osg::Shader(osg::Shader::VERTEX, vertSrc));
program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragSrc));
geometry->getOrCreateStateSet()->setAttributeAndModes(program, osg::StateAttribute::ON);
geometry->getOrCreateStateSet()->addUniform(new osg::Uniform("texture_unit", 0));
geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
// Setup blending equations for premultiplied alpha
// https://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha/
geometry->getOrCreateStateSet()->setAttributeAndModes(new osg::BlendEquation(osg::BlendEquation::FUNC_ADD), osg::StateAttribute::ON);
geometry->getOrCreateStateSet()->setAttributeAndModes(new osg::BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON);
geometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
return geometry;
}
int main(int argc, char* argv[])
{
osgEarth::initialize();
osg::ArgumentParser arguments(&argc, argv);
osgViewer::Viewer viewer(arguments);
viewer.addEventHandler(new osgViewer::StatsHandler());
osg::ref_ptr< Blend2DImage > image = new Blend2DImage(256, 256);
//osg::ref_ptr< Blend2DImage > image = new Blend2DImage(1024, 1024);
osg::Texture2D* texture = new osg::Texture2D(image.get());
texture->setDataVariance(osg::Object::DYNAMIC);
texture->setResizeNonPowerOfTwoHint(false);
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
viewer.setSceneData(makeTexturedQuad(texture));
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
viewer.realize();
while (!viewer.done())
{
viewer.frame();
}
return viewer.run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment