/* Copyright (C) 2003 Reed Mideke. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // // bkgrnd2d Plugin // // Code by reyalP aka Reed Mideke // // Based on various other plugins // #include "bkgrnd2d.h" CBackgroundRender render; CBackgroundImage backgroundXY( XY ),backgroundXZ( XZ ),backgroundYZ( YZ ); CBackgroundRender::CBackgroundRender(){ refCount = 1; } CBackgroundRender::~CBackgroundRender(){ } void CBackgroundRender::Register(){ g_QglTable.m_pfnHookGL2DWindow( this ); } void CBackgroundRender::Draw2D( VIEWTYPE vt ){ switch ( vt ) { case XY: backgroundXY.Render(); break; case XZ: backgroundXZ.Render(); break; case YZ: backgroundYZ.Render(); break; } } CBackgroundImage::CBackgroundImage( VIEWTYPE vt ){ m_tex = NULL; m_alpha = 0.5; // TODO, sensible defaults ? Or not show until we have extents ? m_xmin = m_ymin = 0.0f; m_xmax = m_ymax = 0.0f; m_bActive = false; m_vt = vt; switch ( m_vt ) { case XY: m_ix = 0; m_iy = 1; break; case XZ: m_ix = 0; m_iy = 2; break; case YZ: m_ix = 1; m_iy = 2; break; } } /* * should cleanup, but I don't think we can be sure it happens before our * interfaces are gone CBackgroundImage::~CBackgroundImage() { } */ void CBackgroundImage::Cleanup(){ if ( m_tex ) { g_QglTable.m_pfn_qglDeleteTextures( 1,&m_tex->texture_number ); g_free( m_tex ); m_tex = NULL; } } void CBackgroundImage::Render(){ if ( !m_bActive || !Valid() ) { return; } g_QglTable.m_pfn_qglPushAttrib( GL_ALL_ATTRIB_BITS ); g_QglTable.m_pfn_qglEnable( GL_TEXTURE_2D ); g_QglTable.m_pfn_qglEnable( GL_BLEND ); g_QglTable.m_pfn_qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); g_QglTable.m_pfn_qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); g_QglTable.m_pfn_qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); g_QglTable.m_pfn_qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); g_QglTable.m_pfn_qglPolygonMode( GL_FRONT,GL_FILL ); // TODO, just so we can tell if we end up going the wrong way // g_QglTable.m_pfn_qglPolygonMode(GL_BACK,GL_LINE); // TODO any other state we should not assume ? g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, m_tex->texture_number ); g_QglTable.m_pfn_qglBegin( GL_QUADS ); g_QglTable.m_pfn_qglColor4f( 1.0,1.0,1.0,m_alpha ); g_QglTable.m_pfn_qglTexCoord2f( 0.0,1.0 ); g_QglTable.m_pfn_qglVertex2f( m_xmin,m_ymin ); g_QglTable.m_pfn_qglTexCoord2f( 1.0,1.0 ); g_QglTable.m_pfn_qglVertex2f( m_xmax,m_ymin ); g_QglTable.m_pfn_qglTexCoord2f( 1.0,0.0 ); g_QglTable.m_pfn_qglVertex2f( m_xmax,m_ymax ); g_QglTable.m_pfn_qglTexCoord2f( 0.0,0.0 ); g_QglTable.m_pfn_qglVertex2f( m_xmin,m_ymax ); g_QglTable.m_pfn_qglEnd(); g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, 0 ); g_QglTable.m_pfn_qglPopAttrib(); } bool CBackgroundImage::Load( const char *filename ){ qtexture_t *newtex; unsigned char *image = NULL; // gets allocated with what ? g_malloc int width = 0, height = 0; g_FuncTable.m_pfnLoadImage( filename,&image,&width,&height ); if ( !image ) { Syn_Printf( MSG_WARN "load %s failed\n",filename ); return false; } // just in case we want to build for an old version // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900 #ifdef BKGRND2D_JPG_WORKAROUND if ( strlen( filename ) > 4 && !strcmp( ".jpg",filename + strlen( filename ) - 4 ) ) { Syn_Printf( MSG_PREFIX ".jpg workaround, clearing alpha channel\n" ); int size = width * height * 4; int i; for ( i = 3; i < size; i += 4 ) { image[i] = 255; } } #endif //TODO bug for stored texture size //TODO whose gl context are we in, anyway ? newtex = g_FuncTable.m_pfnLoadTextureRGBA( image,width,height ); g_free( image ); if ( !newtex ) { Syn_Printf( MSG_WARN "image to texture failed\n" ); return false; } Cleanup(); m_tex = newtex; g_FuncTable.m_pfnSysUpdateWindows( W_XY ); return true; } bool CBackgroundImage::SetExtentsMM(){ entity_s *worldentity; const char *val; int xmin = 0, ymin = 0, xmax = 0, ymax = 0; worldentity = (entity_s *)g_FuncTable.m_pfnGetEntityHandle( 0 ); if ( !worldentity ) { Syn_Printf( MSG_WARN "SetExtentsMM worldspawn not found\n" ); return false; } //TODO val is not NULL even if key does not exist val = g_EntityTable.m_pfnValueForKey( worldentity,"mapcoordsmins" ); if ( !val || !val[0] ) { Syn_Printf( MSG_WARN "SetExtentsMM mapcoordsmins not found\n" ); return false; } // we could be more robust // note contortions due to splashs strange idea of min and max if ( sscanf( val, "%d %d",&xmin,&ymax ) != 2 ) { Syn_Printf( MSG_WARN "SetExtentsMM mapcoordsmins malformed\n" ); return false; } val = g_EntityTable.m_pfnValueForKey( worldentity,"mapcoordsmaxs" ); if ( !val || !val[0] ) { Syn_Printf( MSG_WARN "SetExtentsMM mapcoordsmaxs not found\n" ); return false; } if ( sscanf( val, "%d %d",&xmax,&ymin ) != 2 ) { Syn_Printf( MSG_WARN "SetExtentsMM mapcoordsmaxs malformed\n" ); return false; } //might do sanity check before we commit m_xmin = (float)xmin; m_ymin = (float)ymin; m_xmax = (float)xmax; m_ymax = (float)ymax; g_FuncTable.m_pfnSysUpdateWindows( W_XY ); return true; } // TODO, this should just be exported from core // ripped directly from radiant/select.cpp:Select_GetBounds // static bool get_selection_bounds( vec3_t mins, vec3_t maxs ){ brush_t *b; int i; brush_t *selected_brushes = g_DataTable.m_pfnSelectedBrushes(); //TODO should never happen if ( !selected_brushes ) { Sys_Printf( MSG_PREFIX "selected_brushes = NULL\n" ); return false; } // this should mean no selection if ( selected_brushes == selected_brushes->next ) { Sys_Printf( MSG_PREFIX "nothing selected\n" ); return false; } for ( i = 0 ; i < 3 ; i++ ) { mins[i] = 99999; maxs[i] = -99999; } for ( b = selected_brushes->next ; b != selected_brushes ; b = b->next ) { if ( b->owner->eclass->fixedsize ) { for ( i = 0 ; i < 3 ; i++ ) { if ( b->owner->origin[i] < mins[i] ) { mins[i] = b->owner->origin[i]; } if ( b->owner->origin[i] > maxs[i] ) { maxs[i] = b->owner->origin[i]; } } } else { for ( i = 0 ; i < 3 ; i++ ) { if ( b->mins[i] < mins[i] ) { mins[i] = b->mins[i]; } if ( b->maxs[i] > maxs[i] ) { maxs[i] = b->maxs[i]; } } } } return true; } bool CBackgroundImage::SetExtentsSel(){ vec3_t mins,maxs; if ( !get_selection_bounds( mins,maxs ) ) { return false; } if ( ( (int)mins[m_ix] == (int)maxs[m_ix] ) || ( (int)mins[m_iy] == (int)maxs[m_iy] ) ) { Syn_Printf( MSG_PREFIX "tiny selection\n" ); return false; } m_xmin = mins[m_ix]; m_ymin = mins[m_iy]; m_xmax = maxs[m_ix]; m_ymax = maxs[m_iy]; g_FuncTable.m_pfnSysUpdateWindows( W_XY ); return true; }