View difference between Paste ID: JAXMJNAx and ce64NY7Y
SHOW: | | - or go back to the newest paste.
1
These are a pair of gui objects.
2
guiCopyContainer is a container that can render its contents to a named texture for use in other objects.
3
guiBitmapShader is a child of bitmap control that lets use up to 8 textures (8 seems to work for most modern graphic cards) with a shader similar to how PostEffect goes.
4
5
First we need to make a few changes to the engine in order to read and write a pair of private variables related to gui rendering.
6
-a) Add this as public: (important being public:) in "class FontRenderBatcher" of source\gfx\gfxFontRenderBatcher.h-
7
8
[code]
9
   GFXStateBlockDesc getFontStateBlockDesc();
10
   
11
   void externalSetupFontStateBlock(GFXStateBlockDesc fontSBD);
12
[/code]
13
14
-b) Add this in source\gfx\gfxFontRenderBatcher.cpp-
15
16
[code]GFXStateBlockDesc FontRenderBatcher::getFontStateBlockDesc()
17
{
18
   return mFontSB->getDesc();
19
}
20
21
void FontRenderBatcher::externalSetupFontStateBlock(GFXStateBlockDesc fontSBD)
22
{
23
   fontSBD.cullDefined = true;
24
   fontSBD.cullMode = GFXCullNone;
25
   
26
   fontSBD.samplersDefined = true;
27
   fontSBD.samplers[0].alphaOp = GFXTOPModulate;
28
   fontSBD.samplers[0].magFilter = GFXTextureFilterPoint;
29
   fontSBD.samplers[0].minFilter = GFXTextureFilterPoint;
30
   fontSBD.samplers[0].addressModeU = GFXAddressClamp;
31
   fontSBD.samplers[0].addressModeV = GFXAddressClamp;
32
   fontSBD.samplers[0].alphaArg1 = GFXTATexture;
33
   fontSBD.samplers[0].alphaArg2 = GFXTADiffuse;
34
   // This is an add operation because in D3D, when a texture of format D3DFMT_A8
35
   // is used, the RGB channels are all set to 0.  Therefore a modulate would 
36
   // result in the text always being black.  This may not be the case in OpenGL
37
   // so it may have to change.  -bramage
38
   fontSBD.samplers[0].textureColorOp = GFXTOPAdd;
39
40
   mFontSB = GFX->createStateBlock(fontSBD);
41
}
42
[/code]
43
44
-c) Add this as public: (important being public:) in "class GFXDrawUtil" of source\gfx\gfxDrawUtil.h-
45
46
[code]   GFXStateBlockDesc getBitmapStateBlockDesc();
47
   GFXStateBlockDesc getFontStateBlockDesc();
48
   void externalSetupBitmapStateBlock(GFXStateBlockDesc bitmapSBD);
49
   void externalSetupFontStateBlock(GFXStateBlockDesc fontSBD);
50
   [/code]
51
   
52
   
53
-d) Finally, add this in source\gfx\gfxDrawUtil.cpp-
54
55
[code]GFXStateBlockDesc GFXDrawUtil::getBitmapStateBlockDesc()
56
{
57
   return mBitmapStretchWrapLinearSB->getDesc();
58
}
59
60
GFXStateBlockDesc GFXDrawUtil::getFontStateBlockDesc()
61
{
62
   return mFontRenderBatcher->getFontStateBlockDesc();
63
}
64
65
void GFXDrawUtil::externalSetupBitmapStateBlock(GFXStateBlockDesc bitmapSBD)
66
{
67
   // Linear: Create wrap SB
68
   mBitmapStretchWrapLinearSB = mDevice->createStateBlock(bitmapSBD);
69
70
   // Linear: Create clamp SB
71
   bitmapSBD.samplers[0] = GFXSamplerStateDesc::getClampLinear();
72
   mBitmapStretchLinearSB = mDevice->createStateBlock(bitmapSBD);
73
74
   // Point:
75
   bitmapSBD.samplers[0].minFilter = GFXTextureFilterPoint;
76
   bitmapSBD.samplers[0].mipFilter = GFXTextureFilterPoint;
77
   bitmapSBD.samplers[0].magFilter = GFXTextureFilterPoint;
78
79
   // Point: Create clamp SB, last created clamped so no work required here
80
   mBitmapStretchSB = mDevice->createStateBlock(bitmapSBD);
81
82
   // Point: Create wrap SB, have to do this manually because getWrapLinear doesn't
83
   bitmapSBD.samplers[0].addressModeU = GFXAddressWrap;
84
   bitmapSBD.samplers[0].addressModeV = GFXAddressWrap;
85
   bitmapSBD.samplers[0].addressModeW = GFXAddressWrap;
86
   mBitmapStretchWrapSB = mDevice->createStateBlock(bitmapSBD);
87
88
   //Note: Not sure about rectFill. But it seems to work fine without changes.
89
   //GFXStateBlockDesc rectFill;
90
   //rectFill.setCullMode(GFXCullNone);
91
   //rectFill.setZReadWrite(false);
92
   //rectFill.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
93
   //mRectFillSB = mDevice->createStateBlock(rectFill);
94
}
95
96
void GFXDrawUtil::externalSetupFontStateBlock(GFXStateBlockDesc fontSBD)
97
{
98
   //font StateBlock
99
   mFontRenderBatcher->externalSetupFontStateBlock(fontSBD);
100
}
101
[/code]
102
103
104
//--------------------------------------------------------------------------------------------------
105
106
Now add these c++ files to the source:
107
108
guiCopyContainer.h
109
[code]#ifndef _GUICOPYCONTAINER_H_
110
#define _GUICOPYCONTAINER_H_
111
112
#ifndef _GUICONTAINER_H_
113
#include "gui\containers\guiContainer.h"
114
#endif
115
116
#ifndef _MATTEXTURETARGET_H_
117
#include "materials/matTextureTarget.h"
118
#endif
119
120
class GFXStateBlockData;
121
122
class GuiCopyContainer : public GuiContainer
123
{
124
private:
125
   typedef GuiContainer Parent;
126
127
public:
128
   DECLARE_CONOBJECT(GuiCopyContainer);
129
   DECLARE_CATEGORY( "Gui Containers" );
130
   DECLARE_DESCRIPTION( "A container that can copy its children renders into a texture.");
131
132
   // Constructor/Destructor/ConObject Declaration
133
   GuiCopyContainer();
134
   
135
   static void initPersistFields();
136
   
137
   bool onAdd();
138
   void onRemove();
139
140
   void onRender(Point2I offset, const RectI &updateRect);
141
   
142
   void _setUniqueTextureName( const char *inName );
143
   void _onTextureEvent( GFXTexCallbackCode code );
144
   
145
   void _setupTargets();
146
   void _teardownTargets();
147
   
148
   void copyContainer();
149
   
150
protected:
151
   static bool setTextureName( void *object, const char *index, const char *data );
152
153
   //Set this to true to have the GuiCopyContainer become invisible but active
154
   bool mBlockNormalRender;
155
   bool mAutoCopy;
156
157
   GFXTextureTargetRef mTarget;
158
   GFXTexHandle mTargetTexture;
159
   NamedTexTarget mNamedTarget;
160
   
161
   GFXFormat mTargetFormat;
162
   StringTableEntry mTargetName;
163
   
164
   GFXStateBlockData *mStateBlockData;
165
   GFXStateBlockData *mOldStateBlockData;
166
   GFXStateBlockRef mStateBlock;
167
};
168
/// @}
169
170
#endif // _GUICOPYCONTAINER_H_[/code]
171
172
guiCopyContainer.cpp
173
[code]#include "guiCopyContainer.h"
174
#include "gui/core/guiDefaultControlRender.h"
175
176
#include "console/console.h"
177
#include "console/consoleTypes.h"
178
#include "console/engineAPI.h"
179
180
#include "gfx/gfxDrawUtil.h"
181
#include "gfx/gfxTextureManager.h"
182
#include "gfx/gfxAPI.h"
183
184
#include "gfx/sim/gfxStateBlockData.h"
185
#include "gfx/gfxTransformSaver.h"
186
187
IMPLEMENT_CONOBJECT(GuiCopyContainer);
188
189
ConsoleDocClass( GuiCopyContainer,
190
   "@brief A gui container that copies its content into a named texture.\n\n"
191
   
192
   "@ingroup GuiContainers"
193
);
194
195
GuiCopyContainer::GuiCopyContainer()
196
{
197
   mBlockNormalRender = false;
198
   mAutoCopy = false;
199
   mTargetFormat = GFXFormatR8G8B8A8;
200
   //default mTargetName will be  "copiedcontainer" + n  defined inside onAdd
201
   mTargetName = NULL;
202
   
203
   mStateBlockData = NULL;
204
   mStateBlock = NULL;
205
   mOldStateBlockData = NULL;
206
}
207
208
bool GuiCopyContainer::onAdd()
209
{
210
   if(!Parent::onAdd())
211
      return false;
212
   
213
   _setUniqueTextureName(mTargetName);
214
   //Inside _setUniqueTextureName we have:
215
   //mNamedTarget.registerWithName( mTargetName );
216
217
   _setupTargets();
218
   GFXTextureManager::addEventDelegate( this, &GuiCopyContainer::_onTextureEvent );
219
   return true;
220
}
221
222
void GuiCopyContainer::onRemove()
223
{
224
   mNamedTarget.unregister();
225
   GFXTextureManager::removeEventDelegate( this, &GuiCopyContainer::_onTextureEvent );
226
227
   _teardownTargets();
228
229
   //Needed to avoid
230
   //   Exception thrown : read access violation.
231
   //   **GFXDevice::get**(...) returned nullptr.
232
   //when closing the program while running:
233
   if(mBlockNormalRender && mAutoCopy)
234
      GFX->clear(GFXClearTarget, LinearColorF(0, 0, 0, 0), 1.0f, 0);
235
236
   mTarget = NULL;
237
   mTargetTexture = NULL;
238
   Parent::onRemove();
239
}
240
241
void GuiCopyContainer::initPersistFields()
242
{
243
   addGroup( "CopyContainer" );
244
   
245
      addField( "blockNormalRender", TypeBool, Offset( mBlockNormalRender, GuiCopyContainer ),
246
         "True to disable render of its children even with the visible flag enabled.");
247
      addField( "autoCopy", TypeBool, Offset( mAutoCopy, GuiCopyContainer ),
248
         "If true it calls copyContainer() itself each frame.");
249
      addProtectedField( "textureName", TypeString, Offset( mTargetName, GuiCopyContainer ), &setTextureName, &defaultProtectedGetFn,
250
         "Name of the texture.");
251
      addField( "targetFormat", TypeGFXFormat, Offset( mTargetFormat, GuiCopyContainer ),
252
         "Format of the texture. It should be GFXFormatR8G8B8A8.");
253
      addField( "stateBlock", TYPEID<GFXStateBlockData>(), Offset( mStateBlockData,  GuiCopyContainer ),
254
         "Optional name of a GFXStateBlockData to replace default values." );
255
      
256
   endGroup( "CopyContainer" );
257
258
   Parent::initPersistFields();
259
}
260
261
bool GuiCopyContainer::setTextureName( void *object, const char *index, const char *data )
262
{
263
   static_cast<GuiCopyContainer *>( object )->_setUniqueTextureName(data);
264
   // Return false because the _setUniqueTextureName method will assign 'mTargetName' to the
265
   // argument we are specifying in the call.
266
   return false;
267
}
268
269
void GuiCopyContainer::_setupTargets()
270
{
271
   _teardownTargets();
272
273
   if (!mTarget.isValid())
274
   {
275
      mTarget = GFX->allocRenderToTextureTarget();
276
   }
277
278
   // Update color
279
   Point2I targetSize = getExtent();
280
   if (!mTargetTexture.isValid() || targetSize != mTargetTexture.getWidthHeight())
281
   {
282
      mTargetTexture.set( targetSize.x, targetSize.y, mTargetFormat, &GFXRenderTargetSRGBProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ), 1, 0 );
283
   }
