mirror of
https://github.com/edubart/otclient.git
synced 2025-10-16 12:34:55 +02:00
ui and graphics changes
* implement draw clipping using opengl stencil buffers * allow to create Widgets by style name with g_ui.createWidgetByStyle * styles can now have children widgets * make proper use of the isNotPathable in pathfinding * add scrollbar skin
This commit is contained in:
@@ -49,6 +49,7 @@ void Graphics::init()
|
||||
#endif
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
m_emptyTexture = TexturePtr(new Texture);
|
||||
|
||||
@@ -113,6 +114,29 @@ void Graphics::endRender()
|
||||
{
|
||||
}
|
||||
|
||||
void Graphics::beginClipping(const Rect& clipRect)
|
||||
{
|
||||
// setup stencil buffer for writing
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_ALWAYS, 1, 1);
|
||||
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
||||
|
||||
// draw the clipping area into the stencil buffer
|
||||
glColorMask(0, 0, 0, 0);
|
||||
g_painter.drawFilledRect(clipRect);
|
||||
|
||||
// set stencil buffer for clippig
|
||||
glColorMask(1, 1, 1, 1);
|
||||
glStencilFunc(GL_EQUAL, 1, 1);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
}
|
||||
|
||||
void Graphics::endClipping()
|
||||
{
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
void Graphics::setViewportSize(const Size& size)
|
||||
{
|
||||
glViewport(0, 0, size.width(), size.height());
|
||||
|
@@ -44,6 +44,9 @@ public:
|
||||
void beginRender();
|
||||
void endRender();
|
||||
|
||||
void beginClipping(const Rect& clipRect);
|
||||
void endClipping();
|
||||
|
||||
void setViewportSize(const Size& size);
|
||||
|
||||
int getMaxTextureSize();
|
||||
|
@@ -489,6 +489,8 @@ void Application::registerLuaFunctions()
|
||||
g_lua.bindClassStaticFunction("g_ui", "getStyle", std::bind(&UIManager::getStyle, &g_ui, _1));
|
||||
g_lua.bindClassStaticFunction("g_ui", "getStyleClass", std::bind(&UIManager::getStyleClass, &g_ui, _1));
|
||||
g_lua.bindClassStaticFunction("g_ui", "loadUI", std::bind(&UIManager::loadUI, &g_ui, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_ui", "createWidgetFromStyle", std::bind(&UIManager::createWidgetFromStyle, &g_ui, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_ui", "createWidgetFromOTML", std::bind(&UIManager::createWidgetFromOTML, &g_ui, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_ui", "getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui));
|
||||
g_lua.bindClassStaticFunction("g_ui", "getDraggingWidget", std::bind(&UIManager::getDraggingWidget, &g_ui));
|
||||
g_lua.bindClassStaticFunction("g_ui", "setDebugBoxesDrawing", std::bind(&UIManager::setDebugBoxesDrawing, &g_ui, _1));
|
||||
|
@@ -36,8 +36,9 @@ OTMLDocumentPtr OTMLDocument::create()
|
||||
OTMLDocumentPtr OTMLDocument::parse(const std::string& fileName)
|
||||
{
|
||||
std::stringstream fin;
|
||||
g_resources.loadFile(fileName, fin);
|
||||
return parse(fin, fileName);
|
||||
std::string source = g_resources.checkPath(fileName);
|
||||
g_resources.loadFile(source, fin);
|
||||
return parse(fin, source);
|
||||
}
|
||||
|
||||
OTMLDocumentPtr OTMLDocument::parse(std::istream& in, const std::string& source)
|
||||
|
@@ -306,16 +306,16 @@ void WIN32Window::internalChooseGLVisual()
|
||||
0, // No Accumulation Buffer
|
||||
0, 0, 0, 0, // Accumulation Bits Ignored
|
||||
16, // 16Bit Z-Buffer (Depth Buffer)
|
||||
0, // No Stencil Buffer
|
||||
1, // 1Bit Stencil Buffer
|
||||
0, // No Auxiliary Buffer
|
||||
PFD_MAIN_PLANE, // Main Drawing Layer
|
||||
0, // Reserved
|
||||
0, 0, 0 }; // Layer Masks Ignored
|
||||
|
||||
pixelFormat = ChoosePixelFormat(m_deviceContext, &pfd);
|
||||
if(!pixelFormat)
|
||||
logFatal("Could not find a suitable pixel format");
|
||||
|
||||
pfd.cStencilBits = 8;
|
||||
if(!SetPixelFormat(m_deviceContext, pixelFormat, &pfd))
|
||||
logFatal("Could not set the pixel format");
|
||||
}
|
||||
|
@@ -367,6 +367,7 @@ void X11Window::internalChooseGLVisual()
|
||||
GLX_USE_GL,
|
||||
GLX_RGBA,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_STENCIL_SIZE, 1,
|
||||
None
|
||||
};
|
||||
|
||||
@@ -379,6 +380,7 @@ void X11Window::internalChooseGLVisual()
|
||||
static int attrList[] = {
|
||||
//EGL_BUFFER_SIZE, 24,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_STENCIL_SIZE, 1,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
|
@@ -197,6 +197,7 @@ void UIAnchorLayout::updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anch
|
||||
}
|
||||
}
|
||||
|
||||
newRect.translate(-parentWidget->getVirtualOffset());
|
||||
widget->setRect(newRect);
|
||||
anchorGroup.setUpdated(true);
|
||||
}
|
||||
|
@@ -36,9 +36,9 @@ UIFrameCounter::UIFrameCounter()
|
||||
m_frameCount = 0;
|
||||
}
|
||||
|
||||
void UIFrameCounter::draw()
|
||||
void UIFrameCounter::drawSelf()
|
||||
{
|
||||
UIWidget::draw();
|
||||
UIWidget::drawSelf();
|
||||
|
||||
if(g_clock.ticksElapsed(m_lastFrameTicks) >= 1000) {
|
||||
m_fpsText = Fw::formatString("FPS: %d", m_frameCount);
|
||||
|
@@ -29,7 +29,7 @@ class UIFrameCounter : public UIWidget
|
||||
{
|
||||
public:
|
||||
UIFrameCounter();
|
||||
virtual void draw();
|
||||
void drawSelf();
|
||||
|
||||
void setAlign(Fw::AlignmentFlag align) { m_align = align; }
|
||||
Fw::AlignmentFlag getAlign() { return m_align; }
|
||||
|
@@ -53,7 +53,7 @@ void UIManager::terminate()
|
||||
|
||||
void UIManager::render()
|
||||
{
|
||||
m_rootWidget->draw();
|
||||
m_rootWidget->draw(m_rootWidget->getRect());
|
||||
}
|
||||
|
||||
void UIManager::resize(const Size& size)
|
||||
@@ -349,23 +349,24 @@ UIWidgetPtr UIManager::loadUI(const std::string& file, const UIWidgetPtr& parent
|
||||
else {
|
||||
if(widget)
|
||||
Fw::throwException("cannot have multiple main widgets in otui files");
|
||||
widget = loadWidgetFromOTML(node, parent);
|
||||
widget = createWidgetFromOTML(node, parent);
|
||||
}
|
||||
}
|
||||
|
||||
return widget;
|
||||
} catch(Exception& e) {
|
||||
logError("Failed to load UI from '", file, "': ", e.what());
|
||||
logError("failed to load UI from '", file, "': ", e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
/*
|
||||
UIWidgetPtr UIManager::loadWidgetFromStyle()
|
||||
{
|
||||
|
||||
UIWidgetPtr UIManager::createWidgetFromStyle(const std::string& styleName, const UIWidgetPtr& parent)
|
||||
{
|
||||
OTMLNodePtr node = OTMLNode::create(styleName);
|
||||
return createWidgetFromOTML(node, parent);
|
||||
}
|
||||
*/
|
||||
UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent)
|
||||
|
||||
UIWidgetPtr UIManager::createWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent)
|
||||
{
|
||||
OTMLNodePtr originalStyleNode = getStyle(widgetNode->tag());
|
||||
if(!originalStyleNode)
|
||||
@@ -384,9 +385,11 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const U
|
||||
if(widget) {
|
||||
widget->setStyleFromNode(styleNode);
|
||||
|
||||
for(const OTMLNodePtr& childNode : widgetNode->children()) {
|
||||
if(!childNode->isUnique())
|
||||
loadWidgetFromOTML(childNode, widget);
|
||||
for(const OTMLNodePtr& childNode : styleNode->children()) {
|
||||
if(!childNode->isUnique()) {
|
||||
createWidgetFromOTML(childNode, widget);
|
||||
styleNode->removeChild(childNode);
|
||||
}
|
||||
}
|
||||
} else
|
||||
Fw::throwException("unable to create widget of type '", widgetType, "'");
|
||||
|
@@ -46,8 +46,9 @@ public:
|
||||
OTMLNodePtr getStyle(const std::string& styleName);
|
||||
std::string getStyleClass(const std::string& styleName);
|
||||
|
||||
UIWidgetPtr loadUI(const std::string& file, const UIWidgetPtr& parent = nullptr);
|
||||
UIWidgetPtr loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent);
|
||||
UIWidgetPtr loadUI(const std::string& file, const UIWidgetPtr& parent);
|
||||
UIWidgetPtr createWidgetFromStyle(const std::string& styleName, const UIWidgetPtr& parent);
|
||||
UIWidgetPtr createWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent);
|
||||
|
||||
void setMouseReceiver(const UIWidgetPtr& widget) { m_mouseReceiver = widget; }
|
||||
void setKeyboardReceiver(const UIWidgetPtr& widget) { m_keyboardReceiver = widget; }
|
||||
|
@@ -51,10 +51,22 @@ UIWidget::~UIWidget()
|
||||
#endif
|
||||
}
|
||||
|
||||
void UIWidget::draw()
|
||||
void UIWidget::draw(const Rect& visibleRect)
|
||||
{
|
||||
drawSelf();
|
||||
drawChildren();
|
||||
if(m_children.size() > 0) {
|
||||
bool clip = true;
|
||||
if(this == g_ui.getRootWidget().get())
|
||||
clip = false;
|
||||
|
||||
if(clip)
|
||||
g_graphics.beginClipping(visibleRect);
|
||||
|
||||
drawChildren(visibleRect);
|
||||
|
||||
if(clip)
|
||||
g_graphics.endClipping();
|
||||
}
|
||||
}
|
||||
|
||||
void UIWidget::drawSelf()
|
||||
@@ -72,33 +84,35 @@ void UIWidget::drawSelf()
|
||||
drawText(m_rect);
|
||||
}
|
||||
|
||||
void UIWidget::drawChildren()
|
||||
void UIWidget::drawChildren(const Rect& visibleRect)
|
||||
{
|
||||
// draw children
|
||||
for(const UIWidgetPtr& child : m_children) {
|
||||
// render only visible children with a valid rect inside parent rect
|
||||
if(child->isExplicitlyVisible() &&
|
||||
child->getRect().isValid() &&
|
||||
child->getOpacity() > 0.0f &&
|
||||
child->getRect().intersects(m_rect)) {
|
||||
// store current graphics opacity
|
||||
float oldOpacity = g_painter.getOpacity();
|
||||
if(!child->isExplicitlyVisible() || !child->getRect().isValid() || child->getOpacity() == 0.0f)
|
||||
continue;
|
||||
|
||||
// decrease to self opacity
|
||||
if(child->getOpacity() < oldOpacity)
|
||||
g_painter.setOpacity(child->getOpacity());
|
||||
Rect childVisibleRect = visibleRect.intersection(child->getRect());
|
||||
if(!childVisibleRect.isValid())
|
||||
continue;
|
||||
|
||||
child->draw();
|
||||
// store current graphics opacity
|
||||
float oldOpacity = g_painter.getOpacity();
|
||||
|
||||
// debug draw box
|
||||
if(g_ui.isDrawingDebugBoxes()) {
|
||||
g_painter.setColor(Color::green);
|
||||
g_painter.drawBoundingRect(child->getRect());
|
||||
}
|
||||
//g_fonts.getDefaultFont()->renderText(child->getId(), child->getPosition() + Point(2, 0), Color::red);
|
||||
// decrease to self opacity
|
||||
if(child->getOpacity() < oldOpacity)
|
||||
g_painter.setOpacity(child->getOpacity());
|
||||
|
||||
g_painter.setOpacity(oldOpacity);
|
||||
child->draw(childVisibleRect);
|
||||
|
||||
// debug draw box
|
||||
if(g_ui.isDrawingDebugBoxes()) {
|
||||
g_painter.setColor(Color::green);
|
||||
g_painter.drawBoundingRect(child->getRect());
|
||||
}
|
||||
//g_fonts.getDefaultFont()->renderText(child->getId(), child->getPosition() + Point(2, 0), Color::red);
|
||||
|
||||
g_painter.setOpacity(oldOpacity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,6 +761,7 @@ void UIWidget::setStyle(const std::string& styleName)
|
||||
logTraceError("unable to retrive style '", styleName, "': not a defined style");
|
||||
return;
|
||||
}
|
||||
styleNode = styleNode->clone();
|
||||
applyStyle(styleNode);
|
||||
m_style = styleNode;
|
||||
updateStyle();
|
||||
@@ -839,6 +854,13 @@ void UIWidget::setLastFocusReason(Fw::FocusReason reason)
|
||||
m_lastFocusReason = reason;
|
||||
}
|
||||
|
||||
void UIWidget::setVirtualOffset(const Point& offset)
|
||||
{
|
||||
m_virtualOffset = offset;
|
||||
if(m_layout)
|
||||
m_layout->update();
|
||||
}
|
||||
|
||||
bool UIWidget::isVisible()
|
||||
{
|
||||
if(!m_visible)
|
||||
|
@@ -49,14 +49,15 @@ public:
|
||||
virtual ~UIWidget();
|
||||
|
||||
protected:
|
||||
virtual void draw();
|
||||
virtual void draw(const Rect& visibleRect);
|
||||
virtual void drawSelf();
|
||||
virtual void drawChildren();
|
||||
virtual void drawChildren(const Rect& visibleRect);
|
||||
|
||||
friend class UIManager;
|
||||
|
||||
std::string m_id;
|
||||
Rect m_rect;
|
||||
Point m_virtualOffset;
|
||||
Boolean<true> m_enabled;
|
||||
Boolean<true> m_visible;
|
||||
Boolean<true> m_focusable;
|
||||
@@ -121,6 +122,7 @@ public:
|
||||
void setFixedSize(bool fixed);
|
||||
void setLastFocusReason(Fw::FocusReason reason);
|
||||
void setAutoRepeatDelay(int delay) { m_autoRepeatDelay = delay; }
|
||||
void setVirtualOffset(const Point& offset);
|
||||
|
||||
bool isVisible();
|
||||
bool isChildLocked(const UIWidgetPtr& child);
|
||||
@@ -240,6 +242,7 @@ public:
|
||||
int getChildCount() { return m_children.size(); }
|
||||
Fw::FocusReason getLastFocusReason() { return m_lastFocusReason; }
|
||||
int getAutoRepeatDelay() { return m_autoRepeatDelay; }
|
||||
Point getVirtualOffset() { return m_virtualOffset; }
|
||||
std::string getStyleName() { return m_style->tag(); }
|
||||
|
||||
|
||||
|
@@ -81,9 +81,9 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
|
||||
else if(node->tag() == "background-rect")
|
||||
setBackgroundRect(node->value<Rect>());
|
||||
else if(node->tag() == "icon")
|
||||
setIcon(node->value());
|
||||
setIcon(Fw::resolvePath(node->value(), node->source()));
|
||||
else if(node->tag() == "icon-source")
|
||||
setIcon(node->value());
|
||||
setIcon(Fw::resolvePath(node->value(), node->source()));
|
||||
else if(node->tag() == "icon-color")
|
||||
setIconColor(node->value<Color>());
|
||||
else if(node->tag() == "icon-offset-x")
|
||||
|
@@ -35,7 +35,7 @@ void UIWidget::parseImageStyle(const OTMLNodePtr& styleNode)
|
||||
{
|
||||
for(const OTMLNodePtr& node : styleNode->children()) {
|
||||
if(node->tag() == "image-source")
|
||||
setImageSource(Fw::resolvePath(node->value(), styleNode->source()));
|
||||
setImageSource(Fw::resolvePath(node->value(), node->source()));
|
||||
else if(node->tag() == "image-offset-x")
|
||||
setImageOffsetX(node->value<int>());
|
||||
else if(node->tag() == "image-offset-y")
|
||||
|
Reference in New Issue
Block a user