diff --git a/include/iglrender.h b/include/iglrender.h index 2c079052..23477199 100644 --- a/include/iglrender.h +++ b/include/iglrender.h @@ -65,7 +65,8 @@ enum ESort eSortHighlight = 1027, eSortOverlayFirst = 1028, eSortOverlayLast = 2047, - eSortControlFirst = 2048, + eSortText = 2048, + eSortControlFirst = 2049, eSortControlLast = 3071, eSortGUI0 = 3072, eSortGUI1 = 3073, diff --git a/include/irender.h b/include/irender.h index 51994542..7b93ec13 100644 --- a/include/irender.h +++ b/include/irender.h @@ -52,7 +52,8 @@ const unsigned int RENDER_TEXTURE = 1 << 18; // glEnable(GL_TEXTURE_2D) const unsigned int RENDER_BUMP = 1 << 19; const unsigned int RENDER_PROGRAM = 1 << 20; const unsigned int RENDER_SCREEN = 1 << 21; -const unsigned int RENDER_OVERRIDE = 1 << 22; +const unsigned int RENDER_TEXT = 1 << 22; +const unsigned int RENDER_OVERRIDE = 1 << 23; typedef unsigned int RenderStateFlags; diff --git a/libs/gtkutil/glfont.cpp b/libs/gtkutil/glfont.cpp index 740e5ee4..cc11bd37 100644 --- a/libs/gtkutil/glfont.cpp +++ b/libs/gtkutil/glfont.cpp @@ -22,6 +22,9 @@ #include "glfont.h" #include "igl.h" +#include +#include + // generic string printing with call lists class GLFontCallList : public GLFont { @@ -29,16 +32,257 @@ GLuint m_displayList; int m_pixelHeight; int m_pixelAscent; int m_pixelDescent; +PangoFontMap *m_fontmap; +PangoContext *m_ft2_context; public: -GLFontCallList( GLuint displayList, int asc, int desc, int pixelHeight ) : m_displayList( displayList ), m_pixelHeight( pixelHeight ), m_pixelAscent( asc ), m_pixelDescent( desc ){ +GLFontCallList( GLuint displayList, int asc, int desc, int pixelHeight, PangoFontMap *fontmap, PangoContext *ft2_context ) : + m_displayList( displayList ), m_pixelHeight( pixelHeight ), m_pixelAscent( asc ), m_pixelDescent( desc ), m_fontmap( fontmap ), m_ft2_context( ft2_context ){ } virtual ~GLFontCallList(){ glDeleteLists( m_displayList, 256 ); + g_object_unref( G_OBJECT( m_ft2_context ) ); + g_object_unref( G_OBJECT( m_fontmap ) ); } void printString( const char *s ){ GlobalOpenGL().m_glListBase( m_displayList ); GlobalOpenGL().m_glCallLists( GLsizei( strlen( s ) ), GL_UNSIGNED_BYTE, reinterpret_cast( s ) ); } + +void renderString( const char *s, const GLuint& tex, const unsigned int colour[3], int& wid, int& hei ){ + + PangoLayout *layout; + PangoRectangle log_rect; + FT_Bitmap bitmap; + + layout = pango_layout_new( m_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 ) { + hei = bitmap.rows = PANGO_PIXELS_CEIL( log_rect.height );//m_pixelAscent + m_pixelDescent; + wid = bitmap.width = PANGO_PIXELS_CEIL( log_rect.width ); +// globalOutputStream() << width << " " << height << "rendering\n"; + bitmap.pitch = bitmap.width; + unsigned char *boo = (unsigned char *) malloc( bitmap.rows * bitmap.width ); + memset( boo, 0, bitmap.rows * bitmap.width ); + bitmap.buffer = boo; + bitmap.num_grays = 0xff; + bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + pango_ft2_render_layout_subpixel( &bitmap, layout, -log_rect.x, 0 ); + + hei += 2; + wid += 2; + unsigned char *buf = (unsigned char *) malloc( 4 * hei * wid ); + memset( buf, 0x00, 4 * hei * wid ); + +#if 0 + GLfloat color[4] = { 1, 0, 0, 1 }; + guint32 rgb = ( ( ( guint32 )( color[0] * 255.0 ) ) << 24 ) | + ( ( ( guint32 )( color[1] * 255.0 ) ) << 16 ) | + ( ( ( guint32 )( color[2] * 255.0 ) ) << 8 ); + + GLfloat a = color[3]; + + guint32 *t; + guint8 *row, *row_end; + row = bitmap.buffer + bitmap.rows * bitmap.width; /* past-the-end */ + row_end = bitmap.buffer; /* beginning */ + + t = ( guint32* ) buf; + + if( a == 1.0 ) { + do { + row -= bitmap.width; + for( unsigned int i = 0; i < bitmap.width; i++ ) + *t++ = rgb | ( ( guint32 ) row[i] ); + + } while( row != row_end ); + } else + { + do + { + row -= bitmap.width; + for( unsigned int i = 0; i < bitmap.width; i++ ) + * t++ = rgb | ( ( guint32 )( a* row[i] ) ); + } while( row != row_end ); + } +#endif // 0 + +#if 0 + if( withfond ){ /* with background rectangle */ + int x_max = wid; + int y_max = hei; + int x, y, bitmapIter = 0; + + unsigned int fontColorR = 255; + unsigned int fontColorG = 255; + unsigned int fontColorB = 0; + + unsigned int backgroundColorR = 64; + unsigned int backgroundColorG = 64; + unsigned int backgroundColorB = 64; + float opacity; + + for( y = 0; y < y_max; y++ ) { + for( x = 0; x < x_max; x++ ) { + int iter = ( y * x_max + x ) * 4; + if( x == 0 || y == 0 || x == ( x_max - 1 ) || y == ( y_max - 1 ) ) { + buf[iter] = backgroundColorB; + buf[iter + 1] = backgroundColorG; + buf[iter + 2] = backgroundColorR; + buf[iter + 3] = 150; /* half trans border */ + continue; + } + if( bitmap.buffer[bitmapIter] == 0 ) { + /* Render background color. */ + buf[iter] = backgroundColorB; + buf[iter + 1] = backgroundColorG; + buf[iter + 2] = backgroundColorR; + buf[iter + 3] = 255; + } + else { + /* Calculate alpha (opacity). */ + opacity = bitmap.buffer[bitmapIter] / 255.f; + buf[iter] = fontColorB * opacity + ( 1 - opacity ) * backgroundColorB; + buf[iter + 1] = fontColorG * opacity + ( 1 - opacity ) * backgroundColorG; + buf[iter + 2] = fontColorR * opacity + ( 1 - opacity ) * backgroundColorR; + buf[iter + 3] = 255; + } + ++bitmapIter; + } + } + } +#else + if( 1 ){ /* normal with shadow */ + int x_max = wid; + int y_max = hei; + int x, y, bitmapIter = 0; + +// unsigned int fontColorR = 255; +// unsigned int fontColorG = 255; +// unsigned int fontColorB = 0; + unsigned int fontColorR = colour[0]; + unsigned int fontColorG = colour[1]; + unsigned int fontColorB = colour[2]; + + unsigned int backgroundColorR = 0; + unsigned int backgroundColorG = 0; + unsigned int backgroundColorB = 0; + + for( y = 0; y < y_max; y++ ) { + for( x = 0; x < x_max; x++ ) { + int iter = ( y * x_max + x ) * 4; + if( x == 0 || y == 0 || x == 1 || y == 1 ) { + buf[iter] = fontColorB; + buf[iter + 1] = fontColorG; + buf[iter + 2] = fontColorR; + buf[iter + 3] = 0; + continue; + } + if( bitmap.buffer[bitmapIter] == 0 ){ + buf[iter] = fontColorB; + buf[iter + 1] = fontColorG; + buf[iter + 2] = fontColorR; + buf[iter + 3] = 0; + } + else{ + buf[iter] = backgroundColorB; + buf[iter + 1] = backgroundColorG; + buf[iter + 2] = backgroundColorR; + buf[iter + 3] = bitmap.buffer[bitmapIter]; + } + ++bitmapIter; + } + } + + bitmapIter = 0; + for( y = 0; y < y_max; y++ ) { + for( x = 0; x < x_max; x++ ) { + int iter = ( y * x_max + x ) * 4; + if( x == 0 || y == 0 || x == ( x_max - 1 ) || y == ( y_max - 1 ) ) { + continue; + } + if( bitmap.buffer[bitmapIter] != 0 ) { + if( buf[iter + 3] == 0 ){ + buf[iter] = fontColorB; + buf[iter + 1] = fontColorG; + buf[iter + 2] = fontColorR; + buf[iter + 3] = bitmap.buffer[bitmapIter]; + } + else{ + /* Calculate alpha (opacity). */ + float opacityFont = bitmap.buffer[bitmapIter] / 255.f; + float opacityBack = buf[iter + 3] / 255.f; + buf[iter] = fontColorB * opacityFont + ( 1 - opacityFont ) * backgroundColorB; + buf[iter + 1] = fontColorG * opacityFont + ( 1 - opacityFont ) * backgroundColorG; + buf[iter + 2] = fontColorR * opacityFont + ( 1 - opacityFont ) * backgroundColorR; + buf[iter + 3] = ( opacityFont + ( 1 - opacityFont ) * opacityBack ) * 255.f; + } + } + ++bitmapIter; + } + } + } +#endif // 0 + else{ /* normal */ + int x_max = wid; + int y_max = hei; + int x, y, bitmapIter = 0; + +// unsigned int fontColorR = 0; +// unsigned int fontColorG = 255; +// unsigned int fontColorB = 0; + unsigned int fontColorR = colour[0]; + unsigned int fontColorG = colour[1]; + unsigned int fontColorB = colour[2]; + + for( y = 0; y < y_max; y++ ) { + for( x = 0; x < x_max; x++ ) { + int iter = ( y * x_max + x ) * 4; + if( x == 0 || y == 0 || x == ( x_max - 1 ) || y == ( y_max - 1 ) ) { + buf[iter] = fontColorB; + buf[iter + 1] = fontColorG; + buf[iter + 2] = fontColorR; + buf[iter + 3] = 0; + continue; + } + buf[iter] = fontColorB; + buf[iter + 1] = fontColorG; + buf[iter + 2] = fontColorR; + buf[iter + 3] = bitmap.buffer[bitmapIter]; + ++bitmapIter; + } + } + } + + + + //Now we just setup some texture paramaters. + glBindTexture( GL_TEXTURE_2D, tex ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); +// glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); +// glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + //Here we actually create the texture itself + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, wid, hei, + 0, GL_BGRA, GL_UNSIGNED_BYTE, buf ); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + free( buf ); + free( boo ); + } + g_object_unref( G_OBJECT( layout ) ); +} virtual int getPixelAscent() const { return m_pixelAscent; } @@ -351,6 +595,9 @@ GLFont *glfont_create( const char* font_string ){ PangoFont* font = gdk_gl_font_use_pango_font( font_desc, 0, 256, font_list_base ); + PangoFontMap *fontmap = 0; + PangoContext *ft2_context = 0; + if ( font == 0 ) { pango_font_description_free( font_desc ); font_desc = pango_font_description_from_string( "arial 8" ); @@ -382,9 +629,9 @@ GLFont *glfont_create( const char* font_string ){ if ( font != 0 ) { - PangoFontMap *fontmap = pango_ft2_font_map_new(); + fontmap = pango_ft2_font_map_new(); pango_ft2_font_map_set_resolution( PANGO_FT2_FONT_MAP( fontmap ), 72, 72 ); - PangoContext *ft2_context = pango_font_map_create_context( fontmap ); + ft2_context = pango_font_map_create_context( fontmap ); pango_context_set_font_description( ft2_context, font_desc ); PangoLayout *layout = pango_layout_new( ft2_context ); @@ -399,15 +646,22 @@ GLFont *glfont_create( const char* font_string ){ g_object_unref( G_OBJECT( layout ) ); int font_descent_pango_units = log_rect.height - font_ascent_pango_units; + /* settings for render to tex; need to multiply size, so that bitmap callLists way size would be approximately = texture way */ + gint fontsize = pango_font_description_get_size( font_desc ); + fontsize *= 3; + fontsize /= 2; //*15/11 is equal to bitmap callLists size + pango_font_description_set_size( font_desc, fontsize ); + pango_context_set_font_description( ft2_context, font_desc ); + pango_font_description_free( font_desc ); - g_object_unref( G_OBJECT( ft2_context ) ); - g_object_unref( G_OBJECT( fontmap ) ); +// g_object_unref( G_OBJECT( ft2_context ) ); +// g_object_unref( G_OBJECT( fontmap ) ); font_ascent = PANGO_PIXELS_CEIL( font_ascent_pango_units ); font_descent = PANGO_PIXELS_CEIL( font_descent_pango_units ); font_height = font_ascent + font_descent; } - return new GLFontCallList( font_list_base, font_ascent, font_descent, font_height ); + return new GLFontCallList( font_list_base, font_ascent, font_descent, font_height, fontmap, ft2_context ); } diff --git a/libs/gtkutil/glfont.h b/libs/gtkutil/glfont.h index 06bfd4cd..efdde8cf 100644 --- a/libs/gtkutil/glfont.h +++ b/libs/gtkutil/glfont.h @@ -31,6 +31,7 @@ virtual int getPixelHeight() const = 0; virtual int getPixelAscent() const = 0; virtual int getPixelDescent() const = 0; virtual void printString( const char *s ) = 0; +virtual void renderString( const char *s, const GLuint& tex, const unsigned int colour[3], int& wid, int& hei ) = 0; virtual ~GLFont(){ } }; diff --git a/libs/pivot.h b/libs/pivot.h index 93cb3549..3fedaf68 100644 --- a/libs/pivot.h +++ b/libs/pivot.h @@ -235,7 +235,7 @@ class RenderablePivot : public OpenGLRenderable VertexBuffer m_vertices; public: mutable Matrix4 m_localToWorld; -typedef Static StaticShader; +typedef Static StaticShader; static Shader* getShader(){ return StaticShader::instance(); } diff --git a/plugins/entity/doom3group.cpp b/plugins/entity/doom3group.cpp index 15f7f3fa..54ecefb1 100644 --- a/plugins/entity/doom3group.cpp +++ b/plugins/entity/doom3group.cpp @@ -348,7 +348,7 @@ const AABB& localAABB() const { return m_curveBounds; } -void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const { +void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected, const AABB& childBounds ) const { if ( isModel() && selected ) { m_renderOrigin.render( renderer, volume, localToWorld ); } @@ -362,10 +362,6 @@ void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& l if ( !m_curveCatmullRom.m_renderCurve.m_vertices.empty() ) { renderer.addRenderable( m_curveCatmullRom.m_renderCurve, localToWorld ); } -} - -void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected, const AABB& childBounds ) const { - renderSolid( renderer, volume, localToWorld, selected ); if ( g_showNames ) { // draw models as usual @@ -379,10 +375,14 @@ void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix m_name_origin = childBounds.origin; } - renderer.addRenderable( m_renderName, localToWorld ); + m_renderName.render( renderer, volume, localToWorld, selected ); } } +void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected, const AABB& childBounds ) const { + renderSolid( renderer, volume, localToWorld, selected, childBounds ); +} + void testSelect( Selector& selector, SelectionTest& test, SelectionIntersection& best ){ PointVertexArray_testSelect( &m_curveNURBS.m_renderCurve.m_vertices[0], m_curveNURBS.m_renderCurve.m_vertices.size(), test, best ); PointVertexArray_testSelect( &m_curveCatmullRom.m_renderCurve.m_vertices[0], m_curveCatmullRom.m_renderCurve.m_vertices.size(), test, best ); @@ -499,7 +499,7 @@ Doom3GroupInstance( const scene::Path& path, scene::Instance* parent, Doom3Group m_contained.instanceDetach( Instance::path() ); } void renderSolid( Renderer& renderer, const VolumeTest& volume ) const { - m_contained.renderSolid( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() ); + m_contained.renderSolid( renderer, volume, Instance::localToWorld(), getSelectable().isSelected(), Instance::childBounds() ); m_curveNURBS.renderComponentsSelected( renderer, volume, localToWorld() ); m_curveCatmullRom.renderComponentsSelected( renderer, volume, localToWorld() ); diff --git a/plugins/entity/eclassmodel.cpp b/plugins/entity/eclassmodel.cpp index d20538cb..768014a0 100644 --- a/plugins/entity/eclassmodel.cpp +++ b/plugins/entity/eclassmodel.cpp @@ -253,12 +253,12 @@ void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& l renderer.PopState(); } renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly ); + if ( g_showNames ) { + m_renderName.render( renderer, volume, localToWorld, selected ); + } } void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const { renderSolid( renderer, volume, localToWorld, selected ); - if ( g_showNames ) { - renderer.addRenderable( m_renderName, localToWorld ); - } } void translate( const Vector3& translation ){ diff --git a/plugins/entity/entity.cpp b/plugins/entity/entity.cpp index 7d468088..47e5c015 100644 --- a/plugins/entity/entity.cpp +++ b/plugins/entity/entity.cpp @@ -44,6 +44,8 @@ #include "generic.h" #include "doom3group.h" +#include "namedentity.h" + EGameType g_gameType; @@ -391,6 +393,7 @@ void Entity_Construct( EGameType gameType ){ Doom3Group_construct(); RenderablePivot::StaticShader::instance() = GlobalShaderCache().capture( "$PIVOT" ); + RenderableNamedEntity::StaticShader::instance() = GlobalShaderCache().capture( "$TEXT" ); GlobalShaderCache().attachRenderable( StaticRenderableConnectionLines::instance() ); } @@ -399,6 +402,7 @@ void Entity_Destroy(){ GlobalShaderCache().detachRenderable( StaticRenderableConnectionLines::instance() ); GlobalShaderCache().release( "$PIVOT" ); + GlobalShaderCache().release( "$TEXT" ); Doom3Group_destroy(); MiscModel_destroy(); diff --git a/plugins/entity/generic.cpp b/plugins/entity/generic.cpp index 143e10b0..96ce89fc 100644 --- a/plugins/entity/generic.cpp +++ b/plugins/entity/generic.cpp @@ -215,17 +215,20 @@ void renderArrow( Renderer& renderer, const VolumeTest& volume, const Matrix4& l renderer.addRenderable( m_arrow, localToWorld ); } } -void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { +void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const { renderer.SetState( m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials ); renderer.addRenderable( m_aabb_solid, localToWorld ); renderArrow( renderer, volume, localToWorld ); + if ( g_showNames ) { + m_renderName.render( renderer, volume, localToWorld, selected ); + } } -void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { +void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const { renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly ); renderer.addRenderable( m_aabb_wire, localToWorld ); renderArrow( renderer, volume, localToWorld ); if ( g_showNames ) { - renderer.addRenderable( m_renderName, localToWorld ); + m_renderName.render( renderer, volume, localToWorld, selected ); } } @@ -322,10 +325,10 @@ GenericEntityInstance( const scene::Path& path, scene::Instance* parent, Generic } void renderSolid( Renderer& renderer, const VolumeTest& volume ) const { - m_contained.renderSolid( renderer, volume, Instance::localToWorld() ); + m_contained.renderSolid( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() ); } void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const { - m_contained.renderWireframe( renderer, volume, Instance::localToWorld() ); + m_contained.renderWireframe( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() ); } void testSelect( Selector& selector, SelectionTest& test ){ diff --git a/plugins/entity/group.cpp b/plugins/entity/group.cpp index 65d8cca6..861f57fa 100644 --- a/plugins/entity/group.cpp +++ b/plugins/entity/group.cpp @@ -148,13 +148,8 @@ void detach( scene::Traversable::Observer* observer ){ m_traverse.detach( observer ); } -void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { +void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected, const AABB& childBounds ) const { renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly ); -} - -void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, const AABB& childBounds ) const { - renderSolid( renderer, volume, localToWorld ); - if ( g_showNames ) { // don't draw the name for worldspawn if ( !strcmp( m_entity.getEntityClass().name(), "worldspawn" ) ) { @@ -164,10 +159,14 @@ void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix // place name in the middle of the "children cloud" m_name_origin = childBounds.origin; - renderer.addRenderable( m_renderName, localToWorld ); + m_renderName.render( renderer, volume, localToWorld, selected ); } } +void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected, const AABB& childBounds ) const { + renderSolid( renderer, volume, localToWorld, selected, childBounds ); +} + void updateTransform(){ m_transform.localToParent() = g_matrix4_identity; matrix4_translate_by_vec3( m_transform.localToParent(), m_origin ); @@ -299,10 +298,10 @@ GroupInstance( const scene::Path& path, scene::Instance* parent, Group& group ) m_contained.instanceDetach( Instance::path() ); } void renderSolid( Renderer& renderer, const VolumeTest& volume ) const { - m_contained.renderSolid( renderer, volume, Instance::localToWorld() ); + m_contained.renderSolid( renderer, volume, Instance::localToWorld(), getSelectable().isSelected(), Instance::childBounds() ); } void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const { - m_contained.renderWireframe( renderer, volume, Instance::localToWorld(), Instance::childBounds() ); + m_contained.renderWireframe( renderer, volume, Instance::localToWorld(), getSelectable().isSelected(), Instance::childBounds() ); } STRING_CONSTANT( Name, "GroupInstance" ); diff --git a/plugins/entity/light.cpp b/plugins/entity/light.cpp index cef5459f..86713820 100644 --- a/plugins/entity/light.cpp +++ b/plugins/entity/light.cpp @@ -1408,12 +1408,13 @@ void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& l renderer.addRenderable( m_render_center, localToWorld ); } } + + if ( g_showNames && !string_equal( m_named.name(), "light" ) ) { + m_renderName.render( renderer, volume, localToWorld, selected ); + } } void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const { renderSolid( renderer, volume, localToWorld, selected ); - if ( g_showNames && !string_equal( m_named.name(), "light" ) ) { - renderer.addRenderable( m_renderName, localToWorld ); - } } void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){ diff --git a/plugins/entity/miscmodel.cpp b/plugins/entity/miscmodel.cpp index 758152c4..a573859f 100644 --- a/plugins/entity/miscmodel.cpp +++ b/plugins/entity/miscmodel.cpp @@ -194,14 +194,13 @@ void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& l if ( selected ) { m_renderOrigin.render( renderer, volume, localToWorld ); } - renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly ); + if ( g_showNames && !string_equal( m_named.name(), "misc_model" ) ) { + m_renderName.render( renderer, volume, localToWorld, selected ); + } } void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const { renderSolid( renderer, volume, localToWorld, selected ); - if ( g_showNames && !string_equal( m_named.name(), "misc_model" ) ) { - renderer.addRenderable( m_renderName, localToWorld ); - } } void translate( const Vector3& translation ){ diff --git a/plugins/entity/namedentity.h b/plugins/entity/namedentity.h index e29aa524..80e68f82 100644 --- a/plugins/entity/namedentity.h +++ b/plugins/entity/namedentity.h @@ -66,6 +66,9 @@ const char* name() const { const char* classname() const { return m_entity.getEntityClass().name(); } +const Colour3& color() const { + return m_entity.getEntityClass().color; +} void attach( const NameCallback& callback ){ m_changed.insert( callback ); } @@ -86,6 +89,182 @@ void identifierChanged( const char* value ){ typedef MemberCaller1 IdentifierChangedCaller; }; + +#include "renderable.h" +#include "pivot.h" +#include "math/frustum.h" + +class RenderableNamedEntity : public OpenGLRenderable { + NamedEntity& m_named; + const Vector3& m_position; + mutable GLuint m_tex_normal; + mutable GLuint m_tex_selected; + mutable GLuint* m_tex; + int m_width; + int m_height; + unsigned int m_colour[3]; + mutable float m_screenPos[2]; +public: + typedef Static StaticShader; + static Shader* getShader() { + return StaticShader::instance(); + } + RenderableNamedEntity( NamedEntity& named, const Vector3& position ) + : m_named( named ), m_position( position ), m_tex_normal( 0 ), m_tex_selected( 0 ) { + construct_textures( g_showTargetNames ? m_named.name() : m_named.classname() ); + m_named.attach( IdentifierChangedCaller( *this ) ); + } +private: + void setSelected( bool selected ) const { + m_tex = selected ? &m_tex_selected : &m_tex_normal; + } + void setSelectedColour( bool selected ){ + if( selected ){ + m_colour[0] = 255; + m_colour[1] = 255; + m_colour[2] = 0; + } + else{ + m_colour[0] = static_cast( m_named.color()[0] * 255.f ); + m_colour[1] = static_cast( m_named.color()[1] * 255.f ); + m_colour[2] = static_cast( m_named.color()[2] * 255.f ); + } + } + void construct_texture( const char* name ){ + glGenTextures( 1, m_tex ); + if( *m_tex > 0 ) { + GlobalOpenGL().m_font->renderString( name, *m_tex, m_colour, m_width, m_height ); + } + } + void construct_textures( const char* name ){ + setSelected( false ); + setSelectedColour( false ); + construct_texture( name ); + setSelected( true ); + setSelectedColour( true ); + construct_texture( name ); + } + void delete_textures(){ + glDeleteTextures( 1, &m_tex_normal ); + glDeleteTextures( 1, &m_tex_selected ); + m_tex_normal = 0; + m_tex_selected = 0; + } +public: + void render( RenderStateFlags state ) const { + if( *m_tex > 0 ){ + glBindTexture( GL_TEXTURE_2D, *m_tex ); + + //Here we draw the texturemaped quads. + //The bitmap that we got from FreeType was not + //oriented quite like we would like it to be, + //so we need to link the texture to the quad + //so that the result will be properly aligned. + glBegin( GL_QUADS ); + glTexCoord2i( 0, 1 ); + glVertex2f( m_screenPos[0], m_screenPos[1] ); + glTexCoord2i( 0, 0 ); + glVertex2f( m_screenPos[0], m_screenPos[1] + m_height + .01f ); + glTexCoord2i( 1, 0 ); + glVertex2f( m_screenPos[0] + m_width + .01f, m_screenPos[1] + m_height + .01f ); + glTexCoord2i( 1, 1 ); + glVertex2f( m_screenPos[0] + m_width + .01f, m_screenPos[1] ); + glEnd(); + + glBindTexture( GL_TEXTURE_2D, 0 ); + } + } + void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const{ + if( !selected && volume.fill() ){ +// globalOutputStream() << localToWorld << " localToWorld\n"; +// globalOutputStream() << volume.GetModelview() << " modelview\n"; +// globalOutputStream() << volume.GetProjection() << " Projection\n"; +// globalOutputStream() << volume.GetViewport() << " Viewport\n"; + Matrix4 viewproj = matrix4_multiplied_by_matrix4( volume.GetProjection(), volume.GetModelview() ); + Vector3 viewer = vector4_to_vector3( viewer_from_viewproj( viewproj ) ); + Vector3 pos_in_world = matrix4_transformed_point( localToWorld, m_position ); + if( vector3_length_squared( pos_in_world - viewer ) > 512*512 ){ + return; + } + //globalOutputStream() << viewer[0] << " " << viewer[1] << " " << viewer[2] << " Viewer\n"; + //globalOutputStream() << pos_in_world[0] << " " << pos_in_world[1] << " " << pos_in_world[2] << " position\n"; + //globalOutputStream() << m_position[0] << " " << m_position[1] << " " << m_position[2] << " position\n"; + } + + setSelected( selected ); + + Vector4 position; + position[0] = m_position[0]; + position[1] = m_position[1]; + position[2] = m_position[2]; + position[3] = 1.f; + +#if 0 +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " position\n"; + matrix4_transform_vector4( localToWorld, position ); +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " localToWorld\n"; + matrix4_transform_vector4( volume.GetModelview(), position ); +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " Modelview\n"; + matrix4_transform_vector4( volume.GetProjection(), position ); +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " Projection\n"; + position[0] /= position[3]; + position[1] /= position[3]; + position[2] /= position[3]; +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " Projection division\n"; + matrix4_transform_vector4( volume.GetViewport(), position ); +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " Viewport\n"; + +#else + Matrix4 object2screen = volume.GetProjection(); + matrix4_multiply_by_matrix4( object2screen, volume.GetModelview() ); + matrix4_multiply_by_matrix4( object2screen, localToWorld ); +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " position\n"; + matrix4_transform_vector4( object2screen, position ); +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " Projection\n"; + position[0] /= position[3]; + position[1] /= position[3]; + position[2] /= position[3]; +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " Projection division\n"; + matrix4_transform_vector4( volume.GetViewport(), position ); +// globalOutputStream() << position[0] << " " << position[1] << " " << position[2] << " " << position[3] << " Viewport\n"; +#endif + + //globalOutputStream() << volume.GetViewport()[0] << " " << volume.GetViewport()[5] << " Viewport size\n"; + + m_screenPos[0] = position[0]; + m_screenPos[1] = position[1]; + //globalOutputStream() << m_screenPos[0] << " " << m_screenPos[1] << "\n"; + + renderer.PushState(); + +// Pivot2World_viewplaneSpace( m_localToWorld, localToWorld, volume.GetModelview(), volume.GetProjection(), volume.GetViewport() ); + + renderer.Highlight( Renderer::ePrimitive, false ); + renderer.Highlight( Renderer::eFace, false ); + renderer.SetState( getShader(), Renderer::eWireframeOnly ); + renderer.SetState( getShader(), Renderer::eFullMaterials ); + +// m_localToWorld = volume.GetViewport(); +// matrix4_full_invert( m_localToWorld ); + + renderer.addRenderable( *this, g_matrix4_identity ); + + renderer.PopState(); + } + ~RenderableNamedEntity(){ + m_named.detach( IdentifierChangedCaller( *this ) ); + delete_textures(); + } + void identifierChanged( const char* value ){ + delete_textures(); + construct_textures( g_showTargetNames ? value : m_named.classname() ); + } + typedef MemberCaller1 IdentifierChangedCaller; +}; + + + +/* class RenderableNamedEntity : public OpenGLRenderable { const NamedEntity& m_named; @@ -99,7 +278,7 @@ void render( RenderStateFlags state ) const { GlobalOpenGL().drawString( g_showTargetNames ? m_named.name() : m_named.classname() ); } }; - +*/ #endif diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 1746dd77..8fbc8a65 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -1618,7 +1618,7 @@ void CamWnd::Cam_Draw(){ } - unsigned int globalstate = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_ALPHATEST | RENDER_BLEND | RENDER_CULLFACE | RENDER_COLOURARRAY | RENDER_OFFSETLINE | RENDER_POLYGONSMOOTH | RENDER_LINESMOOTH | RENDER_FOG | RENDER_COLOURCHANGE; + unsigned int globalstate = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_ALPHATEST | RENDER_BLEND | RENDER_CULLFACE | RENDER_COLOURARRAY | RENDER_OFFSETLINE | RENDER_POLYGONSMOOTH | RENDER_LINESMOOTH | RENDER_FOG | RENDER_COLOURCHANGE | RENDER_TEXT; switch ( m_Camera.draw_mode ) { case cd_wire: diff --git a/radiant/renderstate.cpp b/radiant/renderstate.cpp index 924688a6..7759cea6 100644 --- a/radiant/renderstate.cpp +++ b/radiant/renderstate.cpp @@ -1138,6 +1138,7 @@ inline void setFogState( const OpenGLFogState& state ){ } #define DEBUG_SHADERS 0 +void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned int globalstate ); class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver { @@ -1312,6 +1313,10 @@ void render( RenderStateFlags globalstate, const Matrix4& modelview, const Matri ( *i ).second->render( current, globalstate, viewer ); } debug_string( "end rendering" ); + + OpenGLState reset = current; /* popmatrix and reset stuff after RENDER_TEXT */ + reset.m_state = current.m_state & ~RENDER_TEXT; + OpenGLState_apply( reset, current, globalstate ); } void realise(){ if ( --m_unrealised == 0 ) { @@ -1620,6 +1625,26 @@ void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned GlobalOpenGL_debugAssertNoErrors(); + if ( delta & ~state & RENDER_TEXT ) { /* disabling in the beginning, so wont override other states */ + if ( GlobalOpenGL().GL_1_3() ) { ///~RENDER_TEXTURE + glActiveTexture( GL_TEXTURE0 ); + glClientActiveTexture( GL_TEXTURE0 ); + } + glDisable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, 0 ); + + glDisable( GL_BLEND ); ///~RENDER_BLEND + + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); ///~RENDER_FILL + + glMatrixMode( GL_PROJECTION ); + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + + GlobalOpenGL_debugAssertNoErrors(); + } + GLProgram* program = ( state & RENDER_PROGRAM ) != 0 ? self.m_program : 0; if ( program != current.m_program ) { @@ -1709,6 +1734,7 @@ void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned glActiveTexture( GL_TEXTURE0 ); } glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); + //glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //uses actual alpha channel, = invis, if qer_trans + empty alpha channel GlobalOpenGL_debugAssertNoErrors(); } else if ( delta & ~state & RENDER_BLEND ) { @@ -1829,6 +1855,34 @@ void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned current.m_alpharef = self.m_alpharef; } + if ( delta & state & RENDER_TEXT ) { /* enabling in the end, so other states can't affect */ + if ( GlobalOpenGL().GL_1_3() ) { ///RENDER_TEXTURE + glActiveTexture( GL_TEXTURE0 ); + glClientActiveTexture( GL_TEXTURE0 ); + } + glEnable( GL_TEXTURE_2D ); + + glEnable( GL_BLEND ); ///RENDER_BLEND + //glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //uses actual alpha channel, = invis, if qer_trans + empty alpha channel + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); ///RENDER_FILL + + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glLoadIdentity(); + GLint viewprt[4]; + glGetIntegerv( GL_VIEWPORT, viewprt ); + //globalOutputStream() << viewprt[2] << " " << viewprt[3] << "\n"; + glOrtho( 0, viewprt[2], 0, viewprt[3], -100, 100 ); + glTranslated( double( viewprt[2] ) / 2.0, double( viewprt[3] ) / 2.0, 0 ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + + GlobalOpenGL_debugAssertNoErrors(); + } + { GLint texture0 = 0; GLint texture1 = 0; @@ -2084,9 +2138,13 @@ void OpenGLShader::construct( const char* name ){ case '{': //add sscanf( name, "{%g %g %g}", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] ); state.m_colour[3] = 1.0f; - state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE /*| RENDER_DEPTHWRITE*/ | RENDER_LIGHTING; + state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE /*| RENDER_DEPTHWRITE */| RENDER_LIGHTING; state.m_blend_src = GL_ONE; state.m_blend_dst = GL_ONE; +// state.m_blend_src = GL_DST_COLOR; +// state.m_blend_dst = GL_SRC_COLOR; +// state.m_blend_src = GL_DST_COLOR; +// state.m_blend_dst = GL_ONE; state.m_sort = OpenGLState::eSortTranslucent; break; @@ -2122,7 +2180,18 @@ void OpenGLShader::construct( const char* name ){ break; } } - if ( string_equal( name + 1, "POINT" ) ) { + if ( string_equal( name + 1, "TEXT" ) ) { + state.m_colour[0] = 1.f; + state.m_colour[1] = 1.f; + state.m_colour[2] = 1.f; + state.m_colour[3] = 1.f; + state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE /*| RENDER_DEPTHTEST | RENDER_DEPTHWRITE*/ /*| RENDER_FILL | RENDER_TEXTURE | RENDER_BLEND */| RENDER_TEXT; + state.m_sort = OpenGLState::eSortText; + state.m_blend_src = GL_SRC_ALPHA; + state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA; + //state.m_depthfunc = GL_LEQUAL; + } + else if ( string_equal( name + 1, "POINT" ) ) { state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE; state.m_sort = OpenGLState::eSortControlFirst; state.m_pointsize = 4; diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp index c1a0b22d..86064b3a 100644 --- a/radiant/xywindow.cpp +++ b/radiant/xywindow.cpp @@ -2636,7 +2636,7 @@ void XYWnd::XY_Draw(){ glLoadMatrixf( reinterpret_cast( &m_modelview ) ); - unsigned int globalstate = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_POLYGONSMOOTH | RENDER_LINESMOOTH; + unsigned int globalstate = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_POLYGONSMOOTH | RENDER_LINESMOOTH | RENDER_TEXT; if ( !g_xywindow_globals.m_bNoStipple ) { globalstate |= RENDER_LINESTIPPLE; }