guiMaterialPreview.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. // Original header:
  23. // GuiMaterialPreview Control for Material Editor Written by Travis Vroman of Gaslight Studios
  24. // Updated 2-14-09
  25. // Portions based off Constructor viewport code.
  26. #include "console/engineAPI.h"
  27. #include "T3D/guiMaterialPreview.h"
  28. #include "renderInstance/renderPassManager.h"
  29. #include "lighting/lightManager.h"
  30. #include "lighting/lightInfo.h"
  31. #include "core/resourceManager.h"
  32. #include "scene/sceneManager.h"
  33. #include "scene/sceneRenderState.h"
  34. #include "renderInstance/renderProbeMgr.h"
  35. #include "T3D/lighting/skylight.h"
  36. #include "gfx/gfxDrawUtil.h"
  37. // GuiMaterialPreview
  38. GuiMaterialPreview::GuiMaterialPreview()
  39. : mMouseState(None),
  40. mModelInstance(NULL),
  41. mMountedModelInstance(NULL),
  42. runThread(0),
  43. lastRenderTime(0),
  44. mLastMousePoint(0, 0),
  45. mFakeSun(NULL),
  46. mMaxOrbitDist(5.0f),
  47. mMinOrbitDist(0.0f),
  48. mOrbitDist(5.0f)
  49. {
  50. mActive = true;
  51. mCameraMatrix.identity();
  52. mCameraRot.set( mDegToRad(30.0f), 0, mDegToRad(-30.0f) );
  53. mCameraPos.set(0.0f, 1.75f, 1.25f);
  54. mCameraMatrix.setColumn(3, mCameraPos);
  55. mOrbitPos.set(0.0f, 0.0f, 0.0f);
  56. mTransStep = 0.01f;
  57. mTranMult = 4.0;
  58. mLightTransStep = 0.01f;
  59. mLightTranMult = 4.0;
  60. mOrbitRelPos = Point3F(0,0,0);
  61. // By default don't do dynamic reflection
  62. // updates for this viewport.
  63. mReflectPriority = 0.0f;
  64. mSkinTag = 0;
  65. }
  66. GuiMaterialPreview::~GuiMaterialPreview()
  67. {
  68. SAFE_DELETE(mModelInstance);
  69. SAFE_DELETE(mFakeSun);
  70. }
  71. bool GuiMaterialPreview::onWake()
  72. {
  73. if( !Parent::onWake() )
  74. return false;
  75. if (!mFakeSun)
  76. mFakeSun = LightManager::createLightInfo();
  77. mFakeSun->setColor( LinearColorF( 1.0f, 1.0f, 1.0f ) );
  78. mFakeSun->setAmbient( LinearColorF( 0.5f, 0.5f, 0.5f ) );
  79. mFakeSun->setDirection( VectorF( 0.0f, 0.707f, -0.707f ) );
  80. mFakeSun->setPosition( mFakeSun->getDirection() * -10000.0f );
  81. mFakeSun->setRange( 2000000.0f );
  82. return true;
  83. }
  84. // This function allows the viewport's ambient color to be changed. This is exposed to script below.
  85. void GuiMaterialPreview::setAmbientLightColor( F32 r, F32 g, F32 b )
  86. {
  87. LinearColorF temp(r, g, b);
  88. temp.clamp();
  89. GuiMaterialPreview::mFakeSun->setAmbient( temp );
  90. }
  91. // This function allows the light's color to be changed. This is exposed to script below.
  92. void GuiMaterialPreview::setLightColor( F32 r, F32 g, F32 b )
  93. {
  94. LinearColorF temp(r, g, b);
  95. temp.clamp();
  96. GuiMaterialPreview::mFakeSun->setColor( temp );
  97. }
  98. // This function is for moving the light in the scene. This needs to be adjusted to keep the light
  99. // from getting all out of whack. For now, we'll just rely on the reset function if we need it
  100. // fixed.
  101. void GuiMaterialPreview::setLightTranslate(S32 modifier, F32 xstep, F32 ystep)
  102. {
  103. F32 _lighttransstep = (modifier & SI_SHIFT ? mLightTransStep : (mLightTransStep*mLightTranMult));
  104. Point3F relativeLightDirection = GuiMaterialPreview::mFakeSun->getDirection();
  105. F32 azimuth = mAtan2(relativeLightDirection.y, relativeLightDirection.x);
  106. F32 elevation = mAsin(relativeLightDirection.z);
  107. // Modify azimuth and elevation based on input
  108. azimuth += xstep * _lighttransstep;
  109. elevation = mClampF(elevation + ystep * _lighttransstep, -M_2PI_F, M_2PI_F);
  110. // Convert back to Cartesian coordinates
  111. relativeLightDirection.x = mCos(elevation) * mCos(azimuth);
  112. relativeLightDirection.y = mCos(elevation) * mSin(azimuth);
  113. relativeLightDirection.z = mSin(elevation);
  114. GuiMaterialPreview::mFakeSun->setDirection(relativeLightDirection);
  115. }
  116. // This is for panning the viewport camera.
  117. void GuiMaterialPreview::setTranslate(S32 modifier, F32 xstep, F32 ystep)
  118. {
  119. F32 transstep = (modifier & SI_SHIFT ? mTransStep : (mTransStep*mTranMult));
  120. F32 nominalDistance = 20.0;
  121. Point3F vec = mCameraPos;
  122. vec -= mOrbitPos;
  123. transstep *= vec.len() / nominalDistance;
  124. if (modifier & SI_PRIMARY_CTRL)
  125. {
  126. mOrbitRelPos.x += ( xstep * transstep );
  127. mOrbitRelPos.y += ( ystep * transstep );
  128. }
  129. else
  130. {
  131. mOrbitRelPos.x += ( xstep * transstep );
  132. mOrbitRelPos.z += ( ystep * transstep );
  133. }
  134. }
  135. // Left Click
  136. void GuiMaterialPreview::onMouseDown(const GuiEvent &event)
  137. {
  138. mMouseState = MovingLight;
  139. mLastMousePoint = event.mousePoint;
  140. mouseLock();
  141. }
  142. // Left Click Release
  143. void GuiMaterialPreview::onMouseUp(const GuiEvent &event)
  144. {
  145. mouseUnlock();
  146. mMouseState = None;
  147. }
  148. // Left Click Drag
  149. void GuiMaterialPreview::onMouseDragged(const GuiEvent &event)
  150. {
  151. if(mMouseState != MovingLight)
  152. {
  153. return;
  154. }
  155. // If we are MovingLight...
  156. else
  157. {
  158. Point2I delta = event.mousePoint - mLastMousePoint;
  159. mLastMousePoint = event.mousePoint;
  160. setLightTranslate(event.modifier, delta.x, delta.y);
  161. }
  162. }
  163. // Right Click
  164. void GuiMaterialPreview::onRightMouseDown(const GuiEvent &event)
  165. {
  166. mMouseState = Rotating;
  167. mLastMousePoint = event.mousePoint;
  168. mouseLock();
  169. }
  170. // Right Click Release
  171. void GuiMaterialPreview::onRightMouseUp(const GuiEvent &event)
  172. {
  173. mouseUnlock();
  174. mMouseState = None;
  175. }
  176. // Right Click Drag
  177. void GuiMaterialPreview::onRightMouseDragged(const GuiEvent &event)
  178. {
  179. if (mMouseState != Rotating)
  180. {
  181. return;
  182. }
  183. Point2I delta = event.mousePoint - mLastMousePoint;
  184. mLastMousePoint = event.mousePoint;
  185. mCameraRot.x += (delta.y * 0.01f);
  186. mCameraRot.z += (delta.x * 0.01f);
  187. }
  188. // Mouse Wheel Scroll Up
  189. bool GuiMaterialPreview::onMouseWheelUp(const GuiEvent &event)
  190. {
  191. mOrbitDist = (mOrbitDist - 0.10f);
  192. return true;
  193. }
  194. // Mouse Wheel Scroll Down
  195. bool GuiMaterialPreview::onMouseWheelDown(const GuiEvent &event)
  196. {
  197. mOrbitDist = (mOrbitDist + 0.10f);
  198. return true;
  199. }
  200. // Mouse Wheel Click
  201. void GuiMaterialPreview::onMiddleMouseDown(const GuiEvent &event)
  202. {
  203. if (!mActive || !mVisible || !mAwake)
  204. {
  205. return;
  206. }
  207. mMouseState = Panning;
  208. mLastMousePoint = event.mousePoint;
  209. mouseLock();
  210. }
  211. // Mouse Wheel Click Release
  212. void GuiMaterialPreview::onMiddleMouseUp(const GuiEvent &event)
  213. {
  214. mouseUnlock();
  215. mMouseState = None;
  216. }
  217. // Mouse Wheel Click Drag
  218. void GuiMaterialPreview::onMiddleMouseDragged(const GuiEvent &event)
  219. {
  220. if (mMouseState != Panning)
  221. {
  222. return;
  223. }
  224. Point2I delta = event.mousePoint - mLastMousePoint;
  225. mLastMousePoint = event.mousePoint;
  226. setTranslate(event.modifier, delta.x, delta.y);
  227. }
  228. // This is used to set the model we want to view in the control object.
  229. void GuiMaterialPreview::setObjectModel(StringTableEntry modelName)
  230. {
  231. deleteModel();
  232. _setModel(modelName);
  233. if (!getModel())
  234. {
  235. Con::warnf("GuiMaterialPreview::setObjectModel - Failed to load model '%s'", modelName);
  236. return;
  237. }
  238. mModelInstance = new TSShapeInstance(getModel(), true);
  239. mModelInstance->resetMaterialList();
  240. mModelInstance->cloneMaterialList();
  241. AssertFatal(mModelInstance, avar("GuiMaterialPreview: Failed to load model %s. Please check your model name and load a valid model.", modelName));
  242. // Initialize camera values:
  243. mOrbitPos = mModelInstance->getShape()->center;
  244. mMinOrbitDist = mModelInstance->getShape()->mRadius;
  245. lastRenderTime = Platform::getVirtualMilliseconds();
  246. }
  247. void GuiMaterialPreview::deleteModel()
  248. {
  249. SAFE_DELETE(mModelInstance);
  250. runThread = 0;
  251. }
  252. // This is called whenever there is a change in the camera.
  253. bool GuiMaterialPreview::processCameraQuery(CameraQuery* query)
  254. {
  255. MatrixF xRot, zRot;
  256. Point3F vecf, vecu, vecr;;
  257. xRot.set(EulerF(mCameraRot.x, 0.0f, 0.0f));
  258. zRot.set(EulerF(0.0f, 0.0f, mCameraRot.z));
  259. if(mMouseState != Panning)
  260. {
  261. // Adjust the camera so that we are still facing the model:
  262. Point3F vec;
  263. mCameraMatrix.mul(zRot, xRot);
  264. mCameraMatrix.getColumn(1, &vec);
  265. vec *= mOrbitDist;
  266. mCameraPos = mOrbitPos - vec;
  267. query->farPlane = 2100.0f;
  268. query->nearPlane = query->farPlane / 5000.0f;
  269. query->fov = 45.0f;
  270. mCameraMatrix.setColumn(3, mCameraPos);
  271. query->cameraMatrix = mCameraMatrix;
  272. }
  273. else
  274. {
  275. mCameraMatrix.mul( zRot, xRot );
  276. mCameraMatrix.getColumn( 1, &vecf ); // Forward vector
  277. mCameraMatrix.getColumn( 2, &vecu ); // Up vector
  278. mCameraMatrix.getColumn( 0, &vecr ); // Right vector
  279. Point3F flatVecf(vecf.x, vecf.y, 0.0f);
  280. Point3F modvecf = flatVecf * mOrbitRelPos.y;
  281. Point3F modvecu = vecu * mOrbitRelPos.z;
  282. Point3F modvecr = vecr * mOrbitRelPos.x;
  283. // Change the orbit position
  284. mOrbitPos += modvecu - modvecr + modvecf;
  285. F32 vecfmul = mOrbitDist;
  286. Point3F virtualVecF = vecf * mOrbitDist;
  287. vecf *= vecfmul;
  288. mCameraPos = mOrbitPos - virtualVecF;
  289. // Update the camera's position
  290. mCameraMatrix.setColumn( 3, (mOrbitPos - vecf) );
  291. query->farPlane = 2100.0f;
  292. query->nearPlane = query->farPlane / 5000.0f;
  293. query->fov = 45.0f;
  294. query->cameraMatrix = mCameraMatrix;
  295. // Reset the relative position
  296. mOrbitRelPos = Point3F(0,0,0);
  297. }
  298. return true;
  299. }
  300. void GuiMaterialPreview::onMouseEnter(const GuiEvent & event)
  301. {
  302. Con::executef(this, "onMouseEnter");
  303. }
  304. void GuiMaterialPreview::onMouseLeave(const GuiEvent & event)
  305. {
  306. Con::executef(this, "onMouseLeave");
  307. }
  308. void GuiMaterialPreview::renderWorld(const RectI &updateRect)
  309. {
  310. // nothing to render, punt
  311. if ( !mModelInstance && !mMountedModelInstance )
  312. return;
  313. S32 time = Platform::getVirtualMilliseconds();
  314. //S32 dt = time - lastRenderTime;
  315. lastRenderTime = time;
  316. F32 left, right, top, bottom, nearPlane, farPlane;
  317. bool isOrtho;
  318. GFX->getFrustum( &left, &right, &bottom, &top, &nearPlane, &farPlane, &isOrtho);
  319. mSaveFrustum = Frustum( isOrtho, left, right, bottom, top, nearPlane, farPlane, MatrixF::Identity );
  320. mSaveProjection = GFX->getProjectionMatrix();
  321. mSaveWorldToScreenScale = GFX->getWorldToScreenScale();
  322. FogData savedFogData = gClientSceneGraph->getFogData();
  323. gClientSceneGraph->setFogData( FogData() ); // no fog in preview window
  324. if (Skylight::smSkylightProbe.isValid())
  325. PROBEMGR->submitProbe(Skylight::smSkylightProbe->getProbeInfo());
  326. RenderPassManager* renderPass = gClientSceneGraph->getDefaultRenderPass();
  327. SceneRenderState state
  328. (
  329. gClientSceneGraph,
  330. SPT_Diffuse,
  331. SceneCameraState( GFX->getViewport(), mSaveFrustum, GFX->getWorldMatrix(), GFX->getProjectionMatrix() ),
  332. renderPass,
  333. true
  334. );
  335. // Set up our TS render state here.
  336. TSRenderState rdata;
  337. rdata.setSceneState( &state );
  338. // We might have some forward lit materials
  339. // so pass down a query to gather lights.
  340. LightQuery query;
  341. query.init( SphereF( Point3F::Zero, 1.0f ) );
  342. rdata.setLightQuery( &query );
  343. // Set up pass transforms
  344. renderPass->assignSharedXform(RenderPassManager::View, MatrixF::Identity);
  345. renderPass->assignSharedXform(RenderPassManager::Projection, GFX->getProjectionMatrix());
  346. LIGHTMGR->unregisterAllLights();
  347. LIGHTMGR->setSpecialLight( LightManager::slSunLightType, mFakeSun );
  348. if ( mModelInstance )
  349. mModelInstance->render( rdata );
  350. if ( mMountedModelInstance )
  351. {
  352. // render a weapon
  353. /*
  354. MatrixF mat;
  355. GFX->pushWorldMatrix();
  356. GFX->multWorld( mat );
  357. GFX->popWorldMatrix();
  358. */
  359. }
  360. renderPass->renderPass( &state );
  361. if (mMouseState == MovingLight)
  362. {
  363. renderSunDirection();
  364. }
  365. gClientSceneGraph->setFogData( savedFogData ); // restore fog setting
  366. // Make sure to remove our fake sun
  367. LIGHTMGR->unregisterAllLights();
  368. }
  369. void GuiMaterialPreview::renderSunDirection() const
  370. {
  371. // Render four arrows aiming in the direction of the sun's light
  372. ColorI color = LinearColorF(mFakeSun->getColor()).toColorI();
  373. F32 length = mModelInstance->getShape()->mBounds.len() * 0.8f;
  374. // Get the sun's vectors
  375. Point3F fwd = mFakeSun->getTransform().getForwardVector();
  376. Point3F up = mFakeSun->getTransform().getUpVector() * length / 8;
  377. Point3F right = mFakeSun->getTransform().getRightVector() * length / 8;
  378. // Calculate the start and end points of the first arrow (bottom left)
  379. Point3F start = mModelInstance->getShape()->center - fwd * length - up / 2 - right / 2;
  380. Point3F end = mModelInstance->getShape()->center - fwd * length / 3 - up / 2 - right / 2;
  381. GFXStateBlockDesc desc;
  382. desc.setZReadWrite(true, true);
  383. GFXDrawUtil* drawUtil = GFX->getDrawUtil();
  384. drawUtil->drawArrow(desc, start, end, color);
  385. drawUtil->drawArrow(desc, start + up, end + up, color);
  386. drawUtil->drawArrow(desc, start + right, end + right, color);
  387. drawUtil->drawArrow(desc, start + up + right, end + up + right, color);
  388. }
  389. // Make sure the orbit distance is within the acceptable range.
  390. void GuiMaterialPreview::setOrbitDistance(F32 distance)
  391. {
  392. mOrbitDist = mClampF(distance, mMinOrbitDist, mMaxOrbitDist);
  393. }
  394. // This function is meant to be used with a button to put everything back to default settings.
  395. void GuiMaterialPreview::resetViewport()
  396. {
  397. // Reset the camera's orientation.
  398. mCameraRot.set( mDegToRad(30.0f), 0, mDegToRad(-30.0f) );
  399. mCameraPos.set(0.0f, 1.75f, 1.25f);
  400. mOrbitDist = 5.0f;
  401. mOrbitPos = mModelInstance->getShape()->center;
  402. // Reset the viewport's lighting.
  403. GuiMaterialPreview::mFakeSun->setColor( LinearColorF( 1.0f, 1.0f, 1.0f ) );
  404. GuiMaterialPreview::mFakeSun->setAmbient( LinearColorF( 0.5f, 0.5f, 0.5f ) );
  405. GuiMaterialPreview::mFakeSun->setDirection( VectorF( 0.0f, 0.707f, -0.707f ) );
  406. }
  407. // Expose the class and functions to the console.
  408. IMPLEMENT_CONOBJECT(GuiMaterialPreview);
  409. ConsoleDocClass( GuiMaterialPreview,
  410. "@brief Visual preview of a specified Material\n\n"
  411. "Editor use only.\n\n"
  412. "@internal"
  413. );
  414. // Set the model.
  415. DefineEngineMethod(GuiMaterialPreview, setModel, void, ( const char* shapeName ),,
  416. "Sets the model to be displayed in this control\n\n"
  417. "@param shapeName Name of the model to display.\n")
  418. {
  419. object->setObjectModel(StringTable->insert(shapeName));
  420. }
  421. DefineEngineMethod(GuiMaterialPreview, deleteModel, void, (),,
  422. "Deletes the preview model.\n")
  423. {
  424. object->deleteModel();
  425. }
  426. // Set orbit distance around the model.
  427. DefineEngineMethod(GuiMaterialPreview, setOrbitDistance, void, ( F32 distance ),,
  428. "Sets the distance at which the camera orbits the object. Clamped to the "
  429. "acceptable range defined in the class by min and max orbit distances.\n\n"
  430. "@param distance The distance to set the orbit to (will be clamped).")
  431. {
  432. object->setOrbitDistance(distance);
  433. }
  434. // Reset control to default values. Meant to be used with a button.
  435. DefineEngineMethod(GuiMaterialPreview, reset, void, (),,
  436. "Resets the viewport to default zoom, pan, rotate and lighting.")
  437. {
  438. object->resetViewport();
  439. }
  440. // This function allows the user to change the light's color.
  441. DefineEngineMethod(GuiMaterialPreview, setLightColor, void, ( LinearColorF color ),,
  442. "Sets the color of the light in the scene.\n")
  443. {
  444. object->setLightColor( color.red, color.green, color.blue );
  445. }
  446. // This function allows the user to change the viewports's ambient color.
  447. DefineEngineMethod(GuiMaterialPreview, setAmbientLightColor, void, ( LinearColorF color ),,
  448. "Sets the color of the ambient light in the scene.\n")
  449. {
  450. object->setAmbientLightColor( color.red, color.green, color.blue );
  451. }