TexEdit.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // TexEdit.cpp
  19. // Project: Nostril (aka Postal)
  20. //
  21. // This module implements the texture editor.
  22. //
  23. // History:
  24. // 10/03/99 JMI Started.
  25. //
  26. // 10/06/99 JMI Now DoModal() accepts two lights to use and some other
  27. // stuff too.
  28. //
  29. // 10/07/99 JMI Changed the default Mudify settings to that of Assets.mak.
  30. //
  31. // JMI Replaced m_fAlt and m_fAzi with a transform so rotations
  32. // can always be relative to the current orientation.
  33. // Also added 'D' as an additional paint key so those keys
  34. // could all be on one hand.
  35. //
  36. // 10/08/99 JMI Holding down shift now causes the manips to ignore the Y
  37. // input and holding control causes them to ignore the X
  38. // input.
  39. //
  40. // JMI Added ValidateTextures() to check for and fix out-of-synch
  41. // texture files.
  42. // In Adjust(), we now free the colors array (otherwise, the
  43. // colors will get saved). Some probably already exist.
  44. //
  45. ////////////////////////////////////////////////////////////////////////////////
  46. //------------------------------------------------------------------------------
  47. // Includes.
  48. //------------------------------------------------------------------------------
  49. #include "RSPiX.h"
  50. #include "TexEdit.h"
  51. #include "Anim3D.h"
  52. #include "update.h"
  53. #include "game.h" // For Paths.
  54. #include "localize.h"
  55. //------------------------------------------------------------------------------
  56. // Macros.
  57. //------------------------------------------------------------------------------
  58. const RString c_strGuiFile = "res/editor/TexEdit.gui";
  59. const long c_lIdAnim = 100;
  60. const long c_lIdPal = 200;
  61. const long c_lIdSpotLight = 601;
  62. const long c_lIdBrightness = 602;
  63. const long c_lIdAdjust = 701;
  64. const long c_lIdFrequency = 702;
  65. const long c_lIdAmount = 703;
  66. const long c_lIdCurColor = 201;
  67. const long c_lIdStatus = 500;
  68. const long c_lIdApply = 301;
  69. const long c_lIdSave = 302;
  70. const long c_lIdRevert = 303;
  71. const long c_lIdQuit = 399;
  72. const long c_lIdTrans = 401;
  73. const long c_lIdScale = 402;
  74. const long c_lIdRotate = 403;
  75. const long c_lIdPaint = 404;
  76. const double c_dScale = 8.0;
  77. const double c_fTransRate = 0.25f / c_dScale;
  78. const double c_fScaleRate = 0.1f / c_dScale;
  79. const double c_fRotRate = 1.0f;
  80. const short c_sPalStart = 106;
  81. const short c_sPalEnd = 201;
  82. const short c_sPalNum = c_sPalEnd - c_sPalStart + 1;
  83. #if 0 // Swatch center colors only -- to guarantee good matching.
  84. const short c_sPalColorsPerSwatch = 8;
  85. const short c_sPalCols = 2;
  86. #else // All swatch colors -- to allow more flexibility when texturing guys.
  87. const short c_sPalColorsPerSwatch = 1;
  88. const short c_sPalCols = 8;
  89. #endif
  90. const short c_sPalDispColorOffset = c_sPalColorsPerSwatch / 2;
  91. const short g_sPalFirstColor = c_sPalStart + c_sPalDispColorOffset;
  92. const short c_sMinBrightness = -64;
  93. const short c_sMaxBrightness = 64;
  94. const short c_sBrightnessRange = c_sMaxBrightness - c_sMinBrightness + 1;
  95. const short c_sDefAdjustFrequency = 2;
  96. const float c_fDefAdjustment = 0.85f;
  97. //------------------------------------------------------------------------------
  98. // Functions.
  99. //------------------------------------------------------------------------------
  100. ////////////////////////////////////////////////////////////////////////////////
  101. // Set the state of the specified push button.
  102. ////////////////////////////////////////////////////////////////////////////////
  103. inline
  104. void
  105. SetPushBtnState(
  106. RGuiItem* pguiRoot, // In: Root GUI.
  107. long lBtnId, // In: ID of btn whose state will be set.
  108. RPushBtn::State state) // In: New state for btn.
  109. {
  110. ASSERT(pguiRoot);
  111. RPushBtn* pbtn = (RPushBtn*)pguiRoot->GetItemFromId(lBtnId);
  112. if (pbtn)
  113. {
  114. pbtn->m_state = state;
  115. pbtn->Compose();
  116. }
  117. }
  118. ////////////////////////////////////////////////////////////////////////////////
  119. // Checks to see if v1 and v2 are going in the same sign direction.
  120. ////////////////////////////////////////////////////////////////////////////////
  121. bool // Returns true if x, y, and z of v1 and v2 are the same (respective 3) signs.
  122. SameSigns_Vector(
  123. RP3d *v1, // In: vector 1
  124. RP3d *v2) // In: vector 1
  125. {
  126. //this is a slooow check!, check the sign bit, or something
  127. if(((int)v1->x >= 0 && (int)v2->x >= 0) || ((int)v1->x < 0 && (int)v2->x < 0))
  128. {
  129. if(((int)v1->y >= 0 && (int)v2->y >= 0) || ((int)v1->y < 0 && (int)v2->y < 0))
  130. {
  131. if(((int)v1->z >= 0 && (int)v2->z >= 0) || ((int)v1->z < 0 && (int)v2->z < 0))
  132. return true;
  133. }
  134. }
  135. return false;
  136. };
  137. ////////////////////////////////////////////////////////////////////////////////
  138. // Using the equation in comments below, this returns the value for 't' from the
  139. // parametric equations of line seg 0--1 and the plane of a, b, c, and D.
  140. // if true, then you can use t, else, t will not have been assigned anything.
  141. // -(a*x0 + b*y0 + c*z0 + D) = t
  142. // a*(x1-x0)+b*(y1-y0)+c*(z1-z0)
  143. ////////////////////////////////////////////////////////////////////////////////
  144. bool // Returns: true of t valid, false otherwise
  145. GetIntersectSubT(
  146. RP3d &pt0, // In: line segment point 0
  147. RP3d &ptSub, // In: line segment point 1
  148. RP3d &ptCoeff,
  149. //double a, double b, double c, double D, // In: coefficients
  150. float fD,
  151. float &t) // In: return t
  152. {
  153. float fdenom=ptCoeff.x*(ptSub.x) + ptCoeff.y*(ptSub.y) + ptCoeff.z*(ptSub.z);
  154. if(fdenom!=0)
  155. {
  156. t= (ptCoeff.x*pt0.x + ptCoeff.y*pt0.y + ptCoeff.z*pt0.z + fD)/fdenom;
  157. t*=-1;
  158. return(true);
  159. }
  160. else
  161. {
  162. return(false);
  163. };
  164. };
  165. ////////////////////////////////////////////////////////////////////////////////
  166. // Checks to see if a point is inside (in the plane of and contained in) the
  167. // given triangle.
  168. ////////////////////////////////////////////////////////////////////////////////
  169. bool // Return true if the given point is inside the given triangle
  170. PointInsideTri(
  171. RP3d &pt0A, // In: point 1 of triangle
  172. RP3d &pt1A, // In: point 2 of triangle
  173. RP3d &pt2A, // In: point 3 of triangle
  174. RP3d &hitpoint) // In: point to check inside triangle
  175. {
  176. /*
  177. if(cheapequalsRP3d(pt0A, hitpoint)
  178. || cheapequalsRP3d(pt1A, hitpoint)
  179. || cheapequalsRP3d(pt2A, hitpoint))
  180. return true;
  181. */
  182. RP3d pt0, pt1, pt2;//pt0=pt0A, pt1=pt1A, pt2=pt2A;
  183. RP3d main_cross;
  184. RP3d result_cross;
  185. //if(cheapequalsRP3d(pt0, hitpoint) || cheapequalsRP3d(pt1, hitpoint)
  186. // || cheapequalsRP3d(pt2, hitpoint))
  187. // return true;
  188. //rspSub(pt0, pt2);
  189. //rspSub(pt1, pt2);
  190. pt0.x=pt0A.x - pt2A.x;
  191. pt0.y=pt0A.y - pt2A.y;
  192. pt0.z=pt0A.z - pt2A.z;
  193. pt1.x=pt1A.x - pt2A.x;
  194. pt1.y=pt1A.y - pt2A.y;
  195. pt1.z=pt1A.z - pt2A.z;
  196. rspCross(pt0, pt1, main_cross);
  197. RP3d hit=hitpoint;
  198. //pt2A is the origin
  199. //pt0=pt0A, pt1=pt1A;
  200. //rspSub(pt0, pt2);
  201. //rspSub(hitpoint, pt2);
  202. //rspCross(pt0, hitpoint, result_cross); //check 0 to hitpoint
  203. pt0.x=pt0A.x - pt2A.x;
  204. pt0.y=pt0A.y - pt2A.y;
  205. pt0.z=pt0A.z - pt2A.z;
  206. rspSub(hitpoint, pt2A);
  207. rspCross(pt0, hitpoint, result_cross); //check 0 to hitpoint
  208. if(SameSigns_Vector(&result_cross, &main_cross))
  209. {
  210. //pt0 is the origin
  211. //pt0=pt0A;
  212. //hitpoint=hit;
  213. //rspSub(pt1, pt0);
  214. //rspSub(hitpoint, pt0);
  215. //pt0 is the origin
  216. pt1.x=pt1A.x-pt0A.x;
  217. pt1.y=pt1A.y-pt0A.y;
  218. pt1.z=pt1A.z-pt0A.z;
  219. hitpoint.x=hit.x-pt0A.x;
  220. hitpoint.y=hit.y-pt0A.y;
  221. hitpoint.z=hit.z-pt0A.z;
  222. rspCross(pt1, hitpoint, result_cross); //check 1 to hitpoint
  223. if(SameSigns_Vector(&result_cross, &main_cross))
  224. {
  225. //pt1 is the origin
  226. //pt1=pt1A;
  227. //hitpoint=hit;
  228. //rspSub(pt2, pt1);
  229. //rspSub(hitpoint, pt1);
  230. //rspCross(pt2, hitpoint, result_cross); //check 2 to hitpoint
  231. //pt1 is the origin
  232. pt2.x=pt2A.x-pt1A.x;
  233. pt2.y=pt2A.y-pt1A.y;
  234. pt2.z=pt2A.z-pt1A.z;
  235. hitpoint.x=hit.x-pt1A.x;
  236. hitpoint.y=hit.y-pt1A.y;
  237. hitpoint.z=hit.z-pt1A.z;
  238. rspCross(pt2, hitpoint, result_cross); //check 2 to hitpoint
  239. if(SameSigns_Vector(&result_cross, &main_cross))
  240. {
  241. hitpoint=hit;
  242. return(true);//point is definitely inside the triangle!
  243. };//check 2
  244. };//check 1
  245. };//check 0
  246. hitpoint=hit;
  247. return(false);
  248. };
  249. ////////////////////////////////////////////////////////////////////////////////
  250. // Checks if a line segment and a triangle intersect
  251. ////////////////////////////////////////////////////////////////////////////////
  252. bool // Returns true if the two shapes intersect.
  253. TriAIntersectsLineSegmentB(
  254. RP3d & normalA, // In: normal vector of triangle A
  255. float fBigA, // In: constant from parametric equation of A
  256. RP3d & pt0A, // In: three points of triangle A
  257. RP3d & pt1A,
  258. RP3d & pt2A,
  259. RP3d & pt0B, // In: two points of line segment B
  260. RP3d & pt1B,
  261. RP3d & hitpoint) // Out: Exact point where line hits triangle
  262. {
  263. float intersect_t;
  264. // point 0--1
  265. RP3d ptSub;
  266. ptSub.x=pt1B.x-pt0B.x;
  267. ptSub.y=pt1B.y-pt0B.y;
  268. ptSub.z=pt1B.z-pt0B.z;
  269. if(GetIntersectSubT(pt0B, ptSub, normalA, fBigA, intersect_t))
  270. {
  271. if(intersect_t>=0 &&
  272. intersect_t<=1)
  273. {
  274. //GetIntersectPointSub(pt0B, ptSub, intersect_t, hitpoint);
  275. hitpoint.x=pt0B.x+ptSub.x*intersect_t;
  276. hitpoint.y=pt0B.y+ptSub.y*intersect_t;
  277. hitpoint.z=pt0B.z+ptSub.z*intersect_t;
  278. if(PointInsideTri(pt0A, pt1A, pt2A, hitpoint))
  279. return(true);
  280. };
  281. };
  282. //hitpoint.x=hitpoint.y=hitpoint.z=0;
  283. return(false);
  284. };
  285. ////////////////////////////////////////////////////////////////////////////////
  286. bool shorterdist(RP3d &pt1, RP3d &pt2)
  287. // true if pt1 is shorter dist than pt2
  288. {
  289. return ((pt1.x*pt1.x + pt1.y*pt1.y + pt1.z*pt1.z) < (pt2.x*pt2.x + pt2.y*pt2.y + pt2.z*pt2.z));
  290. };
  291. void sqrdist(RP3d &pt1, float &fdist)
  292. // returns sqrd dist of point
  293. {
  294. fdist=(pt1.x*pt1.x + pt1.y*pt1.y + pt1.z*pt1.z);
  295. };
  296. ////////////////////////////////////////////////////////////////////////////////
  297. bool
  298. TrianglesIntersectLineSegment(
  299. RP3d &linept1, // In: line segment point 1
  300. RP3d &linept2, // In: line segment point 2 closest to this point. this should be the first point.
  301. U16 *ptri, // In: mesh
  302. RP3d *soparr, // In: points for mesh
  303. short smeshNum, // In: number of points in mesh
  304. RP3d &hitpoint, // Out: point where line hit triangle
  305. long &lHitTriIndex) // Out: index of triangle it hit
  306. {
  307. lHitTriIndex=-1;
  308. short sJ=0;
  309. RP3d normalA;
  310. RP3d pt0A, pt1A, pt2A;
  311. RP3d t_pt1A, t_pt2A;
  312. float fBigA=-1;
  313. RP3d ptclosest, ptwork;
  314. float fclosest=(float)INT_MAX, fdist;
  315. bool bhit=false;
  316. hitpoint.x=hitpoint.y=hitpoint.z=0;
  317. hitpoint.w=1;
  318. normalA.w=1;
  319. for(sJ=0; sJ<smeshNum; sJ++)
  320. {
  321. //assign points
  322. pt0A=soparr[*ptri++];
  323. pt1A=soparr[*ptri++];
  324. pt2A=soparr[*ptri++];
  325. //get the normals of triangle 1
  326. t_pt1A.x=pt1A.x-pt0A.x;
  327. t_pt1A.y=pt1A.y-pt0A.y;
  328. t_pt1A.z=pt1A.z-pt0A.z;
  329. t_pt2A.x=pt2A.x-pt0A.x;
  330. t_pt2A.y=pt2A.y-pt0A.y;
  331. t_pt2A.z=pt2A.z-pt0A.z;
  332. rspCross(t_pt1A, t_pt2A, normalA);
  333. //and the constant
  334. fBigA=(-normalA.x*pt0A.x - normalA.y*pt0A.y - normalA.z*pt0A.z);
  335. // Linesegment B intersects polygon A -------------------------------------------------------------------
  336. if(TriAIntersectsLineSegmentB(normalA, fBigA, pt0A, pt1A, pt2A, linept1, linept2, hitpoint))
  337. {
  338. rspCopy(ptwork, linept2);
  339. rspSub(ptwork, hitpoint);
  340. sqrdist(ptwork, fdist);
  341. if(fdist < fclosest)
  342. {
  343. fclosest=fdist;
  344. lHitTriIndex=sJ;
  345. rspCopy(ptclosest, hitpoint);
  346. bhit=true;
  347. };
  348. //return(true);
  349. };
  350. };//sJ for-loop
  351. if(bhit)
  352. {
  353. rspCopy(hitpoint, ptclosest);
  354. };
  355. return(bhit);
  356. };
  357. ////////////////////////////////////////////////////////////////////////////////
  358. // Transform psopSrc into psopDst with the supplied transform in addition to
  359. // the screen/view pipeline.
  360. ////////////////////////////////////////////////////////////////////////////////
  361. void Transform(RSop* psopSrc, RSop* psopDst, RPipeLine* ppipe, RTransform& tObj)
  362. {
  363. RTransform tFull;
  364. long i;
  365. // Use to stretch to z-buffer!
  366. tFull.Make1();
  367. tFull.Mul(ppipe->m_tView.T,tObj.T);
  368. // If there were inhomogeneous transforms, you would need to
  369. // trasnform each pt by two transforms separately!
  370. tFull.PreMulBy(ppipe->m_tScreen.T);
  371. // Add this in to get the model in the correctly offset spot.
  372. const short sMisUnderstoodValueX = -85; // *** WTF is this not sOffsetX? No time for that now.
  373. const short sMisUnderstoodValueY = -20; // *** WTF is this not sOffsetY? No time for that now.
  374. #if 0 // Find the magic offset.
  375. static short sOffX = 0;
  376. static short sOffY = 0;
  377. static U8* pau8KeyStatus = rspGetKeyStatusArray();
  378. if (pau8KeyStatus[RSP_SK_LEFT] & 1)
  379. sOffX--;
  380. if (pau8KeyStatus[RSP_SK_RIGHT] & 1)
  381. sOffX++;
  382. if (pau8KeyStatus[RSP_SK_UP] & 1)
  383. sOffY--;
  384. if (pau8KeyStatus[RSP_SK_DOWN] & 1)
  385. sOffY++;
  386. tFull.Trans(sMisUnderstoodValueX + sOffX, sMisUnderstoodValueY + sOffY, 0);
  387. #else
  388. tFull.Trans(sMisUnderstoodValueX, sMisUnderstoodValueY, 0);
  389. #endif
  390. for (i = 0; i < psopSrc->m_lNum; i++)
  391. {
  392. tFull.TransformInto(psopSrc->m_pArray[i], psopDst->m_pArray[i]);
  393. }
  394. }
  395. ////////////////////////////////////////////////////////////////////////////////
  396. // Create a 3D palette in the specified GUI.
  397. ////////////////////////////////////////////////////////////////////////////////
  398. void
  399. CreatePalette(
  400. RGuiItem* pgui) // In: GUI to contain palette.
  401. {
  402. short sCells = c_sPalNum / c_sPalColorsPerSwatch;
  403. short sCols = c_sPalCols;
  404. short sRows = sCells / sCols;
  405. RRect rcClient;
  406. pgui->GetClient(&rcClient.sX, &rcClient.sY, &rcClient.sW, &rcClient.sH);
  407. short sCellW = rcClient.sW / sCols;
  408. short sCellH = rcClient.sH / sRows;
  409. short sRow, sCol;
  410. short sX, sY;
  411. short sColor = g_sPalFirstColor;
  412. for (sRow = 0, sY = rcClient.sY; sRow < sRows; sRow++, sY += sCellH)
  413. {
  414. for (sCol = 0, sX = rcClient.sX; sCol < sCols; sCol++, sX += sCellW)
  415. {
  416. rspRect(
  417. sColor,
  418. &pgui->m_im,
  419. sX, sY,
  420. sCellW, sCellH,
  421. NULL);
  422. sColor += c_sPalColorsPerSwatch;
  423. }
  424. }
  425. }
  426. ////////////////////////////////////////////////////////////////////////////////
  427. // Set the specified GUI's text and recompose it to reflect the change.
  428. ////////////////////////////////////////////////////////////////////////////////
  429. void
  430. SetText(
  431. RGuiItem* pguiRoot, // In: Root GUI.
  432. long lId, // In: ID of GUI to update.
  433. const char* pszFrmt, // In: Format specifier ala sprintf.
  434. ...) // In: Arguments as specified by format.
  435. {
  436. RGuiItem* pgui = pguiRoot->GetItemFromId(lId);
  437. if (pgui)
  438. {
  439. va_list val;
  440. va_start(val, pszFrmt);
  441. vsprintf(pgui->m_szText, pszFrmt, val);
  442. // Recompose with new text.
  443. pgui->Compose();
  444. }
  445. }
  446. ////////////////////////////////////////////////////////////////////////////////
  447. // Some texture files were out of date when Special Delivery was made. As a
  448. // result, it's _possible_ (however unlikely) that a crash could occur when
  449. // reading the ends of the gramps textures.
  450. //
  451. // It appears the problem is that a cane was added to the gramps' meshes after
  452. // the extra various textures were exported but the extra textures were never
  453. // re-exported so they don't contain enough entries for the cane.
  454. ////////////////////////////////////////////////////////////////////////////////
  455. void
  456. ValidateTextures(
  457. RTexture* ptex, // In: Texture to validate.
  458. short sNum) // In: Number of textures it should have.
  459. {
  460. if (ptex->m_sNum < sNum)
  461. {
  462. short sRes = rspMsgBox(
  463. RSP_MB_ICN_QUERY | RSP_MB_BUT_YESNO,
  464. "Incorrect Texture File",
  465. "This texture file does not have enough entries to cover the entire mesh.\n"
  466. "Do you want this utility to recreate the texture scheme filling in the\n"
  467. "empty entries with bright green?");
  468. switch (sRes)
  469. {
  470. case RSP_MB_RET_YES:
  471. {
  472. short sOrigNum = ptex->m_sNum;
  473. // Create temp space for the existing colors.
  474. U8* pau8 = new U8[sOrigNum];
  475. // Duplicate the existing colors.
  476. short sColor;
  477. for (sColor = 0; sColor < sOrigNum; sColor++)
  478. {
  479. pau8[sColor] = ptex->m_pIndices[sColor];
  480. }
  481. // Free the existing colors.
  482. ptex->FreeIndices();
  483. // Resize.
  484. ptex->m_sNum = sNum;
  485. ptex->AllocIndices();
  486. // Copy the original colors back.
  487. for (sColor = 0; sColor < sOrigNum; sColor++)
  488. {
  489. ptex->m_pIndices[sColor] = pau8[sColor];
  490. }
  491. // Fill the remaining colors as bright green.
  492. for ( ; sColor < sNum; sColor++)
  493. {
  494. ptex->m_pIndices[sColor] = 250; // Part of static Postal palette.
  495. }
  496. delete pau8;
  497. pau8 = 0;
  498. break;
  499. }
  500. case RSP_MB_RET_NO:
  501. break;
  502. }
  503. }
  504. }
  505. //------------------------------------------------------------------------------
  506. // Construction.
  507. //------------------------------------------------------------------------------
  508. ////////////////////////////////////////////////////////////////////////////////
  509. // Default constructor.
  510. ////////////////////////////////////////////////////////////////////////////////
  511. CTexEdit::CTexEdit(void)
  512. {
  513. m_pguiRoot = NULL;
  514. m_pguiAnim = NULL;
  515. m_pguiCurColor = NULL;
  516. m_pguiPal = NULL;
  517. m_scene.SetupPipeline(NULL, NULL, c_dScale);
  518. m_manip = Trans;
  519. m_bDragging = false;
  520. m_sCursorResetX = 0;
  521. m_sCursorResetY = 0;
  522. ResetTransformation();
  523. m_bQuit = false;
  524. m_u8Color = g_sPalFirstColor;
  525. m_lTriIndex = -1;
  526. m_ptexSrc = NULL;
  527. m_ptexchanSrc = NULL;
  528. m_bModified = false;
  529. m_bSpotLight = false;
  530. m_sBrightness = 0;
  531. }
  532. ////////////////////////////////////////////////////////////////////////////////
  533. // Destructor.
  534. ////////////////////////////////////////////////////////////////////////////////
  535. CTexEdit::~CTexEdit(void)
  536. {
  537. }
  538. //------------------------------------------------------------------------------
  539. // Methods.
  540. //------------------------------------------------------------------------------
  541. //////////////////////////////////////////////////////////////////////////////
  542. // Edit the texture of the specified 3D animation in a modal dialog.
  543. //////////////////////////////////////////////////////////////////////////////
  544. void
  545. CTexEdit::DoModal(
  546. CAnim3D* panim, // In: 3D animation to paint on.
  547. RAlpha* pltAmbient, // In: Ambient light.
  548. RAlpha* pltSpot, // In: Spot light.
  549. const RString& strFile) // In: Filename to save modified texture as.
  550. {
  551. m_pguiRoot = RGuiItem::LoadInstantiate(FullPathVD(c_strGuiFile) );
  552. if (m_pguiRoot)
  553. {
  554. RProcessGui gm;
  555. // Get composite buffer.
  556. RImage* pimComposite;
  557. rspNameBuffers(&pimComposite);
  558. // Remember center.
  559. m_sCursorResetX = pimComposite->m_sWidth / 2;
  560. m_sCursorResetY = pimComposite->m_sHeight / 2;
  561. // Center.
  562. m_pguiRoot->Move(
  563. pimComposite->m_sWidth / 2 - m_pguiRoot->m_im.m_sWidth / 2,
  564. pimComposite->m_sHeight / 2 - m_pguiRoot->m_im.m_sHeight / 2);
  565. // Get the 3D render surface.
  566. m_pguiAnim = m_pguiRoot->GetItemFromId(c_lIdAnim);
  567. ASSERT(m_pguiAnim);
  568. // Get the palette surface.
  569. m_pguiPal = m_pguiRoot->GetItemFromId(c_lIdPal);
  570. ASSERT(m_pguiPal);
  571. CreatePalette(m_pguiPal);
  572. m_pguiCurColor = m_pguiRoot->GetItemFromId(c_lIdCurColor);
  573. ASSERT(m_pguiCurColor);
  574. SetColor(g_sPalFirstColor);
  575. m_bSpotLight = false;
  576. // Get light to use.
  577. RRect rcClient;
  578. m_pguiAnim->GetClient(&rcClient.sX, &rcClient.sY, &rcClient.sW, &rcClient.sH);
  579. short sOffsetX = rcClient.sX + rcClient.sW / 2;
  580. short sOffsetY = rcClient.sY + rcClient.sH - 5;
  581. ResetTransformation();
  582. SetManip(Paint);
  583. // Even though there's many channels of many textures per person, they are all the
  584. // very same resource (on disk & in memory).
  585. m_ptexchanSrc = panim->m_ptextures;
  586. m_ptexSrc = m_ptexchanSrc->GetAtTime(0);
  587. // Validate texture thinger.
  588. ValidateTextures(m_ptexSrc, panim->m_pmeshes->GetAtTime(0)->m_sNum);
  589. // Duplicate into a care-free work area.
  590. m_texWork = *m_ptexSrc;
  591. m_bModified = false;
  592. m_strFileName = strFile;
  593. // Set notifications.
  594. SetToNotify(c_lIdQuit, QuitCall_Static);
  595. SetToNotify(c_lIdTrans, ManipCall_Static);
  596. SetToNotify(c_lIdScale, ManipCall_Static);
  597. SetToNotify(c_lIdRotate, ManipCall_Static);
  598. SetToNotify(c_lIdPaint, ManipCall_Static);
  599. SetToNotify(c_lIdPal, ColorCall_Static);
  600. SetToNotify(c_lIdApply, ApplyCall_Static);
  601. SetToNotify(c_lIdSave, SaveCall_Static);
  602. SetToNotify(c_lIdRevert, RevertCall_Static);
  603. SetToNotify(c_lIdSpotLight, SpotCall_Static);
  604. SetToNotify(c_lIdBrightness, BrightnessCall_Static);
  605. SetToNotify(c_lIdAdjust, AdjustCall_Static);
  606. SetToNotify(c_lIdAnim, AnimCall_Static);
  607. // Set initial brightness.
  608. RScrollBar* psb = (RScrollBar*)m_pguiRoot->GetItemFromId(c_lIdBrightness);
  609. ASSERT(psb);
  610. ASSERT(psb->m_type == RGuiItem::ScrollBar);
  611. psb->SetPos(50);
  612. SetText(m_pguiRoot, c_lIdFrequency, "%hd", c_sDefAdjustFrequency);
  613. SetText(m_pguiRoot, c_lIdAmount, "%g", c_fDefAdjustment);
  614. // Get up to two controls that can end the processing that can be
  615. // passed on the DoModal() line. More buttons can be set though.
  616. // Set up ptrs and erase buffer.
  617. gm.Prepare(m_pguiRoot, NULL, NULL);
  618. RInputEvent ie;
  619. m_bQuit = false;
  620. m_lTriIndex = -1;
  621. RTransform trans;
  622. CSprite3 sprite;
  623. RSop sopView;
  624. long lTime = 0;
  625. // Process GUI.
  626. while (m_bQuit == false)
  627. {
  628. // System Update //////////////////////////////////////
  629. ie.type = RInputEvent::None;
  630. // Critical callage.
  631. UpdateSystem();
  632. rspGetNextInputEvent(&ie);
  633. // Setup current 3D info ///////////////////////////////
  634. sprite.m_pmesh = panim->m_pmeshes->GetAtTime(lTime);
  635. sprite.m_psop = panim->m_psops->GetAtTime(lTime);
  636. sprite.m_ptrans = &trans;
  637. sprite.m_ptex = &m_texWork;
  638. sprite.m_psphere = panim->m_pbounds->GetAtTime(lTime);
  639. sprite.m_sBrightness = m_sBrightness;
  640. // Transformation //////////////////////////////////////
  641. trans.Make1();
  642. ComposeTransform(trans);
  643. // View Space SOP //////////////////////////////////////
  644. // Create View Space SOP for checking mouse against triangles and
  645. // drawing feedback for such.
  646. if (sopView.m_lNum != sprite.m_psop->m_lNum)
  647. sopView.Alloc(sprite.m_psop->m_lNum);
  648. Transform(sprite.m_psop, &sopView, &m_scene.m_pipeline, trans);
  649. // Process User Manips /////////////////////////////////
  650. ProcessManip(m_pguiAnim->m_sPressed != 0, &ie, &sprite, &sopView);
  651. // Output //////////////////////////////////////////////
  652. rspRect(
  653. 0,
  654. &m_pguiAnim->m_im,
  655. 0, 0,
  656. m_pguiAnim->m_im.m_sWidth,
  657. m_pguiAnim->m_im.m_sHeight,
  658. &rcClient);
  659. DoOutput(&sprite, &sopView, trans, m_bSpotLight ? pltSpot : pltAmbient, &m_pguiAnim->m_im, sOffsetX, sOffsetY, rcClient);
  660. gm.DoModeless(m_pguiRoot, &ie, pimComposite);
  661. // If quiting . . .
  662. if (m_bQuit)
  663. {
  664. // If modified . . .
  665. if (m_bModified)
  666. {
  667. // Query if user wants to apply the work textures (and not lose changes).
  668. short sRes = rspMsgBox(
  669. RSP_MB_ICN_QUERY | RSP_MB_BUT_YESNOCANCEL,
  670. g_pszAppName,
  671. "Apply changes before exiting texture editor?");
  672. switch (sRes)
  673. {
  674. case RSP_MB_RET_YES: // Yes - apply.
  675. Apply();
  676. break;
  677. case RSP_MB_RET_NO: // No - don't apply.
  678. break;
  679. case RSP_MB_RET_CANCEL: // Cancel - don't quit.
  680. m_bQuit = false;
  681. rspSetQuitStatus(FALSE);
  682. break;
  683. }
  684. }
  685. }
  686. }
  687. // Clean up ptrs, erase buffer, and dirty rect list.
  688. gm.Unprepare();
  689. m_ptexSrc = NULL;
  690. m_ptexchanSrc = NULL;
  691. m_texWork.FreeIndices();
  692. delete m_pguiRoot;
  693. m_pguiRoot = NULL;
  694. m_pguiAnim = NULL;
  695. m_pguiCurColor = NULL;
  696. m_pguiPal = NULL;
  697. }
  698. else
  699. {
  700. rspMsgBox(
  701. RSP_MB_ICN_STOP | RSP_MB_BUT_OK,
  702. g_pszAppName,
  703. g_pszFileOpenError_s,
  704. FullPathVD(c_strGuiFile) );
  705. }
  706. }
  707. //////////////////////////////////////////////////////////////////////////////
  708. // Render the 3D animation at the specified time.
  709. //////////////////////////////////////////////////////////////////////////////
  710. void
  711. CTexEdit::DoOutput(
  712. CSprite3* psprite, // In: 3D data to render.
  713. RSop* psopView, // In: View space SOP.
  714. RTransform& trans, // In: Transformation.
  715. RAlpha* palphaLight, // In: Light.
  716. RImage* pimDst, // In: Destination for result.
  717. short sOffsetX, // In: X offset.
  718. short sOffsetY, // In: Y offset.
  719. RRect& rcClip) // In: Dst clip rect.
  720. {
  721. m_scene.Render3D(
  722. pimDst, // Destination image.
  723. sOffsetX, // Destination 2D x coord.
  724. sOffsetY, // Destination 2D y coord.
  725. psprite, // 3D sprite to render.
  726. palphaLight, // Light to render with.
  727. &rcClip); // Dst clip rect.
  728. #if 0 // Draw wire frame.
  729. RMesh* pmesh = psprite->m_pmesh;
  730. short sTris = pmesh->m_sNum;
  731. U16* pu16Vertex = pmesh->m_pArray;
  732. while (sTris--)
  733. {
  734. const RP3d& v1 = psopView->m_pArray[*pu16Vertex++];
  735. const RP3d& v2 = psopView->m_pArray[*pu16Vertex++];
  736. const RP3d& v3 = psopView->m_pArray[*pu16Vertex++];
  737. rspLine(255, pimDst, v1.x, v1.y, v2.x, v2.y, &rcClip);
  738. rspLine(255, pimDst, v2.x, v2.y, v3.x, v3.y, &rcClip);
  739. rspLine(255, pimDst, v3.x, v3.y, v1.x, v1.y, &rcClip);
  740. }
  741. #endif
  742. // If cursor shown . . .
  743. if (m_manip == Paint)
  744. {
  745. if (m_lTriIndex >= 0)
  746. {
  747. RMesh* pmesh = psprite->m_pmesh;
  748. ASSERT(m_lTriIndex < pmesh->m_sNum);
  749. if (m_lTriIndex < pmesh->m_sNum)
  750. {
  751. long lVertexIndex = m_lTriIndex * 3;
  752. const RP3d& v1 = psopView->m_pArray[pmesh->m_pArray[lVertexIndex++] ];
  753. const RP3d& v2 = psopView->m_pArray[pmesh->m_pArray[lVertexIndex++] ];
  754. const RP3d& v3 = psopView->m_pArray[pmesh->m_pArray[lVertexIndex++] ];
  755. rspLine(255, pimDst, v1.x, v1.y, v2.x, v2.y, &rcClip);
  756. rspLine(255, pimDst, v2.x, v2.y, v3.x, v3.y, &rcClip);
  757. rspLine(255, pimDst, v3.x, v3.y, v1.x, v1.y, &rcClip);
  758. }
  759. }
  760. }
  761. }
  762. ////////////////////////////////////////////////////////////////////////////////
  763. // Processes drags and keys into transform stuff.
  764. ////////////////////////////////////////////////////////////////////////////////
  765. void
  766. CTexEdit::ProcessManip(
  767. bool bButtonDown, // In: true if mouse button down.
  768. RInputEvent* pie, // In: Current input event.
  769. CSprite3* psprite, // In: 3D data to process.
  770. RSop* psopView) // In: View space SOP.
  771. {
  772. // Transformation Manipulation Processing /////////////////
  773. if (bButtonDown && m_manip != Paint)
  774. {
  775. // If first time . . .
  776. if (m_bDragging == false)
  777. {
  778. rspSetMouse(m_sCursorResetX, m_sCursorResetY);
  779. rspHideMouseCursor();
  780. m_bDragging = true;
  781. }
  782. short sCursorX, sCursorY;
  783. rspGetMouse(&sCursorX, &sCursorY, NULL);
  784. rspSetMouse(m_sCursorResetX, m_sCursorResetY);
  785. short sDeltaX = sCursorX - m_sCursorResetX;
  786. short sDeltaY = m_sCursorResetY - sCursorY;
  787. static U8* pau8KeyStatus = rspGetKeyStatusArray();
  788. if (pau8KeyStatus[RSP_SK_SHIFT] & 1)
  789. sDeltaY = 0;
  790. if (pau8KeyStatus[RSP_SK_CONTROL] & 1)
  791. sDeltaX = 0;
  792. switch (m_manip)
  793. {
  794. case Trans:
  795. m_fX += sDeltaX * c_fTransRate;
  796. m_fY += sDeltaY * c_fTransRate;
  797. break;
  798. case Scale:
  799. if (sDeltaY)
  800. {
  801. m_fScale += sDeltaY * c_fScaleRate;
  802. if (m_fScale < 0.1f)
  803. m_fScale = 0.1f;
  804. if (m_fScale > 1.0f)
  805. m_fScale = 1.0f;
  806. }
  807. break;
  808. case Rot:
  809. m_transRot.Ry(rspMod360(sDeltaX * c_fRotRate) );
  810. m_transRot.Rx(rspMod360(-sDeltaY * c_fRotRate) );
  811. break;
  812. }
  813. }
  814. else
  815. {
  816. if (m_bDragging == true)
  817. {
  818. rspShowMouseCursor();
  819. m_bDragging = false;
  820. }
  821. }
  822. // Paint Processing /////////////////////////////////
  823. if (m_manip == Paint)
  824. {
  825. RP3d hitpoint;
  826. RP3d linept1, linept2;
  827. short sMouseX, sMouseY;
  828. rspGetMouse(&sMouseX, &sMouseY, NULL);
  829. m_pguiAnim->TopPosToChild(&sMouseX, &sMouseY);
  830. linept1.x = sMouseX;
  831. linept1.y = sMouseY;
  832. linept1.z = -SHRT_MAX;
  833. linept2.x = sMouseX;
  834. linept2.y = sMouseY;
  835. linept2.z = SHRT_MAX;
  836. long lTriIndex;
  837. bool bHit = TrianglesIntersectLineSegment(
  838. linept1, // In: line segment point 1
  839. linept2, // In: line segment point 2 closest to this point. this should be the first point.
  840. psprite->m_pmesh->m_pArray, // In: mesh
  841. psopView->m_pArray, // In: points for mesh
  842. psprite->m_pmesh->m_sNum, // In: number of points in mesh
  843. hitpoint, // Out: point where line hit triangle
  844. lTriIndex); // Out: index of triangle it hit
  845. if (bHit)
  846. {
  847. m_lTriIndex = lTriIndex;
  848. SetStatusText("Triangle %ld", m_lTriIndex);
  849. if (bButtonDown)
  850. {
  851. RTexture* ptex = psprite->m_ptex;
  852. // Get into texture and replace current triangle index with our current color.
  853. if (ptex->m_pIndices)
  854. {
  855. ASSERT(m_lTriIndex < ptex->m_sNum);
  856. // Set new color for this texture.
  857. ptex->m_pIndices[m_lTriIndex] = m_u8Color;
  858. // Note modification.
  859. m_bModified = true;
  860. }
  861. }
  862. }
  863. else
  864. {
  865. // If last time we found a triangle . . .
  866. if (m_lTriIndex >= 0)
  867. {
  868. // Clear status text.
  869. SetStatusText("");
  870. }
  871. else
  872. {
  873. // Otherwise, text does not refer to a triangle. So leave it.
  874. }
  875. m_lTriIndex = -1;
  876. }
  877. }
  878. // Color Palette Processing ///////////////////
  879. if (m_pguiPal->m_sPressed)
  880. {
  881. short sMouseX, sMouseY;
  882. rspGetMouse(&sMouseX, &sMouseY, NULL);
  883. m_pguiPal->TopPosToChild(&sMouseX, &sMouseY);
  884. // Get color directly out of GUI.
  885. U8 u8Color = *(m_pguiPal->m_im.m_pData + (sMouseY * m_pguiPal->m_im.m_lPitch) + sMouseX);
  886. SetColor(u8Color);
  887. // Go into paint mode when a color is chosen. Feels right somehow.
  888. SetManip(Paint);
  889. }
  890. // Input processing ///////////////////////////
  891. if (pie->sUsed == FALSE)
  892. {
  893. if (pie->type == RInputEvent::Key)
  894. {
  895. switch (pie->lKey)
  896. {
  897. case 'T':
  898. case 't':
  899. SetManip(Trans);
  900. break;
  901. case 'S':
  902. case 's':
  903. SetManip(Scale);
  904. break;
  905. case 'R':
  906. case 'r':
  907. SetManip(Rot);
  908. break;
  909. case 'P':
  910. case 'p':
  911. case 'D':
  912. case 'd':
  913. SetManip(Paint);
  914. break;
  915. case 'I':
  916. case 'i':
  917. ResetTransformation();
  918. break;
  919. case 27:
  920. m_bQuit = true;
  921. break;
  922. case '\r':
  923. m_transRot.Make1();
  924. break;
  925. }
  926. }
  927. }
  928. if (rspGetQuitStatus() != FALSE)
  929. {
  930. m_bQuit = true;
  931. }
  932. }
  933. //------------------------------------------------------------------------------
  934. // Querries.
  935. //------------------------------------------------------------------------------
  936. //------------------------------------------------------------------------------
  937. // Internal Functions.
  938. //------------------------------------------------------------------------------
  939. //////////////////////////////////////////////////////////////////////////////
  940. // Apply work colors to real thing.
  941. //////////////////////////////////////////////////////////////////////////////
  942. void
  943. CTexEdit::Apply(void)
  944. {
  945. if (m_ptexSrc)
  946. {
  947. *m_ptexSrc = m_texWork;
  948. m_bModified = false;
  949. SetStatusText("Applied.");
  950. }
  951. }
  952. //////////////////////////////////////////////////////////////////////////////
  953. // Revert work colors to real thing.
  954. //////////////////////////////////////////////////////////////////////////////
  955. void
  956. CTexEdit::Revert(void)
  957. {
  958. if (m_ptexSrc)
  959. {
  960. m_texWork = *m_ptexSrc;
  961. m_bModified = false;
  962. SetStatusText("Reverted.");
  963. }
  964. }
  965. //////////////////////////////////////////////////////////////////////////////
  966. // Save work colors to real thing.
  967. //////////////////////////////////////////////////////////////////////////////
  968. void
  969. CTexEdit::Save(void)
  970. {
  971. Apply();
  972. if (m_ptexchanSrc)
  973. {
  974. if (rspEZSave(m_ptexchanSrc, m_strFileName) == 0)
  975. {
  976. SetStatusText("Applied; Saved \"%s\".", (const char*)m_strFileName);
  977. }
  978. else
  979. {
  980. SetStatusText("Applied; Failed to save \"%s\".", (const char*)m_strFileName);
  981. }
  982. }
  983. }
  984. //////////////////////////////////////////////////////////////////////////////
  985. // Set the current manipulation type.
  986. //////////////////////////////////////////////////////////////////////////////
  987. void
  988. CTexEdit::SetManip(
  989. Manip manip) // In: New manipulation type.
  990. {
  991. if (m_pguiRoot)
  992. {
  993. SetPushBtnState(m_pguiRoot, m_manip + c_lIdTrans, RPushBtn::Off);
  994. m_manip = manip;
  995. SetPushBtnState(m_pguiRoot, m_manip + c_lIdTrans, RPushBtn::On);
  996. }
  997. }
  998. //////////////////////////////////////////////////////////////////////////////
  999. // Set the current palette color.
  1000. //////////////////////////////////////////////////////////////////////////////
  1001. void
  1002. CTexEdit::SetColor(
  1003. U8 u8Color) // In: New color index.
  1004. {
  1005. // Make sure it's in range . . .
  1006. if (u8Color >= c_sPalStart && u8Color <= c_sPalEnd)
  1007. {
  1008. m_u8Color = u8Color;
  1009. if (m_pguiCurColor)
  1010. {
  1011. // Show current color in this item.
  1012. short sX, sY, sW, sH;
  1013. m_pguiCurColor->GetClient(&sX, &sY, &sW, &sH);
  1014. rspRect(
  1015. u8Color,
  1016. &m_pguiCurColor->m_im,
  1017. sX, sY,
  1018. sW, sH,
  1019. NULL);
  1020. }
  1021. }
  1022. }
  1023. ////////////////////////////////////////////////////////////////////////////////
  1024. // Set the specified button to notify.
  1025. ////////////////////////////////////////////////////////////////////////////////
  1026. void
  1027. CTexEdit::SetToNotify(
  1028. long lBtnId, // In: ID of btn whose callback will be set.
  1029. RGuiItem::BtnUpCall pfn) // In: Function to notify.
  1030. {
  1031. ASSERT(m_pguiRoot);
  1032. RGuiItem* pgui = m_pguiRoot->GetItemFromId(lBtnId);
  1033. if (pgui)
  1034. {
  1035. pgui->m_bcUser = pfn;
  1036. pgui->m_ulUserInstance = (ULONG)this;
  1037. }
  1038. }
  1039. //////////////////////////////////////////////////////////////////////////////
  1040. // Set the specified gui to notify.
  1041. //////////////////////////////////////////////////////////////////////////////
  1042. void
  1043. CTexEdit::SetToNotify(
  1044. long lId, // In: ID of gui whose callback will be set.
  1045. RGuiItem::InputEventCall pfn) // In: Function to notify.
  1046. {
  1047. ASSERT(m_pguiRoot);
  1048. RGuiItem* pgui = m_pguiRoot->GetItemFromId(lId);
  1049. if (pgui)
  1050. {
  1051. pgui->m_fnInputEvent = pfn;
  1052. pgui->m_ulUserInstance = (ULONG)this;
  1053. }
  1054. }
  1055. //////////////////////////////////////////////////////////////////////////////
  1056. // Set the specified scrollbar to notify.
  1057. //////////////////////////////////////////////////////////////////////////////
  1058. void
  1059. CTexEdit::SetToNotify(
  1060. long lId, // In: ID of scrollbar whose callback will be set.
  1061. RScrollBar::UpdatePosCall pfn) // In: Function to notify.
  1062. {
  1063. ASSERT(m_pguiRoot);
  1064. RScrollBar* psb = (RScrollBar*)m_pguiRoot->GetItemFromId(lId);
  1065. if (psb)
  1066. {
  1067. if (psb->m_type == RGuiItem::ScrollBar)
  1068. {
  1069. psb->m_upcUser = pfn;
  1070. psb->m_ulUserInstance = (ULONG)this;
  1071. }
  1072. }
  1073. }
  1074. //////////////////////////////////////////////////////////////////////////////
  1075. // Set the status text field to that specified.
  1076. //////////////////////////////////////////////////////////////////////////////
  1077. void
  1078. CTexEdit::SetStatusText(
  1079. const char* pszFrmt, // In: Format specifier ala sprintf.
  1080. ...) // In: Arguments as specified by format.
  1081. {
  1082. RGuiItem* pguiStatus = m_pguiRoot->GetItemFromId(c_lIdStatus);
  1083. if (pguiStatus)
  1084. {
  1085. va_list val;
  1086. va_start(val, pszFrmt);
  1087. vsprintf(pguiStatus->m_szText, pszFrmt, val);
  1088. // Recompose with new text.
  1089. pguiStatus->Compose();
  1090. }
  1091. }
  1092. //////////////////////////////////////////////////////////////////////////////
  1093. // Compose tarnsformations in the specified transform. Init transform before
  1094. // calling as necessary.
  1095. //////////////////////////////////////////////////////////////////////////////
  1096. void
  1097. CTexEdit::ComposeTransform(
  1098. RTransform& trans) // In: Transform to compose in.
  1099. {
  1100. trans = m_transRot;
  1101. trans.Scale(m_fScale, m_fScale, m_fScale);
  1102. trans.Trans(m_fX, m_fY, 0.0f);
  1103. }
  1104. //------------------------------------------------------------------------------
  1105. // Callbacks.
  1106. //------------------------------------------------------------------------------
  1107. ////////////////////////////////////////////////////////////////////////////////
  1108. // Called when user presses Quit.
  1109. ////////////////////////////////////////////////////////////////////////////////
  1110. void
  1111. CTexEdit::QuitCall(RGuiItem* pgui)
  1112. {
  1113. m_bQuit = true;
  1114. }
  1115. ////////////////////////////////////////////////////////////////////////////////
  1116. // Called when user presses a manipulation mode button.
  1117. ////////////////////////////////////////////////////////////////////////////////
  1118. void
  1119. CTexEdit::ManipCall(RGuiItem* pgui)
  1120. {
  1121. SetManip(Manip(pgui->m_lId - c_lIdTrans) );
  1122. }
  1123. ////////////////////////////////////////////////////////////////////////////////
  1124. // Called when user clicks in the color palette
  1125. ////////////////////////////////////////////////////////////////////////////////
  1126. void
  1127. CTexEdit::ColorCall(RGuiItem* pgui, RInputEvent* pie)
  1128. {
  1129. if (pie->type == RInputEvent::Mouse)
  1130. {
  1131. switch (pie->sEvent)
  1132. {
  1133. case RSP_MB0_PRESSED:
  1134. {
  1135. #if 0 // This is now done in ProcessManip().
  1136. // Get color directly out of GUI.
  1137. U8 u8Color = *(pgui->m_im.m_pData + (pie->sPosY * pgui->m_im.m_lPitch) + pie->sPosX);
  1138. SetColor(u8Color);
  1139. // Go into paint mode when a color is chosen. Feels right somehow.
  1140. SetManip(Paint);
  1141. #endif
  1142. break;
  1143. }
  1144. }
  1145. }
  1146. }
  1147. ////////////////////////////////////////////////////////////////////////////////
  1148. // Called when user presses Apply.
  1149. ////////////////////////////////////////////////////////////////////////////////
  1150. void
  1151. CTexEdit::ApplyCall(RGuiItem* pgui)
  1152. {
  1153. Apply();
  1154. }
  1155. ////////////////////////////////////////////////////////////////////////////////
  1156. // Called when user presses Save.
  1157. ////////////////////////////////////////////////////////////////////////////////
  1158. void
  1159. CTexEdit::SaveCall(RGuiItem* pgui)
  1160. {
  1161. Save();
  1162. }
  1163. ////////////////////////////////////////////////////////////////////////////////
  1164. // Called when user presses Revert.
  1165. ////////////////////////////////////////////////////////////////////////////////
  1166. void
  1167. CTexEdit::RevertCall(RGuiItem* pgui)
  1168. {
  1169. Revert();
  1170. }
  1171. ////////////////////////////////////////////////////////////////////////////////
  1172. // Called when user presses Spot light button.
  1173. ////////////////////////////////////////////////////////////////////////////////
  1174. void
  1175. CTexEdit::SpotCall(RGuiItem* pgui)
  1176. {
  1177. ASSERT(pgui->m_type == RGuiItem::PushBtn);
  1178. RPushBtn* pbtn = (RPushBtn*)pgui;
  1179. m_bSpotLight = (pbtn->m_state == RPushBtn::On) ? true : false;
  1180. }
  1181. ////////////////////////////////////////////////////////////////////////////////
  1182. // Called when user adjust Brightness scrollbar.
  1183. ////////////////////////////////////////////////////////////////////////////////
  1184. void
  1185. CTexEdit::BrightnessCall(RScrollBar* psb)
  1186. {
  1187. long lMin, lMax;
  1188. psb->GetRange(&lMin, &lMax);
  1189. float fRange = lMax - lMin + 1;
  1190. if (fRange != 0.0f)
  1191. m_sBrightness = c_sMinBrightness + (psb->GetPos() / fRange) * c_sBrightnessRange;
  1192. }
  1193. ////////////////////////////////////////////////////////////////////////////////
  1194. // Called when user presses Adjust button.
  1195. ////////////////////////////////////////////////////////////////////////////////
  1196. void
  1197. CTexEdit::AdjustCall(RGuiItem* pgui)
  1198. {
  1199. // Get frequency.
  1200. long lFreq = m_pguiRoot->GetVal(c_lIdFrequency);
  1201. char szText[GUI_MAX_STR];
  1202. m_pguiRoot->GetText(c_lIdAmount, szText, sizeof(szText) );
  1203. float fAdjust = strtod(szText, NULL);
  1204. // Get palette to work with.
  1205. U8 au8Red[256];
  1206. U8 au8Green[256];
  1207. U8 au8Blue[256];
  1208. rspGetPaletteEntries(
  1209. 0, // Palette entry to start copying from
  1210. 256, // Number of palette entries to do
  1211. au8Red, // Pointer to first red component to copy to
  1212. au8Green, // Pointer to first green component to copy to
  1213. au8Blue, // Pointer to first blue component to copy to
  1214. sizeof(U8) ); // Number of bytes by which to increment pointers after each copy
  1215. // Unmap colors from palette into full color values.
  1216. m_texWork.Unmap(
  1217. au8Red,
  1218. au8Green,
  1219. au8Blue,
  1220. sizeof(U8) );
  1221. // Adjust colors.
  1222. m_texWork.Adjust(
  1223. fAdjust,
  1224. lFreq);
  1225. // Remap onto palette.
  1226. m_texWork.Remap(
  1227. c_sPalStart,
  1228. c_sPalNum,
  1229. au8Red,
  1230. au8Green,
  1231. au8Blue,
  1232. sizeof(U8) );
  1233. // Get rid of full colors.
  1234. m_texWork.FreeColors();
  1235. }
  1236. ////////////////////////////////////////////////////////////////////////////////
  1237. // Called when user clicks in the anim surface.
  1238. ////////////////////////////////////////////////////////////////////////////////
  1239. void
  1240. CTexEdit::AnimCall(RGuiItem* pgui, RInputEvent* pie)
  1241. {
  1242. if (pie->type == RInputEvent::Mouse)
  1243. {
  1244. switch (pie->sEvent)
  1245. {
  1246. case RSP_MB1_PRESSED:
  1247. // Do NOT Get color directly out of GUI. The color there has already
  1248. // undergone lighting effects. Get the color from the actual texture.
  1249. if (m_lTriIndex)
  1250. {
  1251. U8 u8Color = m_texWork.m_pIndices[m_lTriIndex];
  1252. SetColor(u8Color);
  1253. }
  1254. break;
  1255. }
  1256. }
  1257. }
  1258. //------------------------------------------------------------------------------
  1259. // EOF
  1260. //------------------------------------------------------------------------------