284
   
285
   mTarget->attachTexture( GFXTextureTarget::RenderSlot(GFXTextureTarget::Color0), mTargetTexture );
286
   mNamedTarget.setTexture(0, mTargetTexture);
287
288
}
289
290
void GuiCopyContainer::_teardownTargets()
291
{
292
   mNamedTarget.release();
293
   mTargetTexture = NULL;
294
}
295
296
297
void GuiCopyContainer::_setUniqueTextureName( const char *inName )
298
{
299
   String outName( inName );
300
301
   if ( outName.isEmpty() )
302
      outName = "copiedcontainer";
303
304
   if ( mNamedTarget.registerWithName( outName ) )
305
   {
306
      mTargetName = StringTable->EmptyString();
307
      mTargetName = StringTable->insert(outName);
308
      return;
309
   }
310
311
   S32 suffixNumb = -1;
312
   String nameStr( String::GetTrailingNumber( outName, suffixNumb ) );
313
   suffixNumb = mAbs( suffixNumb ) + 1;
314
315
   #define MAX_TRIES 100
316
317
   for ( U32 i = 0; i < MAX_TRIES; i++ )
318
   {   
319
	   outName = String::ToString("%s%d", nameStr.c_str(), suffixNumb);
320
321
      if ( mNamedTarget.registerWithName( outName ) )
322
      {
323
         mTargetName = StringTable->EmptyString();
324
         mTargetName = StringTable->insert(outName);
325
         return;
326
      }
327
328
      suffixNumb++;
329
   }
330
331
   Con::errorf( "_setUniqueTextureName - failed after %d attempts", inName, MAX_TRIES );
332
   mTargetName = NULL;
333
   return;
334
}
335
336
337
void GuiCopyContainer::_onTextureEvent( GFXTexCallbackCode code )
338
{
339
   switch(code)
340
   {
341
      case GFXZombify:
342
         _teardownTargets();
343
         break;
344
345
      case GFXResurrect:
346
         _setupTargets();
347
         break;
348
   }
349
}
350
351
void GuiCopyContainer::onRender(Point2I offset, const RectI &updateRect)
352
{
353
   if (mAutoCopy)
354
      copyContainer();
355
356
   if(!mBlockNormalRender)
357
   {
358
      RectI ctrlRect(offset, getExtent());
359
360
      //if opaque, fill the update rect with the fill color
361
      if ( mProfile->mOpaque )
362
         GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);
363
      
364
      //if there's a border, draw the border
365
      if ( mProfile->mBorder )
366
         renderBorder(ctrlRect, mProfile);
367
      
368
      renderChildControls(offset, updateRect);
369
   }
370
}
371
372
373
void GuiCopyContainer::copyContainer()
374
{
375
   if( dStrIsEmpty(mTargetName) )
376
   {
377
       Con::errorf("Name of the texture couldn't be set properly.");
378
       return;
379
   }
380
   
381
   Point2I size = getExtent();
382
   if(size.x == 0 || size.y == 0)
383
   {
384
      return;
385
   }
386
   
387
   // Make sure we have a clean matrix state 
388
   // before we start rendering anything!
389
   GFXTransformSaver saver;
390
   //GFX->setWorldMatrix( MatrixF::Identity );
391
   //GFX->setViewMatrix( MatrixF::Identity );
392
   //GFX->setProjectionMatrix( MatrixF::Identity );
393
394
   bool tempAwake=false;
395
   if (!isAwake())
396
   {
397
      tempAwake=true;
398
      awaken();
399
   }
400
   
401
   if (mTarget->getSize() != size)
402
   {
403
      _setupTargets();
404
      mNamedTarget.setViewport( RectI( Point2I::Zero, size ) );
405
   }
406
   
407
   RectI screenRect(0, 0, size.x, size.y);
408
   
409
   // Set active target
410
   GFX->pushActiveRenderTarget();
411
   GFX->setActiveRenderTarget(mTarget);
412
413
   // Clear the current viewport area
414
   GFX->setViewport(screenRect);
415
   GFX->clear(GFXClearTarget, LinearColorF(0, 0, 0, 0), 1.0f, 0);
416
   
417
   if ( mStateBlockData == NULL )
418
   {
419
      if( mStateBlockData != mOldStateBlockData )
420
         mOldStateBlockData = NULL;
421
      renderChildControls(Point2I(0,0),RectI(Point2I(0,0), getExtent()));
422
   }
423
   else
424
   {
425
      GFXStateBlockDesc prev_bitmapDefaultGuiDesc( GFX->getDrawUtil()->getBitmapStateBlockDesc() );
426
      GFXStateBlockDesc prev_fontDefaultGuiDesc( GFX->getDrawUtil()->getFontStateBlockDesc() );
427
      GFXStateBlockDesc prev_mDefaultGuiDesc( mDefaultGuiSB->getDesc() );
428
      
429
      GFXStateBlockDesc desc;
430
      if( mStateBlockData != mOldStateBlockData )
431
      {
432
         mOldStateBlockData = mStateBlockData;
433
         desc = mStateBlockData->getState();
434
         mStateBlock = GFX->createStateBlock(desc);
435
      }
436
      else
437
      {
438
         desc = mStateBlock->getDesc();
439
      }
440
         
441
      mDefaultGuiSB = mStateBlock;
442
      GFX->setStateBlock( mStateBlock );
443
      
444
      GFX->getDrawUtil()->externalSetupBitmapStateBlock(desc);
445
      GFX->getDrawUtil()->externalSetupFontStateBlock(desc);
446
      
447
      renderChildControls(Point2I(0,0),RectI(Point2I(0,0), getExtent()));
448
      
449
      mDefaultGuiSB = GFX->createStateBlock( prev_mDefaultGuiDesc );
450
      GFX->setStateBlock(mDefaultGuiSB);   
451
      
452
      GFX->getDrawUtil()->externalSetupBitmapStateBlock(prev_bitmapDefaultGuiDesc);
453
      GFX->getDrawUtil()->externalSetupFontStateBlock(prev_fontDefaultGuiDesc);
454
   }
455
   
456
   mTarget->resolve();
457
   GFX->popActiveRenderTarget();
458
   
459
   if(tempAwake)
460
      sleep();
461
   
462
   //Test. It copies the named texture into a file
463
   /*
464
   GFXTexHandle theTex;
465
   NamedTexTarget *namedTarget = NULL;
466
   namedTarget = NamedTexTarget::find(mTargetName);
467
   if ( namedTarget )
468
   {
469
      theTex = namedTarget->getTexture( 0 );
470
   }
471
   
472
   if ( theTex.isValid() )
473
   {
474
      theTex->dumpToDisk("png", "./testXX.png");
475
   }  
476
   */
477
}
478
479
DefineEngineMethod( GuiCopyContainer, copyContainer, void,(),,
480
   "@brief Copy its contents into the named texture.")
