shdhwshader.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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/shdhwshader.cpp $*
  25. * *
  26. * $Org Author:: Kenny_m
  27. * *
  28. * $Author:: Kenny_m
  29. *
  30. * $Modtime:: 07/07/02 12:18p $*
  31. * *
  32. * $Revision:: 3 $*
  33. * *
  34. * 06/06/02 KM added software vertex shader fallback check
  35. * 07/07/02 KM Generic shader functions for factoring HW shader code
  36. *---------------------------------------------------------------------------------------------*
  37. * Functions: *
  38. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  39. #include <stdio.h>
  40. #include "shdhwshader.h"
  41. #include "dx8wrapper.h"
  42. #include "rinfo.h"
  43. #include "shdhw_constants.h"
  44. //**********************************************************************************************
  45. //! Execute and wait for a hidden shell command
  46. /*! 5/27/02 5:39p KJM Created
  47. */
  48. void ShdHWShader::Shell_Run(char* cmd)
  49. {
  50. int result;
  51. #ifdef WIN32
  52. STARTUPINFO si;
  53. PROCESS_INFORMATION pi;
  54. memset(&pi, 0, sizeof(pi));
  55. memset(&si, 0, sizeof(si));
  56. si.cb = sizeof(si);
  57. si.dwFlags=STARTF_USESHOWWINDOW;
  58. si.wShowWindow=SW_HIDE;
  59. static bool found=false;
  60. static char work_dir[_MAX_PATH];
  61. if (!found)
  62. {
  63. char* shader_path="\\shaders\\";
  64. ::GetCurrentDirectory(_MAX_PATH,work_dir);
  65. strcat(work_dir,shader_path);
  66. }
  67. result=CreateProcess(0,cmd,0,0,0,0,0,work_dir,&si,&pi);
  68. if (result)
  69. {
  70. WaitForSingleObject(pi.hThread, INFINITE);
  71. // Close process and thread handles.
  72. CloseHandle(pi.hProcess);
  73. CloseHandle(pi.hThread);
  74. found=true;
  75. }
  76. else
  77. {
  78. int err=GetLastError();
  79. MessageBox
  80. (
  81. NULL,
  82. "Failed to execute preprocessor on shader\n"
  83. "Ensure shaders folder is in application subdirectory\n",
  84. "Shader Asset Error",
  85. MB_OK
  86. );
  87. WWASSERT_PRINT(result,"Failed to execute preprocessor on shader (ensure shaders folder is in application subdirectory)");
  88. }
  89. #else
  90. result=system(cmd);
  91. #endif
  92. }
  93. //**********************************************************************************************
  94. //! Preprocess and assemble a HW shader from file
  95. /*! 5/27/02 5:39p KJM Created
  96. */
  97. void ShdHWShader::Preprocess_And_Assemble_Shader_From_File
  98. (
  99. char* file_name,
  100. LPD3DXBUFFER* constants,
  101. LPD3DXBUFFER* shader_code
  102. )
  103. {
  104. char shell_command[_MAX_PATH];
  105. char temp_path[_MAX_PATH];
  106. char temp_file[_MAX_PATH];
  107. GetTempPath(_MAX_PATH, temp_path);
  108. GetTempFileName(temp_path,"shd",1,temp_file);
  109. _snprintf
  110. (
  111. shell_command,
  112. sizeof(shell_command),
  113. "shaders\\rspp %s %s",
  114. file_name,
  115. temp_file
  116. );
  117. LPD3DXBUFFER* errors=NULL;
  118. Shell_Run(shell_command);
  119. HRESULT result=D3DXAssembleShaderFromFile
  120. (
  121. temp_file,
  122. NULL,
  123. constants,
  124. shader_code,
  125. errors
  126. );
  127. WWASSERT_PRINT(result==D3D_OK,"Failed to assemble shader from file");
  128. }
  129. // 06/06/02 KM added software vertex shader fallback check
  130. bool ShdHWVertexShader::Using_Hardware=true;
  131. //**********************************************************************************************
  132. //! Destruct this vertex shader
  133. /*! 5/27/02 5:39p KJM Created
  134. */
  135. ShdHWVertexShader::~ShdHWVertexShader()
  136. {
  137. Destroy();
  138. }
  139. //**********************************************************************************************
  140. //! Destroy this vertex shader
  141. /*! 5/27/02 5:39p KJM Created
  142. */
  143. void ShdHWVertexShader::Destroy()
  144. {
  145. if (Shader)
  146. {
  147. DX8Wrapper::_Get_D3D_Device8()->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE);
  148. DX8Wrapper::_Get_D3D_Device8()->DeleteVertexShader(Shader);
  149. Shader=0;
  150. }
  151. }
  152. //**********************************************************************************************
  153. //! Create Vertex Shader from a file and vertex stream declaration
  154. /*! 05/27/02 5:39p KJM Created
  155. /*! 06/06/02 KM added software vertex shader fallback check
  156. */
  157. DWORD ShdHWVertexShader::Create
  158. (
  159. char* file_name,
  160. DWORD* vertex_shader_declaration
  161. )
  162. {
  163. // Create vertex shader
  164. LPD3DXBUFFER shader_code=NULL;
  165. Preprocess_And_Assemble_Shader_From_File
  166. (
  167. file_name,
  168. NULL,
  169. &shader_code
  170. );
  171. // try hardware first
  172. Using_Hardware=true;
  173. HRESULT result=DX8Wrapper::_Get_D3D_Device8()->CreateVertexShader
  174. (
  175. (DWORD*)vertex_shader_declaration,
  176. (DWORD*)shader_code->GetBufferPointer(),
  177. (DWORD*)&Shader,
  178. 0
  179. );
  180. if (result!=D3D_OK)
  181. {
  182. // try software
  183. Using_Hardware=false;
  184. result=DX8Wrapper::_Get_D3D_Device8()->CreateVertexShader
  185. (
  186. (DWORD*)vertex_shader_declaration,
  187. (DWORD*)shader_code->GetBufferPointer(),
  188. (DWORD*)&Shader,
  189. D3DUSAGE_SOFTWAREPROCESSING
  190. );
  191. WWASSERT_PRINT(result==D3D_OK,"Failed to create vertex shader");
  192. }
  193. if (shader_code) shader_code->Release();
  194. return Shader;
  195. }
  196. //**********************************************************************************************
  197. //! Create Vertex Shader from a dword constant and vertex stream declaration
  198. /*! 07/19/02 3:39p KJM Created
  199. */
  200. DWORD ShdHWVertexShader::Create
  201. (
  202. DWORD* shader_code_str,
  203. DWORD* vertex_shader_declaration
  204. )
  205. {
  206. HRESULT result;
  207. LPD3DXBUFFER shader_code=NULL;
  208. LPD3DXBUFFER errors=NULL;
  209. result=D3DXAssembleShader
  210. (
  211. shader_code_str,
  212. strlen((char*)shader_code_str),
  213. NULL,//D3DXASM_DEBUG,
  214. NULL,
  215. &shader_code,
  216. &errors
  217. );
  218. if (result!=D3D_OK)
  219. {
  220. OutputDebugString((char*)errors->GetBufferPointer());
  221. WWASSERT_PRINT(result==D3D_OK,"Failed to assemble shader");
  222. }
  223. // try hardware first
  224. Using_Hardware=true;
  225. result=DX8Wrapper::_Get_D3D_Device8()->CreateVertexShader
  226. (
  227. (DWORD*)vertex_shader_declaration,
  228. (DWORD*)shader_code->GetBufferPointer(),
  229. (DWORD*)&Shader,
  230. 0
  231. );
  232. if (result!=D3D_OK)
  233. {
  234. // try software
  235. Using_Hardware=false;
  236. result=DX8Wrapper::_Get_D3D_Device8()->CreateVertexShader
  237. (
  238. (DWORD*)vertex_shader_declaration,
  239. (DWORD*)shader_code->GetBufferPointer(),
  240. (DWORD*)&Shader,
  241. D3DUSAGE_SOFTWAREPROCESSING
  242. );
  243. WWASSERT_PRINT(result==D3D_OK,"Failed to create vertex shader");
  244. if (result!=D3D_OK)
  245. {
  246. OutputDebugString((char*)shader_code_str);
  247. }
  248. }
  249. return Shader;
  250. }
  251. //**********************************************************************************************
  252. //! Destruct this pixel shader
  253. /*! 5/27/02 5:39p KJM Created
  254. */
  255. ShdHWPixelShader::~ShdHWPixelShader()
  256. {
  257. Destroy();
  258. }
  259. //**********************************************************************************************
  260. //! Destroy this pixel shader
  261. /*! 5/27/02 5:39p KJM Created
  262. */
  263. void ShdHWPixelShader::Destroy()
  264. {
  265. if (Shader)
  266. {
  267. DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(0);
  268. DX8Wrapper::_Get_D3D_Device8()->DeletePixelShader(Shader);
  269. Shader=0;
  270. }
  271. }
  272. //**********************************************************************************************
  273. //! Create Pixel Shader from a file
  274. /*! 5/27/02 5:39p KJM Created
  275. */
  276. DWORD ShdHWPixelShader::Create(char* file_name)
  277. {
  278. // Create pixel shader
  279. LPD3DXBUFFER shader_code=NULL;
  280. Preprocess_And_Assemble_Shader_From_File
  281. (
  282. file_name,
  283. NULL,
  284. &shader_code
  285. );
  286. HRESULT result=DX8Wrapper::_Get_D3D_Device8()->CreatePixelShader
  287. (
  288. (DWORD*)shader_code->GetBufferPointer(),
  289. (DWORD*)&Shader
  290. );
  291. WWASSERT_PRINT(result==D3D_OK,"Failed to create pixel shader");
  292. return Shader;
  293. }
  294. //**********************************************************************************************
  295. //! Create Pixel Shader from a dword constant
  296. /*! 07/19/02 3:39p KJM Created
  297. */
  298. DWORD ShdHWPixelShader::Create(DWORD* shader_code_str)
  299. {
  300. HRESULT result;
  301. LPD3DXBUFFER shader_code=NULL;
  302. LPD3DXBUFFER errors;
  303. result=D3DXAssembleShader
  304. (
  305. shader_code_str,
  306. strlen((char*)shader_code_str),
  307. NULL,
  308. NULL,
  309. &shader_code,
  310. &errors
  311. );
  312. if (result!=D3D_OK)
  313. {
  314. OutputDebugString((char*)errors->GetBufferPointer());
  315. WWASSERT_PRINT(result==D3D_OK,"Failed to assemble shader");
  316. }
  317. result=DX8Wrapper::_Get_D3D_Device8()->CreatePixelShader
  318. (
  319. (DWORD*)shader_code->GetBufferPointer(),
  320. (DWORD*)&Shader
  321. );
  322. WWASSERT_PRINT(result==D3D_OK,"Failed to create pixel shader");
  323. return Shader;
  324. }
  325. //**********************************************************************************************
  326. //! Apply generic lighting
  327. /*! 07/07/02 12:23p KJM Created
  328. */
  329. void ShdHWVertexShader::Light
  330. (
  331. RenderInfoClass& rinfo,
  332. Vector4& ambient,
  333. Vector4& diffuse,
  334. Vector4& specular
  335. )
  336. {
  337. LightEnvironmentClass* lenv=rinfo.light_environment;
  338. Vector4 light_ambient(1,1,1,1);
  339. if (lenv)
  340. {
  341. int num_lights=lenv->Get_Light_Count();
  342. // most cases set up and use the light environment
  343. if (num_lights)
  344. {
  345. const Vector3& amb=lenv->Get_Equivalent_Ambient();
  346. light_ambient.Set
  347. (
  348. amb.X,
  349. amb.Y,
  350. amb.Z,
  351. 0
  352. );
  353. int i;
  354. int max=LightEnvironmentClass::Get_Max_Lights();
  355. if (num_lights>max) num_lights=max;
  356. Vector4 cdir, ccol;
  357. for (i=0;i<max;i++)
  358. {
  359. if (i<num_lights)
  360. {
  361. Vector3 rot;
  362. const Vector3& dir=lenv->Get_Light_Direction(i);
  363. const Vector3& col=lenv->Get_Light_Diffuse(i);
  364. cdir.Set(dir.X,dir.Y,dir.Z,1.0f);
  365. ccol.Set(col.X,col.Y,col.Z,1.0f);
  366. }
  367. else
  368. {
  369. // if no light just set color to zero
  370. ccol.Set(0,0,0,0);
  371. }
  372. DX8Wrapper::Set_Vertex_Shader_Constant(CV_LIGHT_DIRECTION_0+i, &cdir, 1);
  373. DX8Wrapper::Set_Vertex_Shader_Constant(CV_LIGHT_COLOR_0+i, &ccol, 1);
  374. }
  375. }
  376. else
  377. {
  378. const Vector3& amb_col=DX8Wrapper::Get_Ambient();
  379. light_ambient.X=amb_col.X;
  380. light_ambient.Y=amb_col.Y;
  381. light_ambient.Z=amb_col.Z;
  382. // otherwise have to extract light from render state
  383. int max=LightEnvironmentClass::Get_Max_Lights();
  384. int i;
  385. RenderStateStruct state;
  386. DX8Wrapper::Get_Render_State(state);
  387. Vector4 cdir, ccol;
  388. for (i=0;i<max;i++)
  389. {
  390. if (state.LightEnable[i])
  391. {
  392. D3DLIGHT8& light=state.Lights[i];
  393. // handle directional and positional lights
  394. if (light.Type==D3DLIGHT_DIRECTIONAL)
  395. {
  396. const D3DXVECTOR3& dir=state.Lights[i].Direction;
  397. cdir.Set(-dir.x,-dir.y,-dir.z,0.0f);
  398. }
  399. else
  400. {
  401. const D3DXVECTOR3& pos=state.Lights[i].Position;
  402. // just normalise the light position for now (as only appears to be used in w3dview)
  403. cdir.Set(pos.x,pos.y,pos.z,0.0f);
  404. }
  405. cdir.Normalize();
  406. ccol.Set
  407. (
  408. state.Lights[i].Diffuse.r,
  409. state.Lights[i].Diffuse.g,
  410. state.Lights[i].Diffuse.b,
  411. 1.0f
  412. );
  413. }
  414. else
  415. {
  416. // if no light just set color to zero
  417. ccol.Set(0,0,0,0);
  418. }
  419. DX8Wrapper::Set_Vertex_Shader_Constant(CV_LIGHT_DIRECTION_0+i, &cdir, 1);
  420. DX8Wrapper::Set_Vertex_Shader_Constant(CV_LIGHT_COLOR_0+i, &ccol, 1);
  421. }
  422. }
  423. }
  424. light_ambient.X*=ambient.X;
  425. light_ambient.Y*=ambient.Y;
  426. light_ambient.Z*=ambient.Z;
  427. DX8Wrapper::Set_Vertex_Shader_Constant(CV_AMBIENT, &light_ambient, 1);
  428. DX8Wrapper::Set_Vertex_Shader_Constant(CV_DIFFUSE, &diffuse, 1);
  429. DX8Wrapper::Set_Vertex_Shader_Constant(CV_SPECULAR, &specular, 1);
  430. }
  431. //**********************************************************************************************
  432. //! Apply generic lighting (no specular supplied)
  433. /*! 07/07/02 12:23p KJM Created
  434. */
  435. void ShdHWVertexShader::Light
  436. (
  437. RenderInfoClass& rinfo,
  438. Vector4& ambient,
  439. Vector4& diffuse
  440. )
  441. {
  442. Vector4 specular(0,0,0,0);
  443. Light(rinfo,ambient,diffuse,specular);
  444. }