swf_show debug rendering

This commit is contained in:
Robert Beckebans 2015-06-09 17:58:24 +02:00
parent 6d4a3f107b
commit d4eb9f8d93
5 changed files with 520 additions and 9 deletions

View file

@ -385,6 +385,9 @@ private:
const idMaterial* guiCursor_arrow;
const idMaterial* guiCursor_hand;
const idMaterial* white;
// RB begin
const idFont* debugFont;
// RB end
private:
friend class idSWFSprite;
@ -450,6 +453,13 @@ private:
uint64 GLStateForRenderState( const swfRenderState_t& renderState );
void FindTooltipIcons( idStr* text );
// RB: debugging tools
swfRect_t CalcRect( const idSWFSpriteInstance* sprite, const swfRenderState_t& renderState );
void DrawRect( idRenderSystem* gui, const swfRect_t& rect, const idVec4& color );
int DrawText( idRenderSystem* gui, float x, float y, float scale, idVec4 color, const char* text, float adjust, int limit, int style );
int DrawText( idRenderSystem* gui, const char* text, float textScale, int textAlign, idVec4 color, const swfRect_t& rectDraw, bool wrap, int cursor = -1, bool calcOnly = false, idList<int>* breaks = NULL, int limit = 0 );
// RB end
//----------------------------------
// SWF_Image.cpp
//----------------------------------

View file

@ -900,7 +900,7 @@ void idSWF::WriteJSON( const char* filename )
// export fill draws
file->WriteFloatString( "\t\t\t\"fillDraws\":\n\t\t\t[\n" );
if( shape->fillDraws.Num() > 1 )
{
idLib::Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s.Shape%i has %i fill draws\n", filename, i, shape->fillDraws.Num() );
@ -1026,7 +1026,7 @@ void idSWF::WriteJSON( const char* filename )
for( int v = 0; v < fillDraw.startVerts.Num(); v++ )
{
const idVec2& vert = fillDraw.startVerts[v];
file->WriteFloatString( "\t\t\t\t\t\t{ \"v\": [ %f, %f ] }%s\n", vert.x, vert.y, ( v == ( fillDraw.startVerts.Num() - 1 ) ) ? "" : "," );
}
file->WriteFloatString( "\t\t\t\t\t]" );
@ -1051,7 +1051,7 @@ void idSWF::WriteJSON( const char* filename )
for( int v = 0; v < fillDraw.indices.Num(); v++ )
{
const uint16& vert = fillDraw.indices[v];
file->WriteFloatString( "%i%s", vert, ( v == fillDraw.indices.Num() - 1 ) ? "" : ", " );
}
#else
@ -1267,15 +1267,19 @@ void idSWF::WriteJSON( const char* filename )
if( dictionary[i].type != SWF_DICT_NULL )
{
file->WriteFloatString( "\t\t}%s\n", ( i == ( dictionary.Num() - 1 ) ) ? "" : "," );
//file->WriteFloatString( "\t\t}%s\n", ( i == ( dictionary.Num() - 1 ) ) ? "" : "," );
file->WriteFloatString( "\t\t},\n" );
}
}
file->WriteFloatString( "\t],\n" );
file->WriteFloatString( "\t\"mainsprite\":\n\t{\n" );
file->WriteFloatString( "\t\t{\n" );
file->WriteFloatString( "\t\t\t\"type\": \"SPRITE\",\n" );
file->WriteFloatString( "\t\t\t\"characterID\": %i,\n", dictionary.Num() );
file->WriteFloatString( "\t\t\t\"mainsprite\": true,\n" );
mainsprite->WriteJSON( file, dictionary.Num() );
file->WriteFloatString( "\t}\n}\n" );
file->WriteFloatString( "\t\t}\n" );
file->WriteFloatString( "\t]\n" );
file->WriteFloatString( "}\n" );
}
// RB end

View file