481
{
482
   object->copyContainer();
483
}
484
[/code]
485
486
guiBitmapShader.h
487
[code]#ifndef _GUIBITMAPSHADER_H_
488
#define _GUIBITMAPSHADER_H_
489
490
#ifndef _GUIBITMAPCTRL_H_
491
#include "gui/controls/guiBitmapCtrl.h"
492
#endif
493
494
class GFXStateBlockData;
495
class ShaderData;
496
497
/// Renders a bitmap that can use a Shader.
498
class GuiBitmapShader : public GuiBitmapCtrl
499
{
500
public:
501
   typedef GuiBitmapCtrl Parent;
502
503
   enum { NumTextures = 8 };
504
505
protected:
506
   Point2F mPosVertex[4]; //It needs to be float to avoid aproximation errors when rotating
507
   Point2F mUVValues[4];
508
   bool mAutoResizeBitmap;
509
   Point2I mOldGuiExtent;
510
511
   FileName mTexFilename[NumTextures];
512
   FileName mOldTexFilename[NumTextures];
513
   GFXTexHandle mTextures[NumTextures];
514
515
   ShaderData *mShaderData;
516
   ShaderData *mOldShaderData;
517
   GFXStateBlockData *mStateBlockData;
518
   GFXStateBlockData *mOldStateBlockData;
519
   
520
   GFXStateBlockRef mStateBlock;
521
   GFXShaderRef mShader;
522
   GFXShaderConstBufferRef mShaderConsts;
523
   
524
   //
525
   GFXShaderConstHandle *mModelViewProjSC;
526
   GFXShaderConstHandle *mGuiSizeSC;
527
   GFXShaderConstHandle *mTexSizeSC[NumTextures];
528
   GFXShaderConstHandle *mGuiOffsetSC;
529
   GFXShaderConstHandle *mAccumTimeSC;
530
   GFXShaderConstHandle *mDeltaTimeSC;
531
   //
532
533
   void _setupStateBlock();
534
   bool _setupShader();
535
   void _setupConstants();
536
   
537
   bool _setupTexture( U8 slot );
538
   void setTexture( U8 index, const String &texFilePath );
539
   
540
   void _doAutoResizeBitmap(Point2I extent, Point2I oldGuiExtent);
541
   
542
   //
543
   U32 mShaderReloadKey;
544
545
   class EffectConst
546
   {
547
   public:
548
549
      EffectConst( const String &name, const String &val )
550
         : mName( name ), 
551
           mHandle( NULL ),
552
           mDirty( true )
553
      {
554
         set( val );
555
      }
556
557
      void set( const String &newVal );
558
559
      void setToBuffer( GFXShaderConstBufferRef buff );
560
561
      String mName;
562
563
      GFXShaderConstHandle *mHandle;
564
565
      String mStringVal;
566
567
      bool mDirty;
568
   };
569
570
   typedef HashTable<StringCase,EffectConst*> EffectConstTable;
571
572
   EffectConstTable mEffectConsts;
573
   
574
public:
575
   DECLARE_CONOBJECT( GuiBitmapShader );
576
   DECLARE_CATEGORY( "Gui Images" );
577
   DECLARE_DESCRIPTION( "A control that displays an image like GuiBitmapCtrl.\n"
578
                        "But the image can use a Shader.");
579
580
   GuiBitmapShader();
581
   ~GuiBitmapShader();
582
   
583
   static void initPersistFields();
584
   
585
   DECLARE_CALLBACK( void, setShaderConsts, () );
586
587
   void onRender(Point2I offset, const RectI &updateRect);
588
   
589
   bool drawBitmapShader(Point2I offset);
590
   void setShaderConst( const String &name, const String &val );
591
   
592
   Point2F getCenter();
593
   //vertex: 0,1,2 or 3
594
   Point2F getVertexPosition(U8 vertex);
595
   void setVertexPosition(Point2F vertexPos, U8 vertex);
596
   void moveVertex(Point2I distance, U8 vertex );
597
   void rotateVertex(F32 angleDeg, Point2I pivot, U8 vertex);
598
   void scaleVertex(F32 scale, Point2I pivot, U8 vertex);
599
   F32 getBitmapProportions();
600
   Point4F getBitmapBounds();
601
   void setOldGuiExtent(Point2I value) { mOldGuiExtent = value; }
602
};
603
604
#endif //_GUIBITMAPTSHADER_H_
605
[/code]
606
607
guiBitmapShader.cpp
608
[code]#include "platform/platform.h"
609
#include "guiBitmapShader.h"
610
611
#include "console/console.h"
612
#include "console/consoleTypes.h"
613
#include "console/engineAPI.h"
614
#include "gfx/gfxDevice.h"
615
#include "gfx/gfxDrawUtil.h"
616
617
#include "materials/shaderData.h"
618
#include "gfx/sim/gfxStateBlockData.h"
619
620
#include "materials/materialManager.h"
621
#include "materials/matTextureTarget.h"
622
#include "core/strings/stringUnit.h"
623
#include "math/mMathFn.h"
624
//#include "postFx/postEffectManager.h" //it was here for getBackBufferTex()
625
626
IMPLEMENT_CONOBJECT(GuiBitmapShader);
627
628
ConsoleDocClass( GuiBitmapShader,
629
   "@brief A gui control that is used to display an image with shader.\n\n"
630
   
631
   "@ingroup GuiControls"
632
);
633
634
IMPLEMENT_CALLBACK( GuiBitmapShader, setShaderConsts, void, (), (),
635
   "Called immediate before processing this effect. This is the user's chance "
636
   "to set the value of shader uniforms (constants).\n"
637
   "@see setShaderConst"
638
);
639
640
//---------------------------------
641
void GuiBitmapShader::EffectConst::set( const String &newVal )
642
{
643
   if ( mStringVal == newVal )
644
      return;
645
646
   mStringVal = newVal;
647
   mDirty = true;
648
}
649
650
void GuiBitmapShader::EffectConst::setToBuffer( GFXShaderConstBufferRef buff )
651
{
652
   // Nothing to do if the value hasn't changed.
653
   if ( !mDirty )
654
      return;
655
   mDirty = false;
656
657
   // If we don't have a handle... get it now.
658
   if ( !mHandle )
659
      mHandle = buff->getShader()->getShaderConstHandle( mName );
660
661
   // If the handle isn't valid then we're done.
662
   if ( !mHandle->isValid() )
663
      return;
664
665
   const GFXShaderConstType type = mHandle->getType();
666
667
   // For now, we're only going
668
   // to support float4 arrays.
669
   // Expand to other types as necessary.
670
   U32 arraySize = mHandle->getArraySize();
671
672
   const char *strVal = mStringVal.c_str();
673
674
   if ( type == GFXSCT_Int )
675
   {
676
      S32 val;
677
      Con::setData( TypeS32, &val, 0, 1, &strVal );
678
      buff->set( mHandle, val );
679
   }
680
   else if ( type == GFXSCT_Float )
681
   {
682
      F32 val;
683
      Con::setData( TypeF32, &val, 0, 1, &strVal );
684
      buff->set( mHandle, val );
685
   }
686
   else if ( type == GFXSCT_Float2 )
687
   {
688
      Point2F val;
689
      Con::setData( TypePoint2F, &val, 0, 1, &strVal );
690
      buff->set( mHandle, val );
691
   }
692
   else if ( type == GFXSCT_Float3 )
693
   {
694
      Point3F val;
695
      Con::setData( TypePoint3F, &val, 0, 1, &strVal );
696
      buff->set( mHandle, val );
697
   }
698
   else if ( type == GFXSCT_Float4 )
699
   {
700
      Point4F val;
701
702
      if ( arraySize > 1 )
703
      {
704
         // Do array setup!
705
         //U32 unitCount = StringUnit::getUnitCount( strVal, "\t" );
706
         //AssertFatal( unitCount == arraySize, "" );
707
708
         String tmpString;
709
         Vector<Point4F> valArray;
710
711
         for ( U32 i = 0; i < arraySize; i++ )
712
         {
713
            tmpString = StringUnit::getUnit( strVal, i, "\t" );
714
            valArray.increment();
715
            const char *tmpCStr = tmpString.c_str();
716
717
            Con::setData( TypePoint4F, &valArray.last(), 0, 1, &tmpCStr );
718
         }
719
720
         AlignedArray<Point4F> rectData( valArray.size(), sizeof( Point4F ), (U8*)valArray.address(), false );
721
         buff->set( mHandle, rectData );
722
      }
723
      else
724
      {
725
         // Do regular setup.
726
         Con::setData( TypePoint4F, &val, 0, 1, &strVal );
727
         buff->set( mHandle, val );
728
      }
729
   }
730
   else
731
   {
732
#if TORQUE_DEBUG
733
      const char* err = avar("GuiBitmapShader::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
734
      Con::errorf(err);
735
      GFXAssertFatal(0,err);
736
#endif
737
   }
738
}
739
//---------------------------------
740
741
GuiBitmapShader::GuiBitmapShader()
742
{
743
   mPosVertex[0] = Point2F(0.0,0.0);
744
   mPosVertex[1] = Point2F(64.0,0.0);
745
   mPosVertex[2] = Point2F(0.0,64.0);
746
   mPosVertex[3] = Point2F(64.0,64.0);
747
   mUVValues[0] = Point2F(0.0,0.0);
748
   mUVValues[1] = Point2F(1.0,0.0);
749
   mUVValues[2] = Point2F(0.0,1.0);
750
   mUVValues[3] = Point2F(1.0,1.0);
751
   mAutoResizeBitmap = false;
752
   mOldGuiExtent = Point2I(0,0);
753
   
754
   mTexFilename[0] = "$inTex";
755
   mOldTexFilename[0] = "$inTex";
756
   mTexSizeSC[0] = NULL; //another SC
757
   for( U8 i = 1; i < NumTextures; i++ )
758
   {
759
      mTexFilename[i] = String::EmptyString;
760
      mOldTexFilename[i] = String::EmptyString;
761
      mTexSizeSC[i] = NULL; //another SC
762
   }
763
764
   mShaderData = NULL;
765
   mShader = NULL;
766
   mStateBlockData = NULL;
767
   mStateBlock = NULL;
768
   mShaderConsts = NULL;
769
   
770
   mOldShaderData = NULL;
771
   mOldStateBlockData = NULL;
772
   
773
   //SC
774
   mModelViewProjSC = NULL;
775
   mGuiSizeSC = NULL;
776
   mGuiOffsetSC = NULL;
777
   mAccumTimeSC = NULL;
778
   mDeltaTimeSC = NULL;
779
   
780
   mShaderReloadKey = 0;
781
}
782
783
GuiBitmapShader::~GuiBitmapShader()
784
{
785
   for ( U8 i = 0; i < NumTextures; i++ )
786
   {
787
      mTextures[i].free();
788
      mTextures[i] = NULL;
789
   }
790
   
791
   EffectConstTable::Iterator iter = mEffectConsts.begin();
792
   for ( ; iter != mEffectConsts.end(); iter++ )
793
      delete iter->value;
794
}
795
796
void GuiBitmapShader::initPersistFields()
797
{
798
   ///I add this here so in the editor the order keeps correct
799
   addGroup( "Bitmap" );
800
      ///Parent will add bitmap here
801
   endGroup( "Bitmap" );
802
   
803
   addGroup( "Bitmap transform" );
804
      addField( "pointTL", TypePoint2F, Offset( mPosVertex[0], GuiBitmapShader), "Location of the top left vertex." );
805
      addField( "pointTR", TypePoint2F, Offset( mPosVertex[1], GuiBitmapShader), "Location of the top right vertex." );
806
      addField( "pointBL", TypePoint2F, Offset( mPosVertex[2], GuiBitmapShader), "Location of the bottom left vertex." );
807
      addField( "pointBR", TypePoint2F, Offset( mPosVertex[3], GuiBitmapShader), "Location of the bottom right vertex." );
808
      addField( "uvTL", TypePoint2F, Offset( mUVValues[0], GuiBitmapShader), "UV values of the top left vertex." );
809
      addField( "uvTR", TypePoint2F, Offset( mUVValues[1], GuiBitmapShader), "UV values of the top right vertex." );
810
      addField( "uvBL", TypePoint2F, Offset( mUVValues[2], GuiBitmapShader), "UV values of the bottom left vertex." );
811
      addField( "uvBR", TypePoint2F, Offset( mUVValues[3], GuiBitmapShader), "UV values of the bottom right vertex." );
812
      addField( "autoResize", TypeBool, Offset( mAutoResizeBitmap, GuiBitmapShader ), "Bitmap resizes if the gui changes size." );
813
   endGroup( "Bitmap transform" );
814
   
815
   addGroup( "Bitmap shader" );
816
      addField( "shader", TYPEID<ShaderData>(), Offset( mShaderData, GuiBitmapShader ),
817
         "Name of a ShaderData for this effect." );
818
      addField( "stateBlock", TYPEID<GFXStateBlockData>(), Offset( mStateBlockData,  GuiBitmapShader ),
819
         "Name of a GFXStateBlockData for this effect." );
820
      addField( "texture", TypeImageFilename, Offset( mTexFilename, GuiBitmapShader ), NumTextures,
821
         "Input textures to this shader ( samplers )." );
822
   endGroup( "Bitmap shader" );
823
824
   Parent::initPersistFields();
825
   removeField( "wrap" ); //It comes from Parent::initPersistFields(). Not used in this gui.
826
}
827
828
void GuiBitmapShader::onRender(Point2I offset, const RectI &updateRect)
829
{
830
   Point2I extent = getExtent();
831
   if (mAutoResizeBitmap)
832
   {
833
      if (mOldGuiExtent.x != extent.x || mOldGuiExtent.y != extent.y)
834
      {
835
         _doAutoResizeBitmap(extent, mOldGuiExtent);
836
         mOldGuiExtent = extent;
837
      }
838
   }
839
   
840
   bool drawingSuccess = drawBitmapShader(offset);
841
   if (mProfile->mBorder || !drawingSuccess )
842
   {
843
      RectI rect(offset.x, offset.y, extent.x, extent.y);
844
      GFX->getDrawUtil()->drawRect(rect, mProfile->mBorderColor);
845
   }
846
   
847
   renderChildControls(offset, updateRect);
848
}
849
850
bool GuiBitmapShader::drawBitmapShader(Point2I offset)
851
{
852
   _setupStateBlock();
853
   bool customShader = true;
854
   customShader = _setupShader();
855
   
856
   //Shader textures
857
   // Set the textures.
858
   bool thereIsTexture = false;
859
   for ( U8 i = 0; i < NumTextures; i++ )
860
   {
861
      thereIsTexture = _setupTexture( i );
862
      if(i==0 && !customShader && !thereIsTexture)
863
         return false;
864
   }
865
   
866
   const F32 fillConv = GFX->getFillConventionOffset();
867
   GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, 4, GFXBufferTypeVolatile );
868
   verts.lock();
869
   Point2F vertexLocation;
870
   for(U8 v = 0; v<4; v++)
871
   {
872
      vertexLocation = mPosVertex[v] + Point2F((F32)offset.x,(F32)offset.y);
873
      verts[v].point.set(vertexLocation.x - fillConv, vertexLocation.y - fillConv, 0.f );
874
      verts[v].texCoord.set( mUVValues[v].x, mUVValues[v].y );
875
      verts[v].color = mColor;
876
   }
877
   verts.unlock();
878
   
879
   GFX->setVertexBuffer( verts );
880
   GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
881
   return true;
882
}
883
884
bool GuiBitmapShader::_setupTexture( U8 stage )
885
{
886
   const String &texFilename = mTexFilename[ stage ];
887
   
888
   if(texFilename.compare( mOldTexFilename[ stage ], 0, String::NoCase ) != 0 )
889
   {
890
      setTexture(stage, texFilename);
891
   }
892
893
   GFXTexHandle theTex;
894
   NamedTexTarget *namedTarget = NULL;
895
896
   if ( texFilename.compare( "$inTex", 0, String::NoCase ) == 0 )
897
   {
898
      theTex = mTextureObject;
899
   }
900
   else if ( texFilename.compare( "$backBuffer", 0, String::NoCase ) == 0 )
901
   {
902
      //Here I wanted "theTex = PFXMGR->getBackBufferTex();" like PostFX but it throws some texture leak
903
      //A copy of the base of the code of getBackBufferTex() seems to work
904
      GFXTarget *target = GFX->getActiveRenderTarget();
905
      
906
      const Point2I &targetSize = target->getSize();
907
      GFXFormat targetFormat = target->getFormat();
908
909
      theTex.set( targetSize.x, targetSize.y, 
910
                              targetFormat, 
911
                              &GFXRenderTargetProfile, "theTex" );
912
913
      target->resolveTo( theTex );
914
   }
915
   else if ( texFilename.isNotEmpty() && texFilename[0] == '#' )
916
   {
917
      namedTarget = NamedTexTarget::find( texFilename.c_str() + 1 );
918
      if ( namedTarget )
919
      {
920
         theTex = namedTarget->getTexture( 0 );
921
      }
922
   }
923
   else
924
   {
925
      theTex = mTextures[ stage ];
926
   }
927
928
   if ( theTex.isValid() )
929
   {
930
      if (mShaderConsts)
931
      {
932
         if (mTexSizeSC[stage]->isValid())
933
         {
934
            Point2F texSizeConst;
935
            texSizeConst.x = (F32)theTex->getWidth();
936
            texSizeConst.y = (F32)theTex->getHeight();
937
            mShaderConsts->set(mTexSizeSC[stage], texSizeConst);
938
         }
939
      }
940
941
      GFX->setTexture( stage, theTex );
942
      return true;
943
   }
944
   return false; //theTex is not valid
945
}
946
947
void GuiBitmapShader::setTexture( U8 index, const String &texFilePath )
948
{
949
	// Set the new texture name.
950
	mTexFilename[index] = texFilePath;
951
   mOldTexFilename[index] = texFilePath;
952
   mTextures[index].free();
953
   mTextures[index] = NULL;
954
955
   // Skip empty stages or ones with variable or target names.
956
   if (	texFilePath.isEmpty() || texFilePath[0] == '$' || texFilePath[0] == '#' )
957
      return;
958
959
   // Try to load the texture.
960
   mTextures[index].set( texFilePath, &GFXTexturePersistentProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) );
