From 07edad611f8a696218e5436127a0b6a85fbb92e6 Mon Sep 17 00:00:00 2001 From: Aloshi Date: Wed, 19 Mar 2014 15:03:23 -0500 Subject: [PATCH] "Fixed" the long-time weird rendering artifacts that are apparently caused by vertex coordinates not being integers. A better fix would be to move to OpenGL 3/GLES 2 and do rounding in the shader. But I don't have time for that. --- DEVNOTES.md | 10 +++++++ src/Renderer.h | 1 + src/Renderer_draw_gl.cpp | 6 +++++ src/Renderer_init_sdlgl.cpp | 10 +++---- src/Util.cpp | 38 ++++++++++++++++++++++++++- src/Util.h | 11 +++++++- src/components/ButtonComponent.cpp | 5 ++-- src/components/ComponentList.cpp | 23 ++++++++-------- src/components/DateTimeComponent.cpp | 3 ++- src/components/ImageComponent.cpp | 6 ++++- src/components/NinePatchComponent.cpp | 10 ++++++- src/components/RatingComponent.cpp | 6 ++++- src/components/SliderComponent.cpp | 7 ++--- src/components/TextComponent.cpp | 7 +++-- src/resources/Font.cpp | 7 +++++ 15 files changed, 120 insertions(+), 30 deletions(-) diff --git a/DEVNOTES.md b/DEVNOTES.md index d9d207aec..808a47f17 100644 --- a/DEVNOTES.md +++ b/DEVNOTES.md @@ -33,3 +33,13 @@ Creating a new GameListView Class ================================= 1. Don't allow the user to navigate to the root node's parent. If you use a stack of some sort to keep track of past cursor states this will be a natural side effect. + + + +Creating a new Component +======================== + +If your component is not made up of other components, and you draw something to the screen with OpenGL, make sure: + +* Your vertex positions are rounded before you render (you can use round(float) in Util.h to do this). +* Your transform matrix's translation is rounded (you can use roundMatrix(affine3f) in Util.h to do this). \ No newline at end of file diff --git a/src/Renderer.h b/src/Renderer.h index bd3cc0d48..c286974ee 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -38,6 +38,7 @@ namespace Renderer void setMatrix(const Eigen::Affine3f& transform); void drawRect(int x, int y, int w, int h, unsigned int color, GLenum blend_sfactor = GL_SRC_ALPHA, GLenum blend_dfactor = GL_ONE_MINUS_SRC_ALPHA); + void drawRect(float x, float y, float w, float h, unsigned int color, GLenum blend_sfactor = GL_SRC_ALPHA, GLenum blend_dfactor = GL_ONE_MINUS_SRC_ALPHA); } #endif diff --git a/src/Renderer_draw_gl.cpp b/src/Renderer_draw_gl.cpp index a5bb90642..2ca93a2e4 100644 --- a/src/Renderer_draw_gl.cpp +++ b/src/Renderer_draw_gl.cpp @@ -6,6 +6,7 @@ #include #include "Log.h" #include +#include "Util.h" namespace Renderer { std::stack clipStack; @@ -87,6 +88,11 @@ namespace Renderer { } } + void drawRect(float x, float y, float w, float h, unsigned int color, GLenum blend_sfactor, GLenum blend_dfactor) + { + drawRect((int)round(x), (int)round(y), (int)round(w), (int)round(h), color, blend_sfactor, blend_dfactor); + } + void drawRect(int x, int y, int w, int h, unsigned int color, GLenum blend_sfactor, GLenum blend_dfactor) { #ifdef USE_OPENGL_ES diff --git a/src/Renderer_init_sdlgl.cpp b/src/Renderer_init_sdlgl.cpp index aedc1a5d9..f4a5da1ee 100644 --- a/src/Renderer_init_sdlgl.cpp +++ b/src/Renderer_init_sdlgl.cpp @@ -43,6 +43,10 @@ namespace Renderer SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + // multisample anti-aliasing + //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); + #ifdef USE_OPENGL_ES SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); #endif @@ -91,12 +95,6 @@ namespace Renderer sdlContext = SDL_GL_CreateContext(sdlWindow); - //usually display width/height are not specified, i.e. zero, which SDL automatically takes as "native resolution" - //so, since other things rely on the size of the screen (damn currently unnormalized coordinate system), we set it here - //even though the system was already initialized - this makes sure it gets reinitialized to the original resolution when we return from a game - //display_width = sdlWindow->w; - //display_height = sdlWindow->h; - //hide mouse cursor initialCursorState = SDL_ShowCursor(0) == 1; diff --git a/src/Util.cpp b/src/Util.cpp index d96434299..f23f3d0bf 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -19,4 +19,40 @@ std::string& strToUpper(std::string& str) std::string strToUpper(const std::string& str) { return strToUpper(str.c_str()); -} \ No newline at end of file +} + +float round(float num) +{ + return (float)((int)(num + 0.5f)); +} + +Eigen::Affine3f& roundMatrix(Eigen::Affine3f& mat) +{ + mat.translation()[0] = round(mat.translation()[0]); + mat.translation()[1] = round(mat.translation()[1]); + return mat; +} + +Eigen::Affine3f roundMatrix(const Eigen::Affine3f& mat) +{ + Eigen::Affine3f ret = mat; + roundMatrix(ret); + return ret; +} + +Eigen::Vector3f roundVector(const Eigen::Vector3f& vec) +{ + Eigen::Vector3f ret = vec; + ret[0] = round(ret[0]); + ret[1] = round(ret[1]); + ret[2] = round(ret[2]); + return ret; +} + +Eigen::Vector2f roundVector(const Eigen::Vector2f& vec) +{ + Eigen::Vector2f ret = vec; + ret[0] = round(ret[0]); + ret[1] = round(ret[1]); + return ret; +} diff --git a/src/Util.h b/src/Util.h index 42c8222d0..c057cb747 100644 --- a/src/Util.h +++ b/src/Util.h @@ -1,5 +1,14 @@ #include +#include std::string strToUpper(const char* from); std::string& strToUpper(std::string& str); -std::string strToUpper(const std::string& str); \ No newline at end of file +std::string strToUpper(const std::string& str); + +Eigen::Affine3f& roundMatrix(Eigen::Affine3f& mat); +Eigen::Affine3f roundMatrix(const Eigen::Affine3f& mat); + +Eigen::Vector3f roundVector(const Eigen::Vector3f& vec); +Eigen::Vector2f roundVector(const Eigen::Vector2f& vec); + +float round(float num); diff --git a/src/components/ButtonComponent.cpp b/src/components/ButtonComponent.cpp index 3a914113e..75cc8b52d 100644 --- a/src/components/ButtonComponent.cpp +++ b/src/components/ButtonComponent.cpp @@ -85,13 +85,14 @@ void ButtonComponent::updateImage() void ButtonComponent::render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); - + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); + mBox.render(trans); if(mTextCache) { Eigen::Vector3f centerOffset((mSize.x() - mTextCache->metrics.size.x()) / 2, (mSize.y() - mTextCache->metrics.size.y()) / 2, 0); + centerOffset = roundVector(centerOffset); trans = trans.translate(centerOffset); Renderer::setMatrix(trans); diff --git a/src/components/ComponentList.cpp b/src/components/ComponentList.cpp index 96f3cebe7..c6085ea0a 100644 --- a/src/components/ComponentList.cpp +++ b/src/components/ComponentList.cpp @@ -1,4 +1,5 @@ #include "ComponentList.h" +#include "../Util.h" #define TOTAL_HORIZONTAL_PADDING_PX 20 @@ -128,16 +129,16 @@ void ComponentList::render(const Eigen::Affine3f& parentTrans) if(!size()) return; - Eigen::Affine3f trans = parentTrans * getTransform(); - + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); + // clip everything to be inside our bounds Eigen::Vector3f dim(mSize.x(), mSize.y(), 0); dim = trans * dim - trans.translation(); - Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), - (int)trans.translation().y()), Eigen::Vector2i((int)dim.x(), (int)dim.y())); + Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), + Eigen::Vector2i((int)round(dim.x()), (int)round(dim.y()))); // scroll the camera - trans.translate(Eigen::Vector3f(0, -mCameraOffset, 0)); + trans.translate(Eigen::Vector3f(0, -round(mCameraOffset), 0)); // draw our entries renderChildren(trans); @@ -154,24 +155,24 @@ void ComponentList::render(const Eigen::Affine3f& parentTrans) // (1 - dst) + 0x77 const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data); - Renderer::drawRect(0, (int)mSelectorBarOffset, (int)mSize.x(), (int)selectedRowHeight, 0xFFFFFFFF, + Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x(), selectedRowHeight, 0xFFFFFFFF, GL_ONE_MINUS_DST_COLOR, GL_ZERO); - Renderer::drawRect(0, (int)mSelectorBarOffset, (int)mSize.x(), (int)selectedRowHeight, 0x777777FF, + Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x(), selectedRowHeight, 0x777777FF, GL_ONE, GL_ONE); // hack to draw 2px dark on left/right of the bar - Renderer::drawRect(0, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF); - Renderer::drawRect((int)mSize.x() - 2, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF); + Renderer::drawRect(0.0f, mSelectorBarOffset, 2.0f, selectedRowHeight, 0x878787FF); + Renderer::drawRect(mSize.x() - 2.0f, mSelectorBarOffset, 2.0f, selectedRowHeight, 0x878787FF); } // draw separators float y = 0; for(unsigned int i = 0; i < mEntries.size(); i++) { - Renderer::drawRect(0, (int)y, (int)mSize.x(), 1, 0xC6C7C6FF); + Renderer::drawRect(0.0f, y, mSize.x(), 1.0f, 0xC6C7C6FF); y += getRowHeight(mEntries.at(i).data); } - Renderer::drawRect(0, (int)y, (int)mSize.x(), 1, 0xC6C7C6FF); + Renderer::drawRect(0.0f, y, mSize.x(), 1.0f, 0xC6C7C6FF); Renderer::popClipRect(); } diff --git a/src/components/DateTimeComponent.cpp b/src/components/DateTimeComponent.cpp index a705612ac..aeda8cbc4 100644 --- a/src/components/DateTimeComponent.cpp +++ b/src/components/DateTimeComponent.cpp @@ -3,6 +3,7 @@ #include "../Renderer.h" #include "../Window.h" #include "../Log.h" +#include "../Util.h" DateTimeComponent::DateTimeComponent(Window* window) : GuiComponent(window), mEditing(false), mEditIndex(0), mDisplayMode(DISP_DATE), mRelativeUpdateAccumulator(0), @@ -136,7 +137,7 @@ void DateTimeComponent::update(int deltaTime) void DateTimeComponent::render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); Renderer::setMatrix(trans); if(mTextCache) diff --git a/src/components/ImageComponent.cpp b/src/components/ImageComponent.cpp index cb5c32723..732b5b2c9 100644 --- a/src/components/ImageComponent.cpp +++ b/src/components/ImageComponent.cpp @@ -5,6 +5,7 @@ #include "../Log.h" #include "../Renderer.h" #include "../ThemeData.h" +#include "../Util.h" Eigen::Vector2i ImageComponent::getTextureSize() const { @@ -136,7 +137,7 @@ void ImageComponent::setColorShift(unsigned int color) void ImageComponent::render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); Renderer::setMatrix(trans); if(mTexture && getOpacity() > 0) @@ -172,6 +173,9 @@ void ImageComponent::buildImageArray(int posX, int posY, GLfloat* points, GLfloa points[8] = posX - (mSize.x() * mOrigin.x()); points[9] = posY + (mSize.y() * (1 - mOrigin.y())); points[10] = posX + (mSize.x() * (1 -mOrigin.x())); points[11] = posY + (mSize.y() * (1 - mOrigin.y())); + // round vertices + for(int i = 0; i < 12; i++) + points[i] = round(points[i]); texs[0] = 0; texs[1] = py; diff --git a/src/components/NinePatchComponent.cpp b/src/components/NinePatchComponent.cpp index 8cda3e697..75615f065 100644 --- a/src/components/NinePatchComponent.cpp +++ b/src/components/NinePatchComponent.cpp @@ -3,6 +3,7 @@ #include "../Log.h" #include "../Renderer.h" #include "../ThemeData.h" +#include "../Util.h" NinePatchComponent::NinePatchComponent(Window* window, const std::string& path, unsigned int edgeColor, unsigned int centerColor) : GuiComponent(window), mEdgeColor(edgeColor), mCenterColor(centerColor), @@ -121,11 +122,18 @@ void NinePatchComponent::buildVertices() v += 6; } + + // round vertices + for(int i = 0; i < 6*9; i++) + { + mVertices[i].pos = roundVector(mVertices[i].pos); + } } void NinePatchComponent::render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); + if(mTexture && mVertices != NULL) { Renderer::setMatrix(trans); diff --git a/src/components/RatingComponent.cpp b/src/components/RatingComponent.cpp index ec2d04535..dacfd7329 100644 --- a/src/components/RatingComponent.cpp +++ b/src/components/RatingComponent.cpp @@ -1,6 +1,7 @@ #include "RatingComponent.h" #include "../Renderer.h" #include "../Window.h" +#include "../Util.h" RatingComponent::RatingComponent(Window* window) : GuiComponent(window) { @@ -71,11 +72,14 @@ void RatingComponent::updateVertices() mVertices[10].pos << fw, 0.0f; mVertices[10].tex << numStars, 1.0f; mVertices[11] = mVertices[7]; + + for(int i = 0; i < 12; i++) + mVertices[i].pos = roundVector(mVertices[i].pos); } void RatingComponent::render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); Renderer::setMatrix(trans); glEnable(GL_TEXTURE_2D); diff --git a/src/components/SliderComponent.cpp b/src/components/SliderComponent.cpp index 4a2029b06..c9d848838 100644 --- a/src/components/SliderComponent.cpp +++ b/src/components/SliderComponent.cpp @@ -3,6 +3,7 @@ #include "../Renderer.h" #include "../resources/Font.h" #include "../Log.h" +#include "../Util.h" SliderComponent::SliderComponent(Window* window, float min, float max, float increment, const std::string& suffix) : GuiComponent(window), mMin(min), mMax(max), mIncrement(increment), mMoveRate(0), mRepeatWaitTimer(0), mKnob(window), mSuffix(suffix) @@ -74,7 +75,7 @@ void SliderComponent::update(int deltaTime) void SliderComponent::render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); Renderer::setMatrix(trans); // render suffix @@ -84,8 +85,8 @@ void SliderComponent::render(const Eigen::Affine3f& parentTrans) float width = mSize.x() - mKnob.getSize().x() - (mValueCache ? mValueCache->metrics.size.x() + 4 : 0); //render line - const int lineWidth = 2; - Renderer::drawRect((int)mKnob.getSize().x() / 2, (int)mSize.y() / 2 - lineWidth / 2, (int)width, lineWidth, 0x777777FF); + const float lineWidth = 2; + Renderer::drawRect(mKnob.getSize().x() / 2, mSize.y() / 2 - lineWidth / 2, width, lineWidth, 0x777777FF); //render knob mKnob.render(trans); diff --git a/src/components/TextComponent.cpp b/src/components/TextComponent.cpp index d450c59c2..cd997a66a 100644 --- a/src/components/TextComponent.cpp +++ b/src/components/TextComponent.cpp @@ -3,6 +3,7 @@ #include "../Log.h" #include "../Window.h" #include "../ThemeData.h" +#include "../Util.h" TextComponent::TextComponent(Window* window) : GuiComponent(window), mFont(Font::get(FONT_SIZE_MEDIUM)), mColor(0x000000FF), mAutoCalcExtent(true, true), mCentered(false) @@ -68,11 +69,12 @@ void TextComponent::setCentered(bool center) void TextComponent::render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); + Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform()); Eigen::Vector3f dim(mSize.x(), mSize.y(), 0); dim = trans * dim - trans.translation(); - Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), Eigen::Vector2i((int)dim.x(), (int)dim.y())); + Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), + Eigen::Vector2i((int)(dim.x() + 0.5f), (int)(dim.y() + 0.5f))); if(mTextCache) { @@ -80,6 +82,7 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans) { const Eigen::Vector2f& textSize = mTextCache->metrics.size; Eigen::Vector3f off((getSize().x() - textSize.x()) / 2, (getSize().y() - textSize.y()) / 2, 0); + off = roundVector(off); trans.translate(off); Renderer::setMatrix(trans); diff --git a/src/resources/Font.cpp b/src/resources/Font.cpp index aa628f73a..7d53c47fc 100644 --- a/src/resources/Font.cpp +++ b/src/resources/Font.cpp @@ -5,6 +5,7 @@ #include "../Renderer.h" #include #include "../Log.h" +#include "../Util.h" FT_Library Font::sLibrary; bool Font::libraryInitialized = false; @@ -475,6 +476,12 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of vert[i + 5].tex[0] = vert[i + 1].tex.x(); vert[i + 5].tex[1] = vert[i + 0].tex.y(); + // round + for(int j = 0; j < 6; j++) + { + vert[i + j].pos = roundVector(vert[i + j].pos); + } + x += charData[letter].advX * fontScale; }