@ -68,6 +68,9 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ )
guiCursor_hand = declManager->FindMaterial( "ui/assets/guicursor_hand" );
white = declManager->FindMaterial( "_white" );
// RB:
debugFont = renderSystem->RegisterFont( "Arial Narrow" );
tooltipButtonImage.Append( keyButtonImages_t( "<JOY1>", "guis/assets/hud/controller/xb360/a", "guis/assets/hud/controller/ps3/cross", 37, 37, 0 ) );
tooltipButtonImage.Append( keyButtonImages_t( "<JOY2>", "guis/assets/hud/controller/xb360/b", "guis/assets/hud/controller/ps3/circle", 37, 37, 0 ) );
tooltipButtonImage.Append( keyButtonImages_t( "<JOY3>", "guis/assets/hud/controller/xb360/x", "guis/assets/hud/controller/ps3/square", 37, 37, 0 ) );

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013 Robert Beckebans
Copyright (C) 2013-2015 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -42,6 +42,8 @@ idCVar swf_skipSolids( "swf_skipSolids", "0", CVAR_BOOL, "" );
idCVar swf_skipGradients( "swf_skipGradients", "0", CVAR_BOOL, "" );
idCVar swf_skipLineDraws( "swf_skipLineDraws", "0", CVAR_BOOL, "" );
idCVar swf_skipBitmaps( "swf_skipBitmaps", "0", CVAR_BOOL, "" );
idCVar swf_show( "swf_show", "0", CVAR_INTEGER, "" );
// RB end
extern idCVar swf_textStrokeSize;
@ -462,6 +464,33 @@ void idSWF::RenderSprite( idRenderSystem* gui, idSWFSpriteInstance* spriteInstan
//idLib::Warning( "%s: Tried to render an unrenderable character %d", filename.c_str(), entry->type );
}
}
// RB begin
if( swf_show.GetInteger() > 0 && !spriteInstance->name.IsEmpty() )//Icmp( "buttonBar" ) == 0 )
{
swfRect_t rect = CalcRect( spriteInstance, renderState );
DrawRect( gui, rect, colorRed );
if( swf_show.GetInteger() > 1 )
{
idVec4 color = colorWhite;
if( spriteInstance->parent != NULL && spriteInstance->parent == mainspriteInstance )
{
color = colorCyan;
}
idStr str;
//str = display.spriteInstance->name.c_str();
sprintf( str, "%s\n%s", spriteInstance->name.c_str(), GetName() );
DrawText( gui, str, 0.35f, 0, color, swfRect_t( rect.tl.x, rect.tl.y, 300, 40 ), false );
//DrawText( gui, str, 0.25 * 2, 0, colorWhite, swfRect_t( rect.tl.x, rect.tl.y, 300, 40 ), false );
}
}
// RB end
for( int j = 0; j < activeMasks.Num(); j++ )
{
const swfDisplayEntry_t* mask = activeMasks[ j ];
@ -1876,4 +1905,434 @@ void idSWF::FindTooltipIcons( idStr* text )
}
}
// RB begin
swfRect_t idSWF::CalcRect( const idSWFSpriteInstance* spriteInstance, const swfRenderState_t& renderState )
{
swfRect_t bounds;
bounds.tl.x = renderState.matrix.tx;
bounds.tl.y = renderState.matrix.ty;
bounds.br.x = renderState.matrix.tx;
bounds.br.y = renderState.matrix.ty;
if( spriteInstance == NULL )
{
idLib::Warning( "%s: CalcRect: spriteInstance == NULL", filename.c_str() );
return bounds;
}
#if 1
for( int i = 0; i < spriteInstance->displayList.Num(); i++ )
{
const swfDisplayEntry_t& display = spriteInstance->displayList[i];
idSWFDictionaryEntry* entry = FindDictionaryEntry( display.characterID );
if( entry == NULL )
{
continue;
}
swfRenderState_t renderState2;
renderState2.matrix = display.matrix.Multiply( renderState.matrix );
if( entry->type == SWF_DICT_SPRITE )
{
swfRect_t spriteBounds = CalcRect( display.spriteInstance, renderState2 );
if( spriteBounds.tl.x < bounds.tl.x )
{
bounds.tl.x = spriteBounds.tl.x;
}
else if( spriteBounds.br.x > bounds.br.x )
{
bounds.br.x = spriteBounds.br.x;
}
if( spriteBounds.tl.y < bounds.tl.y )
{
bounds.tl.y = spriteBounds.tl.y;
}
else if( spriteBounds.br.y > bounds.br.y )
{
bounds.br.y = spriteBounds.br.y;
}
}
else if( entry->type == SWF_DICT_SHAPE )
{
const idSWFShape* shape = entry->shape;
for( int i = 0; i < shape->fillDraws.Num(); i++ )
{
const idSWFShapeDrawFill& fill = shape->fillDraws[i];
for( int j = 0; j < fill.startVerts.Num(); j++ )
{
const idVec2& xy = fill.startVerts[j];
idVec2 p = renderState.matrix.Transform( xy );//.Scale( scaleToVirtual );
if( p.x < bounds.tl.x )
{
bounds.tl.x = p.x;
}
else if( p.x > bounds.br.x )
{
bounds.br.x = p.x;
}
if( p.y < bounds.tl.y )
{
bounds.tl.y = p.y;
}
else if( p.y > bounds.br.y )
{
bounds.br.y = p.y;
}
}
}
}
else if( entry->type == SWF_DICT_MORPH )
{
// TODO
}
else if( entry->type == SWF_DICT_EDITTEXT )
{
// TODO
}
else
{
//idLib::Warning( "%s: Tried to render an unrenderable character %d", filename.c_str(), entry->type );
}
}
#endif
return bounds;
}
void idSWF::DrawRect( idRenderSystem* gui, const swfRect_t& rect, const idVec4& color )
{
renderSystem->SetColor( color );
float x = rect.tl.x;
float y = rect.tl.y;
float w = fabs( rect.br.x - rect.tl.x );
float h = fabs( rect.br.y - rect.tl.y );
float size = 1;
DrawStretchPic( x, y, size, h, 0, 0, 0, 0, white );
DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, white );
DrawStretchPic( x, y, w, size, 0, 0, 0, 0, white );
DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, white );
}
static triIndex_t quadPicIndexes[6] = { 3, 0, 2, 2, 0, 1 };
int idSWF::DrawText( idRenderSystem* gui, float x, float y, float scale, idVec4 color, const char* text, float adjust, int limit, int style )
{
/*
if( !matIsIdentity || cursor != -1 )
{
// fallback to old code
return idDeviceContext::DrawText( x, y, scale, color, text, adjust, limit, style, cursor );
}
*/
idStr drawText = text;
if( drawText.Length() == 0 )
{
return 0;
}
if( color.w == 0.0f )
{
return 0;
}
const uint32 currentColor = PackColor( color );
uint32 currentColorNativeByteOrder = LittleLong( currentColor );
int len = drawText.Length();
if( limit > 0 && len > limit )
{
len = limit;
}
int charIndex = 0;
while( charIndex < drawText.Length() )
{
uint32 textChar = drawText.UTF8Char( charIndex );
if( textChar == C_COLOR_ESCAPE )
{
// I'm not sure if inline text color codes are used anywhere in the game,
// they may only be needed for multi-color user names
idVec4 newColor;
uint32 colorIndex = drawText.UTF8Char( charIndex );
if( colorIndex == C_COLOR_DEFAULT )
{
newColor = color;
}
else
{
newColor = idStr::ColorForIndex( colorIndex );
newColor[3] = color[3];
}
renderSystem->SetColor( newColor );
currentColorNativeByteOrder = LittleLong( PackColor( newColor ) );
continue;
}
scaledGlyphInfo_t glyphInfo;
debugFont->GetScaledGlyph( scale, textChar, glyphInfo );
// PaintChar( x, y, glyphInfo );
float drawY = y - glyphInfo.top;
float drawX = x + glyphInfo.left;
float w = glyphInfo.width;
float h = glyphInfo.height;
float s = glyphInfo.s1;
float t = glyphInfo.t1;
float s2 = glyphInfo.s2;
float t2 = glyphInfo.t2;
float xOffset = 0;
float yOffset = 0;
//idDrawVert* verts = gui->AllocTris( fill.startVerts.Num(), fill.indices.Ptr(), fill.indices.Num(), material, renderState.stereoDepth );
//if( !ClippedCoords( &drawX, &drawY, &w, &h, &s, &t, &s2, &t2 ) )
{
float x1 = xOffset + drawX * scaleToVirtual.x;
float x2 = xOffset + ( drawX + w ) * scaleToVirtual.x;
float y1 = yOffset + drawY * scaleToVirtual.y;
float y2 = yOffset + ( drawY + h ) * scaleToVirtual.y;
idDrawVert* verts = gui->AllocTris( 4, quadPicIndexes, 6, glyphInfo.material, STEREO_DEPTH_TYPE_NONE );
if( verts != NULL )
{
verts[0].xyz[0] = x1;
verts[0].xyz[1] = y1;
verts[0].xyz[2] = 0.0f;
verts[0].SetTexCoord( s, t );
verts[0].SetNativeOrderColor( currentColorNativeByteOrder );
verts[0].ClearColor2();
verts[1].xyz[0] = x2;
verts[1].xyz[1] = y1;
verts[1].xyz[2] = 0.0f;
verts[1].SetTexCoord( s2, t );
verts[1].SetNativeOrderColor( currentColorNativeByteOrder );
verts[1].ClearColor2();
verts[2].xyz[0] = x2;
verts[2].xyz[1] = y2;
verts[2].xyz[2] = 0.0f;
verts[2].SetTexCoord( s2, t2 );
verts[2].SetNativeOrderColor( currentColorNativeByteOrder );
verts[2].ClearColor2();
verts[3].xyz[0] = x1;
verts[3].xyz[1] = y2;
verts[3].xyz[2] = 0.0f;
verts[3].SetTexCoord( s, t2 );
verts[3].SetNativeOrderColor( currentColorNativeByteOrder );
verts[3].ClearColor2();
}
}
x += glyphInfo.xSkip + adjust;
}
return drawText.Length();
}
int idSWF::DrawText( idRenderSystem* gui, const char* text, float textScale, int textAlign, idVec4 color, const swfRect_t& rectDraw, bool wrap, int cursor, bool calcOnly, idList<int>* breaks, int limit )
{
int count = 0;
int charIndex = 0;
int lastBreak = 0;
float y = 0.0f;
float textWidth = 0.0f;
float textWidthAtLastBreak = 0.0f;
float charSkip = idMath::Ftoi( debugFont->GetMaxCharWidth( textScale ) ) + 1;
float lineSkip = idMath::Ftoi( debugFont->GetMaxCharWidth( textScale ) );
bool lineBreak = false;
bool wordBreak = false;
float rectWidth = fabs( rectDraw.br.x - rectDraw.tl.x );
float rectHeight = fabs( rectDraw.br.y - rectDraw.tl.y );
idStr drawText = text;
idStr textBuffer;
if( !calcOnly && !( text && *text ) )
{
//if( cursor == 0 )
//{
// renderSystem->SetColor( color );
// DrawEditCursor( rectDraw.tl.x, lineSkip + rectDraw.y, textScale );
//}
return idMath::Ftoi( rectWidth / charSkip );
}
y = lineSkip + rectDraw.y();
if( breaks )
{
breaks->Append( 0 );
}
while( charIndex < drawText.Length() )
{
uint32 textChar = drawText.UTF8Char( charIndex );
// See if we need to start a new line.
if( textChar == '\n' || textChar == '\r' || charIndex == drawText.Length() )
{
lineBreak = true;
if( charIndex < drawText.Length() )
{
// New line character and we still have more text to read.
char nextChar = drawText[ charIndex + 1 ];
if( ( textChar == '\n' && nextChar == '\r' ) || ( textChar == '\r' && nextChar == '\n' ) )
{
// Just absorb extra newlines.
textChar = drawText.UTF8Char( charIndex );
}
}
}
// Check for escape colors if not then simply get the glyph width.
if( textChar == C_COLOR_ESCAPE && charIndex < drawText.Length() )
{
textBuffer.AppendUTF8Char( textChar );
textChar = drawText.UTF8Char( charIndex );
}
// If the character isn't a new line then add it to the text buffer.
if( textChar != '\n' && textChar != '\r' )
{
textWidth += debugFont->GetGlyphWidth( textScale, textChar );
textBuffer.AppendUTF8Char( textChar );
}
if( !lineBreak && ( textWidth > rectWidth ) )
{
// The next character will cause us to overflow, if we haven't yet found a suitable
// break spot, set it to be this character
if( textBuffer.Length() > 0 && lastBreak == 0 )
{
lastBreak = textBuffer.Length();
textWidthAtLastBreak = textWidth;
}
wordBreak = true;
}
else if( lineBreak || ( wrap && ( textChar == ' ' || textChar == '\t' ) ) )
{
// The next character is in view, so if we are a break character, store our position
lastBreak = textBuffer.Length();
textWidthAtLastBreak = textWidth;
}
// We need to go to a new line
if( lineBreak || wordBreak )
{
float x = rectDraw.tl.x;
if( textWidthAtLastBreak > 0 )
{
textWidth = textWidthAtLastBreak;
}
// Align text if needed
#if 0
if( textAlign == ALIGN_RIGHT )
{
x = rectDraw.tl.x + rectWidth - textWidth;
}
else if( textAlign == ALIGN_CENTER )
{
x = rectDraw.tl.x + ( rectWidth - textWidth ) / 2;
}
#endif
if( wrap || lastBreak > 0 )
{
// This is a special case to handle breaking in the middle of a word.
// if we didn't do this, the cursor would appear on the end of this line
// and the beginning of the next.
if( wordBreak && cursor >= lastBreak && lastBreak == textBuffer.Length() )
{
cursor++;
}
}
// Draw what's in the current text buffer.
if( !calcOnly )
{
if( lastBreak > 0 )
{
count += DrawText( gui, x, y, textScale, color, textBuffer.Left( lastBreak ).c_str(), 0, 0, 0 );
textBuffer = textBuffer.Right( textBuffer.Length() - lastBreak );
}
else
{
count += DrawText( gui, x, y, textScale, color, textBuffer.c_str(), 0, 0, 0 );
textBuffer.Clear();
}
}
if( cursor < lastBreak )
{
cursor = -1;
}
else if( cursor >= 0 )
{
cursor -= ( lastBreak + 1 );
}
// If wrap is disabled return at this point.
if( !wrap )
{
return lastBreak;
}
// If we've hit the allowed character limit then break.
if( limit && count > limit )
{
break;
}
y += lineSkip + 5;
if( !calcOnly && y > rectDraw.Bottom() )
{
break;
}
// If breaks were requested then make a note of this one.
if( breaks )
{
breaks->Append( drawText.Length() - charIndex );
}
// Reset necessary parms for next line.
lastBreak = 0;
textWidth = 0;
textWidthAtLastBreak = 0;
lineBreak = false;
wordBreak = false;
// Reassess the remaining width
for( int i = 0; i < textBuffer.Length(); )
{
if( textChar != C_COLOR_ESCAPE )
{
textWidth += debugFont->GetGlyphWidth( textScale, textBuffer.UTF8Char( i ) );
}
}
continue;
}
}
return idMath::Ftoi( rectWidth / charSkip );
}

View file

@ -67,6 +67,41 @@ struct swfRect_t
swfRect_t();
idVec2 tl;
idVec2 br;
// RB: helpers
swfRect_t( float x, float y, float w, float h )
{
tl.x = x;
tl.y = y;
br.x = x + w;
br.y = y + h;
}
float x() const
{
return tl.x;
}
float y() const
{
return tl.y;
}
float w() const
{
return fabs( br.x - tl.x );
}
float h() const
{
return fabs( br.y - tl.y );
}
float Bottom() const
{
return br.y;
}
// RB end
};
struct swfMatrix_t
{