961
}
962
963
void GuiBitmapShader::_setupStateBlock()
964
{
965
   if ( mStateBlock.isNull() || mStateBlockData != mOldStateBlockData )
966
   {
967
      mOldStateBlockData = mStateBlockData;
968
      GFXStateBlockDesc desc;
969
      if ( mStateBlockData )
970
         desc = mStateBlockData->getState();
971
      else
972
         desc = GFX->getDrawUtil()->getBitmapStateBlockDesc(); //default values from drawUtil
973
      
974
      mStateBlock = GFX->createStateBlock( desc );
975
   }
976
977
   GFX->setStateBlock( mStateBlock );
978
}
979
980
bool GuiBitmapShader::_setupShader()
981
{
982
   if ( mShaderData == NULL || mShaderData != mOldShaderData )
983
   {
984
      if(mOldShaderData)
985
      {
986
         //Maybe use this to clean mShaderConsts because the "allocConstBuffer"?
987
         //delete[] mShaderConsts;
988
         
989
         mShaderConsts = NULL;
990
         mShader = NULL;
991
992
         //kinda cheat.
993
         mShaderReloadKey--;
994
         EffectConstTable::Iterator iter = mEffectConsts.begin();
995
         for ( ; iter != mEffectConsts.end(); iter++ )
996
            delete iter->value;
997
         mEffectConsts = EffectConstTable();
998
      }
999
      
1000
      mOldShaderData = mShaderData;
1001
      
1002
      if( mShaderData )
1003
      {
1004
         if ( mShaderData->getPixVersion() <= GFX->getPixelShaderVersion() )
1005
            mShader = mShaderData->getShader();
1006
      }
1007
   }
1008
   
1009
   if ( !mShader ) //mShaderData failed
1010
   {
1011
      GFX->setupGenericShaders( GFXDevice::GSModColorTexture );
1012
      return false;
1013
   }
1014
   else
1015
   {
1016
      _setupConstants();
1017
      GFX->setShader( mShader );
1018
1019
      GFX->setShaderConstBuffer( mShaderConsts );
1020
      return true;
1021
   }
1022
}
1023
1024
void GuiBitmapShader::_setupConstants()
1025
{
1026
   // Alloc the const buffer.
1027
   if ( mShaderConsts.isNull() )
1028
   {
1029
      mShaderConsts = mShader->allocConstBuffer();
1030
      mModelViewProjSC = mShader->getShaderConstHandle( "$modelView" );
1031
      mGuiSizeSC = mShader->getShaderConstHandle( "$guiSize" );
1032
      
1033
      mTexSizeSC[0] = mShader->getShaderConstHandle( "$texSize0" );
1034
      mTexSizeSC[1] = mShader->getShaderConstHandle( "$texSize1" );
1035
      mTexSizeSC[2] = mShader->getShaderConstHandle( "$texSize2" );
1036
      mTexSizeSC[3] = mShader->getShaderConstHandle( "$texSize3" );
1037
      mTexSizeSC[4] = mShader->getShaderConstHandle( "$texSize4" );
1038
      mTexSizeSC[5] = mShader->getShaderConstHandle( "$texSize5" );
1039
      mTexSizeSC[6] = mShader->getShaderConstHandle( "$texSize6" );
1040
      mTexSizeSC[7] = mShader->getShaderConstHandle( "$texSize7" );
1041
      
1042
      mGuiOffsetSC = mShader->getShaderConstHandle( "$guiOffset" );
1043
      
1044
      mAccumTimeSC = mShader->getShaderConstHandle( "$accumTime" );
1045
      mDeltaTimeSC = mShader->getShaderConstHandle( "$deltaTime" );
1046
   }
1047
   
1048
   MatrixF xform(GFX->getProjectionMatrix());
1049
   xform *= GFX->getViewMatrix();
1050
   xform *= GFX->getWorldMatrix();
1051
   mShaderConsts->setSafe( mModelViewProjSC, xform );
1052
   
1053
   if ( mGuiSizeSC->isValid() )
1054
   {
1055
      Point2F guiSize = Point2F((F32)getExtent().x,(F32)getExtent().y);
1056
      mShaderConsts->set( mGuiSizeSC, guiSize );
1057
   }
1058
   
1059
   if ( mGuiOffsetSC->isValid() )
1060
   {
1061
      Point2F guiOffset = Point2F((F32)getPosition().x,(F32)getPosition().y);
1062
      mShaderConsts->set( mGuiOffsetSC, guiOffset );
1063
   }
1064
   
1065
   mShaderConsts->setSafe( mAccumTimeSC, MATMGR->getTotalTime() );
1066
   mShaderConsts->setSafe( mDeltaTimeSC, MATMGR->getDeltaTime() );
1067
   
1068
   ///
1069
   // Set EffectConsts - specified from script
1070
1071
   // If our shader has reloaded since last frame we must mark all
1072
   // EffectConsts dirty so they will be reset.
1073
   if ( mShader->getReloadKey() != mShaderReloadKey )
1074
   {
1075
      mShaderReloadKey = mShader->getReloadKey();
1076
1077
      EffectConstTable::Iterator iter = mEffectConsts.begin();
1078
      for ( ; iter != mEffectConsts.end(); iter++ )
1079
      {
1080
         iter->value->mDirty = true;
1081
         iter->value->mHandle = NULL;
1082
      }
1083
   }
1084
   
1085
   setShaderConsts_callback();
1086
   
1087
   EffectConstTable::Iterator iter = mEffectConsts.begin();
1088
   for ( ; iter != mEffectConsts.end(); iter++ )
1089
      iter->value->setToBuffer( mShaderConsts );
1090
}
1091
1092
void GuiBitmapShader::setShaderConst( const String &name, const String &val )
1093
{
1094
   PROFILE_SCOPE( GuiBitmapShader_SetShaderConst );
1095
1096
   EffectConstTable::Iterator iter = mEffectConsts.find( name );
1097
   if ( iter == mEffectConsts.end() )
1098
   {
1099
      EffectConst *newConst = new EffectConst( name, val );
1100
      iter = mEffectConsts.insertUnique( name, newConst );
1101
   }
1102
1103
   iter->value->set( val );
1104
}
1105
1106
DefineEngineMethod( GuiBitmapShader, setShaderConst, void, ( const char* name, const char* value ),,
1107
   "Sets the value of a uniform defined in the shader. This will usually "
1108
   "be called within the setShaderConsts callback. Array type constants are "
1109
   "not supported.\n"    
1110
   "@param name Name of the constanst, prefixed with '$'.\n" 
1111
   "@param value Value to set, space seperate values with more than one element.\n"
1112
   "@tsexample\n"
1113
   "function MyGBTS::setShaderConsts( %this )\n"
1114
   "{\n"
1115
   "   // example float4 uniform\n"
1116
   "   %this.setShaderConst( \"$colorMod\", \"1.0 0.9 1.0 1.0\" );\n"
1117
   "   // example float1 uniform\n"
1118
   "   %this.setShaderConst( \"$strength\", \"3.0\" );\n"
1119
   "   // example integer uniform\n"
1120
   "   %this.setShaderConst( \"$loops\", \"5\" );"
1121
   "}\n"
1122
   "@endtsexample" )   
