DeviceContext.cpp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. 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.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "DeviceContext.h"
  23. idVec4 idDeviceContext::colorPurple;
  24. idVec4 idDeviceContext::colorOrange;
  25. idVec4 idDeviceContext::colorYellow;
  26. idVec4 idDeviceContext::colorGreen;
  27. idVec4 idDeviceContext::colorBlue;
  28. idVec4 idDeviceContext::colorRed;
  29. idVec4 idDeviceContext::colorBlack;
  30. idVec4 idDeviceContext::colorWhite;
  31. idVec4 idDeviceContext::colorNone;
  32. idCVar gui_smallFontLimit( "gui_smallFontLimit", "0.30", CVAR_GUI | CVAR_ARCHIVE, "" );
  33. idCVar gui_mediumFontLimit( "gui_mediumFontLimit", "0.60", CVAR_GUI | CVAR_ARCHIVE, "" );
  34. idList<fontInfoEx_t> idDeviceContext::fonts;
  35. int idDeviceContext::FindFont( const char *name ) {
  36. int c = fonts.Num();
  37. for (int i = 0; i < c; i++) {
  38. if (idStr::Icmp(name, fonts[i].name) == 0) {
  39. return i;
  40. }
  41. }
  42. // If the font was not found, try to register it
  43. idStr fileName = name;
  44. fileName.Replace("fonts", va("fonts/%s", fontLang.c_str()) );
  45. fontInfoEx_t fontInfo;
  46. int index = fonts.Append( fontInfo );
  47. if ( renderSystem->RegisterFont( fileName, fonts[index] ) ){
  48. idStr::Copynz( fonts[index].name, name, sizeof( fonts[index].name ) );
  49. return index;
  50. } else {
  51. common->Printf( "Could not register font %s [%s]\n", name, fileName.c_str() );
  52. return -1;
  53. }
  54. }
  55. void idDeviceContext::SetupFonts() {
  56. fonts.SetGranularity( 1 );
  57. fontLang = cvarSystem->GetCVarString( "sys_lang" );
  58. // western european languages can use the english font
  59. if ( fontLang == "french" || fontLang == "german" || fontLang == "spanish" || fontLang == "italian" ) {
  60. fontLang = "english";
  61. }
  62. // Default font has to be added first
  63. FindFont( "fonts" );
  64. }
  65. void idDeviceContext::SetFont( int num ) {
  66. if ( num >= 0 && num < fonts.Num() ) {
  67. activeFont = &fonts[num];
  68. } else {
  69. activeFont = &fonts[0];
  70. }
  71. }
  72. void idDeviceContext::Init() {
  73. xScale = 0.0;
  74. SetSize(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
  75. whiteImage = declManager->FindMaterial("guis/assets/white.tga");
  76. whiteImage->SetSort( SS_GUI );
  77. mbcs = false;
  78. SetupFonts();
  79. activeFont = &fonts[0];
  80. colorPurple = idVec4(1, 0, 1, 1);
  81. colorOrange = idVec4(1, 1, 0, 1);
  82. colorYellow = idVec4(0, 1, 1, 1);
  83. colorGreen = idVec4(0, 1, 0, 1);
  84. colorBlue = idVec4(0, 0, 1, 1);
  85. colorRed = idVec4(1, 0, 0, 1);
  86. colorWhite = idVec4(1, 1, 1, 1);
  87. colorBlack = idVec4(0, 0, 0, 1);
  88. colorNone = idVec4(0, 0, 0, 0);
  89. cursorImages[CURSOR_ARROW] = declManager->FindMaterial("ui/assets/guicursor_arrow.tga");
  90. cursorImages[CURSOR_HAND] = declManager->FindMaterial("ui/assets/guicursor_hand.tga");
  91. scrollBarImages[SCROLLBAR_HBACK] = declManager->FindMaterial("ui/assets/scrollbarh.tga");
  92. scrollBarImages[SCROLLBAR_VBACK] = declManager->FindMaterial("ui/assets/scrollbarv.tga");
  93. scrollBarImages[SCROLLBAR_THUMB] = declManager->FindMaterial("ui/assets/scrollbar_thumb.tga");
  94. scrollBarImages[SCROLLBAR_RIGHT] = declManager->FindMaterial("ui/assets/scrollbar_right.tga");
  95. scrollBarImages[SCROLLBAR_LEFT] = declManager->FindMaterial("ui/assets/scrollbar_left.tga");
  96. scrollBarImages[SCROLLBAR_UP] = declManager->FindMaterial("ui/assets/scrollbar_up.tga");
  97. scrollBarImages[SCROLLBAR_DOWN] = declManager->FindMaterial("ui/assets/scrollbar_down.tga");
  98. cursorImages[CURSOR_ARROW]->SetSort( SS_GUI );
  99. cursorImages[CURSOR_HAND]->SetSort( SS_GUI );
  100. scrollBarImages[SCROLLBAR_HBACK]->SetSort( SS_GUI );
  101. scrollBarImages[SCROLLBAR_VBACK]->SetSort( SS_GUI );
  102. scrollBarImages[SCROLLBAR_THUMB]->SetSort( SS_GUI );
  103. scrollBarImages[SCROLLBAR_RIGHT]->SetSort( SS_GUI );
  104. scrollBarImages[SCROLLBAR_LEFT]->SetSort( SS_GUI );
  105. scrollBarImages[SCROLLBAR_UP]->SetSort( SS_GUI );
  106. scrollBarImages[SCROLLBAR_DOWN]->SetSort( SS_GUI );
  107. cursor = CURSOR_ARROW;
  108. enableClipping = true;
  109. overStrikeMode = true;
  110. mat.Identity();
  111. origin.Zero();
  112. initialized = true;
  113. }
  114. void idDeviceContext::Shutdown() {
  115. fontName.Clear();
  116. clipRects.Clear();
  117. fonts.Clear();
  118. Clear();
  119. }
  120. void idDeviceContext::Clear() {
  121. initialized = false;
  122. useFont = NULL;
  123. activeFont = NULL;
  124. mbcs = false;
  125. }
  126. idDeviceContext::idDeviceContext() {
  127. Clear();
  128. }
  129. void idDeviceContext::SetTransformInfo(const idVec3 &org, const idMat3 &m) {
  130. origin = org;
  131. mat = m;
  132. }
  133. //
  134. // added method
  135. void idDeviceContext::GetTransformInfo(idVec3& org, idMat3& m )
  136. {
  137. m = mat;
  138. org = origin;
  139. }
  140. //
  141. void idDeviceContext::PopClipRect() {
  142. if (clipRects.Num()) {
  143. clipRects.RemoveIndex(clipRects.Num()-1);
  144. }
  145. }
  146. void idDeviceContext::PushClipRect(idRectangle r) {
  147. clipRects.Append(r);
  148. }
  149. void idDeviceContext::PushClipRect(float x, float y, float w, float h) {
  150. clipRects.Append(idRectangle(x, y, w, h));
  151. }
  152. bool idDeviceContext::ClippedCoords(float *x, float *y, float *w, float *h, float *s1, float *t1, float *s2, float *t2) {
  153. if ( enableClipping == false || clipRects.Num() == 0 ) {
  154. return false;
  155. }
  156. int c = clipRects.Num();
  157. while( --c > 0 ) {
  158. idRectangle *clipRect = &clipRects[c];
  159. float ox = *x;
  160. float oy = *y;
  161. float ow = *w;
  162. float oh = *h;
  163. if ( ow <= 0.0f || oh <= 0.0f ) {
  164. break;
  165. }
  166. if (*x < clipRect->x) {
  167. *w -= clipRect->x - *x;
  168. *x = clipRect->x;
  169. } else if (*x > clipRect->x + clipRect->w) {
  170. *x = *w = *y = *h = 0;
  171. }
  172. if (*y < clipRect->y) {
  173. *h -= clipRect->y - *y;
  174. *y = clipRect->y;
  175. } else if (*y > clipRect->y + clipRect->h) {
  176. *x = *w = *y = *h = 0;
  177. }
  178. if (*w > clipRect->w) {
  179. *w = clipRect->w - *x + clipRect->x;
  180. } else if (*x + *w > clipRect->x + clipRect->w) {
  181. *w = clipRect->Right() - *x;
  182. }
  183. if (*h > clipRect->h) {
  184. *h = clipRect->h - *y + clipRect->y;
  185. } else if (*y + *h > clipRect->y + clipRect->h) {
  186. *h = clipRect->Bottom() - *y;
  187. }
  188. if ( s1 && s2 && t1 && t2 && ow > 0.0f ) {
  189. float ns1, ns2, nt1, nt2;
  190. // upper left
  191. float u = ( *x - ox ) / ow;
  192. ns1 = *s1 * ( 1.0f - u ) + *s2 * ( u );
  193. // upper right
  194. u = ( *x + *w - ox ) / ow;
  195. ns2 = *s1 * ( 1.0f - u ) + *s2 * ( u );
  196. // lower left
  197. u = ( *y - oy ) / oh;
  198. nt1 = *t1 * ( 1.0f - u ) + *t2 * ( u );
  199. // lower right
  200. u = ( *y + *h - oy ) / oh;
  201. nt2 = *t1 * ( 1.0f - u ) + *t2 * ( u );
  202. // set values
  203. *s1 = ns1;
  204. *s2 = ns2;
  205. *t1 = nt1;
  206. *t2 = nt2;
  207. }
  208. }
  209. return (*w == 0 || *h == 0) ? true : false;
  210. }
  211. void idDeviceContext::AdjustCoords(float *x, float *y, float *w, float *h) {
  212. if (x) {
  213. *x *= xScale;
  214. }
  215. if (y) {
  216. *y *= yScale;
  217. }
  218. if (w) {
  219. *w *= xScale;
  220. }
  221. if (h) {
  222. *h *= yScale;
  223. }
  224. }
  225. void idDeviceContext::DrawStretchPic(float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *shader) {
  226. idDrawVert verts[4];
  227. glIndex_t indexes[6];
  228. indexes[0] = 3;
  229. indexes[1] = 0;
  230. indexes[2] = 2;
  231. indexes[3] = 2;
  232. indexes[4] = 0;
  233. indexes[5] = 1;
  234. verts[0].xyz[0] = x;
  235. verts[0].xyz[1] = y;
  236. verts[0].xyz[2] = 0;
  237. verts[0].st[0] = s1;
  238. verts[0].st[1] = t1;
  239. verts[0].normal[0] = 0;
  240. verts[0].normal[1] = 0;
  241. verts[0].normal[2] = 1;
  242. verts[0].tangents[0][0] = 1;
  243. verts[0].tangents[0][1] = 0;
  244. verts[0].tangents[0][2] = 0;
  245. verts[0].tangents[1][0] = 0;
  246. verts[0].tangents[1][1] = 1;
  247. verts[0].tangents[1][2] = 0;
  248. verts[1].xyz[0] = x + w;
  249. verts[1].xyz[1] = y;
  250. verts[1].xyz[2] = 0;
  251. verts[1].st[0] = s2;
  252. verts[1].st[1] = t1;
  253. verts[1].normal[0] = 0;
  254. verts[1].normal[1] = 0;
  255. verts[1].normal[2] = 1;
  256. verts[1].tangents[0][0] = 1;
  257. verts[1].tangents[0][1] = 0;
  258. verts[1].tangents[0][2] = 0;
  259. verts[1].tangents[1][0] = 0;
  260. verts[1].tangents[1][1] = 1;
  261. verts[1].tangents[1][2] = 0;
  262. verts[2].xyz[0] = x + w;
  263. verts[2].xyz[1] = y + h;
  264. verts[2].xyz[2] = 0;
  265. verts[2].st[0] = s2;
  266. verts[2].st[1] = t2;
  267. verts[2].normal[0] = 0;
  268. verts[2].normal[1] = 0;
  269. verts[2].normal[2] = 1;
  270. verts[2].tangents[0][0] = 1;
  271. verts[2].tangents[0][1] = 0;
  272. verts[2].tangents[0][2] = 0;
  273. verts[2].tangents[1][0] = 0;
  274. verts[2].tangents[1][1] = 1;
  275. verts[2].tangents[1][2] = 0;
  276. verts[3].xyz[0] = x;
  277. verts[3].xyz[1] = y + h;
  278. verts[3].xyz[2] = 0;
  279. verts[3].st[0] = s1;
  280. verts[3].st[1] = t2;
  281. verts[3].normal[0] = 0;
  282. verts[3].normal[1] = 0;
  283. verts[3].normal[2] = 1;
  284. verts[3].tangents[0][0] = 1;
  285. verts[3].tangents[0][1] = 0;
  286. verts[3].tangents[0][2] = 0;
  287. verts[3].tangents[1][0] = 0;
  288. verts[3].tangents[1][1] = 1;
  289. verts[3].tangents[1][2] = 0;
  290. bool ident = !mat.IsIdentity();
  291. if ( ident ) {
  292. verts[0].xyz -= origin;
  293. verts[0].xyz *= mat;
  294. verts[0].xyz += origin;
  295. verts[1].xyz -= origin;
  296. verts[1].xyz *= mat;
  297. verts[1].xyz += origin;
  298. verts[2].xyz -= origin;
  299. verts[2].xyz *= mat;
  300. verts[2].xyz += origin;
  301. verts[3].xyz -= origin;
  302. verts[3].xyz *= mat;
  303. verts[3].xyz += origin;
  304. }
  305. renderSystem->DrawStretchPic( &verts[0], &indexes[0], 4, 6, shader, ident );
  306. }
  307. void idDeviceContext::DrawMaterial(float x, float y, float w, float h, const idMaterial *mat, const idVec4 &color, float scalex, float scaley) {
  308. renderSystem->SetColor(color);
  309. float s0, s1, t0, t1;
  310. //
  311. // handle negative scales as well
  312. if ( scalex < 0 )
  313. {
  314. w *= -1;
  315. scalex *= -1;
  316. }
  317. if ( scaley < 0 )
  318. {
  319. h *= -1;
  320. scaley *= -1;
  321. }
  322. //
  323. if( w < 0 ) { // flip about vertical
  324. w = -w;
  325. s0 = 1 * scalex;
  326. s1 = 0;
  327. }
  328. else {
  329. s0 = 0;
  330. s1 = 1 * scalex;
  331. }
  332. if( h < 0 ) { // flip about horizontal
  333. h = -h;
  334. t0 = 1 * scaley;
  335. t1 = 0;
  336. }
  337. else {
  338. t0 = 0;
  339. t1 = 1 * scaley;
  340. }
  341. if ( ClippedCoords( &x, &y, &w, &h, &s0, &t0, &s1, &t1 ) ) {
  342. return;
  343. }
  344. AdjustCoords(&x, &y, &w, &h);
  345. DrawStretchPic( x, y, w, h, s0, t0, s1, t1, mat);
  346. }
  347. void idDeviceContext::DrawMaterialRotated(float x, float y, float w, float h, const idMaterial *mat, const idVec4 &color, float scalex, float scaley, float angle) {
  348. renderSystem->SetColor(color);
  349. float s0, s1, t0, t1;
  350. //
  351. // handle negative scales as well
  352. if ( scalex < 0 )
  353. {
  354. w *= -1;
  355. scalex *= -1;
  356. }
  357. if ( scaley < 0 )
  358. {
  359. h *= -1;
  360. scaley *= -1;
  361. }
  362. //
  363. if( w < 0 ) { // flip about vertical
  364. w = -w;
  365. s0 = 1 * scalex;
  366. s1 = 0;
  367. }
  368. else {
  369. s0 = 0;
  370. s1 = 1 * scalex;
  371. }
  372. if( h < 0 ) { // flip about horizontal
  373. h = -h;
  374. t0 = 1 * scaley;
  375. t1 = 0;
  376. }
  377. else {
  378. t0 = 0;
  379. t1 = 1 * scaley;
  380. }
  381. if ( angle == 0.0f && ClippedCoords( &x, &y, &w, &h, &s0, &t0, &s1, &t1 ) ) {
  382. return;
  383. }
  384. AdjustCoords(&x, &y, &w, &h);
  385. DrawStretchPicRotated( x, y, w, h, s0, t0, s1, t1, mat, angle);
  386. }
  387. void idDeviceContext::DrawStretchPicRotated(float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *shader, float angle) {
  388. idDrawVert verts[4];
  389. glIndex_t indexes[6];
  390. indexes[0] = 3;
  391. indexes[1] = 0;
  392. indexes[2] = 2;
  393. indexes[3] = 2;
  394. indexes[4] = 0;
  395. indexes[5] = 1;
  396. verts[0].xyz[0] = x;
  397. verts[0].xyz[1] = y;
  398. verts[0].xyz[2] = 0;
  399. verts[0].st[0] = s1;
  400. verts[0].st[1] = t1;
  401. verts[0].normal[0] = 0;
  402. verts[0].normal[1] = 0;
  403. verts[0].normal[2] = 1;
  404. verts[0].tangents[0][0] = 1;
  405. verts[0].tangents[0][1] = 0;
  406. verts[0].tangents[0][2] = 0;
  407. verts[0].tangents[1][0] = 0;
  408. verts[0].tangents[1][1] = 1;
  409. verts[0].tangents[1][2] = 0;
  410. verts[1].xyz[0] = x + w;
  411. verts[1].xyz[1] = y;
  412. verts[1].xyz[2] = 0;
  413. verts[1].st[0] = s2;
  414. verts[1].st[1] = t1;
  415. verts[1].normal[0] = 0;
  416. verts[1].normal[1] = 0;
  417. verts[1].normal[2] = 1;
  418. verts[1].tangents[0][0] = 1;
  419. verts[1].tangents[0][1] = 0;
  420. verts[1].tangents[0][2] = 0;
  421. verts[1].tangents[1][0] = 0;
  422. verts[1].tangents[1][1] = 1;
  423. verts[1].tangents[1][2] = 0;
  424. verts[2].xyz[0] = x + w;
  425. verts[2].xyz[1] = y + h;
  426. verts[2].xyz[2] = 0;
  427. verts[2].st[0] = s2;
  428. verts[2].st[1] = t2;
  429. verts[2].normal[0] = 0;
  430. verts[2].normal[1] = 0;
  431. verts[2].normal[2] = 1;
  432. verts[2].tangents[0][0] = 1;
  433. verts[2].tangents[0][1] = 0;
  434. verts[2].tangents[0][2] = 0;
  435. verts[2].tangents[1][0] = 0;
  436. verts[2].tangents[1][1] = 1;
  437. verts[2].tangents[1][2] = 0;
  438. verts[3].xyz[0] = x;
  439. verts[3].xyz[1] = y + h;
  440. verts[3].xyz[2] = 0;
  441. verts[3].st[0] = s1;
  442. verts[3].st[1] = t2;
  443. verts[3].normal[0] = 0;
  444. verts[3].normal[1] = 0;
  445. verts[3].normal[2] = 1;
  446. verts[3].tangents[0][0] = 1;
  447. verts[3].tangents[0][1] = 0;
  448. verts[3].tangents[0][2] = 0;
  449. verts[3].tangents[1][0] = 0;
  450. verts[3].tangents[1][1] = 1;
  451. verts[3].tangents[1][2] = 0;
  452. bool ident = !mat.IsIdentity();
  453. if ( ident ) {
  454. verts[0].xyz -= origin;
  455. verts[0].xyz *= mat;
  456. verts[0].xyz += origin;
  457. verts[1].xyz -= origin;
  458. verts[1].xyz *= mat;
  459. verts[1].xyz += origin;
  460. verts[2].xyz -= origin;
  461. verts[2].xyz *= mat;
  462. verts[2].xyz += origin;
  463. verts[3].xyz -= origin;
  464. verts[3].xyz *= mat;
  465. verts[3].xyz += origin;
  466. }
  467. //Generate a translation so we can translate to the center of the image rotate and draw
  468. idVec3 origTrans;
  469. origTrans.x = x+(w/2);
  470. origTrans.y = y+(h/2);
  471. origTrans.z = 0;
  472. //Rotate the verts about the z axis before drawing them
  473. idMat4 rotz;
  474. rotz.Identity();
  475. float sinAng = idMath::Sin(angle);
  476. float cosAng = idMath::Cos(angle);
  477. rotz[0][0] = cosAng;
  478. rotz[0][1] = sinAng;
  479. rotz[1][0] = -sinAng;
  480. rotz[1][1] = cosAng;
  481. for(int i = 0; i < 4; i++) {
  482. //Translate to origin
  483. verts[i].xyz -= origTrans;
  484. //Rotate
  485. verts[i].xyz = rotz * verts[i].xyz;
  486. //Translate back
  487. verts[i].xyz += origTrans;
  488. }
  489. renderSystem->DrawStretchPic( &verts[0], &indexes[0], 4, 6, shader, (angle == 0.0) ? false : true );
  490. }
  491. void idDeviceContext::DrawFilledRect( float x, float y, float w, float h, const idVec4 &color) {
  492. if ( color.w == 0.0f ) {
  493. return;
  494. }
  495. renderSystem->SetColor(color);
  496. if (ClippedCoords(&x, &y, &w, &h, NULL, NULL, NULL, NULL)) {
  497. return;
  498. }
  499. AdjustCoords(&x, &y, &w, &h);
  500. DrawStretchPic( x, y, w, h, 0, 0, 0, 0, whiteImage);
  501. }
  502. void idDeviceContext::DrawRect( float x, float y, float w, float h, float size, const idVec4 &color) {
  503. if ( color.w == 0.0f ) {
  504. return;
  505. }
  506. renderSystem->SetColor(color);
  507. if (ClippedCoords(&x, &y, &w, &h, NULL, NULL, NULL, NULL)) {
  508. return;
  509. }
  510. AdjustCoords(&x, &y, &w, &h);
  511. DrawStretchPic( x, y, size, h, 0, 0, 0, 0, whiteImage );
  512. DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, whiteImage );
  513. DrawStretchPic( x, y, w, size, 0, 0, 0, 0, whiteImage );
  514. DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, whiteImage );
  515. }
  516. void idDeviceContext::DrawMaterialRect( float x, float y, float w, float h, float size, const idMaterial *mat, const idVec4 &color) {
  517. if ( color.w == 0.0f ) {
  518. return;
  519. }
  520. renderSystem->SetColor(color);
  521. DrawMaterial( x, y, size, h, mat, color );
  522. DrawMaterial( x + w - size, y, size, h, mat, color );
  523. DrawMaterial( x, y, w, size, mat, color );
  524. DrawMaterial( x, y + h - size, w, size, mat, color );
  525. }
  526. void idDeviceContext::SetCursor(int n) {
  527. cursor = (n < CURSOR_ARROW || n >= CURSOR_COUNT) ? CURSOR_ARROW : n;
  528. }
  529. void idDeviceContext::DrawCursor(float *x, float *y, float size) {
  530. if (*x < 0) {
  531. *x = 0;
  532. }
  533. if (*x >= vidWidth) {
  534. *x = vidWidth;
  535. }
  536. if (*y < 0) {
  537. *y = 0;
  538. }
  539. if (*y >= vidHeight) {
  540. *y = vidHeight;
  541. }
  542. renderSystem->SetColor(colorWhite);
  543. AdjustCoords(x, y, &size, &size);
  544. DrawStretchPic( *x, *y, size, size, 0, 0, 1, 1, cursorImages[cursor]);
  545. }
  546. /*
  547. =======================================================================================================================
  548. =======================================================================================================================
  549. */
  550. void idDeviceContext::PaintChar(float x,float y,float width,float height,float scale,float s,float t,float s2,float t2,const idMaterial *hShader) {
  551. float w, h;
  552. w = width * scale;
  553. h = height * scale;
  554. if (ClippedCoords(&x, &y, &w, &h, &s, &t, &s2, &t2)) {
  555. return;
  556. }
  557. AdjustCoords(&x, &y, &w, &h);
  558. DrawStretchPic(x, y, w, h, s, t, s2, t2, hShader);
  559. }
  560. void idDeviceContext::SetFontByScale(float scale) {
  561. if (scale <= gui_smallFontLimit.GetFloat()) {
  562. useFont = &activeFont->fontInfoSmall;
  563. activeFont->maxHeight = activeFont->maxHeightSmall;
  564. activeFont->maxWidth = activeFont->maxWidthSmall;
  565. } else if (scale <= gui_mediumFontLimit.GetFloat()) {
  566. useFont = &activeFont->fontInfoMedium;
  567. activeFont->maxHeight = activeFont->maxHeightMedium;
  568. activeFont->maxWidth = activeFont->maxWidthMedium;
  569. } else {
  570. useFont = &activeFont->fontInfoLarge;
  571. activeFont->maxHeight = activeFont->maxHeightLarge;
  572. activeFont->maxWidth = activeFont->maxWidthLarge;
  573. }
  574. }
  575. int idDeviceContext::DrawText(float x, float y, float scale, idVec4 color, const char *text, float adjust, int limit, int style, int cursor) {
  576. int len, count;
  577. idVec4 newColor;
  578. const glyphInfo_t *glyph;
  579. float useScale;
  580. SetFontByScale(scale);
  581. useScale = scale * useFont->glyphScale;
  582. count = 0;
  583. if ( text && color.w != 0.0f ) {
  584. const unsigned char *s = (const unsigned char*)text;
  585. renderSystem->SetColor(color);
  586. memcpy(&newColor[0], &color[0], sizeof(idVec4));
  587. len = strlen(text);
  588. if (limit > 0 && len > limit) {
  589. len = limit;
  590. }
  591. while (s && *s && count < len) {
  592. if ( *s < GLYPH_START || *s > GLYPH_END ) {
  593. s++;
  594. continue;
  595. }
  596. glyph = &useFont->glyphs[*s];
  597. //
  598. // int yadj = Assets.textFont.glyphs[text[i]].bottom +
  599. // Assets.textFont.glyphs[text[i]].top; float yadj = scale *
  600. // (Assets.textFont.glyphs[text[i]].imageHeight -
  601. // Assets.textFont.glyphs[text[i]].height);
  602. //
  603. if ( idStr::IsColor((const char*)s) ) {
  604. if ( *(s+1) == C_COLOR_DEFAULT ) {
  605. newColor = color;
  606. } else {
  607. newColor = idStr::ColorForIndex( *(s+1) );
  608. newColor[3] = color[3];
  609. }
  610. if (cursor == count || cursor == count+1) {
  611. float partialSkip = ((glyph->xSkip * useScale) + adjust) / 5.0f;
  612. if ( cursor == count ) {
  613. partialSkip *= 2.0f;
  614. } else {
  615. renderSystem->SetColor(newColor);
  616. }
  617. DrawEditCursor(x - partialSkip, y, scale);
  618. }
  619. renderSystem->SetColor(newColor);
  620. s += 2;
  621. count += 2;
  622. continue;
  623. } else {
  624. float yadj = useScale * glyph->top;
  625. PaintChar(x,y - yadj,glyph->imageWidth,glyph->imageHeight,useScale,glyph->s,glyph->t,glyph->s2,glyph->t2,glyph->glyph);
  626. if (cursor == count) {
  627. DrawEditCursor(x, y, scale);
  628. }
  629. x += (glyph->xSkip * useScale) + adjust;
  630. s++;
  631. count++;
  632. }
  633. }
  634. if (cursor == len) {
  635. DrawEditCursor(x, y, scale);
  636. }
  637. }
  638. return count;
  639. }
  640. void idDeviceContext::SetSize(float width, float height) {
  641. vidWidth = VIRTUAL_WIDTH;
  642. vidHeight = VIRTUAL_HEIGHT;
  643. xScale = yScale = 0.0f;
  644. if ( width != 0.0f && height != 0.0f ) {
  645. xScale = vidWidth * ( 1.0f / width );
  646. yScale = vidHeight * ( 1.0f / height );
  647. }
  648. }
  649. int idDeviceContext::CharWidth( const char c, float scale ) {
  650. glyphInfo_t *glyph;
  651. float useScale;
  652. SetFontByScale(scale);
  653. fontInfo_t *font = useFont;
  654. useScale = scale * font->glyphScale;
  655. glyph = &font->glyphs[(const unsigned char)c];
  656. return idMath::FtoiFast( glyph->xSkip * useScale );
  657. }
  658. int idDeviceContext::TextWidth( const char *text, float scale, int limit ) {
  659. int i, width;
  660. SetFontByScale( scale );
  661. const glyphInfo_t *glyphs = useFont->glyphs;
  662. if ( text == NULL ) {
  663. return 0;
  664. }
  665. width = 0;
  666. if ( limit > 0 ) {
  667. for ( i = 0; text[i] != '\0' && i < limit; i++ ) {
  668. if ( idStr::IsColor( text + i ) ) {
  669. i++;
  670. } else {
  671. width += glyphs[((const unsigned char *)text)[i]].xSkip;
  672. }
  673. }
  674. } else {
  675. for ( i = 0; text[i] != '\0'; i++ ) {
  676. if ( idStr::IsColor( text + i ) ) {
  677. i++;
  678. } else {
  679. width += glyphs[((const unsigned char *)text)[i]].xSkip;
  680. }
  681. }
  682. }
  683. return idMath::FtoiFast( scale * useFont->glyphScale * width );
  684. }
  685. int idDeviceContext::TextHeight(const char *text, float scale, int limit) {
  686. int len, count;
  687. float max;
  688. glyphInfo_t *glyph;
  689. float useScale;
  690. const char *s = text;
  691. SetFontByScale(scale);
  692. fontInfo_t *font = useFont;
  693. useScale = scale * font->glyphScale;
  694. max = 0;
  695. if (text) {
  696. len = strlen(text);
  697. if (limit > 0 && len > limit) {
  698. len = limit;
  699. }
  700. count = 0;
  701. while (s && *s && count < len) {
  702. if ( idStr::IsColor(s) ) {
  703. s += 2;
  704. continue;
  705. }
  706. else {
  707. glyph = &font->glyphs[*(const unsigned char*)s];
  708. if (max < glyph->height) {
  709. max = glyph->height;
  710. }
  711. s++;
  712. count++;
  713. }
  714. }
  715. }
  716. return idMath::FtoiFast( max * useScale );
  717. }
  718. int idDeviceContext::MaxCharWidth(float scale) {
  719. SetFontByScale(scale);
  720. float useScale = scale * useFont->glyphScale;
  721. return idMath::FtoiFast( activeFont->maxWidth * useScale );
  722. }
  723. int idDeviceContext::MaxCharHeight(float scale) {
  724. SetFontByScale(scale);
  725. float useScale = scale * useFont->glyphScale;
  726. return idMath::FtoiFast( activeFont->maxHeight * useScale );
  727. }
  728. const idMaterial *idDeviceContext::GetScrollBarImage(int index) {
  729. if (index >= SCROLLBAR_HBACK && index < SCROLLBAR_COUNT) {
  730. return scrollBarImages[index];
  731. }
  732. return scrollBarImages[SCROLLBAR_HBACK];
  733. }
  734. // this only supports left aligned text
  735. idRegion *idDeviceContext::GetTextRegion(const char *text, float textScale, idRectangle rectDraw, float xStart, float yStart) {
  736. #if 0
  737. const char *p, *textPtr, *newLinePtr;
  738. char buff[1024];
  739. int len, textWidth, newLine, newLineWidth;
  740. float y;
  741. float charSkip = MaxCharWidth(textScale) + 1;
  742. float lineSkip = MaxCharHeight(textScale);
  743. textWidth = 0;
  744. newLinePtr = NULL;
  745. #endif
  746. return NULL;
  747. /*
  748. if (text == NULL) {
  749. return;
  750. }
  751. textPtr = text;
  752. if (*textPtr == '\0') {
  753. return;
  754. }
  755. y = lineSkip + rectDraw.y + yStart;
  756. len = 0;
  757. buff[0] = '\0';
  758. newLine = 0;
  759. newLineWidth = 0;
  760. p = textPtr;
  761. textWidth = 0;
  762. while (p) {
  763. if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') {
  764. newLine = len;
  765. newLinePtr = p + 1;
  766. newLineWidth = textWidth;
  767. }
  768. if ((newLine && textWidth > rectDraw.w) || *p == '\n' || *p == '\0') {
  769. if (len) {
  770. float x = rectDraw.x ;
  771. buff[newLine] = '\0';
  772. DrawText(x, y, textScale, color, buff, 0, 0, 0);
  773. if (!wrap) {
  774. return;
  775. }
  776. }
  777. if (*p == '\0') {
  778. break;
  779. }
  780. y += lineSkip + 5;
  781. p = newLinePtr;
  782. len = 0;
  783. newLine = 0;
  784. newLineWidth = 0;
  785. continue;
  786. }
  787. buff[len++] = *p++;
  788. buff[len] = '\0';
  789. textWidth = TextWidth( buff, textScale, -1 );
  790. }
  791. */
  792. }
  793. void idDeviceContext::DrawEditCursor( float x, float y, float scale ) {
  794. if ( (int)( com_ticNumber >> 4 ) & 1 ) {
  795. return;
  796. }
  797. SetFontByScale(scale);
  798. float useScale = scale * useFont->glyphScale;
  799. const glyphInfo_t *glyph2 = &useFont->glyphs[(overStrikeMode) ? '_' : '|'];
  800. float yadj = useScale * glyph2->top;
  801. PaintChar(x, y - yadj,glyph2->imageWidth,glyph2->imageHeight,useScale,glyph2->s,glyph2->t,glyph2->s2,glyph2->t2,glyph2->glyph);
  802. }
  803. 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 ) {
  804. const char *p, *textPtr, *newLinePtr;
  805. char buff[1024];
  806. int len, newLine, newLineWidth, count;
  807. float y;
  808. float textWidth;
  809. float charSkip = MaxCharWidth( textScale ) + 1;
  810. float lineSkip = MaxCharHeight( textScale );
  811. float cursorSkip = ( cursor >= 0 ? charSkip : 0 );
  812. bool lineBreak, wordBreak;
  813. SetFontByScale( textScale );
  814. textWidth = 0;
  815. newLinePtr = NULL;
  816. if (!calcOnly && !(text && *text)) {
  817. if (cursor == 0) {
  818. renderSystem->SetColor(color);
  819. DrawEditCursor(rectDraw.x, lineSkip + rectDraw.y, textScale);
  820. }
  821. return idMath::FtoiFast( rectDraw.w / charSkip );
  822. }
  823. textPtr = text;
  824. y = lineSkip + rectDraw.y;
  825. len = 0;
  826. buff[0] = '\0';
  827. newLine = 0;
  828. newLineWidth = 0;
  829. p = textPtr;
  830. if ( breaks ) {
  831. breaks->Append(0);
  832. }
  833. count = 0;
  834. textWidth = 0;
  835. lineBreak = false;
  836. wordBreak = false;
  837. while (p) {
  838. if ( *p == '\n' || *p == '\r' || *p == '\0' ) {
  839. lineBreak = true;
  840. if ((*p == '\n' && *(p + 1) == '\r') || (*p == '\r' && *(p + 1) == '\n')) {
  841. p++;
  842. }
  843. }
  844. int nextCharWidth = ( idStr::CharIsPrintable(*p) ? CharWidth( *p, textScale ) : cursorSkip );
  845. // FIXME: this is a temp hack until the guis can be fixed not not overflow the bounding rectangles
  846. // the side-effect is that list boxes and edit boxes will draw over their scroll bars
  847. // The following line and the !linebreak in the if statement below should be removed
  848. nextCharWidth = 0;
  849. if ( !lineBreak && ( textWidth + nextCharWidth ) > rectDraw.w ) {
  850. // The next character will cause us to overflow, if we haven't yet found a suitable
  851. // break spot, set it to be this character
  852. if ( len > 0 && newLine == 0 ) {
  853. newLine = len;
  854. newLinePtr = p;
  855. newLineWidth = textWidth;
  856. }
  857. wordBreak = true;
  858. } else if ( lineBreak || ( wrap && (*p == ' ' || *p == '\t') ) ) {
  859. // The next character is in view, so if we are a break character, store our position
  860. newLine = len;
  861. newLinePtr = p + 1;
  862. newLineWidth = textWidth;
  863. }
  864. if ( lineBreak || wordBreak ) {
  865. float x = rectDraw.x;
  866. if (textAlign == ALIGN_RIGHT) {
  867. x = rectDraw.x + rectDraw.w - newLineWidth;
  868. } else if (textAlign == ALIGN_CENTER) {
  869. x = rectDraw.x + (rectDraw.w - newLineWidth) / 2;
  870. }
  871. if ( wrap || newLine > 0 ) {
  872. buff[newLine] = '\0';
  873. // This is a special case to handle breaking in the middle of a word.
  874. // if we didn't do this, the cursor would appear on the end of this line
  875. // and the beginning of the next.
  876. if ( wordBreak && cursor >= newLine && newLine == len ) {
  877. cursor++;
  878. }
  879. }
  880. if (!calcOnly) {
  881. count += DrawText(x, y, textScale, color, buff, 0, 0, 0, cursor);
  882. }
  883. if ( cursor < newLine ) {
  884. cursor = -1;
  885. } else if ( cursor >= 0 ) {
  886. cursor -= ( newLine + 1 );
  887. }
  888. if ( !wrap ) {
  889. return newLine;
  890. }
  891. if ( ( limit && count > limit ) || *p == '\0' ) {
  892. break;
  893. }
  894. y += lineSkip + 5;
  895. if ( !calcOnly && y > rectDraw.Bottom() ) {
  896. break;
  897. }
  898. p = newLinePtr;
  899. if (breaks) {
  900. breaks->Append(p - text);
  901. }
  902. len = 0;
  903. newLine = 0;
  904. newLineWidth = 0;
  905. textWidth = 0;
  906. lineBreak = false;
  907. wordBreak = false;
  908. continue;
  909. }
  910. buff[len++] = *p++;
  911. buff[len] = '\0';
  912. // update the width
  913. if ( *( buff + len - 1 ) != C_COLOR_ESCAPE && (len <= 1 || *( buff + len - 2 ) != C_COLOR_ESCAPE)) {
  914. textWidth += textScale * useFont->glyphScale * useFont->glyphs[ (const unsigned char)*( buff + len - 1 ) ].xSkip;
  915. }
  916. }
  917. return idMath::FtoiFast( rectDraw.w / charSkip );
  918. }
  919. /*
  920. =============
  921. idRectangle::String
  922. =============
  923. */
  924. char *idRectangle::String( void ) const {
  925. static int index = 0;
  926. static char str[ 8 ][ 48 ];
  927. char *s;
  928. // use an array so that multiple toString's won't collide
  929. s = str[ index ];
  930. index = (index + 1)&7;
  931. sprintf( s, "%.2f %.2f %.2f %.2f", x, y, w, h );
  932. return s;
  933. }