Created
August 21, 2020 17:19
-
-
Save jasonbeverage/3d1439fe936d9307a8aab76c9a5e5a31 to your computer and use it in GitHub Desktop.
Playing with blend2d in osg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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