1123
{
1124
   object->setShaderConst( name, value );
1125
}
1126
1127
//------------------------------------------------------------------------------
1128
void GuiBitmapShader::_doAutoResizeBitmap(Point2I extent, Point2I oldGuiExtent)
1129
{
1130
   if(oldGuiExtent.x != 0)
1131
   {
1132
      F32 factor = (F32)extent.x / (F32)oldGuiExtent.x;
1133
      mPosVertex[0].x *= factor;
1134
      mPosVertex[1].x *= factor;
1135
      mPosVertex[2].x *= factor;
1136
      mPosVertex[3].x *= factor;
1137
   }
1138
   if(oldGuiExtent.y != 0)
1139
   {
1140
      F32 factor = (F32)extent.y / (F32)oldGuiExtent.y;
1141
      mPosVertex[0].y *= factor;
1142
      mPosVertex[1].y *= factor;
1143
      mPosVertex[2].y *= factor;
1144
      mPosVertex[3].y *= factor;
1145
   }
1146
}
1147
1148
Point2F GuiBitmapShader::getCenter()
1149
{
1150
   return Point2F((mPosVertex[0].x+mPosVertex[1].x+mPosVertex[2].x+mPosVertex[3].x)/4.0,
1151
      (mPosVertex[0].y+mPosVertex[1].y+mPosVertex[2].y+mPosVertex[3].y)/4.0);
1152
}
1153
1154
Point2F GuiBitmapShader::getVertexPosition(U8 vertex)
1155
{
1156
   if (vertex > 3)
1157
      return Point2F(-9999.9,-9999.9);
1158
   
1159
   return mPosVertex[vertex];
1160
}
1161
1162
void GuiBitmapShader::setVertexPosition(Point2F vertexPos, U8 vertex)
1163
{
1164
   if (vertex > 3)
1165
      return;
1166
   
1167
   mPosVertex[vertex] = vertexPos;
1168
}
1169
1170
void GuiBitmapShader::moveVertex(Point2I distance, U8 vertex )
1171
{
1172
   if (vertex > 3)
1173
      return;
1174
   
1175
   mPosVertex[vertex] += Point2F((F32)distance.x,(F32)distance.y);
1176
}
1177
1178
void GuiBitmapShader::rotateVertex(F32 angleDeg, Point2I pivot, U8 vertex)
1179
{
1180
   if (vertex > 3)
1181
      return;
1182
   
1183
   if(mPosVertex[vertex].x == (F32)pivot.x && mPosVertex[vertex].y == (F32)pivot.y)
1184
      return;
1185
   
1186
   Point2F vector = Point2F(mPosVertex[vertex].x - (F32)pivot.x, mPosVertex[vertex].y - (F32)pivot.y);
1187
   
1188
   F32 dist = mSqrt((vector.x * vector.x) + (vector.y * vector.y));
1189
   F32 angl = mAtan2( vector.x , vector.y );
1190
   
1191
   mPosVertex[vertex].x = (dist*mSin(angl - mDegToRad(angleDeg))) + pivot.x;
1192
   mPosVertex[vertex].y = (dist*mCos(angl - mDegToRad(angleDeg))) + pivot.y;
1193
}
1194
1195
void GuiBitmapShader::scaleVertex(F32 scale, Point2I pivot, U8 vertex)
1196
{
1197
   if (vertex > 3)
1198
      return;
1199
   
1200
   if(mPosVertex[vertex].x == pivot.x && mPosVertex[vertex].y == pivot.y)
1201
      return;
1202
   
1203
   Point2F vector = Point2F(mPosVertex[vertex].x - (F32)pivot.x, mPosVertex[vertex].y - (F32)pivot.y);
1204
   
1205
   vector.x *= scale;
1206
   vector.y *= scale;
1207
   
1208
   mPosVertex[vertex] = Point2F(vector.x + (F32)pivot.x, vector.y + (F32)pivot.y);
1209
}
1210
1211
F32 GuiBitmapShader::getBitmapProportions()
1212
{
1213
   if ( mTextureObject )
1214
   {
1215
      return (F32)mTextureObject->getWidth() / (F32)mTextureObject->getHeight();
1216
   }
1217
   else
1218
      return 0.0;
1219
}
1220
1221
Point4F GuiBitmapShader::getBitmapBounds()
1222
{
1223
   Point4F bounds = Point4F(mPosVertex[0].x,mPosVertex[0].y,mPosVertex[0].x,mPosVertex[0].y);
1224
   for(U8 i = 1; i<4; i++)
1225
   {
1226
      if(mPosVertex[i].x<bounds.x)
1227
         bounds.x = mPosVertex[i].x;
1228
      if(mPosVertex[i].x>bounds.z)
1229
         bounds.z = mPosVertex[i].x;
1230
      
1231
      if(mPosVertex[i].y<bounds.y)
1232
         bounds.y = mPosVertex[i].y;
1233
      if(mPosVertex[i].y>bounds.w)
1234
         bounds.w = mPosVertex[i].y;
1235
   }
1236
   return bounds;
1237
}
1238
1239
//-----------------------------------------------------------------------------
1240
1241
DefineEngineMethod(GuiBitmapShader, getCenter, Point2F, (),,
1242
   "@brief Get the center of mass of the bitmap.\n\n"
1243
   "@return A point2F. You may want to convert it into a Point2I." )
