From Jeremy Moles, updates to osgWidget

Merged my Robert Osfield from OpenSceneGraph-osgWidget-dev.
This commit is contained in:
Robert Osfield
2008-11-28 14:35:33 +00:00
parent d3b2d9b074
commit 9748fdd605
35 changed files with 1234 additions and 639 deletions

View File

@@ -1,13 +1,15 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: Frame.cpp 59 2008-05-15 20:55:31Z cubicool $
#include <osg/io_utils>
#include <osgDB/ReadFile>
#include <osgWidget/WindowManager>
#include <osgWidget/Frame>
#include <cassert>
namespace osgWidget {
std::string Frame::cornerToString(CORNER c) {
std::string Frame::cornerTypeToString(CornerType c)
{
if(c == CORNER_LOWER_LEFT) return "CornerLowerLeft";
else if(c == CORNER_LOWER_RIGHT) return "CornerLowerRight";
@@ -17,7 +19,8 @@ std::string Frame::cornerToString(CORNER c) {
else return "CornerUpperLeft";
}
std::string Frame::borderToString(BORDER b) {
std::string Frame::borderTypeToString(BorderType b)
{
if(b == BORDER_LEFT) return "BorderLeft";
else if(b == BORDER_RIGHT) return "BorderRight";
@@ -27,54 +30,44 @@ std::string Frame::borderToString(BORDER b) {
else return "BorderBottom";
}
Frame::Corner::Corner(CORNER corner, point_type width, point_type height):
Widget (cornerToString(corner), width, height),
_corner (corner) {
setEventMask(EVENT_MASK_MOUSE_DRAG);
Frame::Corner::Corner(CornerType corner, point_type width, point_type height):
Widget (cornerTypeToString(corner), width, height),
_corner (corner)
{
}
Frame::Corner::Corner(const Corner& corner, const osg::CopyOp& co):
Widget (corner, co),
_corner (corner._corner) {
_corner (corner._corner)
{
}
bool Frame::Corner::mouseDrag(double x, double y, WindowManager* wm) {
Window* parent = getParent();
void Frame::Corner::parented(Window* window) {
Frame* parent = dynamic_cast<Frame*>(getParent());
if(!parent) return false;
if(!parent) return;
if(wm->isInvertedY()) {
if(_corner == CORNER_UPPER_LEFT) {
if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y);
}
if(parent->canResize()) setEventMask(EVENT_MASK_MOUSE_DRAG);
}
else if(_corner == CORNER_UPPER_RIGHT) {
if(parent->resizeAdd(x, -y)) parent->addY(y);
}
bool Frame::Corner::mouseDrag(double x, double y, WindowManager* wm)
{
Frame* parent = dynamic_cast<Frame*>(getParent());
else if(_corner == CORNER_LOWER_RIGHT) parent->resizeAdd(x, y);
if(!parent || !parent->canResize()) return false;
else {
if(parent->resizeAdd(-x, y)) parent->addX(x);
}
if(_corner == CORNER_UPPER_LEFT) {
if(parent->resizeAdd(-x, y)) parent->addX(x);
}
else if(_corner == CORNER_UPPER_RIGHT) parent->resizeAdd(x, y);
else if(_corner == CORNER_LOWER_RIGHT) {
if(parent->resizeAdd(x, -y)) parent->addY(y);
}
// These are basically flipped-around versions of the above routines; we
// do it this way to avoid lots of uncessary if tests.
else {
if(_corner == CORNER_UPPER_LEFT) {
if(parent->resizeAdd(-x, y)) parent->addX(x);
}
else if(_corner == CORNER_UPPER_RIGHT) parent->resizeAdd(x, y);
else if(_corner == CORNER_LOWER_RIGHT) {
if(parent->resizeAdd(x, -y)) parent->addY(y);
}
else {
if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y);
}
if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y);
}
parent->update();
@@ -82,34 +75,84 @@ bool Frame::Corner::mouseDrag(double x, double y, WindowManager* wm) {
return true;
}
Frame::Border::Border(BORDER border, point_type width, point_type height):
Widget (borderToString(border), width, height),
_border (border) {
Frame::Border::Border(BorderType border, point_type width, point_type height):
Widget (borderTypeToString(border), width, height),
_border (border)
{
setCanFill(true);
setEventMask(EVENT_MASK_MOUSE_DRAG);
}
Frame::Border::Border(const Border& border, const osg::CopyOp& co):
Widget (border, co),
_border (border._border) {
_border (border._border)
{
}
bool Frame::Border::mouseDrag(double x, double y, WindowManager* wm) {
Window* parent = getParent();
void Frame::Border::parented(Window* window) {
Frame* parent = dynamic_cast<Frame*>(getParent());
if(!parent) return false;
if(!parent) return;
if(_border == BORDER_LEFT) {
if(parent->resizeAdd(-x, 0.0f)) parent->addX(x);
if(parent->canResize()) setEventMask(EVENT_MASK_MOUSE_DRAG);
}
void Frame::Border::positioned()
{
osg::Image* image = _image();
if(!image) return;
Frame* parent = dynamic_cast<Frame*>(getParent());
if(!parent || !parent->canTexture()) return;
point_type w = image->s() / 8.0f;
point_type h = getHeight();
if(_border == BORDER_LEFT) setTexCoordRegion(w * 3, 0.0f, w, h);
else if(_border == BORDER_RIGHT) setTexCoordRegion(w * 4, 0.0f, w, h);
else if(_border == BORDER_TOP) {
// TODO: Temporary; fix this.
point_type tx1 = (w * 2) / image->s();
point_type tx2 = w / image->s();
point_type tx3 = getWidth() / w;
setTexCoord(tx1, tx3, LL);
setTexCoord(tx1, 0.0f, LR);
setTexCoord(tx2, 0.0f, UR);
setTexCoord(tx2, tx3, UL);
}
else if(_border == BORDER_RIGHT) parent->resizeAdd(x, 0.0f);
else {
point_type tx1 = (w * 7) / image->s();
point_type tx2 = (w * 6) / image->s();
point_type tx3 = getWidth() / w;
else if(_border == BORDER_TOP) parent->addOrigin(x, y);
setTexCoord(tx1, tx3, LL);
setTexCoord(tx1, 0.0f, LR);
setTexCoord(tx2, 0.0f, UR);
setTexCoord(tx2, tx3, UL);
}
}
bool Frame::Border::mouseDrag(double x, double y, WindowManager* wm)
{
Frame* parent = dynamic_cast<Frame*>(getParent());
if(!parent) return false;
if(_border == BORDER_TOP && parent->canMove()) parent->addOrigin(x, y);
else {
// The only BORDER that inverted-Y affects is this...
if(wm->isInvertedY()) parent->resizeAdd(0.0f, y);
if(!parent->canResize()) return false;
if(_border == BORDER_LEFT) {
if(parent->resizeAdd(-x, 0.0f)) parent->addX(x);
}
else if(_border == BORDER_RIGHT) parent->resizeAdd(x, 0.0f);
else {
if(parent->resizeAdd(0.0f, -y)) parent->addY(y);
@@ -121,54 +164,29 @@ bool Frame::Border::mouseDrag(double x, double y, WindowManager* wm) {
return true;
}
Frame::Frame(const std::string& name):
Table(name, 3, 3) {
Frame::Frame(const std::string& name, unsigned int flags):
Table (name, 3, 3),
_flags (flags)
{
}
Frame::Frame(const Frame& frame, const osg::CopyOp& co):
Table(frame, co) {
Table(frame, co)
{
}
Widget* Frame::_getCorner(CORNER c) const {
return const_cast<Widget*>(getByName(cornerToString(c)));
Widget* Frame::_getCorner(CornerType c) const
{
return const_cast<Widget*>(getByName(cornerTypeToString(c)));
}
Widget* Frame::_getBorder(BORDER b) const {
return const_cast<Widget*>(getByName(borderToString(b)));
Widget* Frame::_getBorder(BorderType b) const
{
return const_cast<Widget*>(getByName(borderTypeToString(b)));
}
void Frame::managed(WindowManager* wm) {
Window::managed(wm);
// Our Frame is created in an inverted-Y environment, so if this is the case
// just return here.
if(wm->isInvertedY()) return;
Corner* ll = getCorner(CORNER_LOWER_LEFT);
Corner* lr = getCorner(CORNER_LOWER_RIGHT);
Corner* ul = getCorner(CORNER_UPPER_LEFT);
Corner* ur = getCorner(CORNER_UPPER_RIGHT);
Border* t = getBorder(BORDER_TOP);
Border* b = getBorder(BORDER_BOTTOM);
if(!ll || !lr || !ul || !ur || !t || !b) {
warn()
<< "One or more of your Corner/Border objects in the Frame ["
<< _name << "] are invalid; cannot invert orientation." << std::endl
;
return;
}
ll->setCornerAndName(CORNER_UPPER_LEFT);
lr->setCornerAndName(CORNER_UPPER_RIGHT);
ul->setCornerAndName(CORNER_LOWER_LEFT);
ur->setCornerAndName(CORNER_LOWER_RIGHT);
t->setBorderAndName(BORDER_BOTTOM);
b->setBorderAndName(BORDER_TOP);
}
bool Frame::setWindow(Window* window) {
bool Frame::setWindow(Window* window)
{
if(!window) return false;
EmbeddedWindow* ew = getEmbeddedWindow();
@@ -186,24 +204,25 @@ Frame* Frame::createSimpleFrame(
point_type ch,
point_type w,
point_type h,
unsigned int flags,
Frame* exFrame
) {
Frame* frame = 0;
// Use an "existing frame" if we have it (for example, if you've in inherited from
// Frame and want to use this stuff.
if(!exFrame) frame = new Frame(name);
if(!exFrame) frame = new Frame(name, flags);
else frame = exFrame;
frame->addWidget(new Corner(CORNER_UPPER_LEFT, cw, ch), 0, 0);
frame->addWidget(new Border(BORDER_TOP, w, ch), 0, 1);
frame->addWidget(new Corner(CORNER_UPPER_RIGHT, cw, ch), 0, 2);
frame->addWidget(new Border(BORDER_LEFT, cw, h), 1, 0);
frame->addWidget(new Border(BORDER_RIGHT, cw, h), 1, 2);
frame->addWidget(new Corner(CORNER_LOWER_LEFT, cw, ch), 2, 0);
frame->addWidget(new Border(BORDER_BOTTOM, w, ch), 2, 1);
frame->addWidget(new Corner(CORNER_LOWER_RIGHT, cw, ch), 2, 2);
frame->addWidget(new Corner(CORNER_LOWER_LEFT, cw, ch), 0, 0);
frame->addWidget(new Border(BORDER_BOTTOM, w, ch), 0, 1);
frame->addWidget(new Corner(CORNER_LOWER_RIGHT, cw, ch), 0, 2);
frame->addWidget(new Border(BORDER_LEFT, cw, h), 1, 0);
frame->addWidget(new Border(BORDER_RIGHT, cw, h), 1, 2);
frame->addWidget(new Corner(CORNER_UPPER_LEFT, cw, ch), 2, 0);
frame->addWidget(new Border(BORDER_TOP, w, ch), 2, 1);
frame->addWidget(new Corner(CORNER_UPPER_RIGHT, cw, ch), 2, 2);
EmbeddedWindow* ew = new EmbeddedWindow(name, w, h);
@@ -214,6 +233,7 @@ Frame* Frame::createSimpleFrame(
return frame;
}
/*
Frame* Frame::createSimpleFrameWithSingleTexture(
const std::string& name,
const std::string& texture,
@@ -247,5 +267,332 @@ Frame* Frame::createSimpleFrameWithSingleTexture(
return frame;
}
*/
// Inspired by: http://www.wowwiki.com/EdgeFiles
Frame* Frame::createSimpleFrameWithSingleTexture(
const std::string& name,
osg::Image* image,
point_type width,
point_type height,
unsigned int flags,
Frame* exFrame
) {
Frame* frame = 0;
double w = width;
double h = height;
if (image)
{
w = image->s() / 8.0f;
h = image->t();
}
// The same as above...
if(!exFrame) frame = createSimpleFrame(name, w, h, width, height, flags);
else frame = createSimpleFrame(name, w, h, width, height, 0, exFrame);
if (image)
{
for(unsigned int i = 0; i < 9; i++) frame->getObjects()[i]->setImage(image);
XYCoord twh(w, h);
frame->getCorner(CORNER_UPPER_LEFT )->setTexCoordRegion(0.0f, 0.0f, twh);
frame->getBorder(BORDER_TOP )->setTexCoordRegion(w, 0.0f, twh);
frame->getCorner(CORNER_UPPER_RIGHT)->setTexCoordRegion(w * 2, 0.0f, twh);
frame->getBorder(BORDER_LEFT )->setTexCoordRegion(w * 3, 0.0f, twh);
frame->getBorder(BORDER_RIGHT )->setTexCoordRegion(w * 4, 0.0f, twh);
frame->getCorner(CORNER_LOWER_LEFT )->setTexCoordRegion(w * 5, 0.0f, twh);
frame->getBorder(BORDER_BOTTOM )->setTexCoordRegion(w * 6, 0.0f, twh);
frame->getCorner(CORNER_LOWER_RIGHT)->setTexCoordRegion(w * 7, 0.0f, twh);
// We set all of these to wrap vertically, but the REAL texture coordinates will
// be generated properly in the positioned() method.
frame->getByRowCol(0, 1)->setTexCoordWrapVertical();
frame->getByRowCol(1, 0)->setTexCoordWrapVertical();
frame->getByRowCol(1, 2)->setTexCoordWrapVertical();
frame->getByRowCol(2, 1)->setTexCoordWrapVertical();
// frame->getEmbeddedWindow()->setTexCoordRegion(cw, ch, tw - (cw * 2.0f), th - (ch * 2.0f));
}
else
{
osg::notify(osg::WARN) << "createSimpleFrameWithSingleTexture with a null image, the frame " << name << " will be use texture" << std::endl;
}
return frame;
}
bool Frame::resizeFrame(point_type w, point_type h) {
Border* left = getBorder(BORDER_LEFT);
Border* right = getBorder(BORDER_RIGHT);
Border* top = getBorder(BORDER_TOP);
Border* bottom = getBorder(BORDER_BOTTOM);
if(!left || !right || !top || !bottom) return false;
return resize(
left->getWidth() + right->getWidth() + w,
top->getHeight() + bottom->getHeight() + h
);
}
osg::Image* createNatifEdgeImageFromTheme(osg::Image* theme);
Frame* Frame::createSimpleFrameFromTheme(
const std::string& name,
osg::Image* image,
point_type width,
point_type height,
unsigned int flags,
Frame* exFrame
) {
osg::ref_ptr<osg::Image> natifImage = createNatifEdgeImageFromTheme(image);
Frame* frame;
frame = createSimpleFrameWithSingleTexture(name, natifImage.get(), width, height, flags, exFrame);
if (frame && image && natifImage.valid())
{
const unsigned int bpps = image->getPixelSizeInBits() / 8;
const unsigned int one_third_s = image->s()/3;
unsigned char* srcdata = (unsigned char*)image->data();
osg::Vec4 color(0,0,0,1);
for (unsigned int d = 0; d < bpps; d++)
{
color[d] = srcdata[one_third_s * image->s() * bpps + (one_third_s) * bpps + d] * 1.0/255.0;
}
frame->getEmbeddedWindow()->setColor(color);
}
return frame;
}
// (c) 2006-2008 Jean-Sébastien Guay
// adapted by Cedric Pinson
/** Implementation of copyImage. */
template<typename T>
void copyDataImpl(const osg::Image* source,
const unsigned int x1, const unsigned int y1,
const unsigned int x2, const unsigned int y2,
osg::Image* destination,
const unsigned int xd = 0, const unsigned int yd = 0)
{
if ((unsigned int)destination->s() >= xd + (x2 - x1) &&
(unsigned int)destination->t() >= yd + (y2 - y1))
{
const unsigned int bpps = source->getPixelSizeInBits() / (8 * sizeof(T));
T* srcdata = (T*)source->data();
T* dstdata = (T*)destination->data();
for (unsigned int y = 0; y < y2 - y1; ++y)
{
for (unsigned int x = 0; x < x2 - x1; ++x)
{
for (unsigned int d = 0; d < bpps; d++)
{
T v = srcdata[(y + y1) * source->s() * bpps + (x + x1) * bpps + d];
dstdata[(yd + y) * destination->s() * bpps + (xd + x) * bpps + d] = v;
}
}
}
}
else
assert(false && "copyDataImpl: Incorrect image dimensions.");
}
/** Copies a rectangle of corners (x1, y1), (x2, y2) from an image into
another image starting at position (xd, yd). No scaling is done, the
pixels are just copied, so the destination image must be at least
(xd + (x2 - x1)) by (yd + (y2 - y1)) pixels. */
void copyData(const osg::Image* source,
const unsigned int x1, const unsigned int y1,
const unsigned int x2, const unsigned int y2,
osg::Image* destination,
const unsigned int xd, const unsigned int yd)
{
if (source->getDataType() == destination->getDataType())
{
if (source->getDataType() == GL_UNSIGNED_BYTE)
{
copyDataImpl<unsigned char>(source, x1, y1, x2, y2,
destination, xd, yd);
}
else
{
assert(false && "copyData not implemented for this data type");
}
}
else
{
assert(false && "source and destination images must be of the same type.");
return;
}
}
/** Implementation of rotateImage. */
template<typename T>
osg::Image* rotateImageImpl(osg::Image* image)
{
if (image->s() == image->t())
{
const unsigned int s = image->s();
const unsigned int bpp = image->getPixelSizeInBits() / (8 * sizeof(T));
osg::ref_ptr<osg::Image> destination = new osg::Image;
destination->allocateImage(s, s, 1,
image->getPixelFormat(), image->getDataType(),
image->getPacking());
destination->setInternalTextureFormat(image->getInternalTextureFormat());
T* srcdata = (T*)image->data();
T* dstdata = (T*)destination->data();
for (unsigned int y = 0; y < s; ++y)
{
for (unsigned int x = 0; x < s; ++x)
{
for (unsigned int p = 0; p < bpp; p++)
dstdata[y * s * bpp + x * bpp + p] = srcdata[x * s * bpp + y * bpp + p];
}
}
return destination.release();
}
else
{
assert(false && "rotateImageImpl: Image must be square.");
return 0;
}
}
/** Rotates an osg::Image by 90 degrees. Returns a new osg::Image, be sure to
store it in a ref_ptr so it will be freed correctly. */
osg::Image* rotateImage(osg::Image* image)
{
if (image->getDataType() == GL_UNSIGNED_BYTE)
{
return rotateImageImpl<unsigned char>(image);
}
else
{
assert(false && "rotateImage not implemented for this data type");
return 0;
}
}
// SOURCE
// +---+---+---+
// | 1 | 2 | 3 |
// +---+---+---+
// | 4 | | 5 |
// +---+---+---+
// | 6 | 7 | 8 |
// +---+---+---+
// FINAL
// +---+---+---+---+---+---+---+---+
// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
// +---+---+---+---+---+---+---+---+
// 1. Upper-Left corner.
// 2. Top border (rotated 90 degrees CCW).
// 3. Upper-Right corner.
// 4. Left border.
// 5. Right border.
// 6. Bottom-Left corner.
// 7. Bottom border (rotated 90 degrees CCW).
// 8. Bottom-Right corner.
osg::Image* createNatifEdgeImageFromTheme(osg::Image* theme)
{
if (!theme) {
osg::notify(osg::WARN) << "can't create a natif edge image from null image theme as argument" << std::endl;
return 0;
}
osg::ref_ptr<osg::Image> final = new osg::Image;
const int s = theme->s();
const int t = theme->t();
const GLenum pixelFormat = theme->getPixelFormat();
const GLenum dataType = theme->getDataType();
const GLint internalFormat = theme->getInternalTextureFormat();
unsigned int packing = theme->getPacking();
if (s != t)
{
osg::notify(osg::WARN) << "width and height are different, bad format theme image " << theme->getFileName() << std::endl;
return 0;
}
// check size
int ceilvalue = static_cast<int>(ceil(s * 1.0 / 3));
int intvalue = s/3;
if (intvalue != ceilvalue)
{
osg::notify(osg::WARN) << "the size of theme file " << theme->getFileName() << " can not be divided by 3, check the documentation about theme format" << std::endl;
return 0;
}
const unsigned int one_third_s = s/3;
const unsigned int one_third_t = t/3;
final->allocateImage(8 * one_third_s , one_third_t, 1, pixelFormat, dataType, packing);
final->setInternalTextureFormat(internalFormat);
// copy 1 (6 in source)
copyData(theme, 0, 2 * one_third_s, one_third_s, 3 * one_third_s, final.get(), 0, 0);
// rotate and copy 2
osg::ref_ptr<osg::Image> rotateandcopy2 = new osg::Image;
rotateandcopy2->allocateImage(one_third_s , one_third_t, 1, pixelFormat, dataType, packing);
rotateandcopy2->setInternalTextureFormat(internalFormat);
copyData(theme, one_third_s, 0, 2 * one_third_s , one_third_s, rotateandcopy2.get(), 0, 0);
rotateandcopy2 = rotateImage(rotateandcopy2.get());
rotateandcopy2->flipHorizontal();
copyData(rotateandcopy2.get(), 0, 0, one_third_s , one_third_s, final.get(), 6*one_third_s, 0);
// copy 3 (8 in source)
copyData(theme, 2*one_third_s , 2 *one_third_s, 3*one_third_s , 3 * one_third_s, final.get(), 2 * one_third_s, 0);
// copy 4
copyData(theme, 0, one_third_s, one_third_s , 2 * one_third_s, final.get(), 3 * one_third_s, 0);
// copy 5
copyData(theme, 2*one_third_s , one_third_s, 3 * one_third_s , 2 * one_third_s, final.get(), 4 * one_third_s, 0);
// copy 6 (1 in source)
copyData(theme, 0 , 0, one_third_s, one_third_s, final.get(), 5 * one_third_s, 0);
// rotate and copy 7
osg::ref_ptr<osg::Image> rotateandcopy7 = new osg::Image;
rotateandcopy7->allocateImage(one_third_s , one_third_t, 1, pixelFormat, dataType, packing);
rotateandcopy7->setInternalTextureFormat(internalFormat);
copyData(theme, one_third_s, 2*one_third_s, 2 * one_third_s , 3 * one_third_s, rotateandcopy7.get(), 0, 0);
rotateandcopy7 = rotateImage(rotateandcopy7.get());
rotateandcopy7->flipHorizontal();
copyData(rotateandcopy7.get(), 0, 0, one_third_s , one_third_s, final.get(), one_third_s, 0);
// copy 8 (3 in source)
copyData(theme, 2 * one_third_s, 0, 3 * one_third_s , one_third_s , final.get(), 7 * one_third_s, 0);
return final.release();
}
}