From: Rudolf Polzer Date: Sun, 5 Dec 2010 15:52:23 +0000 (+0100) Subject: Merge remote branch 'origin/divVerent/pangofix' X-Git-Tag: xonotic-v0.5.0~144 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=commitdiff_plain;h=bc2185ec9485c3bb60f6a3d3f6df8d802de7357b;hp=db2c428f2e1821e30bbb1026986a167f6a6498d9 Merge remote branch 'origin/divVerent/pangofix' --- diff --git a/Makefile b/Makefile index bb2f743c..564a3c97 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,9 @@ LIBS_PNG ?= $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) li CPPFLAGS_GTK ?= $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) gtk+-2.0 --cflags $(STDERR_TO_DEVNULL)) LIBS_GTK ?= $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) gtk+-2.0 --libs-only-L $(STDERR_TO_DEVNULL)) \ $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) gtk+-2.0 --libs-only-l $(STDERR_TO_DEVNULL)) +CPPFLAGS_PANGOFT2 ?= $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) pangoft2 --cflags $(STDERR_TO_DEVNULL)) +LIBS_PANGOFT2 ?= $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) pangoft2 --libs-only-L $(STDERR_TO_DEVNULL)) \ + $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) pangoft2 --libs-only-l $(STDERR_TO_DEVNULL)) CPPFLAGS_GTKGLEXT ?= $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) gtkglext-1.0 --cflags $(STDERR_TO_DEVNULL)) LIBS_GTKGLEXT ?= $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) gtkglext-1.0 --libs-only-L $(STDERR_TO_DEVNULL)) \ $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKGCONFIG) gtkglext-1.0 --libs-only-l $(STDERR_TO_DEVNULL)) @@ -320,6 +323,7 @@ dependencies-check: checkheader libpng12-dev png.h png_create_read_struct "$(CPPFLAGS_PNG)" "$(LIBS_PNG)"; \ checkheader "mesa-common-dev (or another OpenGL library)" GL/gl.h glClear "$(CPPFLAGS_GL)" "$(LIBS_GL)"; \ checkheader libgtk2.0-dev gtk/gtkdialog.h gtk_dialog_run "$(CPPFLAGS_GTK)" "$(LIBS_GTK)"; \ + checkheader libpango1.0-dev pango/pangoft2.h pango_ft2_font_map_new "$(CPPFLAGS_PANGOFT2)" "$(LIBS_PANGOFT2)"; \ checkheader libgtkglext1-dev gtk/gtkglwidget.h gtk_widget_get_gl_context "$(CPPFLAGS_GTKGLEXT)" "$(LIBS_GTKGLEXT)"; \ [ "$(OS)" != "Win32" ] && checkheader libc6-dev dlfcn.h dlopen "$(CPPFLAGS_DL)" "$(LIBS_DL)"; \ checkheader zlib1g-dev zlib.h zlibVersion "$(CPPFLAGS_ZLIB)" "$(LIBS_ZLIB)"; \ @@ -544,8 +548,8 @@ $(INSTALLDIR)/q3data.$(EXE): \ $(if $(findstring $(OS),Win32),icons/q3data.o,) \ $(INSTALLDIR)/radiant.$(EXE): LDFLAGS_EXTRA := $(MWINDOWS) -$(INSTALLDIR)/radiant.$(EXE): LIBS_EXTRA := $(LIBS_GL) $(LIBS_DL) $(LIBS_XML) $(LIBS_GLIB) $(LIBS_GTK) $(LIBS_GTKGLEXT) $(LIBS_ZLIB) -$(INSTALLDIR)/radiant.$(EXE): CPPFLAGS_EXTRA := $(CPPFLAGS_GL) $(CPPFLAGS_DL) $(CPPFLAGS_XML) $(CPPFLAGS_GLIB) $(CPPFLAGS_GTK) $(CPPFLAGS_GTKGLEXT) -Ilibs -Iinclude +$(INSTALLDIR)/radiant.$(EXE): LIBS_EXTRA := $(LIBS_GL) $(LIBS_DL) $(LIBS_XML) $(LIBS_GLIB) $(LIBS_GTK) $(LIBS_GTKGLEXT) $(LIBS_ZLIB) $(LIBS_PANGOFT2) +$(INSTALLDIR)/radiant.$(EXE): CPPFLAGS_EXTRA := $(CPPFLAGS_GL) $(CPPFLAGS_DL) $(CPPFLAGS_XML) $(CPPFLAGS_GLIB) $(CPPFLAGS_GTK) $(CPPFLAGS_GTKGLEXT) $(CPPFLAGS_PANGOFT2) -Ilibs -Iinclude $(INSTALLDIR)/radiant.$(EXE): \ radiant/autosave.o \ radiant/brushmanip.o \ @@ -645,7 +649,7 @@ libprofile.$(A): \ libs/profile/file.o \ libs/profile/profile.o \ -libgtkutil.$(A): CPPFLAGS_EXTRA := $(CPPFLAGS_GLIB) $(CPPFLAGS_GTK) $(CPPFLAGS_GTKGLEXT) -Ilibs -Iinclude +libgtkutil.$(A): CPPFLAGS_EXTRA := $(CPPFLAGS_GLIB) $(CPPFLAGS_GTK) $(CPPFLAGS_GTKGLEXT) $(CPPFLAGS_PANGOFT2) -Ilibs -Iinclude libgtkutil.$(A): \ libs/gtkutil/accelerator.o \ libs/gtkutil/button.o \ diff --git a/include/igl.h b/include/igl.h index 7ea3b944..35174967 100644 --- a/include/igl.h +++ b/include/igl.h @@ -1976,6 +1976,7 @@ typedef unsigned int GLhandleARB; #endif +#include "gtkutil/glfont.h" /// \brief A module which wraps a runtime-binding of the standard OpenGL functions. /// Provides convenience functions for querying availabiliy of extensions, rendering text and error-checking. @@ -1997,16 +1998,12 @@ struct OpenGLBinding /// \brief Asserts that there no OpenGL errors have occurred since the last call to glGetError. void (*assertNoErrors)(const char *file, int line); - GLuint m_font; - int m_fontHeight; - int m_fontAscent; - int m_fontDescent; + GLFont *m_font; // MUST be set! /// \brief Renders \p string at the current raster-position of the current context. void drawString(const char* string) const { - m_glListBase(m_font); - m_glCallLists(GLsizei(strlen(string)), GL_UNSIGNED_BYTE, reinterpret_cast(string)); + m_font->printString(string); } /// \brief Renders \p character at the current raster-position of the current context. diff --git a/libs/gtkutil/glfont.cpp b/libs/gtkutil/glfont.cpp index d2d3b870..91090f3c 100644 --- a/libs/gtkutil/glfont.cpp +++ b/libs/gtkutil/glfont.cpp @@ -20,10 +20,45 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "glfont.h" +#include "igl.h" + +// generic string printing with call lists +class GLFontCallList: public GLFont +{ + GLuint m_displayList; + int m_pixelHeight; + int m_pixelAscent; + int m_pixelDescent; + public: + GLFontCallList(GLuint displayList, int asc, int desc, int pixelHeight) : m_displayList(displayList), m_pixelHeight(pixelHeight), m_pixelAscent(asc), m_pixelDescent(desc) + { + } + virtual ~GLFontCallList() + { + glDeleteLists(m_displayList, 256); + } + void printString(const char *s) + { + GlobalOpenGL().m_glListBase(m_displayList); + GlobalOpenGL().m_glCallLists(GLsizei(strlen(s)), GL_UNSIGNED_BYTE, reinterpret_cast(s)); + } + virtual int getPixelAscent() const + { + return m_pixelAscent; + } + virtual int getPixelDescent() const + { + return m_pixelDescent; + } + virtual int getPixelHeight() const + { + return m_pixelHeight; + } +}; + #ifdef _WIN32 #include #endif -#include #include "debugging/debugging.h" // LordHavoc: this is code for direct Xlib bitmap character fetching, as an @@ -38,7 +73,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include -GLFont glfont_create(const char* font_string) +GLFont *glfont_create(const char* font_string) { GLuint font_list_base; XFontStruct *fontInfo; @@ -91,20 +126,14 @@ GLFont glfont_create(const char* font_string) /* *height = fontInfo->ascent + fontInfo->descent; *width = fontInfo->max_bounds.width; */ - return GLFont(font_list_base, fontInfo->ascent + fontInfo->descent); + return new GLFontCallList(font_list_base, fontInfo->ascent, fontInfo->descent, fontInfo->ascent + fontInfo->descent); } -void glfont_release(GLFont& font) -{ - glDeleteLists(font.getDisplayList(), 256); - font = GLFont(0, 0); -} - -#else +#elif 0 #include -GLFont glfont_create(const char* font_string) +GLFont *glfont_create(const char* font_string) { GLuint font_list_base = glGenLists (256); gint font_height = 0, font_ascent = 0, font_descent = 0; @@ -148,12 +177,170 @@ GLFont glfont_create(const char* font_string) if(font_height > 256) font_height = 16; - return GLFont(font_list_base, font_ascent, font_descent, font_height); + return new GLFontCallList(font_list_base, font_ascent, font_descent, font_height); } +#endif + +// new font code ripped from ZeroRadiant -void glfont_release(GLFont& font) +#include +#include + +class GLFontInternal: public GLFont { - glDeleteLists(font.getDisplayList(), 256); - font = GLFont(0, 0, 0, 0); -} + const char *font_string; + int font_height; + int font_ascent; + int font_descent; + int y_offset_bitmap_render_pango_units; + PangoContext *ft2_context; + PangoFontMap *fontmap; + + public: + GLFontInternal(const char *_font_string): font_string(_font_string) + { + PangoFontDescription *font_desc; + PangoLayout *layout; + PangoRectangle log_rect; + int font_ascent_pango_units; + int font_descent_pango_units; + +#if !PANGO_VERSION_CHECK(1,22,0) + ft2_context = pango_ft2_get_context(72, 72); +#else + fontmap = pango_ft2_font_map_new(); + pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fontmap), 72, 72); + ft2_context = pango_font_map_create_context(fontmap); #endif + + font_desc = pango_font_description_from_string(font_string); + //pango_font_description_set_size(font_desc, 10 * PANGO_SCALE); + pango_context_set_font_description(ft2_context, font_desc); + pango_font_description_free(font_desc); + // TODO fallback to fixed 8, courier new 8 + + layout = pango_layout_new(ft2_context); +#if !PANGO_VERSION_CHECK(1,22,0) + PangoLayoutIter *iter; + iter = pango_layout_get_iter(layout); + font_ascent_pango_units = pango_layout_iter_get_baseline(iter); + pango_layout_iter_free(iter); +#else + font_ascent_pango_units = pango_layout_get_baseline(layout); +#endif + pango_layout_get_extents(layout, NULL, &log_rect); + g_object_unref(G_OBJECT(layout)); + font_descent_pango_units = log_rect.height - font_ascent_pango_units; + + font_ascent = PANGO_PIXELS_CEIL(font_ascent_pango_units); + font_descent = PANGO_PIXELS_CEIL(font_descent_pango_units); + font_height = font_ascent + font_descent; + y_offset_bitmap_render_pango_units = (font_ascent * PANGO_SCALE) - font_ascent_pango_units; + } + + virtual ~GLFontInternal() + { + g_object_unref(G_OBJECT(ft2_context)); + g_object_unref(G_OBJECT(fontmap)); + } + + // Renders the input text at the current location with the current color. + // The X position of the current location is used to place the left edge of the text image, + // where the text image bounds are defined as the logical extents of the line of text. + // The Y position of the current location is used to place the bottom of the text image. + // You should offset the Y position by the amount returned by gtk_glwidget_font_descent() + // if you want to place the baseline of the text image at the current Y position. + // Note: A problem with this function is that if the lower left corner of the text falls + // just a hair outside of the viewport (meaning the current raster position is invalid), + // then no text will be rendered. The solution to this is a very hacky one. You can search + // Google for "glDrawPixels clipping". + virtual void printString(const char *s) + { + // The idea for this code initially came from the font-pangoft2.c example that comes with GtkGLExt. + + PangoLayout *layout; + PangoRectangle log_rect; + FT_Bitmap bitmap; + unsigned char *begin_bitmap_buffer; + GLfloat color[4]; + GLint previous_unpack_alignment; + GLboolean previous_blend_enabled; + GLint previous_blend_func_src; + GLint previous_blend_func_dst; + GLfloat previous_red_bias; + GLfloat previous_green_bias; + GLfloat previous_blue_bias; + GLfloat previous_alpha_scale; + + layout = pango_layout_new(ft2_context); + pango_layout_set_width(layout, -1); // -1 no wrapping. All text on one line. + pango_layout_set_text(layout, s, -1); // -1 null-terminated string. + pango_layout_get_extents(layout, NULL, &log_rect); + + if (log_rect.width > 0 && log_rect.height > 0) { + bitmap.rows = font_ascent + font_descent; + bitmap.width = PANGO_PIXELS_CEIL(log_rect.width); + bitmap.pitch = -bitmap.width; // Rendering it "upside down" for OpenGL. + begin_bitmap_buffer = (unsigned char *) g_malloc(bitmap.rows * bitmap.width); + memset(begin_bitmap_buffer, 0, bitmap.rows * bitmap.width); + bitmap.buffer = begin_bitmap_buffer + (bitmap.rows - 1) * bitmap.width; // See pitch above. + bitmap.num_grays = 0xff; + bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + pango_ft2_render_layout_subpixel(&bitmap, layout, -log_rect.x, + y_offset_bitmap_render_pango_units); + GlobalOpenGL().m_glGetFloatv(GL_CURRENT_COLOR, color); + + // Save state. I didn't see any OpenGL push/pop operations for these. + // Question: Is saving/restoring this state necessary? Being safe. + GlobalOpenGL().m_glGetIntegerv(GL_UNPACK_ALIGNMENT, &previous_unpack_alignment); + previous_blend_enabled = GlobalOpenGL().m_glIsEnabled(GL_BLEND); + GlobalOpenGL().m_glGetIntegerv(GL_BLEND_SRC, &previous_blend_func_src); + GlobalOpenGL().m_glGetIntegerv(GL_BLEND_DST, &previous_blend_func_dst); + GlobalOpenGL().m_glGetFloatv(GL_RED_BIAS, &previous_red_bias); + GlobalOpenGL().m_glGetFloatv(GL_GREEN_BIAS, &previous_green_bias); + GlobalOpenGL().m_glGetFloatv(GL_BLUE_BIAS, &previous_blue_bias); + GlobalOpenGL().m_glGetFloatv(GL_ALPHA_SCALE, &previous_alpha_scale); + + GlobalOpenGL().m_glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + GlobalOpenGL().m_glEnable(GL_BLEND); + GlobalOpenGL().m_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GlobalOpenGL().m_glPixelTransferf(GL_RED_BIAS, color[0]); + GlobalOpenGL().m_glPixelTransferf(GL_GREEN_BIAS, color[1]); + GlobalOpenGL().m_glPixelTransferf(GL_BLUE_BIAS, color[2]); + GlobalOpenGL().m_glPixelTransferf(GL_ALPHA_SCALE, color[3]); + + GlobalOpenGL().m_glDrawPixels(bitmap.width, bitmap.rows, + GL_ALPHA, GL_UNSIGNED_BYTE, begin_bitmap_buffer); + g_free(begin_bitmap_buffer); + + // Restore state in reverse order of how we set it. + GlobalOpenGL().m_glPixelTransferf(GL_ALPHA_SCALE, previous_alpha_scale); + GlobalOpenGL().m_glPixelTransferf(GL_BLUE_BIAS, previous_blue_bias); + GlobalOpenGL().m_glPixelTransferf(GL_GREEN_BIAS, previous_green_bias); + GlobalOpenGL().m_glPixelTransferf(GL_RED_BIAS, previous_red_bias); + GlobalOpenGL().m_glBlendFunc(previous_blend_func_src, previous_blend_func_dst); + if (!previous_blend_enabled) { GlobalOpenGL().m_glDisable(GL_BLEND); } + GlobalOpenGL().m_glPixelStorei(GL_UNPACK_ALIGNMENT, previous_unpack_alignment); + } + + g_object_unref(G_OBJECT(layout)); + } + + virtual int getPixelAscent() const + { + return font_ascent; + } + virtual int getPixelDescent() const + { + return font_descent; + } + virtual int getPixelHeight() const + { + return font_height; + } +}; + +GLFont *glfont_create(const char* font_string) +{ + return new GLFontInternal(font_string); +} diff --git a/libs/gtkutil/glfont.h b/libs/gtkutil/glfont.h index 454c6a97..0d1e0000 100644 --- a/libs/gtkutil/glfont.h +++ b/libs/gtkutil/glfont.h @@ -26,33 +26,17 @@ typedef unsigned int GLuint; class GLFont { - GLuint m_displayList; - int m_pixelHeight; - int m_pixelAscent; - int m_pixelDescent; -public: - GLFont(GLuint displayList, int asc, int desc, int pixelHeight) : m_displayList(displayList), m_pixelHeight(pixelHeight), m_pixelAscent(asc), m_pixelDescent(desc) - { - } - GLuint getDisplayList() const - { - return m_displayList; - } - int getPixelHeight() const - { - return m_pixelHeight; - } - int getPixelAscent() const - { - return m_pixelAscent; - } - int getPixelDescent() const - { - return m_pixelDescent; - } + public: + virtual int getPixelHeight() const = 0; + virtual int getPixelAscent() const = 0; + virtual int getPixelDescent() const = 0; + virtual void printString(const char *s) = 0; + virtual ~GLFont() + { + } }; -GLFont glfont_create(const char* font_string); -void glfont_release(GLFont& font); +GLFont *glfont_create(const char* font_string); +// release with delete #endif diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 8a0c8949..f0744e48 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -1692,11 +1692,11 @@ void CamWnd::Cam_Draw() if(g_camwindow_globals_private.m_showStats) { - glRasterPos3f(1.0f, static_cast(m_Camera.height) - GlobalOpenGL().m_fontDescent, 0.0f); + glRasterPos3f(1.0f, static_cast(m_Camera.height) - GlobalOpenGL().m_font->getPixelDescent(), 0.0f); extern const char* Renderer_GetStats(); GlobalOpenGL().drawString(Renderer_GetStats()); - glRasterPos3f(1.0f, static_cast(m_Camera.height) - GlobalOpenGL().m_fontDescent - GlobalOpenGL().m_fontHeight, 0.0f); + glRasterPos3f(1.0f, static_cast(m_Camera.height) - GlobalOpenGL().m_font->getPixelDescent() - GlobalOpenGL().m_font->getPixelHeight(), 0.0f); extern const char* Cull_GetStats(); GlobalOpenGL().drawString(Cull_GetStats()); } diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index ea4edf31..0aaf6647 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -3316,13 +3316,10 @@ void GridStatus_onTextureLockEnabledChanged() } } -namespace -{ - GLFont g_font(0, 0, 0, 0); -} - void GlobalGL_sharedContextCreated() { + GLFont *g_font = NULL; + // report OpenGL information globalOutputStream() << "GL_VENDOR: " << reinterpret_cast(glGetString (GL_VENDOR)) << "\n"; globalOutputStream() << "GL_RENDERER: " << reinterpret_cast(glGetString (GL_RENDERER)) << "\n"; @@ -3347,10 +3344,7 @@ void GlobalGL_sharedContextCreated() g_font = glfont_create(fontname); #endif - GlobalOpenGL().m_font = g_font.getDisplayList(); - GlobalOpenGL().m_fontHeight = g_font.getPixelHeight(); - GlobalOpenGL().m_fontAscent = g_font.getPixelAscent(); - GlobalOpenGL().m_fontDescent = g_font.getPixelDescent(); + GlobalOpenGL().m_font = g_font; } void GlobalGL_sharedContextDestroyed() diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp index 774c0f85..95d490ab 100644 --- a/radiant/texwindow.cpp +++ b/radiant/texwindow.cpp @@ -370,7 +370,7 @@ const char* TextureBrowser_getComonShadersDir() inline int TextureBrowser_fontHeight(TextureBrowser& textureBrowser) { - return GlobalOpenGL().m_fontHeight; + return GlobalOpenGL().m_font->getPixelHeight(); } const char* TextureBrowser_GetSelectedShader(TextureBrowser& textureBrowser) diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp index 567d17f7..16a6274d 100644 --- a/radiant/xywindow.cpp +++ b/radiant/xywindow.cpp @@ -1849,10 +1849,8 @@ void XYWnd::XY_DrawGrid(void) { // draw coordinate text if needed if ( g_xywindow_globals_private.show_coordinates) { glColor4fv(vector4_to_array(Vector4(g_xywindow_globals.color_gridtext, 1.0f))); - // why does this not work on windows: - // float offx = m_vOrigin[nDim2] + h - (1 + GlobalOpenGL().m_fontAscent) / m_fScale; - float offx = m_vOrigin[nDim2] + h - 13 / m_fScale; - float offy = m_vOrigin[nDim1] - w + 1 / m_fScale; + float offx = m_vOrigin[nDim2] + h - (4 + GlobalOpenGL().m_font->getPixelAscent()) / m_fScale; + float offy = m_vOrigin[nDim1] - w + 4 / m_fScale; for (x = xb - fmod(xb, stepx); x <= xe ; x += stepx) { glRasterPos2f (x, offx); sprintf (text, "%g", x); @@ -2522,10 +2520,10 @@ void XYWnd::XY_Draw() } } glBegin (GL_LINE_LOOP); - glVertex2i (0, 0); - glVertex2i (m_nWidth-1, 0); - glVertex2i (m_nWidth-1, m_nHeight-1); - glVertex2i (0, m_nHeight-1); + glVertex2f (0.5, 0.5); + glVertex2f (m_nWidth-0.5, 1); + glVertex2f (m_nWidth-0.5, m_nHeight-0.5); + glVertex2f (0.5, m_nHeight-0.5); glEnd(); } }