1244
{
1245
   return object->getCenter();
1246
}
1247
1248
DefineEngineMethod(GuiBitmapShader, moveBitmap, void, (Point2I distance),,
1249
   "@brief Move the bitmap.\n\n"
1250
   "@param distance Pixels (x,y) to move.\n"
1251
   "+x: right, -x: left, +y: down, -y: up")
1252
{
1253
   object->moveVertex(distance,0);
1254
   object->moveVertex(distance,1);
1255
   object->moveVertex(distance,2);
1256
   object->moveVertex(distance,3);
1257
}
1258
1259
DefineEngineMethod(GuiBitmapShader, rotateBitmap, void, (F32 angleDeg, Point2I pivot),,
1260
   "@brief Rotate the bitmap.\n\n"
1261
   "@param angleDeg Angle in degrees to rotate (positive clockwise).\n"
1262
   "@param pivot Point around vertices rotate.\n\"0 0\" is top left of the gui.")
1263
{
1264
   object->rotateVertex(angleDeg,pivot,0);
1265
   object->rotateVertex(angleDeg,pivot,1);
1266
   object->rotateVertex(angleDeg,pivot,2);
1267
   object->rotateVertex(angleDeg,pivot,3);
1268
}
1269
1270
DefineEngineMethod(GuiBitmapShader, scaleBitmap, void, (F32 scale, Point2I pivot),,
1271
   "@brief Resize the bitmap.\n\n"
1272
   "@param scale Number to scale. 1.0 keeps size.\n"
1273
   "@param pivot Point around vertices scale the distance.\n\"0 0\" is top left of the gui.")
1274
{
1275
   object->scaleVertex(scale,pivot,0);
1276
   object->scaleVertex(scale,pivot,1);
1277
   object->scaleVertex(scale,pivot,2);
1278
   object->scaleVertex(scale,pivot,3);
1279
}
1280
1281
DefineEngineMethod(GuiBitmapShader, fillExpand, void, (bool keepBitmapRatio),,
1282
   "@brief Expand the bitmap to fill the gui.\n\n"
1283
   "@param keepBitmapRatio If true the bitmap keeps proportions of $inTex.\n")
