renderColours.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. // We have reduced the renderer to just 2 phases: specifiers and visuals, where
  2. // the second phase does both colours and new lines in parallel. As a result,
  3. // the positions update code is vastly simplified because we only need to track
  4. // one phase not more - there is no need to update the first phase while it is
  5. // running.
  6. #if !defined Y_TEXT_MAX_COLOUR_EMBEDS
  7. #if defined Y_TEXT_MAX_COLOR_EMBEDS
  8. #define Y_TEXT_MAX_COLOUR_EMBEDS (Y_TEXT_MAX_COLOR_EMBEDS)
  9. #else
  10. #define Y_TEXT_MAX_COLOUR_EMBEDS (128)
  11. #endif
  12. #endif
  13. enum e_TEXT_RENDER_COLOUR
  14. {
  15. e_TEXT_RENDER_COLOUR_END = 0x01000000, // {/}
  16. e_TEXT_RENDER_COLOUR_FADE = 0x00010000, // {>XXXXXX}
  17. e_TEXT_RENDER_COLOUR_STAR = 0x00000100, // {*}
  18. e_TEXT_RENDER_COLOUR_LINE = 0x00000001, // \n, \r, \r\n
  19. e_TEXT_RENDER_COLOUR_MASK = 0xFEFEFEFE,
  20. e_TEXT_RENDER_COLOUR_FLAG = 0x01010101
  21. }
  22. // This function takes a list of positions in a string, and the length and
  23. // position of a new string inserted in to the original string, and returns a
  24. // list of positions adjusted for after that insertion. The input is actually a
  25. // list of relative jumps, and the output is a progressively updated list of
  26. // absolute locations. The input and output also includes additional data, but
  27. // this data is not in a 2D array but all concatenated.
  28. Y_TEXT_STATIC stock TextR_UpdateRelToAbs(rel[], abs[], &idx, addition, insertPos)
  29. {
  30. // rel = 5 5 7 8 0
  31. // old = 0 5 10 17 25
  32. // idx = 0
  33. // add = 11
  34. // isp = 7
  35. // idx = 2
  36. // add = 3
  37. // isp = 30
  38. // idx = 4
  39. // add = 3
  40. // isp = 32
  41. // abs = 0 5 21 28 42
  42. new
  43. pos = abs[idx];
  44. while (pos <= insertPos)
  45. {
  46. if (!rel[idx]) return;
  47. pos += rel[idx++],
  48. abs[idx] = rel[idx], // First slot is data.
  49. abs[++idx] = pos; // Second slot is insertion point.
  50. }
  51. abs[idx] += addition;
  52. }
  53. Y_TEXT_STATIC stock TextR_CompleteRelToAbs(rel[], abs[], &idx)
  54. {
  55. // Afterwards (to complete any stragglers). The function above only updates
  56. // the list and converts relative jumps to absolute ones as long as there is
  57. // processing left to do on specifiers. If we run out of specifiers before
  58. // the relative jumps have been converted, then we need to finish them off
  59. // explicitly.
  60. new
  61. pos = abs[idx];
  62. while (rel[idx])
  63. {
  64. pos += rel[idx++],
  65. abs[idx] = rel[idx],
  66. abs[++idx] = pos;
  67. }
  68. abs[0] = idx; // Save the length just in case.
  69. }
  70. Y_TEXT_STATIC stock TextR_Render(string:str[], colourList[])
  71. {
  72. static
  73. colourLocations[Y_TEXT_MAX_COLOUR_EMBEDS];
  74. new
  75. colourIdx;
  76. ////////////////////////////////////////////////////////////////////////////
  77. ////////////////////////////////////////////////////////////////////////////
  78. //// ////
  79. //// PHASE 1 - SPECIFIERS ////
  80. //// ////
  81. ////////////////////////////////////////////////////////////////////////////
  82. ////////////////////////////////////////////////////////////////////////////
  83. // There is an embedded linked list of locations of specifiers.
  84. for (new off = str[0], pos, ins; off; )
  85. {
  86. // Jump to the next location.
  87. pos = pos + off + ins;
  88. // Get the next specifier relative offset.
  89. off = str[pos];
  90. // Do this specifier. Returns number of bytes the string GREW by, that
  91. // may not be the number of characters written, nor may it be positive.
  92. ins = TextR_DoSpecifier(str[pos]);
  93. // Update the other linked lists to account for this new data.
  94. TextR_UpdateRelToAbs(colourList, colourLocations, colourIdx, ins, pos);
  95. }
  96. // Copy the remaining relative locations over.
  97. TextR_CompleteRelToAbs(colourList, colourLocations, colourIdx);
  98. ////////////////////////////////////////////////////////////////////////////
  99. ////////////////////////////////////////////////////////////////////////////
  100. //// ////
  101. //// PHASE 2 - COLORS ////
  102. //// ////
  103. ////////////////////////////////////////////////////////////////////////////
  104. ////////////////////////////////////////////////////////////////////////////
  105. // Note that "colours" is spelt "colors" above PURELY for symmetry.
  106. new
  107. offset = 0;
  108. // Loop over the linked list of absolute colour locations.
  109. for (new i = 1; i < colourIdx; i += 2)
  110. {
  111. // Get the colour to be displayed, and where it is to be displayed.
  112. // new
  113. // col = colourLocations[i++],
  114. // pos = colourLocations[i++] + offset;
  115. // As we loop through the string, our offsets get bigger and bigger
  116. offset += TextR_DoColour(str, offset, colourLocations, i, colourIdx);
  117. }
  118. }
  119. /*Y_TEXT_STATIC stock TextR_DoColour(string:str[], offset, colourLocations[], i, colourIdx)
  120. {
  121. new
  122. c = colourLocations[i++],
  123. pos = colourLocations[i++];
  124. }*/
  125. /**
  126. Get the colour at the end of a fade area, ignoring any spaces.
  127. **/
  128. /*Y_TEXT_STATIC stock TextR_GetFadeEnd(colourLocations[], start)
  129. {
  130. do
  131. {
  132. start += 2;
  133. }
  134. while (colourLocations[start] & 1);
  135. return colourLocations[start];
  136. }
  137. / **
  138. Get the length of a fade, before any newlines are applied.
  139. ** /
  140. Y_TEXT_STATIC stock TextR_GetFadeLen(colourLocations[], start)
  141. {
  142. new
  143. len = colourLocations[start + 1];
  144. do
  145. {
  146. start += 2;
  147. }
  148. while (colourLocations[start] & 1);
  149. return colourLocations[start + 1] - len;
  150. }
  151. / **
  152. Get the number of newlines within a fade.
  153. ** /
  154. Y_TEXT_STATIC stock TextR_GetFadeNLs(colourLocations[], start)
  155. {
  156. new
  157. nls = -1;
  158. do
  159. {
  160. start += 2,
  161. ++nls;
  162. }
  163. while (colourLocations[start] & 1);
  164. return nls;
  165. }*/
  166. /**
  167. Get all information about the extent of this fade.
  168. **/
  169. Y_TEXT_STATIC stock TextR_GetFadeData(colourLocations[], start, &endColour, &endPos, &newLines)
  170. {
  171. newLines = 0;
  172. for ( ; ; )
  173. {
  174. // These lines are not mutually exclusive.
  175. if (colourLocations[start - 1] & _:e_TEXT_RENDER_COLOUR_LINE) ++newLines;
  176. // Don't check for an end condition, just don't fail!
  177. start += 2;
  178. // New lines at the END of a fade don't count as being IN the fade, so
  179. // we can do the increment in the middle of the loop.
  180. if (colourLocations[start - 1] & ~_:e_TEXT_RENDER_COLOUR_LINE)
  181. {
  182. endColour = colourLocations[start - 1],
  183. endPos = colourLocations[start];
  184. return;
  185. }
  186. }
  187. }
  188. // Don't call this with an offset.
  189. Y_TEXT_STATIC stock TextR_GetColourAtPoint(pos, colourLocations[])
  190. {
  191. }
  192. Y_TEXT_STATIC stock TextR_DoSpecifier(string:str[])
  193. {
  194. // Resolve what the specifier is, including all its parameters (which may be
  195. // very complex, indeed, variable length).
  196. new
  197. len = 0,
  198. headerLen = 2,
  199. header = str[1];
  200. // Look at the header and get more information...
  201. // Return the number of characters inserted, minus the length of the header.
  202. return len - headerLen;
  203. }
  204. // Relatives.
  205. /*
  206. new
  207. nextUpdate = curUpdate + 1,
  208. nexPos = dst[nextUpdate] = src[curUpdate] + dst[curUpdate] + addition;
  209. */
  210. // Colours are stored in a very unique manner (at least I've never seen it
  211. // before). Most people can't tell the difference visually between, say,
  212. // 0x286A44FF and 0x286A45FF (it's hard enough to read the difference). There
  213. // is just one bit different, and that is the LSB of the Blue component, meaning
  214. // that it makes a trivial contribution to the colour displayed. If we use
  215. // these LSBs for something else, then it doesn't matter if they are set or not
  216. // for the display of the colour, and we can instead get 4 bit flags embedded
  217. // within the colour.
  218. /*
  219. if (c == e_TEXT_RENDER_COLOUR_LINE)
  220. {
  221. // New line.
  222. }
  223. else
  224. {
  225. // Actually a colour.
  226. switch (c & e_TEXT_RENDER_COLOUR_FLAG)
  227. {
  228. case e_TEXT_RENDER_COLOUR_END:
  229. c = original;
  230. case e_TEXT_RENDER_COLOUR_FADE:
  231. fade = true;
  232. case e_TEXT_RENDER_COLOUR_STAR:
  233. c = GetNextParam();
  234. case e_TEXT_RENDER_COLOUR_FADE | e_TEXT_RENDER_COLOUR_END:
  235. c = original, fade = true;
  236. case e_TEXT_RENDER_COLOUR_FADE | e_TEXT_RENDER_COLOUR_STAR:
  237. c = GetNextParam(), fade = true;
  238. // No other combinations are valid.
  239. }
  240. }
  241. */
  242. Y_TEXT_STATIC stock TextR_InsertColour(str[], len, pos, &oldColour, newColour, &bool:pending) <y_text_colour : y_text_colour_gt>
  243. {
  244. new
  245. oldType = oldColour & 0xFF,
  246. oldLite = oldColour >>> 8,
  247. nc = Colours_SAMPToGT(newColour >>> 8, (oldType == 0 || oldType == 'x') ? (oldLite) : (3)),
  248. newType = nc & 0xFF,
  249. newLite = nc >>> 8;
  250. static const
  251. cs_hTags[] = "~x~~h~~h~~h~~h~~h~%s";
  252. if (newType == oldType || newType == 'x')
  253. {
  254. // We don't need to output the type when the colour is 'x'.
  255. oldLite = (newLite - oldLite) * 3;
  256. if (oldLite == 0) return 0; // The two are identical.
  257. else if (oldLite > 0)
  258. {
  259. // Only need add some more "~h~"s.
  260. return
  261. format(str[pos], len - pos, cs_hTags[sizeof (cs_hTags) - 3 - oldLite], str[pos]),
  262. oldColour = nc,
  263. oldLite;
  264. }
  265. }
  266. // Need a whole new colour outputting.
  267. return
  268. newLite *= 3,
  269. format(str[pos], len - pos, cs_hTags[sizeof (cs_hTags) - 6 - newLite], str[pos]),
  270. str[pos + 1] = newType,
  271. oldColour = nc,
  272. 3 + newLite;
  273. }
  274. /**
  275. <summary>TextR_InsertColour</summary>
  276. <param name="str">The string we are inserting a colour in to.</param>
  277. <param name="len">The total length of this string.</param>
  278. <param name="pos">The position in the string we want to insert at.</param>
  279. <param name="oldColour">The previous colour for comparison.</param>
  280. <param name="newColour">The new colour to insert.</param>
  281. <param name="pending">Don't write if this colour is followed by a space.</param>
  282. <remarks>
  283. The format "oldColour" is not constant between different state versions
  284. of this function, it is determined purely by what display mode is in use.
  285. On the other hand, "newColour" is always "RRGGBBAA" with component LSBs used
  286. for formatting flags.
  287. </remarks>
  288. **/
  289. Y_TEXT_STATIC stock TextR_InsertColour(str[], len, pos, &oldColour, newColour, &bool:pending) <y_text_colour : y_text_colour_scm>
  290. {
  291. // Insert a colour of the form "{RRGGBB}".
  292. newColour &= (_:e_TEXT_RENDER_COLOUR_MASK & 0xFFFFFF00); // SCM ignores alpha.
  293. P:4("TextR_InsertColour: \"%s\", %i, %i, %04x%04x, %04x%04x, %d", str, len, pos, oldColour >>> 16, oldColour & 0xFFFF, newColour >> 16, newColour & 0xFFFF, pending);
  294. if (oldColour != newColour) // Don't insert at the end.
  295. {
  296. P:7("TextR_InsertColour: STATE 1");
  297. // Don't write any colour out if this colour is followed by a space,
  298. // instead just mark it as pending.
  299. if (str[pos] <= ' ')
  300. {
  301. P:7("TextR_InsertColour: STATE 2");
  302. return
  303. pending = true,
  304. 0;
  305. // Don't set the new colour as the old colour here, to handle this:
  306. //
  307. // {FFAA00}Hi{556677} {FFAA00}There
  308. //
  309. // Without saving the pending old colour, we will just output:
  310. //
  311. // {FFAA00}Hi There
  312. //
  313. // Even less if this is the start of the output; instead we will
  314. // just use the colour in SendClientMessage:
  315. //
  316. // Hi There
  317. //
  318. }
  319. P:7("TextR_InsertColour: STATE 3");
  320. // The colour has changed, we may be able to do this to a greater degree
  321. // by relaxing the conditions on when the two colours are considered the
  322. // same, i.e. when they are within a certain range of each other. I
  323. // might make that determined by the 2 LSBs.
  324. return
  325. pending = false,
  326. format(str[pos], len - pos, "{%06x}%s", newColour >>> 8, str[pos]),
  327. oldColour = newColour,
  328. // Return the inserted length.
  329. 8;
  330. }
  331. P:7("TextR_InsertColour: STATE 4");
  332. return
  333. pending = false,
  334. 0;
  335. }
  336. Y_TEXT_STATIC stock TextR_DoStraightFade(str[], len, &oldColour, startPos, startColour, fadeLen, endColour, &bool:pending)
  337. {
  338. // This function does fades between two points when there are no newlines
  339. // between the fade points.
  340. new
  341. // The individual components of the start colour.
  342. sr = startColour >>> 24,
  343. sg = (startColour >>> 16) & 0xFF,
  344. sb = (startColour >>> 8) & 0xFF,
  345. // The differences between the individual components.
  346. dr = ( endColour >>> 24) - sr,
  347. dg = ((endColour >>> 16) & 0xFF) - sg,
  348. db = ((endColour >>> 8) & 0xFF) - sb;
  349. // Fake variables to save memory, while keeping names.
  350. #define inserted endColour
  351. #define taglen startColour
  352. inserted = 0; // Now amount of data inserted.
  353. // Loop over all the points between the ends.
  354. for (new step = 0; step != fadeLen; ++step)
  355. {
  356. // Don't colour spaces, there is exactly zero point! In this case we
  357. // DON'T copy over the new colour as the existing colour. We also know
  358. // that the very next character will also be coloured, so we don't need
  359. // to worry about the wrong colour being used in the future.
  360. // if (str[startPos] <= ' ') { ++startPos; continue; }
  361. // Use the existing insertion function to do the hard work.
  362. taglen = TextR_InsertColour(str, len, startPos, oldColour,
  363. // These components look like they should be optimisable, but they
  364. // aren't, because we are doing integer divisions so "a * b / c" is
  365. // slightly different to "a * (b / c)", ergo we can't precompute
  366. // parts like "dr / fadeLen".
  367. (((dr * step / fadeLen + sr) & 0xFF) << 24) |
  368. (((dg * step / fadeLen + sg) & 0xFF) << 16) |
  369. (((db * step / fadeLen + sb) & 0xFF) << 8 ), pending),
  370. inserted += taglen,
  371. // Increment to the next insertion point.
  372. startPos += taglen + 1;
  373. }
  374. return inserted;
  375. #undef inserted
  376. #undef taglen
  377. }
  378. Y_TEXT_STATIC stock TextR_DoNLFade(str[], len, &oldColour, startPos, startColour, fadeLen, endColour, colourLocations[], idx, &bool:pending)
  379. {
  380. // This function does fades between two points when there ARE newlines
  381. // between the fade points. First, see if the first item is ALSO a new
  382. // line.
  383. if (!(colourLocations[idx - 1] & _:e_TEXT_RENDER_COLOUR_LINE)) idx += 2;
  384. // Now do all the normal code.
  385. new
  386. // The individual components of the start colour.
  387. sr = startColour >>> 24,
  388. sg = (startColour >>> 16) & 0xFF,
  389. sb = (startColour >>> 8) & 0xFF,
  390. // The differences between the individual components.
  391. dr = ( endColour >>> 24) - sr,
  392. dg = ((endColour >>> 16) & 0xFF) - sg,
  393. db = ((endColour >>> 8) & 0xFF) - sb;
  394. // Fake variables to save memory, while keeping names.
  395. #define inserted endColour
  396. #define taglen startColour
  397. inserted = 0;
  398. // Loop over all the points between the ends.
  399. for (new step = 0, colour; step != fadeLen; ++step)
  400. {
  401. // These components look like they should be optimisable, but they
  402. // aren't, because we are doing integer divisions so "a * b / c" is
  403. // slightly different to "a * (b / c)", ergo we can't precompute parts
  404. // like "dr / fadeLen".
  405. colour =
  406. (((dr * step / fadeLen + sr) & 0xFF) << 24) |
  407. (((dg * step / fadeLen + sg) & 0xFF) << 16) |
  408. (((db * step / fadeLen + sb) & 0xFF) << 8 ) ;
  409. P:7("TextR_DoNLFade: step %d = %06x", step, colour >>> 8);
  410. P:7("TextR_DoNLFade: insert %d, %d, %d", startPos, colourLocations[idx], inserted);
  411. // Check for new lines, and update their locations accordingly.
  412. if (startPos == colourLocations[idx] + inserted)
  413. {
  414. // We don't need to check for the end colour because we don't loop
  415. // that far. This is only triggered by new lines. Note that it
  416. // would be triggered by the start point as well, but we make
  417. // explicit checks for that before the loop because that is the only
  418. // one that needs the checks so we can save time there.
  419. colourLocations[idx] += inserted,
  420. // We have found a new line - save what colour should appear at this
  421. // point, but don't write it out to the string.
  422. colourLocations[idx - 1] = (colour & _:e_TEXT_RENDER_COLOUR_MASK) | _:e_TEXT_RENDER_COLOUR_LINE,
  423. idx += 2,
  424. pending = false,
  425. ++startPos;
  426. }
  427. else
  428. {
  429. // Use the existing insertion function to do the hard work.
  430. P:7("TextR_DoNLFade: %s %d %d %d %d %d", str, len, startPos, oldColour, colour, pending);
  431. taglen = TextR_InsertColour(str, len, startPos, oldColour, colour, pending);
  432. P:7("TextR_DoNLFade: done");
  433. inserted += taglen,
  434. // Increment to the next insertion point.
  435. startPos += taglen + 1;
  436. }
  437. }
  438. return inserted;
  439. #undef inserted
  440. #undef taglen
  441. }
  442. // Originally called "TextR_3f9qzz11", because that was dictated to me by
  443. // someone that can't code, on a plane.
  444. // Y_TEXT_STATIC stock TextR_()
  445. // {
  446. // }
  447. Y_TEXT_STATIC stock TextR_ResolvePending(str[], len, pos, colourLocations[], idx, colour)
  448. {
  449. new
  450. endPos = colourLocations[idx];
  451. while (pos < endPos && str[pos])
  452. {
  453. if (str[pos] <= ' ') ++pos;
  454. else
  455. {
  456. return
  457. // Make it as different as possible quickly.
  458. endPos = ~colour,
  459. // If we have a "pending" colour, then we know that it is
  460. // different to the last colour, because that is how pendings
  461. //are triggered.
  462. TextR_InsertColour(str, len, pos, endPos, colour, bool:idx);
  463. // We know the colour is different, and we know we aren't
  464. // somewhere that will trigger a pending hit, so there's no
  465. // point saving all that data anywhere but here. As a result,
  466. // we re-use "idx" and "endPos" because they aren't needed any
  467. // more.
  468. }
  469. }
  470. // Reached the next colour item - discard this current one. We aren't in a
  471. // fade so any new lines already have a colour assigned.
  472. return 0;
  473. }
  474. Y_TEXT_STATIC stock TextR_GetSlotColour(slot, originalColour, currentColour)
  475. {
  476. if (slot & _:e_TEXT_RENDER_COLOUR_END) return originalColour;
  477. else if (slot & _:e_TEXT_RENDER_COLOUR_STAR) return 0xFEFEFE00; // TODO:.
  478. // "&=", not "&" - not a typo!
  479. else if ((slot &= _:e_TEXT_RENDER_COLOUR_MASK)) return slot;
  480. return currentColour;
  481. }
  482. /*
  483. Y_TEXT_STATIC stock TextR_Render(players, str[], start, end, colour) <y_text_display : y_text_display_scm>
  484. {
  485. #pragma unused players, str, start, end, colour
  486. return 0;
  487. }
  488. Y_TEXT_STATIC stock TextR_Render(players, str[], start, end, colour) <y_text_display : y_text_display_print>
  489. {
  490. #pragma unused players
  491. new
  492. ch = str[end];
  493. return
  494. str[end] = '\0',
  495. P:0("TextR_Render: 0x%04x%04x \"%s\"", colour >>> 16, colour & 0xFFFF, str[start]),
  496. str[end] = ch;
  497. }
  498. */
  499. Y_TEXT_STATIC stock TextR_DoOneColour(str[], len, offset, colourLocations[], &idx, &curColour, initialColour, &pending)
  500. {
  501. new
  502. pos = colourLocations[idx],
  503. flags = colourLocations[idx - 1],
  504. col = TextR_GetSlotColour(flags, initialColour, curColour);
  505. idx += 2;
  506. if (flags & _:e_TEXT_RENDER_COLOUR_FADE)
  507. {
  508. new
  509. endColour,
  510. endPos,
  511. newLines,
  512. TextR_GetFadeData(colourLocations, idx, endColour, endPos, newLines);
  513. if (newLines)
  514. return TextR_DoNLFade(str, len, curColour, pos + offset, col, endPos - pos, TextR_GetSlotColour(endColour, initialColour, curColour), colourLocations, idx, pending);
  515. else
  516. return TextR_DoStraightFade(str, len, curColour, pos + offset, col, endPos - pos, TextR_GetSlotColour(endColour, initialColour, curColour), pending);
  517. }
  518. else if (flags & _:e_TEXT_RENDER_COLOUR_LINE)
  519. {
  520. // Don't do any output here.
  521. return
  522. colourLocations[idx - 3] = col | _:e_TEXT_RENDER_COLOUR_LINE,
  523. 0;
  524. }
  525. return TextR_InsertColour(str, len, pos + offset, curColour, col, pending);
  526. }
  527. #endinput
  528. Y_TEXT_STATIC stock TextR_DoColours(str[], len, colourLocations[], startColour)
  529. {
  530. new
  531. curColour = startColour,
  532. idx = 2;
  533. while (colourLocations[idx])
  534. {
  535. new
  536. bool:pending = false,
  537. colour = colourLocations[idx - 1];
  538. // Is a colour.
  539. if (colour & _:e_TEXT_RENDER_COLOUR_FADE)
  540. {
  541. // Do the fading.
  542. new
  543. endColour
  544. }
  545. switch (e_TEXT_RENDER_COLOUR:colour & e_TEXT_RENDER_COLOUR_FLAG)
  546. {
  547. //case e_TEXT_RENDER_COLOUR_LINE:
  548. case e_TEXT_RENDER_COLOUR_END:
  549. curColour = startColour;
  550. case e_TEXT_RENDER_COLOUR_FADE:
  551. fade = true;
  552. case e_TEXT_RENDER_COLOUR_STAR:
  553. c = GetNextParam();
  554. case e_TEXT_RENDER_COLOUR_FADE | e_TEXT_RENDER_COLOUR_END:
  555. c = original, fade = true;
  556. case e_TEXT_RENDER_COLOUR_FADE | e_TEXT_RENDER_COLOUR_STAR:
  557. c = GetNextParam(), fade = true;
  558. // No other combinations are valid.
  559. }
  560. idx += 2;
  561. }
  562. }
  563. #endinput
  564. LOOP OVER ALL
  565. DO NEXT COLOUR
  566. if (pending)
  567. {
  568. offset += TextR_ResolvePending(str, sizeof (str), pos, colourLocations, colourIdx, newColour);
  569. }
  570. TextR_DoOneColour(str[], len, &pos, &curColour, colourLocations[], &idx, originalColour)
  571. {
  572. new
  573. colour = colourLocations[idx - 1],
  574. rc; // The colour to output.
  575. if (colour & _:e_TEXT_RENDER_COLOUR_FADE)
  576. {
  577. // Start of a fade.
  578. }
  579. switch (e_TEXT_RENDER_COLOUR:colour & ~e_TEXT_RENDER_COLOUR_FADE)
  580. {
  581. // Ending a colour, get the original.
  582. case e_TEXT_RENDER_COLOUR_END: rc = originalColour;
  583. // Starting a new line with the original colour. Exit.
  584. case e_TEXT_RENDER_COLOUR_END | e_TEXT_RENDER_COLOUR_LINE:
  585. {
  586. return
  587. colourLocations[idx - 1] = originalColour | _:e_TEXT_RENDER_COLOUR_LINE,
  588. idx += 2,
  589. 0;
  590. }
  591. // Getting a colour parameter.
  592. case e_TEXT_RENDER_COLOUR_STAR: rc = (0xFEFEFE00 & _:e_TEXT_RENDER_COLOUR_MASK); // TODO: Get the relevant parameter.
  593. // Starting a new line with a colour parameter. Exit.
  594. case e_TEXT_RENDER_COLOUR_STAR | e_TEXT_RENDER_COLOUR_LINE:
  595. {
  596. return
  597. // TODO: Get the relevant parameter.
  598. // HOORAY! Global state has snuck in!
  599. colourLocations[idx - 1] = (0xFEFEFE00 & _:e_TEXT_RENDER_COLOUR_MASK) | _:e_TEXT_RENDER_COLOUR_LINE,
  600. idx += 2,
  601. 0;
  602. }
  603. // Starting a new line with no other data. Get current colour. Exit.
  604. case e_TEXT_RENDER_COLOUR_LINE:
  605. {
  606. return
  607. colourLocations[idx - 1] = curColour | _:e_TEXT_RENDER_COLOUR_LINE,
  608. idx += 2,
  609. 0;
  610. }
  611. // Specified colour, may end a line.
  612. default:
  613. {
  614. if (colour & _:e_TEXT_RENDER_COLOUR_LINE) return idx += 2, 0;
  615. else rc = colour;
  616. }
  617. }
  618. // This code does not AT ALL work for fades!
  619. }
  620. // I think we need to do newlines in a separate pass, and worry about getting
  621. // what colour it is at the time - this shouldn't actually be THAT hard! At
  622. // least vastly simpler than the alternative! In fact, in many cases it will
  623. // be quite easy and we can just keep a record of the times when we need to do
  624. // the more complex method, otherwise we just stick to the simple one.
  625. enum E_RENDERING_DATA
  626. {
  627. PlayerArray:E_RENDERING_DATA_PLAYERS<MAX_PLAYERS>, // Language players.
  628. E_RENDERING_DATA_ORIGINAL_COL, // Colour originally set.
  629. E_RENDERING_DATA_DISPLAY_COL // Colour to start the next line with.
  630. }
  631. {
  632. if (IS_NEW_LINE) // This entry is a new line.
  633. {
  634. // Output a new line, and change the initial display colour.
  635. if (TOO_LONG_SINCE_LAST) // Too long since the last new line.
  636. {
  637. // Mark as needing more complex processing.
  638. }
  639. else
  640. {
  641. // Do simple output.
  642. }
  643. }
  644. if (IS_COLOUR)
  645. {
  646. // Stop fading.
  647. }
  648. }