You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
720 lines
18 KiB
720 lines
18 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Supports sprite preview and sprite icons for entities. |
|
// |
|
//===========================================================================// |
|
|
|
#include "stdafx.h" |
|
#include "hammer_mathlib.h" |
|
#include "Box3D.h" |
|
#include "BSPFile.h" |
|
#include "const.h" |
|
#include "MapDefs.h" // dvs: For COORD_NOTINIT |
|
#include "MapDoc.h" |
|
#include "MapEntity.h" |
|
#include "MapSprite.h" |
|
#include "Render2D.h" |
|
#include "Render3D.h" |
|
#include "hammer.h" |
|
#include "Texture.h" |
|
#include "TextureSystem.h" |
|
#include "materialsystem/imesh.h" |
|
#include "Material.h" |
|
#include "Options.h" |
|
#include "camera.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
|
|
IMPLEMENT_MAPCLASS(CMapSprite) |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Factory function. Used for creating a CMapSprite from a set |
|
// of string parameters from the FGD file. |
|
// Input : *pInfo - Pointer to helper info class which gives us information |
|
// about how to create the class. |
|
// Output : Returns a pointer to the class, NULL if an error occurs. |
|
//----------------------------------------------------------------------------- |
|
CMapClass *CMapSprite::CreateMapSprite(CHelperInfo *pHelperInfo, CMapEntity *pParent) |
|
{ |
|
const char *pszSprite = pHelperInfo->GetParameter(0); |
|
|
|
// |
|
// If we weren't passed a sprite name as an argument, get it from our parent |
|
// entity's "model" key. |
|
// |
|
if (pszSprite == NULL) |
|
{ |
|
pszSprite = pParent->GetKeyValue("model"); |
|
} |
|
|
|
// HACK? |
|
// When loading sprites, it can be the case that 'materials' is prepended |
|
// This is because we have to look in the materials directory for sprites |
|
// Remove the materials prefix... |
|
if (pszSprite) |
|
{ |
|
if (!strnicmp(pszSprite, "materials", 9) && ((pszSprite[9] == '/') || (pszSprite[9] == '\\')) ) |
|
{ |
|
pszSprite += 10; |
|
} |
|
} |
|
|
|
// |
|
// If we have a sprite name, create a sprite object. |
|
// |
|
CMapSprite *pSprite = NULL; |
|
|
|
if (pszSprite != NULL) |
|
{ |
|
pSprite = CreateMapSprite(pszSprite); |
|
if (pSprite != NULL) |
|
{ |
|
// |
|
// Icons are alpha tested. |
|
// |
|
if (!stricmp(pHelperInfo->GetName(), "iconsprite")) |
|
{ |
|
pSprite->SetRenderMode( kRenderTransAlpha ); |
|
pSprite->m_bIsIcon = true; |
|
} |
|
else |
|
{ |
|
// FIXME: Gotta do this a little better |
|
// This initializes the render mode in the sprite |
|
pSprite->SetRenderMode( pSprite->m_eRenderMode ); |
|
} |
|
} |
|
} |
|
|
|
return(pSprite); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Factory. Use this to construct CMapSprite objects, since the |
|
// constructor is protected. |
|
//----------------------------------------------------------------------------- |
|
CMapSprite *CMapSprite::CreateMapSprite(const char *pszSpritePath) |
|
{ |
|
CMapSprite *pSprite = new CMapSprite; |
|
|
|
if (pSprite != NULL) |
|
{ |
|
char szPath[MAX_PATH]; |
|
|
|
pSprite->Initialize(); |
|
|
|
// HACK: Remove the extension, this is for backward compatability |
|
// It's trying to load a .spr, but we're giving it a .vmt. |
|
strcpy( szPath, pszSpritePath ); |
|
char* pDot = strrchr( szPath, '.' ); |
|
if (pDot) |
|
*pDot = 0; |
|
|
|
pSprite->m_pSpriteInfo = CSpriteCache::CreateSprite(szPath); |
|
if (pSprite->m_pSpriteInfo) |
|
{ |
|
pSprite->CalcBounds(); |
|
} |
|
} |
|
|
|
return(pSprite); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor. |
|
//----------------------------------------------------------------------------- |
|
CMapSprite::CMapSprite(void) |
|
{ |
|
Initialize(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor. |
|
//----------------------------------------------------------------------------- |
|
CMapSprite::~CMapSprite(void) |
|
{ |
|
CSpriteCache::Release(m_pSpriteInfo); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets the render mode |
|
//----------------------------------------------------------------------------- |
|
|
|
void CMapSprite::SetRenderMode( int eRenderMode ) |
|
{ |
|
m_eRenderMode = eRenderMode; |
|
if (m_pSpriteInfo) |
|
m_pSpriteInfo->SetRenderMode( m_eRenderMode ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Calculates our bounding box based on the sprite dimensions. |
|
// Input : bFullUpdate - Whether we should recalculate our childrens' bounds. |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::CalcBounds(BOOL bFullUpdate) |
|
{ |
|
CMapClass::CalcBounds(bFullUpdate); |
|
|
|
float fRadius = 8; |
|
|
|
if (m_pSpriteInfo) |
|
{ |
|
fRadius = max(m_pSpriteInfo->GetWidth(), m_pSpriteInfo->GetHeight()) * m_fScale / 2.0; |
|
if (fRadius == 0) |
|
{ |
|
fRadius = 8; |
|
} |
|
} |
|
|
|
// |
|
// Build our bounds for frustum culling in the 3D view. |
|
// |
|
Vector Mins = m_Origin - Vector(fRadius, fRadius, fRadius); |
|
Vector Maxs = m_Origin + Vector(fRadius, fRadius, fRadius); |
|
m_CullBox.UpdateBounds(Mins, Maxs); |
|
|
|
m_BoundingBox = m_CullBox; |
|
|
|
// |
|
// Build our bounds for 2D rendering. We keep sprites small in the 2D views no |
|
// matter how large they are scaled. |
|
// |
|
if (!m_bIsIcon) |
|
{ |
|
fRadius = 2; |
|
} |
|
|
|
Mins = m_Origin - Vector(fRadius, fRadius, fRadius); |
|
Maxs = m_Origin + Vector(fRadius, fRadius, fRadius); |
|
m_Render2DBox.UpdateBounds(Mins, Maxs); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns a copy of this object. |
|
// Output : Pointer to the new object. |
|
//----------------------------------------------------------------------------- |
|
CMapClass *CMapSprite::Copy(bool bUpdateDependencies) |
|
{ |
|
CMapSprite *pCopy = new CMapSprite; |
|
|
|
if (pCopy != NULL) |
|
{ |
|
pCopy->CopyFrom(this, bUpdateDependencies); |
|
} |
|
|
|
return(pCopy); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Turns this into a duplicate of the given object. |
|
// Input : pObject - Pointer to the object to copy from. |
|
// Output : Returns a pointer to this object. |
|
//----------------------------------------------------------------------------- |
|
CMapClass *CMapSprite::CopyFrom(CMapClass *pObject, bool bUpdateDependencies) |
|
{ |
|
CMapSprite *pFrom = dynamic_cast<CMapSprite *>(pObject); |
|
Assert(pObject != NULL); |
|
|
|
if (pObject != NULL) |
|
{ |
|
CMapClass::CopyFrom(pObject, bUpdateDependencies); |
|
|
|
m_Angles = pFrom->m_Angles; |
|
|
|
m_pSpriteInfo = pFrom->m_pSpriteInfo; |
|
CSpriteCache::AddRef(pFrom->m_pSpriteInfo); |
|
|
|
m_nCurrentFrame = pFrom->m_nCurrentFrame; |
|
m_fSecondsPerFrame = pFrom->m_fSecondsPerFrame; |
|
m_fElapsedTimeThisFrame = pFrom->m_fElapsedTimeThisFrame; |
|
m_fScale = pFrom->m_fScale; |
|
SetRenderMode( pFrom->m_eRenderMode ); |
|
m_RenderColor = pFrom->m_RenderColor; |
|
m_bIsIcon = pFrom->m_bIsIcon; |
|
} |
|
|
|
return(this); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : bEnable - |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::EnableAnimation(BOOL bEnable) |
|
{ |
|
//m_bAnimateModels = bEnable; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : Angles - |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::GetAngles(QAngle &Angles) |
|
{ |
|
Angles = m_Angles; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::Initialize(void) |
|
{ |
|
m_Angles.Init(); |
|
|
|
m_eRenderMode = kRenderNormal; |
|
|
|
m_RenderColor.r = 255; |
|
m_RenderColor.g = 255; |
|
m_RenderColor.b = 255; |
|
|
|
m_fSecondsPerFrame = 1; |
|
m_fElapsedTimeThisFrame = 0; |
|
m_nCurrentFrame = 0; |
|
|
|
m_fScale = 0.25; |
|
|
|
m_bIsIcon = false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Updates time and returns the next frame |
|
//----------------------------------------------------------------------------- |
|
int CMapSprite::GetNextSpriteFrame( CRender3D* pRender ) |
|
{ |
|
// |
|
// Determine whether we need to advance to the next frame based on our |
|
// sprite framerate and the elapsed time. |
|
// |
|
int nNumFrames = m_pSpriteInfo->GetFrameCount(); |
|
if (nNumFrames > 1) |
|
{ |
|
float fElapsedTime = pRender->GetElapsedTime(); |
|
m_fElapsedTimeThisFrame += fElapsedTime; |
|
|
|
while (m_fElapsedTimeThisFrame > m_fSecondsPerFrame) |
|
{ |
|
m_nCurrentFrame++; |
|
m_fElapsedTimeThisFrame -= m_fSecondsPerFrame; |
|
} |
|
|
|
m_nCurrentFrame %= nNumFrames; |
|
} |
|
|
|
return m_nCurrentFrame; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : pRender - |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::Render3D(CRender3D *pRender) |
|
{ |
|
int nPasses; |
|
if ((GetSelectionState() != SELECT_NONE) && (!m_bIsIcon)) |
|
{ |
|
if (pRender->NeedsOverlay()) |
|
nPasses = 3; |
|
else |
|
nPasses = 2; |
|
} |
|
else |
|
{ |
|
nPasses = 1; |
|
} |
|
|
|
// |
|
// If we have a sprite, render it. |
|
// |
|
if (m_pSpriteInfo) |
|
{ |
|
// |
|
// Only sprite icons can be clicked on, sprite preview objects cannot. |
|
// |
|
if (m_bIsIcon) |
|
{ |
|
pRender->BeginRenderHitTarget(this); |
|
} |
|
|
|
m_pSpriteInfo->SetOrigin(m_Origin); |
|
m_pSpriteInfo->SetAngles(m_Angles); |
|
|
|
m_pSpriteInfo->Bind(pRender, GetNextSpriteFrame(pRender)); |
|
for (int nPass = 0; nPass < nPasses; nPass++) |
|
{ |
|
if (nPass == 0) |
|
{ |
|
// First pass uses the default rendering mode. |
|
// unless that mode is texture |
|
if (pRender->GetCurrentRenderMode() == RENDER_MODE_LIGHTMAP_GRID) |
|
pRender->PushRenderMode( RENDER_MODE_TEXTURED); |
|
else |
|
pRender->PushRenderMode( RENDER_MODE_CURRENT ); |
|
} |
|
else |
|
{ |
|
if (nPass == nPasses - 1) |
|
{ |
|
// last pass uses wireframe rendering mode. |
|
pRender->PushRenderMode( RENDER_MODE_WIREFRAME); |
|
} |
|
else |
|
{ |
|
pRender->PushRenderMode( RENDER_MODE_SELECTION_OVERLAY ); |
|
} |
|
} |
|
|
|
|
|
m_pSpriteInfo->SetScale(m_fScale > 0 ? m_fScale : 1.0 ); |
|
|
|
float fBlend; |
|
// dvs: lots of things contribute to blend factor. See r_blend in engine. |
|
//if (m_eRenderMode == kRenderNormal) |
|
{ |
|
fBlend = 1.0; |
|
} |
|
|
|
unsigned char color[4]; |
|
SpriteColor( color, m_eRenderMode, m_RenderColor, fBlend * 255); |
|
|
|
// |
|
// If selected, render a yellow wireframe box. |
|
// |
|
if (GetSelectionState() != SELECT_NONE) |
|
{ |
|
if (m_bIsIcon) |
|
{ |
|
pRender->RenderWireframeBox(m_Render2DBox.bmins, m_Render2DBox.bmaxs, 255, 255, 0); |
|
} |
|
else |
|
{ |
|
color[0] = 255; |
|
color[1] = color[2] = 0; |
|
} |
|
|
|
// |
|
// If selected, render the sprite with a yellow wireframe around it. |
|
// |
|
if ( nPass > 0 ) |
|
{ |
|
color[0] = color[1] = 255; |
|
color[2] = 0; |
|
} |
|
} |
|
|
|
MaterialPrimitiveType_t type = (nPass > 0) ? MATERIAL_LINE_LOOP : MATERIAL_POLYGON; |
|
m_pSpriteInfo->SetMaterialPrimitiveType( type ); |
|
|
|
m_pSpriteInfo->DrawSprite3D( pRender, color ); |
|
|
|
pRender->PopRenderMode(); |
|
} |
|
|
|
// |
|
// Only sprite icons can be clicked on, sprite preview objects cannot. |
|
// |
|
if (m_bIsIcon) |
|
{ |
|
pRender->EndRenderHitTarget(); |
|
} |
|
} |
|
// |
|
// Else no sprite, render as a bounding box. |
|
// |
|
else if (m_bIsIcon) |
|
{ |
|
pRender->BeginRenderHitTarget(this); |
|
pRender->RenderBox(m_Render2DBox.bmins, m_Render2DBox.bmaxs, r, g, b, GetSelectionState()); |
|
pRender->EndRenderHitTarget(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &File - |
|
// bRMF - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CMapSprite::SerializeRMF(std::fstream &File, BOOL bRMF) |
|
{ |
|
return(0); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &File - |
|
// bRMF - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CMapSprite::SerializeMAP(std::fstream &File, BOOL bRMF) |
|
{ |
|
return(0); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : pTransBox - |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::DoTransform(const VMatrix &matrix) |
|
{ |
|
BaseClass::DoTransform(matrix); |
|
|
|
matrix3x4_t fCurrentMatrix,fMatrixNew; |
|
AngleMatrix(m_Angles, fCurrentMatrix); |
|
ConcatTransforms(matrix.As3x4(), fCurrentMatrix, fMatrixNew); |
|
MatrixAngles(fMatrixNew, m_Angles); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : pColor - |
|
// pEntity - |
|
// alpha - |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::SpriteColor(unsigned char *pColor, int eRenderMode, colorVec RenderColor, int alpha) |
|
{ |
|
int a; |
|
|
|
if ((eRenderMode == kRenderTransAdd) || (eRenderMode == kRenderGlow) || (eRenderMode == kRenderWorldGlow)) |
|
{ |
|
a = alpha; |
|
} |
|
else |
|
{ |
|
a = 256; |
|
} |
|
|
|
if ((RenderColor.r == 0) && (RenderColor.g == 0) && (RenderColor.b == 0)) |
|
{ |
|
pColor[0] = pColor[1] = pColor[2] = (255 * a) >> 8; |
|
} |
|
else |
|
{ |
|
pColor[0] = ((int)RenderColor.r * a)>>8; |
|
pColor[1] = ((int)RenderColor.g * a)>>8; |
|
pColor[2] = ((int)RenderColor.b * a)>>8; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Notifies that this object's parent entity has had a key value change. |
|
// Input : szKey - The key that changed. |
|
// szValue - The new value of the key. |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::OnParentKeyChanged(const char* szKey, const char* szValue) |
|
{ |
|
if (!stricmp(szKey, "framerate")) |
|
{ |
|
float fFramesPerSecond = atof(szValue); |
|
if (fabs(fFramesPerSecond) > 0.001) |
|
{ |
|
m_fSecondsPerFrame = 1 / fFramesPerSecond; |
|
} |
|
} |
|
else if (!stricmp(szKey, "scale")) |
|
{ |
|
m_fScale = atof(szValue); |
|
if (m_fScale == 0) |
|
{ |
|
m_fScale = 1; |
|
} |
|
m_pSpriteInfo->SetScale(m_fScale); |
|
|
|
PostUpdate(Notify_Changed); |
|
} |
|
else if (!stricmp(szKey, "rendermode")) |
|
{ |
|
switch (atoi(szValue)) |
|
{ |
|
case 0: // "Normal" |
|
{ |
|
SetRenderMode( kRenderNormal ); |
|
break; |
|
} |
|
|
|
case 1: // "Color" |
|
{ |
|
SetRenderMode( kRenderTransColor ); |
|
break; |
|
} |
|
|
|
case 2: // "Texture" |
|
{ |
|
SetRenderMode( kRenderNormal ); |
|
break; |
|
} |
|
|
|
case 3: // "Glow" |
|
{ |
|
SetRenderMode( kRenderGlow ); |
|
break; |
|
} |
|
|
|
case 4: // "Solid" |
|
{ |
|
SetRenderMode( kRenderNormal ); |
|
break; |
|
} |
|
|
|
case 5: // "Additive" |
|
{ |
|
SetRenderMode( kRenderTransAdd ); |
|
break; |
|
} |
|
|
|
case 7: // "Additive Fractional Frame" |
|
{ |
|
SetRenderMode( kRenderTransAddFrameBlend ); |
|
break; |
|
} |
|
|
|
case 9: // "World Space Glow" |
|
{ |
|
SetRenderMode( kRenderWorldGlow ); |
|
break; |
|
} |
|
} |
|
} |
|
// |
|
// If we are the child of a light entity and its color is changing, change our render color. |
|
// |
|
else if (!stricmp(szKey, "_light")) |
|
{ |
|
sscanf(szValue, "%d %d %d", &m_RenderColor.r, &m_RenderColor.g, &m_RenderColor.b); |
|
} |
|
else if (!stricmp(szKey, "angles")) |
|
{ |
|
sscanf(szValue, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]); |
|
PostUpdate(Notify_Changed); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CMapSprite::ShouldRenderLast(void) |
|
{ |
|
return(true); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::Render2D(CRender2D *pRender) |
|
{ |
|
Vector vecMins; |
|
Vector vecMaxs; |
|
GetRender2DBox(vecMins, vecMaxs); |
|
|
|
Vector2D pt,pt2; |
|
pRender->TransformPoint(pt, vecMins); |
|
pRender->TransformPoint(pt2, vecMaxs); |
|
|
|
if ( !IsSelected() ) |
|
{ |
|
pRender->SetDrawColor( r, g, b ); |
|
pRender->SetHandleColor( r, g, b ); |
|
} |
|
else |
|
{ |
|
pRender->SetDrawColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) ); |
|
pRender->SetHandleColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) ); |
|
} |
|
|
|
// Draw the bounding box. |
|
|
|
pRender->DrawBox( vecMins, vecMaxs ); |
|
|
|
// |
|
// Draw center handle. |
|
// |
|
|
|
if ( pRender->IsActiveView() ) |
|
{ |
|
int sizex = abs(pt.x - pt2.x)+1; |
|
int sizey = abs(pt.y - pt2.y)+1; |
|
|
|
// dont draw handle if object is too small |
|
if ( sizex > 6 && sizey > 6 ) |
|
{ |
|
pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_CROSS ); |
|
pRender->DrawHandle( (vecMins+vecMaxs)/2 ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Called by entity code to render sprites |
|
//----------------------------------------------------------------------------- |
|
void CMapSprite::RenderLogicalAt(CRender2D *pRender, const Vector2D &vecMins, const Vector2D &vecMaxs ) |
|
{ |
|
// If we have a sprite, render it. |
|
if (!m_pSpriteInfo) |
|
return; |
|
|
|
m_pSpriteInfo->Bind( pRender, 0 ); |
|
pRender->PushRenderMode( RENDER_MODE_TEXTURED); |
|
|
|
unsigned char color[4] = { 255, 255, 255, 255 }; |
|
|
|
SpriteColor( color, m_eRenderMode, m_RenderColor, 255); |
|
|
|
// If selected, render a yellow wireframe box. |
|
if ( GetSelectionState() != SELECT_NONE ) |
|
{ |
|
color[0] = 255; |
|
color[1] = color[2] = 0; |
|
} |
|
|
|
CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); |
|
IMesh* pMesh = pRenderContext->GetDynamicMesh(); |
|
CMeshBuilder meshBuilder; |
|
meshBuilder.Begin( pMesh, MATERIAL_POLYGON, 4 ); |
|
|
|
meshBuilder.Position3f( vecMins.x, vecMins.y, 0.0f ); |
|
meshBuilder.TexCoord2f(0, 0, 1); |
|
meshBuilder.Color3ub( color[0], color[1], color[2] ); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.Position3f( vecMins.x, vecMaxs.y, 0.0f ); |
|
meshBuilder.TexCoord2f(0, 0, 0); |
|
meshBuilder.Color3ub( color[0], color[1], color[2] ); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.Position3f( vecMaxs.x, vecMaxs.y, 0.0f ); |
|
meshBuilder.TexCoord2f(0, 1, 0); |
|
meshBuilder.Color3ub( color[0], color[1], color[2] ); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.Position3f( vecMaxs.x, vecMins.y, 0.0f ); |
|
meshBuilder.TexCoord2f(0, 1, 1); |
|
meshBuilder.Color3ub( color[0], color[1], color[2] ); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.End(); |
|
pMesh->Draw(); |
|
|
|
pRender->PopRenderMode(); |
|
} |