render2d.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/render2d.cpp $*
  25. * *
  26. * $Org Author:: Byon_g $Modtime:: 1/24/01 3:54p $*
  27. * *
  28. * Author : Kenny Mitchell *
  29. * *
  30. * $Modtime:: 08/05/02 2:40p $*
  31. * *
  32. * $Revision:: 48 $*
  33. * *
  34. * 06/26/02 KM Matrix name change to avoid MAX conflicts *
  35. * 08/05/02 KM Texture class redesign
  36. *---------------------------------------------------------------------------------------------*
  37. * Functions: *
  38. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  39. #include "render2d.h"
  40. #include "mutex.h"
  41. #include "ww3d.h"
  42. #include "refcount.h"
  43. #include "font3d.h"
  44. #include "rect.h"
  45. #include "texture.h"
  46. #include "matrix4.h"
  47. #include "matrix3d.h"
  48. #include "dx8wrapper.h"
  49. #include "dx8indexbuffer.h"
  50. #include "dx8vertexbuffer.h"
  51. #include "sortingrenderer.h"
  52. #include "vertmaterial.h"
  53. #include "dx8fvf.h"
  54. #include "dx8caps.h"
  55. #include "wwprofile.h"
  56. #include "wwmemlog.h"
  57. #include "assetmgr.h"
  58. //#pragma optimize("", off)
  59. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  60. RectClass Render2DClass::ScreenResolution( 0,0,0,0 );
  61. /*
  62. ** Render2DClass
  63. */
  64. Render2DClass::Render2DClass( TextureClass* tex ) :
  65. CoordinateScale( 1, 1 ),
  66. CoordinateOffset( 0, 0 ),
  67. Texture(0),
  68. ZValue(0),
  69. IsHidden( false ),
  70. IsGrayScale (false),
  71. Indices(sizeof(PreAllocatedIndices)/sizeof(unsigned short),PreAllocatedIndices),
  72. Vertices(sizeof(PreAllocatedVertices)/sizeof(Vector2),PreAllocatedVertices),
  73. UVCoordinates(sizeof(PreAllocatedUVCoordinates)/sizeof(Vector2),PreAllocatedUVCoordinates),
  74. Colors(sizeof(PreAllocatedColors)/sizeof(unsigned long),PreAllocatedColors)
  75. {
  76. Set_Texture( tex );
  77. Shader = Get_Default_Shader();
  78. return ;
  79. }
  80. Render2DClass::~Render2DClass()
  81. {
  82. REF_PTR_RELEASE(Texture);
  83. }
  84. void Render2DClass::Set_Screen_Resolution( const RectClass & screen )
  85. {
  86. ScreenResolution = screen;
  87. #if 0
  88. // Fool into pixel doubling - Byon..
  89. if ( screen.Width() >= 1280 ) {
  90. ScreenResolution.Scale( 0.5f );
  91. }
  92. // ScreenResolution = RectClass( 0, 0, 800, 600 );
  93. #endif
  94. }
  95. ShaderClass
  96. Render2DClass::Get_Default_Shader( void )
  97. {
  98. ShaderClass shader;
  99. shader.Set_Depth_Mask( ShaderClass::DEPTH_WRITE_DISABLE );
  100. shader.Set_Depth_Compare( ShaderClass::PASS_ALWAYS );
  101. shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA );
  102. shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_SRC_ALPHA );
  103. shader.Set_Fog_Func( ShaderClass::FOG_DISABLE );
  104. shader.Set_Primary_Gradient( ShaderClass::GRADIENT_MODULATE );
  105. shader.Set_Texturing( ShaderClass::TEXTURING_ENABLE );
  106. return shader;
  107. }
  108. void Render2DClass::Reset(void)
  109. {
  110. Vertices.Reset_Active();
  111. UVCoordinates.Reset_Active();
  112. Colors.Reset_Active();
  113. Indices.Reset_Active();
  114. Update_Bias(); // Keep the bias updated
  115. }
  116. void Render2DClass::Set_Texture(TextureClass* tex)
  117. {
  118. REF_PTR_SET(Texture,tex);
  119. }
  120. void Render2DClass::Set_Texture( const char * filename)
  121. {
  122. TextureClass * tex = WW3DAssetManager::Get_Instance()->Get_Texture( filename, MIP_LEVELS_1 );
  123. Set_Texture( tex );
  124. if ( tex != NULL ) {
  125. SET_REF_OWNER( tex );
  126. tex->Release_Ref();
  127. }
  128. }
  129. /**added for generals to draw disabled button states - MW*/
  130. void Render2DClass::Enable_Grayscale(bool b)
  131. {
  132. IsGrayScale = b;
  133. }
  134. void Render2DClass::Enable_Alpha(bool b)
  135. {
  136. IsGrayScale = false;
  137. if (b) {
  138. Shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA );
  139. Shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_SRC_ALPHA );
  140. }
  141. else {
  142. Shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_ONE);
  143. Shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ZERO );
  144. }
  145. }
  146. void Render2DClass::Enable_Additive(bool b)
  147. {
  148. IsGrayScale = false;
  149. if (b) {
  150. Shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ONE );
  151. Shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_ONE );
  152. }
  153. else {
  154. Shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_ONE);
  155. Shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ZERO );
  156. }
  157. }
  158. void Render2DClass::Enable_Texturing(bool b)
  159. {
  160. if (b) {
  161. Shader.Set_Texturing( ShaderClass::TEXTURING_ENABLE );
  162. }
  163. else {
  164. Shader.Set_Texturing( ShaderClass::TEXTURING_DISABLE );
  165. }
  166. }
  167. void Render2DClass::Set_Coordinate_Range( const RectClass & range )
  168. {
  169. // default range is (-1,1)-(1,-1)
  170. CoordinateScale.X = 2 / range.Width();
  171. CoordinateScale.Y = -2 / range.Height();
  172. CoordinateOffset.X = -(CoordinateScale.X * range.Left) - 1;
  173. CoordinateOffset.Y = -(CoordinateScale.Y * range.Top) + 1;
  174. Update_Bias();
  175. }
  176. void Render2DClass::Update_Bias( void )
  177. {
  178. BiasedCoordinateOffset = CoordinateOffset;
  179. if ( WW3D::Is_Screen_UV_Biased() ) { // Global bais setting
  180. Vector2 bais_add( -0.5f ,-0.5f ); // offset by -0.5,-0.5 in pixels
  181. // Convert from pixels to (-1,1)-(1,-1) units
  182. bais_add.X = bais_add.X / (Get_Screen_Resolution().Width() * 0.5f);
  183. bais_add.Y = bais_add.Y / (Get_Screen_Resolution().Height() * -0.5f);
  184. BiasedCoordinateOffset += bais_add;
  185. }
  186. }
  187. #if 0
  188. Vector2 Render2DClass::Convert_Vert( const Vector2 & v )
  189. {
  190. Vector2 out;
  191. // Convert to (-1,1)-(1,-1)
  192. out.X = v.X * CoordinateScale.X + CoordinateOffset.X;
  193. out.Y = v.Y * CoordinateScale.Y + CoordinateOffset.Y;
  194. // Convert to pixels
  195. out.X = (out.X + 1.0f) * (Get_Screen_Resolution().Width() * 0.5f);
  196. out.Y = (out.Y - 1.0f) * (Get_Screen_Resolution().Height() * -0.5f);
  197. // Round to nearest pixel
  198. out.X = WWMath::Floor( out.X + 0.5f );
  199. out.Y = WWMath::Floor( out.Y + 0.5f );
  200. // Bias
  201. if ( WW3D::Is_Screen_UV_Biased() ) { // Global bais setting
  202. out.X -= 0.5f;
  203. out.Y -= 0.5f;
  204. }
  205. // Convert back to (-1,1)-(1,-1)
  206. out.X = out.X / (Get_Screen_Resolution().Width() * 0.5f) - 1.0f;
  207. out.Y = out.Y / (Get_Screen_Resolution().Height() * -0.5f) + 1.0f;
  208. return out;
  209. }
  210. #else
  211. /*
  212. ** Convert Vert must convert from the convention defined by Set_Coordinate_Range
  213. ** into the convention (-1,1)-(1,-1), which is needed by the renderer.
  214. // NOPE ** In addition, it rounds all coordinates off to the nearest pixel
  215. ** Also, it offsets the coordinates as need for Screen_UV_Bias
  216. */
  217. void Render2DClass::Convert_Vert( Vector2 & vert_out, const Vector2 & vert_in )
  218. {
  219. // Convert to (-1,1)-(1,-1)
  220. vert_out.X = vert_in.X * CoordinateScale.X + BiasedCoordinateOffset.X;
  221. vert_out.Y = vert_in.Y * CoordinateScale.Y + BiasedCoordinateOffset.Y;
  222. }
  223. void Render2DClass::Convert_Vert( Vector2 & vert_out, float x_in, float y_in )
  224. {
  225. // Convert to (-1,1)-(1,-1)
  226. vert_out.X = x_in * CoordinateScale.X + BiasedCoordinateOffset.X;
  227. vert_out.Y = y_in * CoordinateScale.Y + BiasedCoordinateOffset.Y;
  228. }
  229. #endif
  230. void Render2DClass::Move( const Vector2 & move ) // Move all verts
  231. {
  232. Vector2 scaled_move;
  233. scaled_move.X = move.X * CoordinateScale.X;
  234. scaled_move.Y = move.Y * CoordinateScale.Y;
  235. for ( int i = 0; i < Vertices.Count(); i++ ) {
  236. Vertices[i] += scaled_move;
  237. }
  238. }
  239. void Render2DClass::Force_Alpha( float alpha ) // Force all alphas
  240. {
  241. unsigned long a = (unsigned)(WWMath::Clamp( alpha, 0, 1 ) * 255.0f);
  242. a <<= 24;
  243. for ( int i = 0; i < Colors.Count(); i++ ) {
  244. Colors[i] = (Colors[i] & 0x00FFFFFF) | a;
  245. }
  246. }
  247. void Render2DClass::Force_Color( int color ) // Force all alphas
  248. {
  249. for ( int i = 0; i < Colors.Count(); i++ ) {
  250. Colors[i] = color;
  251. }
  252. }
  253. /*
  254. ** Internal Add Quad Elements
  255. ** Caller must mutex lock
  256. */
  257. void Render2DClass::Internal_Add_Quad_Vertices( const Vector2 & v0, const Vector2 & v1, const Vector2 & v2, const Vector2 & v3 )
  258. {
  259. Convert_Vert( *Vertices.Uninitialized_Add(), v0 );
  260. Convert_Vert( *Vertices.Uninitialized_Add(), v1 );
  261. Convert_Vert( *Vertices.Uninitialized_Add(), v2 );
  262. Convert_Vert( *Vertices.Uninitialized_Add(), v3 );
  263. }
  264. void Render2DClass::Internal_Add_Quad_Vertices( const RectClass & screen )
  265. {
  266. Convert_Vert( *Vertices.Uninitialized_Add(), screen.Left, screen.Top );
  267. Convert_Vert( *Vertices.Uninitialized_Add(), screen.Left, screen.Bottom );
  268. Convert_Vert( *Vertices.Uninitialized_Add(), screen.Right, screen.Top );
  269. Convert_Vert( *Vertices.Uninitialized_Add(), screen.Right, screen.Bottom );
  270. }
  271. void Render2DClass::Internal_Add_Quad_UVs( const RectClass & uv )
  272. {
  273. Vector2* uvs;
  274. uvs=UVCoordinates.Uninitialized_Add();
  275. uvs->X = uv.Left; uvs->Y = uv.Top;
  276. uvs=UVCoordinates.Uninitialized_Add();
  277. uvs->X = uv.Left; uvs->Y = uv.Bottom;
  278. uvs=UVCoordinates.Uninitialized_Add();
  279. uvs->X = uv.Right; uvs->Y = uv.Top;
  280. uvs=UVCoordinates.Uninitialized_Add();
  281. uvs->X = uv.Right; uvs->Y = uv.Bottom;
  282. }
  283. void Render2DClass::Internal_Add_Quad_Colors( unsigned long color )
  284. {
  285. unsigned long* colors;
  286. colors=Colors.Uninitialized_Add();
  287. *colors=color;
  288. colors=Colors.Uninitialized_Add();
  289. *colors=color;
  290. colors=Colors.Uninitialized_Add();
  291. *colors=color;
  292. colors=Colors.Uninitialized_Add();
  293. *colors=color;
  294. }
  295. void Render2DClass::Internal_Add_Quad_VColors( unsigned long color1, unsigned long color2 )
  296. {
  297. unsigned long* colors;
  298. colors=Colors.Uninitialized_Add();
  299. *colors=color1;
  300. colors=Colors.Uninitialized_Add();
  301. *colors=color2;
  302. colors=Colors.Uninitialized_Add();
  303. *colors=color1;
  304. colors=Colors.Uninitialized_Add();
  305. *colors=color2;
  306. }
  307. void Render2DClass::Internal_Add_Quad_HColors( unsigned long color1, unsigned long color2 )
  308. {
  309. unsigned long* colors;
  310. colors=Colors.Uninitialized_Add();
  311. *colors=color1;
  312. colors=Colors.Uninitialized_Add();
  313. *colors=color1;
  314. colors=Colors.Uninitialized_Add();
  315. *colors=color2;
  316. colors=Colors.Uninitialized_Add();
  317. *colors=color2;
  318. }
  319. void Render2DClass::Internal_Add_Quad_Indicies( int start_vert_index, bool backfaced )
  320. {
  321. unsigned short * indices;
  322. if (backfaced ^ (CoordinateScale.X * CoordinateScale.Y > 0)) {
  323. indices=Indices.Uninitialized_Add();
  324. *indices = start_vert_index + 1;
  325. indices=Indices.Uninitialized_Add();
  326. *indices = start_vert_index + 0;
  327. indices=Indices.Uninitialized_Add();
  328. *indices = start_vert_index + 2;
  329. indices=Indices.Uninitialized_Add();
  330. *indices = start_vert_index + 1;
  331. indices=Indices.Uninitialized_Add();
  332. *indices = start_vert_index + 2;
  333. indices=Indices.Uninitialized_Add();
  334. *indices = start_vert_index + 3;
  335. } else {
  336. indices=Indices.Uninitialized_Add();
  337. *indices = start_vert_index + 0;
  338. indices=Indices.Uninitialized_Add();
  339. *indices = start_vert_index + 1;
  340. indices=Indices.Uninitialized_Add();
  341. *indices = start_vert_index + 2;
  342. indices=Indices.Uninitialized_Add();
  343. *indices = start_vert_index + 2;
  344. indices=Indices.Uninitialized_Add();
  345. *indices = start_vert_index + 1;
  346. indices=Indices.Uninitialized_Add();
  347. *indices = start_vert_index + 3;
  348. }
  349. }
  350. void Render2DClass::Add_Quad( const Vector2 & v0, const Vector2 & v1, const Vector2 & v2, const Vector2 & v3, const RectClass & uv, unsigned long color )
  351. {
  352. Internal_Add_Quad_Indicies( Vertices.Count() );
  353. Internal_Add_Quad_Vertices( v0, v1, v2, v3 );
  354. Internal_Add_Quad_UVs( uv );
  355. Internal_Add_Quad_Colors( color );
  356. }
  357. void Render2DClass::Add_Quad_Backfaced( const Vector2 & v0, const Vector2 & v1, const Vector2 & v2, const Vector2 & v3, const RectClass & uv, unsigned long color )
  358. {
  359. Internal_Add_Quad_Indicies( Vertices.Count(), true );
  360. Internal_Add_Quad_Vertices( v0, v1, v2, v3 );
  361. Internal_Add_Quad_UVs( uv );
  362. Internal_Add_Quad_Colors( color );
  363. }
  364. void Render2DClass::Add_Quad_VGradient( const Vector2 & v0, const Vector2 & v1, const Vector2 & v2, const Vector2 & v3, const RectClass & uv, unsigned long top_color, unsigned long bottom_color )
  365. {
  366. Internal_Add_Quad_Indicies( Vertices.Count() );
  367. Internal_Add_Quad_Vertices( v0, v1, v2, v3 );
  368. Internal_Add_Quad_UVs( uv );
  369. Internal_Add_Quad_VColors( top_color, bottom_color );
  370. }
  371. void Render2DClass::Add_Quad_HGradient( const Vector2 & v0, const Vector2 & v1, const Vector2 & v2, const Vector2 & v3, const RectClass & uv, unsigned long left_color, unsigned long right_color )
  372. {
  373. Internal_Add_Quad_Indicies( Vertices.Count() );
  374. Internal_Add_Quad_Vertices( v0, v1, v2, v3 );
  375. Internal_Add_Quad_UVs( uv );
  376. Internal_Add_Quad_HColors( left_color, right_color );
  377. }
  378. void Render2DClass::Add_Quad_VGradient( const RectClass & screen, unsigned long top_color, unsigned long bottom_color )
  379. {
  380. Internal_Add_Quad_Indicies( Vertices.Count() );
  381. Internal_Add_Quad_Vertices( screen );
  382. Internal_Add_Quad_UVs( RectClass( 0,0,1,1 ) );
  383. Internal_Add_Quad_VColors( top_color, bottom_color );
  384. }
  385. void Render2DClass::Add_Quad_HGradient( const RectClass & screen, unsigned long left_color, unsigned long right_color )
  386. {
  387. Internal_Add_Quad_Indicies( Vertices.Count() );
  388. Internal_Add_Quad_Vertices( screen );
  389. Internal_Add_Quad_UVs( RectClass( 0,0,1,1 ) );
  390. Internal_Add_Quad_HColors( left_color, right_color );
  391. }
  392. void Render2DClass::Add_Quad( const RectClass & screen, const RectClass & uv, unsigned long color )
  393. {
  394. Internal_Add_Quad_Indicies( Vertices.Count() );
  395. Internal_Add_Quad_Vertices( screen );
  396. Internal_Add_Quad_UVs( uv );
  397. Internal_Add_Quad_Colors( color );
  398. }
  399. void Render2DClass::Add_Quad( const Vector2 & v0, const Vector2 & v1, const Vector2 & v2, const Vector2 & v3, unsigned long color )
  400. {
  401. Internal_Add_Quad_Indicies( Vertices.Count() );
  402. Internal_Add_Quad_Vertices( v0, v1, v2, v3 );
  403. Internal_Add_Quad_UVs( RectClass( 0,0,1,1 ) );
  404. Internal_Add_Quad_Colors( color );
  405. }
  406. void Render2DClass::Add_Quad( const RectClass & screen, unsigned long color )
  407. {
  408. Internal_Add_Quad_Indicies( Vertices.Count() );
  409. Internal_Add_Quad_Vertices( screen );
  410. Internal_Add_Quad_UVs( RectClass( 0,0,1,1 ) );
  411. Internal_Add_Quad_Colors( color );
  412. }
  413. /*
  414. ** Add Tri
  415. */
  416. void Render2DClass::Add_Tri( const Vector2 & v0, const Vector2 & v1, const Vector2 & v2, const Vector2 & uv0, const Vector2 & uv1, const Vector2 & uv2, unsigned long color )
  417. {
  418. int old_vert_count = Vertices.Count();
  419. // Add the verticies (translated to new coordinates)
  420. #if 0
  421. Vertices.Add( Convert_Vert( v0 ), new_vert_count );
  422. Vertices.Add( Convert_Vert( v1 ), new_vert_count );
  423. Vertices.Add( Convert_Vert( v2 ), new_vert_count );
  424. #else
  425. Convert_Vert( *Vertices.Uninitialized_Add(), v0 );
  426. Convert_Vert( *Vertices.Uninitialized_Add(), v1 );
  427. Convert_Vert( *Vertices.Uninitialized_Add(), v2 );
  428. #endif
  429. // Add the uv coordinates
  430. *UVCoordinates.Uninitialized_Add()=uv0;
  431. *UVCoordinates.Uninitialized_Add()=uv1;
  432. *UVCoordinates.Uninitialized_Add()=uv2;
  433. // Add the colors
  434. *Colors.Uninitialized_Add()=color;
  435. *Colors.Uninitialized_Add()=color;
  436. *Colors.Uninitialized_Add()=color;
  437. // Add the faces
  438. *Indices.Uninitialized_Add()=old_vert_count + 0;
  439. *Indices.Uninitialized_Add()=old_vert_count + 1;
  440. *Indices.Uninitialized_Add()=old_vert_count + 2;
  441. }
  442. void Render2DClass::Add_Line( const Vector2 & a, const Vector2 & b, float width, unsigned long color )
  443. {
  444. Add_Line( a, b, width, RectClass( 0,0,1,1 ), color );
  445. }
  446. void Render2DClass::Add_Line( const Vector2 & a, const Vector2 & b, float width, const RectClass & uv, unsigned long color )
  447. {
  448. Vector2 corner_offset = a - b; // get line relative to b
  449. float temp = corner_offset.X; // Rotate 90
  450. corner_offset.X = corner_offset.Y;
  451. corner_offset.Y = -temp;
  452. corner_offset.Normalize(); // scale to length width/2
  453. corner_offset *= width / 2;
  454. Add_Quad( a - corner_offset, a + corner_offset, b - corner_offset, b + corner_offset, uv, color );
  455. //Add_Quad_HGradient(RectClass( a.X -corner_offset.X ,a.Y,b.X,b.Y ), color, color2);
  456. //Add_Quad_HGradient( const RectClass & screen, unsigned long left_color, unsigned long right_color );
  457. }
  458. void Render2DClass::Add_Line( const Vector2 & a, const Vector2 & b, float width, unsigned long color, unsigned long color2 )
  459. {
  460. Add_Line( a, b, width, RectClass( 0,0,1,1 ), color, color2 );
  461. }
  462. void Render2DClass::Add_Line( const Vector2 & a, const Vector2 & b, float width, const RectClass & uv, unsigned long color , unsigned long color2)
  463. {
  464. Vector2 corner_offset = a - b; // get line relative to b
  465. float temp = corner_offset.X; // Rotate 90
  466. corner_offset.X = corner_offset.Y;
  467. corner_offset.Y = -temp;
  468. corner_offset.Normalize(); // scale to length width/2
  469. corner_offset *= width / 2;
  470. Add_Quad_HGradient( a - corner_offset, a + corner_offset, b - corner_offset, b + corner_offset, uv, color,color2);
  471. //Add_Quad_HGradient(RectClass( a.X -corner_offset.X ,a.Y,b.X,b.Y ), color, color2);
  472. }
  473. void Render2DClass::Add_Rect( const RectClass & rect, float border_width, uint32 border_color, uint32 fill_color )
  474. {
  475. //
  476. // First add the outline
  477. //
  478. if( border_width > 0 )
  479. Add_Outline( rect, border_width, border_color );
  480. //
  481. // Next, fill the contents
  482. //
  483. RectClass fill_rect = rect;
  484. if( border_width > 0 )
  485. {
  486. fill_rect.Left += border_width + 1;
  487. fill_rect.Top += border_width + 1;
  488. fill_rect.Right -= border_width - 1;
  489. fill_rect.Bottom -= border_width - 1;
  490. }
  491. Add_Quad (fill_rect, fill_color);
  492. return ;
  493. }
  494. void Render2DClass::Add_Outline( const RectClass & rect, float width, unsigned long color )
  495. {
  496. Add_Outline( rect, width, RectClass( 0,0,1,1 ), color );
  497. }
  498. void Render2DClass::Add_Outline( const RectClass & rect, float width, const RectClass & uv, unsigned long color )
  499. {
  500. //
  501. // Pretty straight forward, simply add the four side of the rectangle as lines.
  502. //
  503. /** @todo colin, I had to tweak these to get precise line drawing, as we want
  504. the UV bias on, but it just isn't lining up */
  505. Add_Line (Vector2 (rect.Left + 1, rect.Bottom), Vector2 (rect.Left + 1, rect.Top + 1), width, color);
  506. Add_Line (Vector2 (rect.Left, rect.Top + 1), Vector2 (rect.Right - 1, rect.Top + 1), width, color);
  507. Add_Line (Vector2 (rect.Right, rect.Top), Vector2 (rect.Right, rect.Bottom - 1), width, color);
  508. Add_Line (Vector2 (rect.Right, rect.Bottom), Vector2 (rect.Left + 1, rect.Bottom), width, color);
  509. }
  510. void Render2DClass::Render(void)
  511. {
  512. if ( !Indices.Count() || IsHidden) {
  513. return;
  514. }
  515. // save the view and projection matrices since we're nuking them
  516. Matrix4x4 view,proj;
  517. Matrix4x4 identity(true);
  518. DX8Wrapper::Get_Transform(D3DTS_VIEW,view);
  519. DX8Wrapper::Get_Transform(D3DTS_PROJECTION,proj);
  520. //
  521. // Configure the viewport for entire screen
  522. //
  523. int width, height, bits;
  524. bool windowed;
  525. WW3D::Get_Device_Resolution( width, height, bits, windowed );
  526. D3DVIEWPORT8 vp = { 0 };
  527. vp.X = 0;
  528. vp.Y = 0;
  529. vp.Width = width;
  530. vp.Height = height;
  531. vp.MinZ = 0;
  532. vp.MaxZ = 1;
  533. DX8Wrapper::Set_Viewport(&vp);
  534. DX8Wrapper::Set_Texture(0,Texture);
  535. VertexMaterialClass *vm=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  536. DX8Wrapper::Set_Material(vm);
  537. REF_PTR_RELEASE(vm);
  538. DX8Wrapper::Set_World_Identity();
  539. DX8Wrapper::Set_View_Identity();
  540. DX8Wrapper::Set_Transform(D3DTS_PROJECTION,identity);
  541. DynamicVBAccessClass vb(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,Vertices.Count());
  542. {
  543. DynamicVBAccessClass::WriteLockClass Lock(&vb);
  544. const FVFInfoClass &fi=vb.FVF_Info();
  545. unsigned char *va=(unsigned char*)Lock.Get_Formatted_Vertex_Array();
  546. int i;
  547. for (i=0; i<Vertices.Count(); i++)
  548. {
  549. Vector3 temp(Vertices[i].X,Vertices[i].Y,ZValue);
  550. *(Vector3*)(va+fi.Get_Location_Offset())=temp;
  551. *(unsigned int*)(va+fi.Get_Diffuse_Offset())=Colors[i];
  552. *(Vector2*)(va+fi.Get_Tex_Offset(0))=UVCoordinates[i];
  553. va+=fi.Get_FVF_Size();
  554. }
  555. }
  556. DynamicIBAccessClass ib(BUFFER_TYPE_DYNAMIC_DX8,Indices.Count());
  557. try {
  558. DynamicIBAccessClass::WriteLockClass Lock(&ib);
  559. unsigned short *mem=Lock.Get_Index_Array();
  560. for (int i=0; i<Indices.Count(); i++)
  561. mem[i]=Indices[i];
  562. IndexBufferExceptionFunc();
  563. } catch(...) {
  564. IndexBufferExceptionFunc();
  565. }
  566. DX8Wrapper::Set_Vertex_Buffer(vb);
  567. DX8Wrapper::Set_Index_Buffer(ib,0);
  568. if (IsGrayScale)
  569. { //special case added to draw grayscale non-alpha blended images.
  570. DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader);
  571. DX8Wrapper::Apply_Render_State_Changes(); //force update of all regular W3D states.
  572. if (DX8Wrapper::Get_Current_Caps()->Support_Dot3())
  573. { //Override W3D states with customizations for grayscale
  574. DX8Wrapper::Set_DX8_Render_State(D3DRS_TEXTUREFACTOR, 0x80A5CA8E);
  575. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLORARG0, D3DTA_TFACTOR | D3DTA_ALPHAREPLICATE);
  576. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  577. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR | D3DTA_ALPHAREPLICATE);
  578. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD);
  579. DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG1, D3DTA_CURRENT);
  580. DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR);
  581. DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
  582. }
  583. else
  584. { //doesn't have DOT3 blend mode so fake it another way.
  585. DX8Wrapper::Set_DX8_Render_State(D3DRS_TEXTUREFACTOR, 0x60606060);
  586. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  587. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
  588. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  589. }
  590. }
  591. else
  592. DX8Wrapper::Set_Shader(Shader);
  593. DX8Wrapper::Draw_Triangles(0,Indices.Count()/3,0,Vertices.Count());
  594. DX8Wrapper::Set_Transform(D3DTS_VIEW,view);
  595. DX8Wrapper::Set_Transform(D3DTS_PROJECTION,proj);
  596. if (IsGrayScale)
  597. ShaderClass::Invalidate(); //force both stages to be reset.
  598. }
  599. /*
  600. ** Render2DTextClass
  601. */
  602. Render2DTextClass::Render2DTextClass(Font3DInstanceClass *font) :
  603. Location(0.0f,0.0f),
  604. Cursor(0.0f,0.0f),
  605. Font(NULL),
  606. WrapWidth(0),
  607. ClipRect(0, 0, 0, 0),
  608. IsClippedEnabled(false)
  609. {
  610. Set_Coordinate_Range( RectClass( -320, -240, 320, 240 ) );
  611. Set_Font( font );
  612. Reset();
  613. }
  614. Render2DTextClass::~Render2DTextClass()
  615. {
  616. REF_PTR_RELEASE(Font);
  617. }
  618. void Render2DTextClass::Reset(void)
  619. {
  620. Render2DClass::Reset();
  621. Cursor = Location;
  622. WrapWidth = 0;
  623. DrawExtents = RectClass( 0,0,0,0 );
  624. TotalExtents = RectClass( 0,0,0,0 );
  625. ClipRect.Set (0, 0, 0, 0);
  626. IsClippedEnabled = false;
  627. }
  628. void Render2DTextClass::Set_Font( Font3DInstanceClass *font )
  629. {
  630. REF_PTR_SET(Font,font);
  631. if ( Font != NULL ) {
  632. Set_Texture( Font->Peek_Texture() );
  633. #define BLOCK_CHAR 0
  634. BlockUV = Font->Char_UV( BLOCK_CHAR );
  635. // Inset it a bit to be sure we have no edge problems
  636. BlockUV.Inflate( Vector2(-BlockUV.Width()/4, -BlockUV.Height()/4) );
  637. }
  638. }
  639. /*
  640. **
  641. */
  642. void Render2DTextClass::Draw_Char( WCHAR ch, unsigned long color )
  643. {
  644. float char_spacing = Font->Char_Spacing( ch );
  645. float char_height = Font->Char_Height();
  646. //
  647. // Check to see if this character is clipped
  648. //
  649. bool is_clipped = false;
  650. if ( IsClippedEnabled &&
  651. (Cursor.X < ClipRect.Left ||
  652. Cursor.X + char_spacing > ClipRect.Right ||
  653. Cursor.Y < ClipRect.Top ||
  654. Cursor.Y + char_height > ClipRect.Bottom))
  655. {
  656. is_clipped = true;
  657. }
  658. if ( ch != (WCHAR)' ' && !is_clipped ) {
  659. RectClass screen( Cursor.X, Cursor.Y, Cursor.X + Font->Char_Width(ch), Cursor.Y + char_height );
  660. Internal_Add_Quad_Indicies( Vertices.Count() );
  661. Internal_Add_Quad_Vertices( screen );
  662. Internal_Add_Quad_UVs( Font->Char_UV( ch ) );
  663. Internal_Add_Quad_Colors( color );
  664. DrawExtents += screen;
  665. TotalExtents += screen;
  666. }
  667. Cursor.X += char_spacing;
  668. }
  669. void Render2DTextClass::Draw_Text( const char * text, unsigned long color )
  670. {
  671. WWMEMLOG(MEM_GEOMETRY);
  672. WideStringClass wide(0,true);
  673. wide.Convert_From( text );
  674. Draw_Text( wide, color );
  675. }
  676. void Render2DTextClass::Draw_Text( const WCHAR * text, unsigned long color )
  677. {
  678. WWMEMLOG(MEM_GEOMETRY);
  679. // Reset the Extents
  680. DrawExtents = RectClass( Location, Location );
  681. if ( TotalExtents.Width() == 0 ) {
  682. TotalExtents = RectClass( Location, Location );
  683. }
  684. while (*text) {
  685. WCHAR ch = *text++;
  686. // Check to see if we need to move to a newline or not
  687. bool wrap = ( ch == (WCHAR)'\n' );
  688. // if the current char is a space, and the next word length puts us past our Width, wrap
  689. if ( ch == (WCHAR)' ' && WrapWidth > 0 ) {
  690. const WCHAR * word = text;
  691. float word_width = Font->Char_Spacing(ch);
  692. while ( (*word != (WCHAR)0) && (*word > (WCHAR)' ') ) {
  693. word_width += Font->Char_Spacing(*word++);
  694. }
  695. wrap = ( (Cursor.X + word_width) >= (Location.X + WrapWidth) );
  696. }
  697. if ( wrap ) {
  698. Cursor.Y += Font->Char_Height();
  699. Cursor.X = Location.X;
  700. } else {
  701. // Draw char at cursor, update cursor and extents
  702. Draw_Char( ch, color );
  703. }
  704. }
  705. }
  706. void Render2DTextClass::Draw_Block( const RectClass & screen, unsigned long color )
  707. {
  708. Internal_Add_Quad_Indicies( Vertices.Count() );
  709. Internal_Add_Quad_Vertices( screen );
  710. Internal_Add_Quad_UVs( BlockUV );
  711. Internal_Add_Quad_Colors( color );
  712. TotalExtents += screen;
  713. }
  714. Vector2 Render2DTextClass::Get_Text_Extents( const WCHAR * text )
  715. {
  716. Vector2 extent (0, Font->Char_Height());
  717. if (text) {
  718. while (*text) {
  719. WCHAR ch = *text++;
  720. if ( ch != (WCHAR)'\n' ) {
  721. extent.X += Font->Char_Spacing( ch );
  722. }
  723. }
  724. }
  725. return extent;
  726. }