From 1a57b26d80327a0b5bc17638aee7223757f4e089 Mon Sep 17 00:00:00 2001 From: timo Date: Fri, 26 Nov 2010 19:50:08 +0000 Subject: [PATCH] apply back 335 and 336, will need to update deps and put a zip out git-svn-id: https://zerowing.idsoftware.com/svn/radiant/GtkRadiant/trunk@343 8a3a26a2-13c4-0310-b231-cf6edde360e5 --- config.py | 13 +-- radiant/camwindow.cpp | 2 - radiant/glwidget.cpp | 200 +++++++++++++++++++++++++++++++++---- radiant/glwidget.h | 7 +- radiant/main.cpp | 7 ++ radiant/mainframe.cpp | 3 - radiant/radiant_VC9.vcproj | 16 +-- radiant/xywindow.cpp | 52 +++++++--- 8 files changed, 239 insertions(+), 61 deletions(-) diff --git a/config.py b/config.py index 563dab65..ad7ad9e9 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,4 @@ -import sys, traceback, platform, re, commands, platform +import sys, traceback, platform, re, commands, platform, subprocess if __name__ != '__main__': from SCons.Script import * @@ -250,14 +250,11 @@ class Config: def CheckoutOrUpdate( self, svnurl, path ): if ( os.path.exists( path ) ): - # NOTE: check the svnurl matches? - cmd = 'svn update "%s"' % path - print cmd + cmd = [ 'svn', 'update', path ] else: - cmd = 'svn checkout %s "%s"' % ( svnurl, path ) - ret = os.system( cmd ) - if ( ret != 0 ): - raise Exception( 'checkout or update failed' ) + cmd = [ 'svn', 'checkout', svnurl, path ] + print( repr( cmd ) ) + subprocess.check_call( cmd ) def FetchGamePaks( self, path ): diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 35c2bde5..81128dfc 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -62,8 +62,6 @@ void CamWnd::OnCreate () if (!MakeCurrent ()) Error ("glMakeCurrent failed"); - gtk_glwidget_create_font (m_pWidget); - // report OpenGL information Sys_Printf ("GL_VENDOR: %s\n", qglGetString (GL_VENDOR)); Sys_Printf ("GL_RENDERER: %s\n", qglGetString (GL_RENDERER)); diff --git a/radiant/glwidget.cpp b/radiant/glwidget.cpp index ab9f0b9d..7a408f9e 100644 --- a/radiant/glwidget.cpp +++ b/radiant/glwidget.cpp @@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "stdafx.h" #include +#include #include "glwidget.h" #include "qgl.h" @@ -206,46 +207,201 @@ gboolean WINAPI gtk_glwidget_make_current (GtkWidget *widget) return gdk_gl_drawable_gl_begin (gldrawable, glcontext); } -GLuint font_list_base; -static gchar font_string[] = "courier 8"; -static gint font_height; -void gtk_glwidget_create_font (GtkWidget *widget) +// Think about rewriting this font stuff to use OpenGL display lists and glBitmap(). +// Bit maps together with display lists may offer a performance increase, but +// they would not allow antialiased fonts. +static const char font_string[] = "Monospace"; +static const int font_height = 10; +static int font_ascent = -1; +static int font_descent = -1; +static int y_offset_bitmap_render_pango_units = -1; +static PangoContext *ft2_context = NULL; +static int _debug_font_created = 0; + + +// Units are pixels. Returns a positive value [most likely]. +int gtk_glwidget_font_ascent() +{ + if (!_debug_font_created) { + Error("Programming error: gtk_glwidget_font_ascent() called but font does not exist; " + "you should have called gtk_glwidget_create_font() first"); + } + + return font_ascent; +} + +// Units are pixels. Returns a positive value [most likely]. +int gtk_glwidget_font_descent() +{ + if (!_debug_font_created) { + Error("Programming error: gtk_glwidget_font_descent() called but font does not exist; " + "you should have called gtk_glwidget_create_font() first"); + } + + return font_descent; +} + +void gtk_glwidget_create_font() { PangoFontDescription *font_desc; - PangoFont *font; - PangoFontMetrics *font_metrics; + PangoLayout *layout; + PangoRectangle log_rect; + int font_ascent_pango_units; + int font_descent_pango_units; + + if (_debug_font_created) { + Error("Programming error: gtk_glwidget_create_font() was already called; " + "you must call gtk_glwidget_destroy_font() before creating font again"); + } + _debug_font_created = 1; - font_list_base = qglGenLists (256); + // This call is deprecated so we'll have to fix it sometime. + ft2_context = pango_ft2_get_context(72, 72); - font_desc = pango_font_description_from_string (font_string); + font_desc = pango_font_description_from_string(font_string); + pango_font_description_set_size(font_desc, font_height * PANGO_SCALE); + pango_context_set_font_description(ft2_context, font_desc); + pango_font_description_free(font_desc); - font = gdk_gl_font_use_pango_font (font_desc, 0, 256, font_list_base); + layout = pango_layout_new(ft2_context); - if(font != NULL) - { - font_metrics = pango_font_get_metrics (font, NULL); +#ifdef _WIN32 + + PangoLayoutIter *iter; + iter = pango_layout_get_iter(layout); + font_ascent_pango_units = pango_layout_iter_get_baseline(iter); + pango_layout_iter_free(iter); + +#else + + // I don't believe that's standard preprocessor syntax? +#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 - font_height = pango_font_metrics_get_ascent (font_metrics) + - pango_font_metrics_get_descent (font_metrics); - font_height = PANGO_PIXELS (font_height); +#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); + y_offset_bitmap_render_pango_units = (font_ascent * PANGO_SCALE) - font_ascent_pango_units; +} - pango_font_metrics_unref (font_metrics); +void gtk_glwidget_destroy_font() +{ + if (!_debug_font_created) { + Error("Programming error: gtk_glwidget_destroy_font() called when font " + "does not exist"); } - pango_font_description_free (font_desc); + font_ascent = -1; + font_descent = -1; + y_offset_bitmap_render_pango_units = -1; + g_object_unref(G_OBJECT(ft2_context)); + _debug_font_created = 0; } +// 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". void gtk_glwidget_print_string(const char *s) { - qglListBase(font_list_base); - qglCallLists(strlen(s), GL_UNSIGNED_BYTE, (unsigned 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; + + if (!_debug_font_created) { + Error("Programming error: gtk_glwidget_print_string() called but font does not exist; " + "you should have called gtk_glwidget_create_font() first"); + } + + 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); + qglGetFloatv(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. + qglGetIntegerv(GL_UNPACK_ALIGNMENT, &previous_unpack_alignment); + previous_blend_enabled = qglIsEnabled(GL_BLEND); + qglGetIntegerv(GL_BLEND_SRC, &previous_blend_func_src); + qglGetIntegerv(GL_BLEND_DST, &previous_blend_func_dst); + qglGetFloatv(GL_RED_BIAS, &previous_red_bias); + qglGetFloatv(GL_GREEN_BIAS, &previous_green_bias); + qglGetFloatv(GL_BLUE_BIAS, &previous_blue_bias); + qglGetFloatv(GL_ALPHA_SCALE, &previous_alpha_scale); + + qglPixelStorei(GL_UNPACK_ALIGNMENT, 1); + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglPixelTransferf(GL_RED_BIAS, color[0]); + qglPixelTransferf(GL_GREEN_BIAS, color[1]); + qglPixelTransferf(GL_BLUE_BIAS, color[2]); + qglPixelTransferf(GL_ALPHA_SCALE, color[3]); + + qglDrawPixels(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. + qglPixelTransferf(GL_ALPHA_SCALE, previous_alpha_scale); + qglPixelTransferf(GL_BLUE_BIAS, previous_blue_bias); + qglPixelTransferf(GL_GREEN_BIAS, previous_green_bias); + qglPixelTransferf(GL_RED_BIAS, previous_red_bias); + qglBlendFunc(previous_blend_func_src, previous_blend_func_dst); + if (!previous_blend_enabled) { qglDisable(GL_BLEND); } + qglPixelStorei(GL_UNPACK_ALIGNMENT, previous_unpack_alignment); + } + + g_object_unref(G_OBJECT(layout)); } void gtk_glwidget_print_char(char s) { - qglListBase(font_list_base); - qglCallLists(1, GL_UNSIGNED_BYTE, (unsigned char *) &s); + char str[2]; + str[0] = s; + str[1] = '\0'; + gtk_glwidget_print_string(str); } - diff --git a/radiant/glwidget.h b/radiant/glwidget.h index 582a5ddb..341ada71 100644 --- a/radiant/glwidget.h +++ b/radiant/glwidget.h @@ -36,10 +36,11 @@ void WINAPI gtk_glwidget_swap_buffers (GtkWidget *widget); gboolean WINAPI gtk_glwidget_make_current (GtkWidget *widget); void WINAPI gtk_glwidget_destroy_context (GtkWidget *widget); void WINAPI gtk_glwidget_create_context (GtkWidget *widget); -void gtk_glwidget_create_font (GtkWidget *widget); - +void gtk_glwidget_create_font(); +int gtk_glwidget_font_ascent(); +int gtk_glwidget_font_descent(); void gtk_glwidget_print_string(const char *s); void gtk_glwidget_print_char(char s); - +void gtk_glwidget_destroy_font(); #endif /* _GLWIDGET_H_ */ diff --git a/radiant/main.cpp b/radiant/main.cpp index 0f7b434d..7e004003 100644 --- a/radiant/main.cpp +++ b/radiant/main.cpp @@ -34,6 +34,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif #include +#include #include #include "stdafx.h" #include @@ -44,6 +45,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "watchbsp.h" #include "filters.h" +#include "glwidget.h" bool g_bBuildList = false; int g_argc; @@ -503,6 +505,11 @@ int main( int argc, char* argv[] ) { // gtk_disable_setlocale(); gtk_init(&argc, &argv); + gtk_gl_init(&argc, &argv); + gdk_gl_init(&argc, &argv); + + // TODO: Find a better place to call this. + gtk_glwidget_create_font(); if ((ptr = getenv ("Q3R_LIBGL")) != NULL) libgl = ptr; diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 402d89d4..493520f0 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -3227,9 +3227,6 @@ void MainFrame::OnSleep() */ Sys_Printf("Done.\n"); - // bring back the GL font - gtk_glwidget_create_font (m_pCamWnd->GetWidget ()); - g_bScreenUpdates = true; Sys_Printf("Dispatching wake msg..."); diff --git a/radiant/radiant_VC9.vcproj b/radiant/radiant_VC9.vcproj index 4a1919fd..403705d1 100755 --- a/radiant/radiant_VC9.vcproj +++ b/radiant/radiant_VC9.vcproj @@ -40,7 +40,7 @@ diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp index ef974f73..110a6f1c 100644 --- a/radiant/xywindow.cpp +++ b/radiant/xywindow.cpp @@ -2232,9 +2232,9 @@ void XYWnd::XY_DrawGrid() while ((step * m_fScale) < 4.0f) // make sure major grid spacing is at least 4 pixels on the screen step *= 8; //Sys_Printf("step after: %i\n", step); - while ((stepx * m_fScale) < 32.0f) // text step x must be at least 32 + while ((stepx * m_fScale) < 40.0f) // text step x must be at least 40 pixels stepx *= 2; - while ((stepy * m_fScale) < 32.0f) // text step y must be at least 32 + while ((stepy * m_fScale) < 40.0f) // text step y must be at least 40 pixels stepy *= 2; qglDisable(GL_TEXTURE_2D); @@ -2334,19 +2334,41 @@ void XYWnd::XY_DrawGrid() if ( g_qeglobals.d_savedinfo.show_coordinates) { qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT]); - float offx = m_vOrigin[nDim2] + h - 6 / m_fScale, offy = m_vOrigin[nDim1] - w + 1 / m_fScale; - for (x=xb-((int)xb)%stepx; x<=xe ; x+=stepx) - { - qglRasterPos2f (x, offx); - sprintf (text, "%i",(int)x); - gtk_glwidget_print_string(text); - } - for (y=yb-((int)yb)%stepy; y<=ye ; y+=stepy) - { - qglRasterPos2f (offy, y); - sprintf (text, "%i",(int)y); - gtk_glwidget_print_string(text); - } + + // Pixels between top of label for vertical grid line and top of grid view window. + // Note: There is currently a bug where the top few pixels of the grid view are hidden + // under the border. So you should add about 5 to the desired value here. However, + // the font ascent reaches higher than all digits, so you can subtract a few from the final + // number. + const int pixelsTopCushion = 4; + + // Pixels between left of label and + // - left of grid view window (for horizontal grid line label) or + // - drawn vertical grid line (for vertical grid line label). + const int pixelsLeftCushion = 2; // IMPORTANT! Must be at least 1 otherwise labels might not be drawn + // because the origin of the text might be off screen due to rounding. + + // Pixels between baseline of horizontal grid line label and drawn horizontal grid line. + const int pixelsButtomCushion = 2; + + float yPosLabelsTop = m_vOrigin[nDim2] + h - (gtk_glwidget_font_ascent() + pixelsTopCushion) / m_fScale; + float xPosLabelsLeft = m_vOrigin[nDim1] - w + pixelsLeftCushion / m_fScale; + float leftCushion = pixelsLeftCushion / m_fScale; + float bottomOffset = (pixelsButtomCushion - gtk_glwidget_font_descent()) / m_fScale; + + // This renders the numbers along varying X on top of the grid view (labels vertical grid lines). + for (x = xb - ((int) xb) % stepx; x <= xe; x += stepx) { + qglRasterPos2f(x + leftCushion, yPosLabelsTop); + sprintf(text, "%i", (int) x); + gtk_glwidget_print_string(text); + } + + // This renders the numbers along varying Y on the left of the grid view (labels horizontal grid lines). + for (y = yb - ((int) yb) % stepy; y <= ye; y += stepy) { + qglRasterPos2f(xPosLabelsLeft, y + bottomOffset); + sprintf(text, "%i", (int) y); + gtk_glwidget_print_string(text); + } if (Active()) qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME]); -- 2.39.2