FONTEDIT.CPP 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. /*******************************************************************************
  2. FILE: FONTEDIT.CPP
  3. DESCRIPTION: Allows editing of 2D animation sequences
  4. AUTHOR: Nicholas C. Newhard
  5. CREATED: 11-30-95
  6. COPYRIGHT: Copyright (c) 1995 Q Studios Corporation
  7. *******************************************************************************/
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <helix.h>
  11. #include <string.h>
  12. #include <io.h>
  13. #include <fcntl.h>
  14. #include "typedefs.h"
  15. #include "engine.h"
  16. #include "key.h"
  17. #include "misc.h"
  18. #include "gameutil.h"
  19. #include "gfx.h"
  20. #include "bstub.h"
  21. #include "globals.h"
  22. #include "debug4g.h"
  23. #include "error.h"
  24. #include "gui.h"
  25. #include "tile.h"
  26. #include "qav.h"
  27. #include "screen.h"
  28. #include "textio.h"
  29. #include "inifile.h"
  30. #include "options.h"
  31. #include "timer.h"
  32. #include "mouse.h"
  33. #include "font.h"
  34. #include <memcheck.h>
  35. #define kAttrTitle (kColorGreen * 16 + kColorWhite)
  36. /***********************************************************************
  37. * CLASS FontEdit
  38. **********************************************************************/
  39. class FontEdit
  40. {
  41. private:
  42. Font theFont;
  43. int theCharacter;
  44. public:
  45. FontEdit( void );
  46. Load( char *zName = NULL );
  47. Draw( void );
  48. };
  49. /***********************************************************************
  50. * FontEdit::FontEdit
  51. **********************************************************************/
  52. FontEdit::FontEdit( void )
  53. {
  54. theCharacter = 'A';
  55. unlink("UNNAMED.FNT");
  56. theFont.Load("UNNAMED");
  57. }
  58. /***********************************************************************
  59. * FontEdit::Load
  60. **********************************************************************/
  61. FontEdit::Load( char *zName )
  62. {
  63. // allocate and initialize a font
  64. if (theFont.Load( zName ) == FALSE)
  65. {
  66. pFont = (FONTDATA *)Resource::Alloc( sizeof(FONTDATA) );
  67. if (pFont == NULL)
  68. ThrowError("Error allocating FNT resource", ES_ERROR );
  69. memcpy(pFont->header.signature, kFontSig, sizeof(pFont->header.signature));
  70. pFont->header.version = kFontVersion;
  71. // create and null terminate the internal font name
  72. memset(pFont->name, 0, kFontNameSize);
  73. strncpy(pFont->name, zName, kFontNameSize);
  74. *(pFont->name + kFontNameSize) = '\0';
  75. pFont->charSpace = 0;
  76. pFont->lineSpace = 0;
  77. pFont->wordSpace = 0;
  78. pFont->firstTile = -1;
  79. // clear the offset and width tables
  80. for (int i = 0; i < SCHAR_MAX; i++ )
  81. {
  82. pFont->tileOffset[i] = -1;
  83. pFont->tileWidth[i] = 0;
  84. }
  85. }
  86. }
  87. // // overlay the tile number
  88. // if ( !keystatus[KEY_CAPSLOCK] )
  89. // {
  90. // sprintf(buffer, "%d", nTile);
  91. // Video.FillBox(0, x, y, x + strlen(buffer) * 4 + 1, y + 7);
  92. // printext256(x + 1, y, gStdColor[14], -1, buffer, 1);
  93. // }
  94. /***********************************************************************
  95. * GLOBALS
  96. **********************************************************************/
  97. char gFontName[128];
  98. char buffer[256];
  99. EHF prevErrorHandler;
  100. static BOOL isModified;
  101. FontEdit theFontEditor;
  102. /***********************************************************************
  103. *
  104. **********************************************************************/
  105. void faketimerhandler( void )
  106. { }
  107. /***********************************************************************
  108. * EditorErrorHandler()
  109. *
  110. * Terminate from error condition, displaying a message in text mode.
  111. *
  112. **********************************************************************/
  113. ErrorResult EditorErrorHandler( const Error& error )
  114. {
  115. uninitengine();
  116. keyRemove();
  117. setvmode(gOldDisplayMode);
  118. // chain to the default error handler
  119. return prevErrorHandler(error);
  120. };
  121. void SaveFont( void )
  122. {
  123. char filename[128];
  124. int hFile;
  125. strcpy(filename, gFontName);
  126. ChangeExtension(filename, ".FNT");
  127. hFile = open(filename, O_CREAT | O_WRONLY | O_BINARY | O_TRUNC, S_IWUSR);
  128. if ( hFile == -1 )
  129. ThrowError("Error creating FNT file", ES_ERROR);
  130. // memcpy(gFont->signature, kFNTSig, sizeof(gFont->signature));
  131. // gFont->version = kFNTVersion;
  132. // if ( !FileWrite(hFile, gFont, sizeof(FONT) + gFont->frames * sizeof(FRAME)) )
  133. // goto WriteError;
  134. close(hFile);
  135. isModified = FALSE;
  136. scrSetMessage("Font saved.");
  137. return;
  138. //WriteError:
  139. // close(hFile);
  140. // ThrowError("Error writing FNT file", ES_ERROR);
  141. }
  142. BOOL LoadFont( void )
  143. {
  144. char filename[128];
  145. int hFile;
  146. int nSize;
  147. strcpy(filename, gFontName);
  148. ChangeExtension(filename, ".FNT");
  149. hFile = open(filename, O_RDONLY | O_BINARY);
  150. if ( hFile == -1 )
  151. return FALSE;
  152. nSize = filelength(hFile);
  153. // if ( !FileRead(hFile, gFont, nSize) )
  154. // goto ReadError;
  155. // if (memcmp(gFont->signature, kFNTSig, sizeof(gFont->signature)) != 0)
  156. // {
  157. // close(hFile);
  158. // ThrowError("FNT file corrupted", ES_ERROR);
  159. // }
  160. /*******************************************************************************
  161. I'm ignoring version information for now. We'll probably have to support
  162. more versions as we make enhancements to the font editor.
  163. *******************************************************************************/
  164. close(hFile);
  165. isModified = FALSE;
  166. return TRUE;
  167. //ReadError:
  168. // close(hFile);
  169. // ThrowError("Error reading FNT file", ES_ERROR);
  170. // return FALSE;
  171. }
  172. BOOL SaveAs( void )
  173. {
  174. if ( GetStringBox("Save As", gFontName) )
  175. {
  176. // load it if it seems valid
  177. if (strlen(gFontName) > 0)
  178. {
  179. SaveFont();
  180. return TRUE;
  181. }
  182. }
  183. return FALSE;
  184. }
  185. BOOL LoadAs( void )
  186. {
  187. if ( GetStringBox("Load Font", gFontName) )
  188. {
  189. // load it if it seems valid
  190. if (strlen(gFontName) > 0)
  191. {
  192. LoadFont();
  193. return TRUE;
  194. }
  195. }
  196. return FALSE;
  197. }
  198. /*******************************************************************************
  199. ** ChangeAcknowledge()
  200. **
  201. ** Returns TRUE if the YES/NO selected, or FALSE if aborted or escape pressed.
  202. *******************************************************************************/
  203. BOOL ChangeAcknowledge(void)
  204. {
  205. // create the dialog
  206. Window dialog(59, 80, 202, 46, "Save Changes?");
  207. TextButton *pbYes = new TextButton( 4, 4, 60, 20, "&Yes", mrYes );
  208. TextButton *pbNo = new TextButton( 68, 4, 60, 20, "&No", mrNo );
  209. TextButton *pbCancel = new TextButton( 132, 4, 60, 20, "&Cancel", mrCancel );
  210. dialog.Insert(pbYes);
  211. dialog.Insert(pbNo);
  212. dialog.Insert(pbCancel);
  213. ShowModal(&dialog);
  214. switch ( dialog.endState )
  215. {
  216. case mrCancel:
  217. return FALSE;
  218. case mrOk:
  219. case mrYes:
  220. return SaveAs();
  221. }
  222. return TRUE;
  223. }
  224. void EditLoop( void )
  225. {
  226. BYTE key, shift, alt, ctrl, pad5;
  227. // int i;
  228. // int t = 0;
  229. int nbuttons;
  230. static int obuttons = 0;
  231. // char buffer[256];
  232. while (1)
  233. {
  234. gFrameTicks = gGameClock - gFrameClock;
  235. gFrameClock += gFrameTicks;
  236. UpdateBlinkClock(gFrameTicks);
  237. clearview(0);
  238. // gFont->DrawTiles();
  239. // sprintf(buffer,"%2i:%03i [%3i]", t / kTimerRate, t % kTimerRate, step);
  240. // printext256(270, 190, gStdColor[15], -1, buffer, 1);
  241. scrDisplayMessage(gStdColor[kColorWhite]);
  242. if (vidoption != 1)
  243. WaitVSync();
  244. scrNextPage();
  245. key = keyGet();
  246. shift = keystatus[KEY_LSHIFT] | keystatus[KEY_RSHIFT];
  247. ctrl = keystatus[KEY_LCTRL] | keystatus[KEY_RCTRL];
  248. alt = keystatus[KEY_LALT] | keystatus[KEY_RALT];
  249. pad5 = keystatus[KEY_PAD5];
  250. switch (key)
  251. {
  252. case KEY_ESC:
  253. keystatus[KEY_ESC] = 0;
  254. if (!isModified || ChangeAcknowledge())
  255. {
  256. // free(gFont);
  257. // gFont = NULL;
  258. return;
  259. }
  260. break;
  261. case KEY_SPACE:
  262. // PlayIt();
  263. break;
  264. case KEY_F2:
  265. if (keystatus[KEY_LCTRL] || keystatus[KEY_RCTRL] || strlen(gFontName) == 0)
  266. SaveAs();
  267. else
  268. SaveFont();
  269. break;
  270. case KEY_F3:
  271. if (!isModified || ChangeAcknowledge())
  272. {
  273. LoadAs();
  274. // t = 0;
  275. // GetFrameTables(t);
  276. }
  277. break;
  278. case KEY_INSERT:
  279. {
  280. // // find first frame starting after t
  281. // for (i = 0; i < gFont->frames; i++)
  282. // {
  283. // if (gAnim->frame[i].timeStart > t)
  284. // break;
  285. // }
  286. //
  287. // if (i < gAnim->frames)
  288. // memmove(&gAnim->frame[i+1], &gAnim->frame[i], (gAnim->frames - i) * sizeof(FRAME));
  289. //
  290. // gAnim->frames++;
  291. //
  292. // memset(&gAnim->frame[i], 0, sizeof(FRAME));
  293. // gAnim->frame[i].timeStart = t;
  294. // gAnim->frame[i].timeStop = t + step;
  295. // gAnim->frame[i].type = kQFrameTile;
  296. // gAnim->frame[i].flags = 0;
  297. // gAnim->frame[i].x = 0;
  298. // gAnim->frame[i].y = 0;
  299. //
  300. // lastTile = gAnim->frame[i].id = tilePick((short)lastTile, SS_ALL);
  301. //
  302. // GetFrameTables(t);
  303. isModified = TRUE;
  304. break;
  305. }
  306. case KEY_DELETE:
  307. // ***
  308. // --gAnim->frames;
  309. // if (editFrame[edit] < &gAnim->frame[gAnim->frames])
  310. // memmove(editFrame[edit], editFrame[edit] + 1, (&gAnim->frame[gAnim->frames] - editFrame[edit]) * sizeof(FRAME));
  311. // GetFrameTables(t);
  312. isModified = TRUE;
  313. break;
  314. case KEY_G:
  315. GetNumberBox("Go To Character (0..126)", 0, 0 );
  316. break;
  317. case KEY_P:
  318. // if (edit >= 0 && editFrame[edit]->type == kQFrameTile)
  319. // {
  320. // // set the palette for the highlighted tile frame
  321. // if ( alt )
  322. // editFrame[edit]->pal = GetNumberBox("Palookup", editFrame[edit]->pal, editFrame[edit]->pal );
  323. // else
  324. // editFrame[edit]->pal = IncRotate(editFrame[edit]->pal, kMaxPLU);
  325. // isModified = TRUE;
  326. // }
  327. break;
  328. case KEY_T:
  329. // if (edit >= 0 && editFrame[edit]->type == kQFrameTile)
  330. // {
  331. // // set translucency flags for the highlighted tile frame
  332. // int flags = editFrame[edit]->flags;
  333. // int level = 0;
  334. //
  335. // if ( flags & kQFrameTranslucent )
  336. // {
  337. // level = 1;
  338. // if ( flags & kQFrameTranslucentR )
  339. // level = 2;
  340. // }
  341. // level = IncRotate(level, 3);
  342. //
  343. // switch ( level )
  344. // {
  345. // case 0:
  346. // flags &= ~kQFrameTranslucent & ~kQFrameTranslucentR;
  347. // break;
  348. //
  349. // case 1:
  350. // flags &= ~kQFrameTranslucentR;
  351. // flags |= kQFrameTranslucent;
  352. // break;
  353. //
  354. // case 2:
  355. // flags |= kQFrameTranslucent | kQFrameTranslucentR;
  356. // break;
  357. // }
  358. // editFrame[edit]->flags = flags;
  359. // isModified = TRUE;
  360. // }
  361. break;
  362. case KEY_V:
  363. // if (edit >= 0 && editFrame[edit]->type == kQFrameTile)
  364. // {
  365. // // pick a tile for the tile frame
  366. // lastTile = editFrame[edit]->id = tilePick((short)editFrame[edit]->id, SS_ALL);
  367. // isModified = TRUE;
  368. // }
  369. break;
  370. case KEY_PADPLUS:
  371. // if (edit >= 0 && editFrame[edit]->type == kQFrameTile)
  372. // {
  373. // editFrame[edit]->shade = ClipLow( editFrame[edit]->shade - 1, -128 );
  374. // isModified = TRUE;
  375. // }
  376. break;
  377. case KEY_PADMINUS:
  378. // if (edit >= 0 && editFrame[edit]->type == kQFrameTile)
  379. // {
  380. // editFrame[edit]->shade = ClipHigh( editFrame[edit]->shade + 1, 127 );
  381. // isModified = TRUE;
  382. // }
  383. break;
  384. case KEY_PAD0:
  385. // if (edit >= 0 && editFrame[edit]->type == kQFrameTile)
  386. // {
  387. // editFrame[edit]->shade = 0;
  388. // isModified = TRUE;
  389. // }
  390. break;
  391. case KEY_TAB:
  392. SetBlinkOff();
  393. isModified = TRUE;
  394. break;
  395. case KEY_UP:
  396. SetBlinkOff();
  397. isModified = TRUE;
  398. break;
  399. case KEY_DOWN:
  400. SetBlinkOff();
  401. isModified = TRUE;
  402. break;
  403. case KEY_LEFT:
  404. SetBlinkOff();
  405. isModified = TRUE;
  406. break;
  407. case KEY_RIGHT:
  408. SetBlinkOff();
  409. isModified = TRUE;
  410. break;
  411. }
  412. Mouse::Read(gFrameTicks);
  413. // which buttons just got pressed
  414. nbuttons = (short)(~obuttons & Mouse::buttons);
  415. obuttons = Mouse::buttons;
  416. // if ( (nbuttons & 2) && editFrames > 1)
  417. // {
  418. // edit = IncRotate(edit, editFrames);
  419. // SetBlinkOn();
  420. // }
  421. if ( Mouse::buttons & 1 )
  422. {
  423. // if ( keystatus[KEY_O] )
  424. // {
  425. // gAnim->SetOrigin(gAnim->origin.x + Mouse::dX2, gAnim->origin.y + Mouse::dY2);
  426. // isModified = TRUE;
  427. // }
  428. // else
  429. // {
  430. // SetBlinkOff();
  431. //
  432. // if (edit >= 0)
  433. // {
  434. // editFrame[edit]->x += Mouse::dX2;
  435. // editFrame[edit]->y += Mouse::dY2;
  436. // isModified = TRUE;
  437. // }
  438. // }
  439. }
  440. // make sure x and y don't cause the tile to go off screen
  441. // if (edit >= 0)
  442. // gAnim->ClipFrameTile(editFrame[edit]);
  443. }
  444. }
  445. void main( int argc, char *argv[] )
  446. {
  447. char title[256];
  448. gOldDisplayMode = getvmode();
  449. sprintf(title, "Ye Olde Font Editor [%s] -- DO NOT DISTRIBUTE", gBuildDate);
  450. tioInit();
  451. tioCenterString(0, 0, tioScreenCols - 1, title, kAttrTitle);
  452. tioCenterString(tioScreenRows - 1, 0, tioScreenCols - 1,
  453. "Copyright (c) 1995 Q Studios Corporation", kAttrTitle);
  454. tioWindow(1, 0, tioScreenRows - 2, tioScreenCols);
  455. if ( _grow_handles(kRequiredFiles) < kRequiredFiles )
  456. ThrowError("Not enough file handles available", ES_ERROR);
  457. gGamma = BloodINI.GetKeyInt("View", "Gamma", 0);
  458. tioPrint("Initializing heap and resource system");
  459. Resource::heap = new QHeap(dpmiDetermineMaxRealAlloc());
  460. tioPrint("Initializing resource archive");
  461. gSysRes.Init("BLOOD.RFF", "*.*");
  462. gGuiRes.Init("GUI.RFF", NULL);
  463. tioPrint("Initializing mouse");
  464. if ( !initmouse() )
  465. tioPrint("Mouse not detected");
  466. // install our error handler
  467. prevErrorHandler = errSetHandler(EditorErrorHandler);
  468. InitEngine();
  469. Mouse::SetRange(xdim, ydim);
  470. tioPrint("Loading tiles");
  471. if (tileInit() == 0)
  472. ThrowError("ART files not found", ES_ERROR);
  473. tioPrint("Initializing screen");
  474. scrInit();
  475. tioPrint("Installing keyboard handler");
  476. keyInstall();
  477. scrCreateStdColors();
  478. tioPrint("Installing timer");
  479. timerRegisterClient(ClockStrobe, kTimerRate);
  480. timerInstall();
  481. tioPrint("Engaging graphics subsystem...");
  482. scrSetGameMode();
  483. scrSetGamma(gGamma);
  484. scrSetDac(0);
  485. strcpy(gFontName, "");
  486. isModified = FALSE;
  487. // gAnim = (EditAnim *)malloc(sizeof(EditAnim) + kMaxFrames * sizeof(FRAME));
  488. // dassert(gAnim != NULL);
  489. if ( argc > 1 )
  490. {
  491. strcpy(gFontName, argv[1]);
  492. theFontEditor.Load(argv[1]);
  493. }
  494. else
  495. {
  496. // gAnim->frames = 0;
  497. // gAnim->duration = 0;
  498. // gAnim->origin.x = 160;
  499. // gAnim->origin.y = 100;
  500. }
  501. EditLoop();
  502. setvmode(gOldDisplayMode);
  503. dprintf("Removing timer\n");
  504. timerRemove();
  505. dprintf("uninitengine()\n");
  506. uninitengine();
  507. dprintf("All subsystems shut down. Processing exit functions\n");
  508. errSetHandler(prevErrorHandler);
  509. }