1284
{
1285
   F32 ratio = object->getBitmapProportions();
1286
   
1287
   //ratio == 0.0 means there is no bitmap asigned. Just set vertices to fill.
1288
   if (!keepBitmapRatio || ratio == 0.0)
1289
   {
1290
      object->setVertexPosition(Point2F(0.0,0.0),0);
1291
      object->setVertexPosition(Point2F(object->getExtent().x,0.0),1);
1292
      object->setVertexPosition(Point2F(0.0, object->getExtent().y),2);
1293
      object->setVertexPosition(Point2F(object->getExtent().x, object->getExtent().y),3);
1294
   }
1295
   else
1296
   {
1297
      //ratio = Width / Height
1298
      F32 guiRatio = (F32)object->getExtent().x / (F32)object->getExtent().y;
1299
      
1300
      if(guiRatio < ratio)
1301
      {
1302
         F32 xExtent = (F32)object->getExtent().x;
1303
         F32 yExtent = xExtent / ratio;
1304
         F32 topPosition = 0.5 * (F32)object->getExtent().y - 0.5 * yExtent;
1305
         F32 bottomPosition = topPosition + yExtent;
1306
         
1307
         object->setVertexPosition(Point2F(0.0,topPosition),0);
1308
         object->setVertexPosition(Point2F(xExtent,topPosition),1);
1309
         object->setVertexPosition(Point2F(0.0,bottomPosition),2);
1310
         object->setVertexPosition(Point2F(xExtent,bottomPosition),3);
1311
      }
1312
      else
1313
      {
1314
         F32 yExtent = (F32)object->getExtent().y;
1315
         F32 xExtent = yExtent * ratio;
1316
         F32 leftPosition = 0.5 * (F32)object->getExtent().x - 0.5 * xExtent;
1317
         F32 rightPosition = leftPosition + xExtent;
1318
         
1319
         object->setVertexPosition(Point2F(leftPosition,0.0),0);
1320
         object->setVertexPosition(Point2F(rightPosition,0.0),1);
1321
         object->setVertexPosition(Point2F(leftPosition,yExtent),2);
1322
         object->setVertexPosition(Point2F(rightPosition,yExtent),3);
1323
      }
1324
   }
1325
}
1326
1327
DefineEngineMethod(GuiBitmapShader, getBitmapBounds, Point4F, (),,
1328
   "@brief Get the bounds of the bitmap.\n\n"
1329
   "@return Point4F. First pair is top left and last is bottom right." )
1330
{
1331
   return object->getBitmapBounds();
1332
}
1333
1334
DefineEngineMethod(GuiBitmapShader, doCenterBitmap, void, (),,
1335
   "@brief Move the bitmap to be centered in the gui.\n")
1336
{
1337
   Point2F bitmapCenter = object->getCenter();
1338
   Point2F guiCenter = Point2F(object->getExtent().x/2.0,object->getExtent().x/2.0);
1339
   
1340
   Point2I distance = Point2I(mRound(guiCenter.x-bitmapCenter.x),mRound(guiCenter.y-bitmapCenter.y));
1341
   
1342
   object->moveVertex(distance,0);
1343
   object->moveVertex(distance,1);
1344
   object->moveVertex(distance,2);
1345
   object->moveVertex(distance,3);
1346
}
1347
1348
DefineEngineMethod(GuiBitmapShader, setBitmapBounds, void, (Point4F newBounds),,
1349
   "@brief Set the bounds of the bitmap.\n\n"
1350
   "@param newBounds First pair is top left and last is bottom right." )
1351
{   
1352
   Point4F oldBounds = object->getBitmapBounds();
1353
   
1354
   F32 horRatio = 0.0;
1355
   F32 verRatio = 0.0;
1356
   
1357
   if (oldBounds.z-oldBounds.x != 0.0)
1358
      horRatio = (newBounds.z-newBounds.x) / (oldBounds.z-oldBounds.x);
1359
   if (oldBounds.w-oldBounds.y != 0.0)
1360
      verRatio = (newBounds.w-newBounds.y) / (oldBounds.w-oldBounds.y);
1361
   
1362
   for(U8 i = 0; i<4; i++)
1363
   {
1364
      Point2F ver = object->getVertexPosition(i);
1365
      object->setVertexPosition( Point2F((horRatio*(ver.x-oldBounds.x))+newBounds.x,(verRatio*(ver.y-oldBounds.y))+newBounds.y), i);
1366
   }
1367
}
1368
   
1369
DefineEngineMethod(GuiBitmapShader, autoResizeGui, void, (),,
1370
   "@brief Move and resize the gui to show all the bitmap.\n")
