123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code 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 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "DeviceContext.h"
- #include "../renderer/GuiModel.h"
- extern idCVar in_useJoystick;
- // bypass rendersystem to directly work on guiModel
- extern idGuiModel * tr_guiModel;
- idVec4 idDeviceContext::colorPurple;
- idVec4 idDeviceContext::colorOrange;
- idVec4 idDeviceContext::colorYellow;
- idVec4 idDeviceContext::colorGreen;
- idVec4 idDeviceContext::colorBlue;
- idVec4 idDeviceContext::colorRed;
- idVec4 idDeviceContext::colorBlack;
- idVec4 idDeviceContext::colorWhite;
- idVec4 idDeviceContext::colorNone;
- void idDeviceContext::Init() {
- xScale = 1.0f;
- yScale = 1.0f;
- xOffset = 0.0f;
- yOffset = 0.0f;
- whiteImage = declManager->FindMaterial("guis/assets/white.tga");
- whiteImage->SetSort( SS_GUI );
- activeFont = renderSystem->RegisterFont( "" );
- colorPurple = idVec4(1, 0, 1, 1);
- colorOrange = idVec4(1, 1, 0, 1);
- colorYellow = idVec4(0, 1, 1, 1);
- colorGreen = idVec4(0, 1, 0, 1);
- colorBlue = idVec4(0, 0, 1, 1);
- colorRed = idVec4(1, 0, 0, 1);
- colorWhite = idVec4(1, 1, 1, 1);
- colorBlack = idVec4(0, 0, 0, 1);
- colorNone = idVec4(0, 0, 0, 0);
- cursorImages[CURSOR_ARROW] = declManager->FindMaterial("ui/assets/guicursor_arrow.tga");
- cursorImages[CURSOR_HAND] = declManager->FindMaterial("ui/assets/guicursor_hand.tga");
- cursorImages[CURSOR_HAND_JOY1] = declManager->FindMaterial("ui/assets/guicursor_hand_cross.tga");
- cursorImages[CURSOR_HAND_JOY2] = declManager->FindMaterial("ui/assets/guicursor_hand_circle.tga");
- cursorImages[CURSOR_HAND_JOY3] = declManager->FindMaterial("ui/assets/guicursor_hand_square.tga");
- cursorImages[CURSOR_HAND_JOY4] = declManager->FindMaterial("ui/assets/guicursor_hand_triangle.tga");
- cursorImages[CURSOR_HAND_JOY1] = declManager->FindMaterial("ui/assets/guicursor_hand_a.tga");
- cursorImages[CURSOR_HAND_JOY2] = declManager->FindMaterial("ui/assets/guicursor_hand_b.tga");
- cursorImages[CURSOR_HAND_JOY3] = declManager->FindMaterial("ui/assets/guicursor_hand_x.tga");
- cursorImages[CURSOR_HAND_JOY4] = declManager->FindMaterial("ui/assets/guicursor_hand_y.tga");
- scrollBarImages[SCROLLBAR_HBACK] = declManager->FindMaterial("ui/assets/scrollbarh.tga");
- scrollBarImages[SCROLLBAR_VBACK] = declManager->FindMaterial("ui/assets/scrollbarv.tga");
- scrollBarImages[SCROLLBAR_THUMB] = declManager->FindMaterial("ui/assets/scrollbar_thumb.tga");
- scrollBarImages[SCROLLBAR_RIGHT] = declManager->FindMaterial("ui/assets/scrollbar_right.tga");
- scrollBarImages[SCROLLBAR_LEFT] = declManager->FindMaterial("ui/assets/scrollbar_left.tga");
- scrollBarImages[SCROLLBAR_UP] = declManager->FindMaterial("ui/assets/scrollbar_up.tga");
- scrollBarImages[SCROLLBAR_DOWN] = declManager->FindMaterial("ui/assets/scrollbar_down.tga");
- cursorImages[CURSOR_ARROW]->SetSort( SS_GUI );
- cursorImages[CURSOR_HAND]->SetSort( SS_GUI );
- scrollBarImages[SCROLLBAR_HBACK]->SetSort( SS_GUI );
- scrollBarImages[SCROLLBAR_VBACK]->SetSort( SS_GUI );
- scrollBarImages[SCROLLBAR_THUMB]->SetSort( SS_GUI );
- scrollBarImages[SCROLLBAR_RIGHT]->SetSort( SS_GUI );
- scrollBarImages[SCROLLBAR_LEFT]->SetSort( SS_GUI );
- scrollBarImages[SCROLLBAR_UP]->SetSort( SS_GUI );
- scrollBarImages[SCROLLBAR_DOWN]->SetSort( SS_GUI );
- cursor = CURSOR_ARROW;
- enableClipping = true;
- overStrikeMode = true;
- mat.Identity();
- matIsIdentity = true;
- origin.Zero();
- initialized = true;
- }
- void idDeviceContext::Shutdown() {
- clipRects.Clear();
- Clear();
- }
- void idDeviceContext::Clear() {
- initialized = false;
- }
- idDeviceContext::idDeviceContext() {
- Clear();
- }
- void idDeviceContext::SetTransformInfo(const idVec3 &org, const idMat3 &m) {
- origin = org;
- mat = m;
- matIsIdentity = mat.IsIdentity();
- }
- //
- // added method
- void idDeviceContext::GetTransformInfo(idVec3& org, idMat3& m )
- {
- m = mat;
- org = origin;
- }
- //
- void idDeviceContext::EnableClipping(bool b) {
- enableClipping = b;
- };
- void idDeviceContext::PopClipRect() {
- if (clipRects.Num()) {
- clipRects.RemoveIndex(clipRects.Num()-1);
- }
- }
- void idDeviceContext::PushClipRect(idRectangle r) {
- clipRects.Append(r);
- }
- bool idDeviceContext::ClippedCoords(float *x, float *y, float *w, float *h, float *s1, float *t1, float *s2, float *t2) {
- if ( enableClipping == false || clipRects.Num() == 0 ) {
- return false;
- }
- int c = clipRects.Num();
- while( --c > 0 ) {
- idRectangle *clipRect = &clipRects[c];
-
- float ox = *x;
- float oy = *y;
- float ow = *w;
- float oh = *h;
- if ( ow <= 0.0f || oh <= 0.0f ) {
- break;
- }
- if (*x < clipRect->x) {
- *w -= clipRect->x - *x;
- *x = clipRect->x;
- } else if (*x > clipRect->x + clipRect->w) {
- *x = *w = *y = *h = 0;
- }
- if (*y < clipRect->y) {
- *h -= clipRect->y - *y;
- *y = clipRect->y;
- } else if (*y > clipRect->y + clipRect->h) {
- *x = *w = *y = *h = 0;
- }
- if (*w > clipRect->w) {
- *w = clipRect->w - *x + clipRect->x;
- } else if (*x + *w > clipRect->x + clipRect->w) {
- *w = clipRect->Right() - *x;
- }
- if (*h > clipRect->h) {
- *h = clipRect->h - *y + clipRect->y;
- } else if (*y + *h > clipRect->y + clipRect->h) {
- *h = clipRect->Bottom() - *y;
- }
- if ( s1 && s2 && t1 && t2 && ow > 0.0f ) {
- float ns1, ns2, nt1, nt2;
- // upper left
- float u = ( *x - ox ) / ow;
- ns1 = *s1 * ( 1.0f - u ) + *s2 * ( u );
- // upper right
- u = ( *x + *w - ox ) / ow;
- ns2 = *s1 * ( 1.0f - u ) + *s2 * ( u );
- // lower left
- u = ( *y - oy ) / oh;
- nt1 = *t1 * ( 1.0f - u ) + *t2 * ( u );
- // lower right
- u = ( *y + *h - oy ) / oh;
- nt2 = *t1 * ( 1.0f - u ) + *t2 * ( u );
- // set values
- *s1 = ns1;
- *s2 = ns2;
- *t1 = nt1;
- *t2 = nt2;
- }
- }
- return (*w == 0 || *h == 0) ? true : false;
- }
- /*
- =============
- DrawStretchPic
- =============
- */
- void idDeviceContext::DrawWinding( idWinding & w, const idMaterial * mat ) {
- idPlane p;
- p.Normal().Set( 1.0f, 0.0f, 0.0f );
- p.SetDist( 0.0f );
- w.ClipInPlace( p );
- p.Normal().Set( -1.0f, 0.0f, 0.0f );
- p.SetDist( -SCREEN_WIDTH );
- w.ClipInPlace( p );
- p.Normal().Set( 0.0f, 1.0f, 0.0f );
- p.SetDist( 0.0f );
- w.ClipInPlace( p );
- p.Normal().Set( 0.0f, -1.0f, 0.0f );
- p.SetDist( -SCREEN_HEIGHT );
- w.ClipInPlace( p );
- if ( w.GetNumPoints() < 3 ) {
- return;
- }
- int numIndexes = 0;
- triIndex_t tempIndexes[(MAX_POINTS_ON_WINDING-2)*3];
- for ( int j = 2; j < w.GetNumPoints(); j++ ) {
- tempIndexes[numIndexes++] = 0;
- tempIndexes[numIndexes++] = j - 1;
- tempIndexes[numIndexes++] = j;
- }
- assert( numIndexes == ( w.GetNumPoints() - 2 ) * 3 );
- idDrawVert * verts = renderSystem->AllocTris( w.GetNumPoints(), tempIndexes, numIndexes, mat );
- if ( verts == NULL ) {
- return;
- }
- uint32 currentColor = renderSystem->GetColor();
- for ( int j = 0 ; j < w.GetNumPoints() ; j++ ) {
- verts[j].xyz.x = xOffset + w[j].x * xScale;
- verts[j].xyz.y = yOffset + w[j].y * yScale;
- verts[j].xyz.z = w[j].z;
- verts[j].SetTexCoord( w[j].s, w[j].t );
- verts[j].SetColor( currentColor );
- verts[j].ClearColor2();
- verts[j].SetNormal( 0.0f, 0.0f, 1.0f );
- verts[j].SetTangent( 1.0f, 0.0f, 0.0f );
- verts[j].SetBiTangent( 0.0f, 1.0f, 0.0f );
- }
- }
- void idDeviceContext::DrawStretchPic(float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *shader) {
- if ( matIsIdentity ) {
- renderSystem->DrawStretchPic( xOffset + x * xScale, yOffset + y * yScale, w * xScale, h * yScale, s1, t1, s2, t2, shader );
- return;
- }
- idFixedWinding winding;
- winding.AddPoint( idVec5( x, y, 0.0f, s1, t1 ) );
- winding.AddPoint( idVec5( x+w, y, 0.0f, s2, t1 ) );
- winding.AddPoint( idVec5( x+w, y+h, 0.0f, s2, t2 ) );
- winding.AddPoint( idVec5( x, y+h, 0.0f, s1, t2 ) );
- for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
- winding[i].ToVec3() -= origin;
- winding[i].ToVec3() *= mat;
- winding[i].ToVec3() += origin;
- }
- DrawWinding( winding, shader );
- }
- void idDeviceContext::DrawMaterial(float x, float y, float w, float h, const idMaterial *mat, const idVec4 &color, float scalex, float scaley) {
- renderSystem->SetColor(color);
- float s0, s1, t0, t1;
- //
- // handle negative scales as well
- if ( scalex < 0 )
- {
- w *= -1;
- scalex *= -1;
- }
- if ( scaley < 0 )
- {
- h *= -1;
- scaley *= -1;
- }
- //
- if( w < 0 ) { // flip about vertical
- w = -w;
- s0 = 1 * scalex;
- s1 = 0;
- }
- else {
- s0 = 0;
- s1 = 1 * scalex;
- }
- if( h < 0 ) { // flip about horizontal
- h = -h;
- t0 = 1 * scaley;
- t1 = 0;
- }
- else {
- t0 = 0;
- t1 = 1 * scaley;
- }
- if ( ClippedCoords( &x, &y, &w, &h, &s0, &t0, &s1, &t1 ) ) {
- return;
- }
- DrawStretchPic( x, y, w, h, s0, t0, s1, t1, mat);
- }
- void idDeviceContext::DrawMaterialRotated(float x, float y, float w, float h, const idMaterial *mat, const idVec4 &color, float scalex, float scaley, float angle) {
-
- renderSystem->SetColor(color);
- float s0, s1, t0, t1;
- //
- // handle negative scales as well
- if ( scalex < 0 )
- {
- w *= -1;
- scalex *= -1;
- }
- if ( scaley < 0 )
- {
- h *= -1;
- scaley *= -1;
- }
- //
- if( w < 0 ) { // flip about vertical
- w = -w;
- s0 = 1 * scalex;
- s1 = 0;
- }
- else {
- s0 = 0;
- s1 = 1 * scalex;
- }
- if( h < 0 ) { // flip about horizontal
- h = -h;
- t0 = 1 * scaley;
- t1 = 0;
- }
- else {
- t0 = 0;
- t1 = 1 * scaley;
- }
- if ( angle == 0.0f && ClippedCoords( &x, &y, &w, &h, &s0, &t0, &s1, &t1 ) ) {
- return;
- }
- DrawStretchPicRotated( x, y, w, h, s0, t0, s1, t1, mat, angle);
- }
- void idDeviceContext::DrawStretchPicRotated(float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *shader, float angle) {
-
- idFixedWinding winding;
- winding.AddPoint( idVec5( x, y, 0.0f, s1, t1 ) );
- winding.AddPoint( idVec5( x+w, y, 0.0f, s2, t1 ) );
- winding.AddPoint( idVec5( x+w, y+h, 0.0f, s2, t2 ) );
- winding.AddPoint( idVec5( x, y+h, 0.0f, s1, t2 ) );
- for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
- winding[i].ToVec3() -= origin;
- winding[i].ToVec3() *= mat;
- winding[i].ToVec3() += origin;
- }
- //Generate a translation so we can translate to the center of the image rotate and draw
- idVec3 origTrans;
- origTrans.x = x+(w/2);
- origTrans.y = y+(h/2);
- origTrans.z = 0;
- //Rotate the verts about the z axis before drawing them
- idMat3 rotz;
- rotz.Identity();
- float sinAng, cosAng;
- idMath::SinCos( angle, sinAng, cosAng );
- rotz[0][0] = cosAng;
- rotz[0][1] = sinAng;
- rotz[1][0] = -sinAng;
- rotz[1][1] = cosAng;
- for (int i = 0; i < winding.GetNumPoints(); i++) {
- winding[i].ToVec3() -= origTrans;
- winding[i].ToVec3() *= rotz;
- winding[i].ToVec3() += origTrans;
- }
-
- DrawWinding( winding, shader );
- }
- void idDeviceContext::DrawFilledRect( float x, float y, float w, float h, const idVec4 &color) {
- if ( color.w == 0.0f ) {
- return;
- }
- renderSystem->SetColor(color);
-
- if (ClippedCoords(&x, &y, &w, &h, NULL, NULL, NULL, NULL)) {
- return;
- }
- DrawStretchPic( x, y, w, h, 0, 0, 0, 0, whiteImage);
- }
- void idDeviceContext::DrawRect( float x, float y, float w, float h, float size, const idVec4 &color) {
- if ( color.w == 0.0f ) {
- return;
- }
- renderSystem->SetColor(color);
-
- if (ClippedCoords(&x, &y, &w, &h, NULL, NULL, NULL, NULL)) {
- return;
- }
- DrawStretchPic( x, y, size, h, 0, 0, 0, 0, whiteImage );
- DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, whiteImage );
- DrawStretchPic( x, y, w, size, 0, 0, 0, 0, whiteImage );
- DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, whiteImage );
- }
- void idDeviceContext::DrawMaterialRect( float x, float y, float w, float h, float size, const idMaterial *mat, const idVec4 &color) {
- if ( color.w == 0.0f ) {
- return;
- }
- renderSystem->SetColor(color);
- DrawMaterial( x, y, size, h, mat, color );
- DrawMaterial( x + w - size, y, size, h, mat, color );
- DrawMaterial( x, y, w, size, mat, color );
- DrawMaterial( x, y + h - size, w, size, mat, color );
- }
- void idDeviceContext::SetCursor(int n) {
-
- if ( n > CURSOR_ARROW && n < CURSOR_COUNT ) {
- keyBindings_t binds = idKeyInput::KeyBindingsFromBinding( "_use", true );
- keyNum_t keyNum = K_NONE;
- if ( in_useJoystick.GetBool() ) {
- keyNum = idKeyInput::StringToKeyNum( binds.gamepad.c_str() );
- }
- if ( keyNum != K_NONE ) {
-
- if ( keyNum == K_JOY1 ) {
- cursor = CURSOR_HAND_JOY1;
- } else if ( keyNum == K_JOY2 ) {
- cursor = CURSOR_HAND_JOY2;
- } else if ( keyNum == K_JOY3 ) {
- cursor = CURSOR_HAND_JOY3;
- } else if ( keyNum == K_JOY4 ) {
- cursor = CURSOR_HAND_JOY4;
- }
- } else {
- cursor = CURSOR_HAND;
- }
- } else {
- cursor = CURSOR_ARROW;
- }
- }
- void idDeviceContext::DrawCursor(float *x, float *y, float size) {
- if (*x < 0) {
- *x = 0;
- }
- if (*x >= VIRTUAL_WIDTH) {
- *x = VIRTUAL_WIDTH;
- }
- if (*y < 0) {
- *y = 0;
- }
- if (*y >= VIRTUAL_HEIGHT) {
- *y = VIRTUAL_HEIGHT;
- }
- renderSystem->SetColor(colorWhite);
- DrawStretchPic( *x, *y, size, size, 0, 0, 1, 1, cursorImages[cursor]);
- }
- /*
- =======================================================================================================================
- =======================================================================================================================
- */
- void idDeviceContext::PaintChar( float x, float y, const scaledGlyphInfo_t & glyphInfo ) {
- y -= glyphInfo.top;
- 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;
- const idMaterial * hShader = glyphInfo.material;
- if ( ClippedCoords( &x, &y, &w, &h, &s, &t, &s2, &t2) ) {
- return;
- }
- DrawStretchPic(x, y, w, h, s, t, s2, t2, hShader);
- }
- int idDeviceContext::DrawText(float x, float y, float scale, idVec4 color, const char *text, float adjust, int limit, int style, int cursor) {
- int len;
- idVec4 newColor;
- idStr drawText = text;
- int charIndex = 0;
- if ( text && color.w != 0.0f ) {
- renderSystem->SetColor(color);
- memcpy(&newColor[0], &color[0], sizeof(idVec4));
- len = drawText.Length();
- if (limit > 0 && len > limit) {
- len = limit;
- }
- float prevGlyphSkip = 0.0f;
- while ( charIndex < len ) {
- uint32 textChar = drawText.UTF8Char( charIndex );
- if ( idStr::IsColor( drawText.c_str() + charIndex ) ) {
- if ( drawText[ charIndex++ ] == C_COLOR_DEFAULT ) {
- newColor = color;
- } else {
- newColor = idStr::ColorForIndex( charIndex );
- newColor[3] = color[3];
- }
- if (cursor == charIndex-1 || cursor == charIndex) {
- float backup = 0.0f;
- if ( prevGlyphSkip > 0.0f ) {
- backup = ( prevGlyphSkip + adjust) / 5.0f;
- }
- if ( cursor == charIndex-1 ) {
- backup *= 2.0f;
- } else {
- renderSystem->SetColor(newColor);
- }
- DrawEditCursor(x - backup, y, scale);
- }
- renderSystem->SetColor(newColor);
- continue;
- } else {
- scaledGlyphInfo_t glyphInfo;
- activeFont->GetScaledGlyph( scale, textChar, glyphInfo );
- prevGlyphSkip = glyphInfo.xSkip;
- PaintChar( x, y, glyphInfo );
- if (cursor == charIndex-1) {
- DrawEditCursor(x, y, scale);
- }
- x += glyphInfo.xSkip + adjust;
- }
- }
- if (cursor == len) {
- DrawEditCursor(x, y, scale);
- }
- }
- return drawText.Length();
- }
- void idDeviceContext::SetSize( float width, float height ) {
- xScale = VIRTUAL_WIDTH / width;
- yScale = VIRTUAL_HEIGHT / height;
- }
- void idDeviceContext::SetOffset( float x, float y ) {
- xOffset = x;
- yOffset = y;
- }
- int idDeviceContext::CharWidth( const char c, float scale ) {
- return idMath::Ftoi( activeFont->GetGlyphWidth( scale, c ) );
- }
- int idDeviceContext::TextWidth( const char *text, float scale, int limit ) {
- if ( text == NULL ) {
- return 0;
- }
- int i;
- float width = 0;
- if ( limit > 0 ) {
- for ( i = 0; text[i] != '\0' && i < limit; i++ ) {
- if ( idStr::IsColor( text + i ) ) {
- i++;
- } else {
- width += activeFont->GetGlyphWidth( scale, ((const unsigned char *)text)[i] );
- }
- }
- } else {
- for ( i = 0; text[i] != '\0'; i++ ) {
- if ( idStr::IsColor( text + i ) ) {
- i++;
- } else {
- width += activeFont->GetGlyphWidth( scale, ((const unsigned char *)text)[i] );
- }
- }
- }
- return idMath::Ftoi( width );
- }
- int idDeviceContext::TextHeight(const char *text, float scale, int limit) {
- return idMath::Ftoi( activeFont->GetLineHeight( scale ) );
- }
- int idDeviceContext::MaxCharWidth(float scale) {
- return idMath::Ftoi( activeFont->GetMaxCharWidth( scale ) );
- }
- int idDeviceContext::MaxCharHeight(float scale) {
- return idMath::Ftoi( activeFont->GetLineHeight( scale ) );
- }
- const idMaterial *idDeviceContext::GetScrollBarImage(int index) {
- if (index >= SCROLLBAR_HBACK && index < SCROLLBAR_COUNT) {
- return scrollBarImages[index];
- }
- return scrollBarImages[SCROLLBAR_HBACK];
- }
- // this only supports left aligned text
- idRegion *idDeviceContext::GetTextRegion(const char *text, float textScale, idRectangle rectDraw, float xStart, float yStart) {
- return NULL;
- }
- void idDeviceContext::DrawEditCursor( float x, float y, float scale ) {
- if ( (int)( idLib::frameNumber >> 4 ) & 1 ) {
- return;
- }
- char cursorChar = (overStrikeMode) ? '_' : '|';
- scaledGlyphInfo_t glyphInfo;
- activeFont->GetScaledGlyph( scale, cursorChar, glyphInfo );
- PaintChar( x, y, glyphInfo );
- }
- int idDeviceContext::DrawText( const char *text, float textScale, int textAlign, idVec4 color, idRectangle 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 = MaxCharWidth( textScale ) + 1;
- float lineSkip = MaxCharHeight( textScale );
- bool lineBreak = false;
- bool wordBreak = false;
- idStr drawText = text;
- idStr textBuffer;
- if (!calcOnly && !(text && *text)) {
- if (cursor == 0) {
- renderSystem->SetColor(color);
- DrawEditCursor(rectDraw.x, lineSkip + rectDraw.y, textScale);
- }
- return idMath::Ftoi( rectDraw.w / 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 += activeFont->GetGlyphWidth( textScale, textChar );
- textBuffer.AppendUTF8Char( textChar );
- }
- if ( !lineBreak && ( textWidth > rectDraw.w ) ) {
- // 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.x;
- if ( textWidthAtLastBreak > 0 ) {
- textWidth = textWidthAtLastBreak;
- }
- // Align text if needed
- if (textAlign == ALIGN_RIGHT) {
- x = rectDraw.x + rectDraw.w - textWidth;
- } else if (textAlign == ALIGN_CENTER) {
- x = rectDraw.x + (rectDraw.w - textWidth) / 2;
- }
- 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(x, y, textScale, color, textBuffer.Left( lastBreak ).c_str(), 0, 0, 0, cursor);
- textBuffer = textBuffer.Right( textBuffer.Length() - lastBreak );
- } else {
- count += DrawText(x, y, textScale, color, textBuffer.c_str(), 0, 0, 0, cursor);
- 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 += activeFont->GetGlyphWidth( textScale, textBuffer.UTF8Char( i ) );
- }
- }
- continue;
- }
- }
- return idMath::Ftoi( rectDraw.w / charSkip );
- }
- /*
- =============
- idRectangle::String
- =============
- */
- char *idRectangle::String() const {
- static int index = 0;
- static char str[ 8 ][ 48 ];
- char *s;
- // use an array so that multiple toString's won't collide
- s = str[ index ];
- index = (index + 1)&7;
- sprintf( s, "%.2f %.2f %.2f %.2f", x, y, w, h );
- return s;
- }
- /*
- ================================================================================================
- OPTIMIZED VERSIONS
- ================================================================================================
- */
- // this is only called for the cursor and debug strings, and it should
- // scope properly with push/pop clipRect
- void idDeviceContextOptimized::EnableClipping(bool b) {
- if ( b == enableClipping ) {
- return;
- }
- enableClipping = b;
- if ( !enableClipping ) {
- PopClipRect();
- } else {
- // the actual value of the rect is irrelvent
- PushClipRect( idRectangle( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ) );
- // allow drawing beyond the normal bounds for debug text
- // this also allows the cursor to draw outside, so we might want
- // to make this exactly the screen bounds, since we aren't likely
- // to ever turn on the gui debug text again...
- clipX1 = -SCREEN_WIDTH;
- clipX2 = SCREEN_WIDTH * 2;
- clipY1 = -SCREEN_HEIGHT;
- clipY2 = SCREEN_HEIGHT * 2;
- }
- };
- void idDeviceContextOptimized::PopClipRect() {
- if (clipRects.Num()) {
- clipRects.SetNum( clipRects.Num()-1 ); // don't resize the list, just change num
- }
- if ( clipRects.Num() > 0 ) {
- const idRectangle & clipRect = clipRects[ clipRects.Num() - 1 ];
- clipX1 = clipRect.x;
- clipY1 = clipRect.y;
- clipX2 = clipRect.x + clipRect.w;
- clipY2 = clipRect.y + clipRect.h;
- } else {
- clipX1 = 0;
- clipY1 = 0;
- clipX2 = SCREEN_WIDTH;
- clipY2 = SCREEN_HEIGHT;
- }
- }
- static const idRectangle baseScreenRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
- void idDeviceContextOptimized::PushClipRect(idRectangle r) {
- const idRectangle & prev = ( clipRects.Num() == 0 ) ? baseScreenRect : clipRects[clipRects.Num()-1];
- // instead of storing the rect, store the intersection of the rect
- // with the previous rect, so ClippedCoords() only has to test against one rect
- idRectangle intersection = prev;
- intersection.ClipAgainst( r, false );
- clipRects.Append( intersection );
- const idRectangle & clipRect = clipRects[ clipRects.Num() - 1 ];
- clipX1 = clipRect.x;
- clipY1 = clipRect.y;
- clipX2 = clipRect.x + clipRect.w;
- clipY2 = clipRect.y + clipRect.h;
- }
- bool idDeviceContextOptimized::ClippedCoords(float *x, float *y, float *w, float *h, float *s1, float *t1, float *s2, float *t2) {
- const float ox = *x;
- const float oy = *y;
- const float ow = *w;
- const float oh = *h;
- // presume visible first
- if ( ox >= clipX1 && oy >= clipY1 && ox + ow <= clipX2 && oy + oh <= clipY2 ) {
- return false;
- }
- // do clipping
- if ( ox < clipX1 ) {
- *w -= clipX1 - ox;
- *x = clipX1;
- } else if ( ox > clipX2 ) {
- return true;
- }
- if ( oy < clipY1) {
- *h -= clipY1 - oy;
- *y = clipY1;
- } else if ( oy > clipY2) {
- return true;
- }
- if ( *x + *w > clipX2 ) {
- *w = clipX2 - *x;
- }
- if ( *y + *h > clipY2 ) {
- *h = clipY2 - *y;
- }
- if ( *w <= 0 || *h <= 0 ) {
- return true;
- }
- // filled rects won't pass in texcoords
- if ( s1 ) {
- float ns1, ns2, nt1, nt2;
- // upper left
- float u = ( *x - ox ) / ow;
- ns1 = *s1 * ( 1.0f - u ) + *s2 * ( u );
- // upper right
- u = ( *x + *w - ox ) / ow;
- ns2 = *s1 * ( 1.0f - u ) + *s2 * ( u );
- // lower left
- u = ( *y - oy ) / oh;
- nt1 = *t1 * ( 1.0f - u ) + *t2 * ( u );
- // lower right
- u = ( *y + *h - oy ) / oh;
- nt2 = *t1 * ( 1.0f - u ) + *t2 * ( u );
- // set values
- *s1 = ns1;
- *s2 = ns2;
- *t1 = nt1;
- *t2 = nt2;
- }
- // still needs to be drawn
- return false;
- }
- /*
- =============
- idDeviceContextOptimized::DrawText
- =============
- */
- static triIndex_t quadPicIndexes[6] = { 3, 0, 2, 2, 0, 1 };
- int idDeviceContextOptimized::DrawText(float x, float y, float scale, idVec4 color, const char *text, float adjust, int limit, int style, int cursor) {
- 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;
- activeFont->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;
- if ( !ClippedCoords( &drawX, &drawY, &w, &h, &s, &t, &s2, &t2) ) {
- float x1 = xOffset + drawX * xScale;
- float x2 = xOffset + ( drawX + w ) * xScale;
- float y1 = yOffset + drawY * yScale;
- float y2 = yOffset + ( drawY + h ) * yScale;
- idDrawVert * verts = tr_guiModel->AllocTris( 4, quadPicIndexes, 6, glyphInfo.material, 0, 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();
- }
|