1371
{
1372
   Point4F bounds = object->getBitmapBounds();
1373
   Point2I newExtent = Point2I(mRound(bounds.z - bounds.x), mRound(bounds.w - bounds.y));
1374
   if (newExtent.x != 0 && newExtent.y != 0)
1375
   {
1376
      object->setExtent(newExtent);
1377
      object->setOldGuiExtent(newExtent);
1378
1379
      Point2I newPosition = object->getPosition() + Point2I(mRound(bounds.x), mRound(bounds.y));
1380
      object->setPosition(newPosition.x,newPosition.y);
1381
1382
      Point2I distance = Point2I(-1 * mRound(bounds.x), -1 * mRound(bounds.y));
1383
      object->moveVertex(distance, 0);
1384
      object->moveVertex(distance, 1);
1385
      object->moveVertex(distance, 2);
1386
      object->moveVertex(distance, 3);
1387
   }
1388
}[/code]
1389
1390
//------------------------------------------------------------------
1391
1392
-Usage-
1393
GuiCopyContainer
1394
1395
In the gui editor you can find it in Lybrary/Containers/GuiCopyConatiner .(or make it in script).
1396
Then just like a normal gui container add any gui inside you want.
1397
You need to add a stateBlock for it to render to texture correctly. This type seems to work the best (add it in some .cs file):
1398
1399
[code]singleton GFXStateBlockData( BasicStateBlock )
1400
{   
1401
   blendDefined = true;
1402
   blendEnable = true; 
1403
   blendSrc = GFXBlendSrcAlpha;
1404
   blendDest = GFXBlendInvSrcAlpha;
1405
   blendOp = GFXBlendOpAdd;
1406
   
1407
   separateAlphaBlendDefined = true;
1408
   separateAlphaBlendEnable = true;
1409
   separateAlphaBlendSrc = GFXBlendOne;
1410
   separateAlphaBlendDest = GFXBlendOne;
1411
   separateAlphaBlendOp = GFXBlendOpAdd;
1412
   
1413
   samplersDefined = true;
1414
   samplerStates[0] = SamplerClampLinear;
1415
};
1416
[/code]
1417
1418
If you're saving the container in the gui you will need to load that before the container is introduced like it's done in mainmenu.gui.
1419
1420
Other variables are:
1421
-textureName: this is the name of the texture you can use in places where named textures are used.
1422
-targetFormat: the format of the texture. GFXFormatR8G8B8A8 is good enough.
1423
1424
-blockNormalRender: if true then the contents of the container are active but not rendered. It's used if you want to have the container in an active gui but you only want to use its named texture.
1425
-autoCopy: if true the gui copies the texture each time onRender is called. If false then the container is passive and you have to use the method manually. Similar on how you can disable PostEffect and make it render one frame.
1426
1427
The method is:
1428
GuiCopyContainer::copyContainer()
1429
It just does the copy of the container to a texture manually. It's used if autoCopy is disabled.
1430
1431
//------------------------------------------------------------------
1432
1433
-Usage-
1434
GuiBitmapShader
1435
1436
In the gui editor you can find it in Lybrary/Images/GuiBitmapShader .(or make it in script).
1437
Then just like a normal gui bitmap control it'll display an image related to how shader is defined and the textures detailed.
1438
1439
If you're saving the gui you will need to load the shader and the stateblock before the gui is loaded like it's done in mainmenu.gui.
1440
1441
Its variables are:
1442
-pointTL, pointTR, pointBL and pointBR: those are Point2F in the coordinates inside the gui ("0 0" being the top left of the gui) that defines the four vertices of the image. There is a method to fill the gui but if you set it manually you can force the 4 faces polygon to have any shape (like diamond or a trapeze).
1443
T top, B bottom, L left and R right but you can rotate it if you want so it's only a way to remember the order. If the order of the polygon is changed it may become backfaced triangles and not render (culling thing).
1444
The stretch of the texture comes from interpolation on the triangles so irregular shapes may not show good results. Use the shader code for that, instead.
1445
-uvTL, uvTR, uvBL and uv BR: those are the uv coordinates in the shader of the previous vertices. If you want to mirror the image you can change the order of these.
1446
-autoResize: if the gui changes size, the vertices are modified to resize the image bounds with the gui.
1447
1448
-shader: the ShaderData used. It can be left blank and the gui will just display the texture[0] with the points and uv values used.
1449
-stateBlock: a GFXStateBlockData that defines how it's rendered. You may leave it blank and it'll use the default one from DrawUtil so you get the options correctly when combining with GuiCopyContainer.
1450
1451
-texture[0-7]: The used textures.
1452
Use "$inTex" to use the image from the bitmap variable.
1453
Use "$backbuffer" to [i]try[/i] to use the backbuffer... but it's a bit hack. Better to use a PostEffect rendering it to named texture and use the #.
1454
Use "#texture" to use a named texture with name "texture" (note the # before the name).
1455
Use the location of the image to use the texture like "data/splash.png".
1456
1457
Then in the hlsl or glsl shader you can use the textures like
1458
TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0);
1459
TORQUE_UNIFORM_SAMPLER2D(basealpha, 1);
1460
TORQUE_UNIFORM_SAMPLER2D(diffuseMapB, 2);
1461
1462
1463
Like PostEffect you can use the setShaderConsts callback to add constants to the shader with setShaderConst like:
1464
[code]$colorVar1 = "0.0 1.0 0.0 1.0";
1465
$colorVar2 = "1.0 0.0 0.0 1.0";
1466
function GuiBitmapShaderName::setShaderConsts( %this )
1467
{
1468
   %this.setShaderConst( "$colorMod", $colorVar1 );
1469
   %this.setShaderConst( "$colorModB", $colorVar2 );
1470
}
1471
[/code]
1472
1473
The gui has some engine uniforms defined you can use:
1474
modelView : transform for vertex drawing
1475
guiSize : float2 with the pixel extent of the gui
1476
texSize0-7 : float2 with the size of the texture[0-7]
1477
guiOffset : the getPosition() of the gui (so it can be loacted in combination with guiSize in screen space)
1478
accumTime : the getTime() milliseconds variable.
1479
deltaTime : the same as accumTime but only for the current frame
1480
1481
Other methods:
1482
-Point2F XXX.getCenter(): returns the center of the four vertices. Use it to rotate better the image, specially if the gui changes size.
1483
-XXX.moveBitmap(Point2I distance): moves the four vertices around that distance. 
1484
-XXX.rotateBitmap(F32 angle, Point2I pivot): rotate the four vertices around the pivot.
1485
-XXX.scaleBitmap(F32 scale, Point2I pivot): scale uniformly the four vertices around the pivot.
1486
-XXX.fillExpand(bool keepBitmapRatio): expands the four vertices to fill the gui. If keepBitmapRatio is true then it will not break the proportions of $inTex.
1487
-Point4F XXX.getBitmapBounds(): returns a Point4F. It represents the rectangle ortogonal rectangle that contains the image. Fist pair is top left and second pair is bottom right coordinates inside the gui.
1488
-XXX.doCenterBitmap(): moves the vertices so its center is the center of the gui.
1489
-XXX.setBitmapBounds(Point4F bounds): scales and moves the vertices so it's located inside the rectangle defined in blounds (first pair is top left and second pair is bottom right coordinates). You can use it to scale the gui with different values for x and y.
1490
-XXX.autoResizeGui(): scales and moves the gui itself so it'll display all the vertices (the vertices coordinates will change, then).
1491
1492
[img]https://i.imgur.com/0FdS9Me.png[/img]
1493
1) GuiBitmapShader. It's using the named texture from 2), a conditional to show red if the uv is lower than a value, it's moving with cos(accumTime) and a file texture to use the alpha as mask.
1494
2) GuiCopyContainer with a bitmap control and a text.
1495
3) bitmap control using setNamedTexture to display 2)
1496
1497
Example of shader (note: only using directx):
1498
cs file:
1499
[code]
1500
singleton ShaderData( TestSOne )
1501
{
1502
   DXVertexShaderFile = "./fileV.hlsl";
1503
   DXPixelShaderFile  = "./fileP.hlsl";
1504
   
1505
   pixVersion = 1.0;
1506
};
1507
1508
singleton GFXStateBlockData( BaseStateBlock )
1509
{   
1510
   blendDefined = true;
1511
   blendEnable = true; 
1512
   blendSrc = GFXBlendSrcAlpha;
1513
   blendDest = GFXBlendInvSrcAlpha;
1514
   blendOp = GFXBlendOpAdd;
1515
   
1516
   separateAlphaBlendDefined = true;
1517
   separateAlphaBlendEnable = true;
1518
   separateAlphaBlendSrc = GFXBlendOne;
1519
   separateAlphaBlendDest = GFXBlendOne;
1520
   separateAlphaBlendOp = GFXBlendOpAdd;
1521
   
1522
   samplersDefined = true;
1523
   samplerStates[0] = SamplerClampLinear;
1524
};
1525
1526
$colorVar1 = "0.0 1.0 0.0 1.0";
1527
$colorVar2 = "1.0 0.0 0.0 1.0";
1528
function TestA::setShaderConsts( %this )
1529
{
1530
   %this.setShaderConst( "$colorMod", $colorVar1 );
1531
   %this.setShaderConst( "$colorModB", $colorVar2 );
1532
}
1533
1534
//type est in the consolo to add the gui in the mainmenu
1535
function est()
1536
{
1537
   MainMenuGui.add(TestA);
1538
   TestA.fillExpand(false);
1539
}
1540
1541
if(!isObject(TestA))
1542
{
1543
   
1544
   new GuiBitmapShader(TestA)
1545
   {
1546
      shader = "TestSOne";
1547
      stateBlock = BaseStateBlock;
1548
      texture[0] = "data/splash.png";
1549
      texture[1] = "$inTex";
1550
      texture[2] = "#copiedcontainer";
1551
      //uvTL = "0.01 0.01";
1552
      //uvTR = "0.99 0.01";
1553
      //uvBL = "0.01 0.99";
1554
      //uvBR = "0.99 0.99";
1555
      bitmap = "data/customdata/scripts/base_img.png";
1556
      color = "255 255 255 255";
1557
      position = "50 50";
1558
      extent = "384 384";
1559
      minExtent = "8 2";
1560
      horizSizing = "right";
1561
      vertSizing = "bottom";
1562
      profile = "GuiDefaultProfile";
1563
      visible = "1";
1564
      active = "1";
1565
      tooltipProfile = "GuiToolTipProfile";
1566
      hovertime = "1000";
1567
      isContainer = "0";
1568
      canSave = "1";
1569
      canSaveDynamicFields = "0";
1570
   };
1571
}
1572
[/code]
1573
1574
fileV.hlsl:
1575
[code]#include "../../../core/rendering/shaders/shaderModel.hlsl"
1576
1577
struct Appdata
1578
{
1579
	float3 position   : POSITION;
1580
	float4 color      : COLOR;
1581
	float2 texCoord   : TEXCOORD0;
1582
};
1583
1584
struct Conn
1585
{
1586
   float4 HPOS             : TORQUE_POSITION;
1587
   float4 color            : COLOR;
1588
   float2 texCoord         : TEXCOORD0;
1589
};
1590
1591
uniform float4x4 modelview;
1592
1593
Conn main( Appdata In )
1594
{
1595
   Conn Out;
1596
   Out.HPOS = mul(modelview, float4(In.position,1.0));
1597
   Out.color = In.color;
1598
   Out.texCoord = In.texCoord;
1599
   return Out;
1600
}[/code]
1601
1602
fileP.hlsl:
1603
[code]#include "../../../core/rendering/shaders/shaderModel.hlsl"
1604
1605
struct datainput {
1606
   float4 HPOS             : TORQUE_POSITION;
1607
   float4 color            : COLOR;
1608
   float2 texCoord         : TEXCOORD0;
1609
};
1610
1611
TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0);
1612
TORQUE_UNIFORM_SAMPLER2D(basealpha, 1);
1613
TORQUE_UNIFORM_SAMPLER2D(diffuseMapB, 2);
1614
1615
uniform float2 guiSize;
1616
uniform float accumTime;
1617
uniform float4 colorMod;
1618
uniform float4 colorModB;
1619
1620
float4 main( datainput IN ) : SV_Target0
1621
{
1622
   IN.texCoord += 0.5*cos(accumTime);
1623
   float4 col = TORQUE_TEX2D(diffuseMap, IN.texCoord);
1624
   col = colorModB;
1625
   if(IN.texCoord.x*guiSize.x > 20 && IN.texCoord.y*guiSize.y > 20)
1626
      col = TORQUE_TEX2D(diffuseMapB, IN.texCoord);
1627
      
1628
   float4 alphy = TORQUE_TEX2D(basealpha, IN.texCoord);
1629
   
1630
   if(alphy.a > -1)
1631
      col = float4(col.xyz,alphy.a);
1632
   else
1633
      col = colorMod;
1634
1635
   //here you can modify colourexit
1636
1637
   return col;
1638
}
1639
1640
[/code]