1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4     (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7  Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 
29 #include "OgrePanelOverlayElement.h"
30 #include "OgreTechnique.h"
31 #include "OgreStringConverter.h"
32 #include "OgreHardwareBufferManager.h"
33 #include "OgreRoot.h"
34 #include "OgreRenderSystem.h"
35 
36 namespace Ogre {
37     //---------------------------------------------------------------------
38     String PanelOverlayElement::msTypeName = "Panel";
39     PanelOverlayElement::CmdTiling PanelOverlayElement::msCmdTiling;
40     PanelOverlayElement::CmdTransparent PanelOverlayElement::msCmdTransparent;
41     PanelOverlayElement::CmdUVCoords PanelOverlayElement::msCmdUVCoords;
42     //---------------------------------------------------------------------
43     // vertex buffer bindings, set at compile time (we could look these up but no point)
44     #define POSITION_BINDING 0
45     #define TEXCOORD_BINDING 1
46 
47     //---------------------------------------------------------------------
PanelOverlayElement(const String & name)48     PanelOverlayElement::PanelOverlayElement(const String& name)
49         : OverlayContainer(name)
50         , mTransparent(false)
51         // Defer creation of texcoord buffer until we know how big it needs to be
52         , mNumTexCoordsInBuffer(0)
53         , mU1(0.0)
54         , mV1(0.0)
55         , mU2(1.0)
56         , mV2(1.0)
57 
58     {
59         // Init tiling
60         for (ushort i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS; ++i)
61         {
62             mTileX[i] = 1.0f;
63             mTileY[i] = 1.0f;
64         }
65 
66         // No normals or colours
67         if (createParamDictionary("PanelOverlayElement"))
68         {
69             addBaseParameters();
70         }
71 
72     }
73     //---------------------------------------------------------------------
~PanelOverlayElement()74     PanelOverlayElement::~PanelOverlayElement()
75     {
76         OGRE_DELETE mRenderOp.vertexData;
77     }
78     //---------------------------------------------------------------------
initialise(void)79     void PanelOverlayElement::initialise(void)
80     {
81         bool init = !mInitialised;
82 
83         OverlayContainer::initialise();
84         if (init)
85         {
86             // Setup render op in advance
87             mRenderOp.vertexData = OGRE_NEW VertexData();
88             // Vertex declaration: 1 position, add texcoords later depending on #layers
89             // Create as separate buffers so we can lock & discard separately
90             VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
91             decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION);
92 
93             // Basic vertex data
94             mRenderOp.vertexData->vertexStart = 0;
95             mRenderOp.vertexData->vertexCount = 4;
96             // No indexes & issue as a strip
97             mRenderOp.useIndexes = false;
98             mRenderOp.operationType = RenderOperation::OT_TRIANGLE_STRIP;
99             mRenderOp.useGlobalInstancingVertexBufferIsAvailable = false;
100 
101             mInitialised = true;
102 
103             _restoreManualHardwareResources();
104         }
105     }
106     //---------------------------------------------------------------------
_restoreManualHardwareResources()107     void PanelOverlayElement::_restoreManualHardwareResources()
108     {
109         if(!mInitialised)
110             return;
111 
112         VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
113 
114         // Vertex buffer #1
115         HardwareVertexBufferSharedPtr vbuf =
116             HardwareBufferManager::getSingleton().createVertexBuffer(
117             decl->getVertexSize(POSITION_BINDING), mRenderOp.vertexData->vertexCount,
118             HardwareBuffer::HBU_STATIC_WRITE_ONLY// mostly static except during resizing
119             );
120         // Bind buffer
121         mRenderOp.vertexData->vertexBufferBinding->setBinding(POSITION_BINDING, vbuf);
122 
123         // Buffers are restored, but with trash within
124         mGeomPositionsOutOfDate = true;
125         mGeomUVsOutOfDate = true;
126     }
127     //---------------------------------------------------------------------
_releaseManualHardwareResources()128     void PanelOverlayElement::_releaseManualHardwareResources()
129     {
130         if(!mInitialised)
131             return;
132 
133         VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding;
134         if (bind->isBufferBound(POSITION_BINDING))
135             bind->unsetBinding(POSITION_BINDING);
136 
137         // Remove all texcoord element declarations
138         if(mNumTexCoordsInBuffer > 0)
139         {
140             if (bind->isBufferBound (TEXCOORD_BINDING))
141                 bind->unsetBinding(TEXCOORD_BINDING);
142 
143             VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
144             for(size_t i = mNumTexCoordsInBuffer; i > 0; --i)
145             {
146                 decl->removeElement(VES_TEXTURE_COORDINATES,
147                     static_cast<unsigned short>(i - 1));
148             }
149             mNumTexCoordsInBuffer = 0;
150         }
151     }
152     //---------------------------------------------------------------------
setTiling(Real x,Real y,ushort layer)153     void PanelOverlayElement::setTiling(Real x, Real y, ushort layer)
154     {
155         OgreAssert (layer < OGRE_MAX_TEXTURE_COORD_SETS, "out of bounds");
156         OgreAssert (x != 0 && y != 0, "tile number must be > 0");
157 
158         mTileX[layer] = x;
159         mTileY[layer] = y;
160 
161         mGeomUVsOutOfDate = true;
162 
163     }
164     //---------------------------------------------------------------------
getTileX(ushort layer) const165     Real PanelOverlayElement::getTileX(ushort layer) const
166     {
167         return mTileX[layer];
168     }
169     //---------------------------------------------------------------------
getTileY(ushort layer) const170     Real PanelOverlayElement::getTileY(ushort layer) const
171     {
172         return mTileY[layer];
173     }
174     //---------------------------------------------------------------------
setTransparent(bool inTransparent)175     void PanelOverlayElement::setTransparent(bool inTransparent)
176     {
177         mTransparent = inTransparent;
178     }
179     //---------------------------------------------------------------------
isTransparent(void) const180     bool PanelOverlayElement::isTransparent(void) const
181     {
182         return mTransparent;
183     }
184     //---------------------------------------------------------------------
setUV(Real u1,Real v1,Real u2,Real v2)185     void PanelOverlayElement::setUV(Real u1, Real v1, Real u2, Real v2)
186     {
187         mU1 = u1;
188         mU2 = u2;
189         mV1 = v1;
190         mV2 = v2;
191         mGeomUVsOutOfDate = true;
192     }
getUV(Real & u1,Real & v1,Real & u2,Real & v2) const193     void PanelOverlayElement::getUV(Real& u1, Real& v1, Real& u2, Real& v2) const
194     {
195         u1 = mU1;
196         u2 = mU2;
197         v1 = mV1;
198         v2 = mV2;
199     }
200     //---------------------------------------------------------------------
getTypeName(void) const201     const String& PanelOverlayElement::getTypeName(void) const
202     {
203         return msTypeName;
204     }
205     //---------------------------------------------------------------------
getRenderOperation(RenderOperation & op)206     void PanelOverlayElement::getRenderOperation(RenderOperation& op)
207     {
208         op = mRenderOp;
209     }
210     //---------------------------------------------------------------------
_updateRenderQueue(RenderQueue * queue)211     void PanelOverlayElement::_updateRenderQueue(RenderQueue* queue)
212     {
213         if (mVisible)
214         {
215 
216             if (!mTransparent && mMaterial)
217             {
218                 OverlayElement::_updateRenderQueue(queue);
219             }
220 
221             // Also add children
222             ChildIterator it = getChildIterator();
223             while (it.hasMoreElements())
224             {
225                 // Give children Z-order 1 higher than this
226                 it.getNext()->_updateRenderQueue(queue);
227             }
228         }
229     }
230     //---------------------------------------------------------------------
updatePositionGeometry(void)231     void PanelOverlayElement::updatePositionGeometry(void)
232     {
233         /*
234             0-----2
235             |    /|
236             |  /  |
237             |/    |
238             1-----3
239         */
240         Real left, right, top, bottom;
241 
242         /* Convert positions into -1, 1 coordinate space (homogenous clip space).
243             - Left / right is simple range conversion
244             - Top / bottom also need inverting since y is upside down - this means
245             that top will end up greater than bottom and when computing texture
246             coordinates, we have to flip the v-axis (ie. subtract the value from
247             1.0 to get the actual correct value).
248         */
249         left = _getDerivedLeft() * 2 - 1;
250         right = left + (mWidth * 2);
251         top = -((_getDerivedTop() * 2) - 1);
252         bottom =  top -  (mHeight * 2);
253 
254         HardwareVertexBufferSharedPtr vbuf =
255             mRenderOp.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
256         HardwareBufferLockGuard vbufLock(vbuf, HardwareBuffer::HBL_DISCARD);
257         float* pPos = static_cast<float*>(vbufLock.pData);
258 
259         // Use the furthest away depth value, since materials should have depth-check off
260         // This initialised the depth buffer for any 3D objects in front
261         Real zValue = Root::getSingleton().getRenderSystem()->getMaximumDepthInputValue();
262         *pPos++ = left;
263         *pPos++ = top;
264         *pPos++ = zValue;
265 
266         *pPos++ = left;
267         *pPos++ = bottom;
268         *pPos++ = zValue;
269 
270         *pPos++ = right;
271         *pPos++ = top;
272         *pPos++ = zValue;
273 
274         *pPos++ = right;
275         *pPos++ = bottom;
276         *pPos++ = zValue;
277     }
278     //---------------------------------------------------------------------
updateTextureGeometry(void)279     void PanelOverlayElement::updateTextureGeometry(void)
280     {
281         // Generate for as many texture layers as there are in material
282         if (mMaterial && mInitialised)
283         {
284             // Assume one technique and pass for the moment
285             size_t numLayers = mMaterial->getTechnique(0)->getPass(0)->getNumTextureUnitStates();
286 
287             VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
288             // Check the number of texcoords we have in our buffer now
289             if (mNumTexCoordsInBuffer > numLayers)
290             {
291                 // remove extras
292                 for (size_t i = mNumTexCoordsInBuffer; i > numLayers; --i)
293                 {
294                     decl->removeElement(VES_TEXTURE_COORDINATES,
295                         static_cast<unsigned short>(i - 1));
296                 }
297             }
298             else if (mNumTexCoordsInBuffer < numLayers)
299             {
300                 // Add extra texcoord elements
301                 size_t offset = VertexElement::getTypeSize(VET_FLOAT2) * mNumTexCoordsInBuffer;
302                 for (size_t i = mNumTexCoordsInBuffer; i < numLayers; ++i)
303                 {
304                     decl->addElement(TEXCOORD_BINDING,
305                         offset, VET_FLOAT2, VES_TEXTURE_COORDINATES,
306                         static_cast<unsigned short>(i));
307                     offset += VertexElement::getTypeSize(VET_FLOAT2);
308 
309                 }
310             }
311 
312             // if number of layers changed at all, we'll need to reallocate buffer
313             if (mNumTexCoordsInBuffer != numLayers)
314             {
315                 // NB reference counting will take care of the old one if it exists
316                 HardwareVertexBufferSharedPtr newbuf =
317                     HardwareBufferManager::getSingleton().createVertexBuffer(
318                     decl->getVertexSize(TEXCOORD_BINDING), mRenderOp.vertexData->vertexCount,
319                     HardwareBuffer::HBU_STATIC_WRITE_ONLY // mostly static except during resizing
320                     );
321                 // Bind buffer, note this will unbind the old one and destroy the buffer it had
322                 mRenderOp.vertexData->vertexBufferBinding->setBinding(TEXCOORD_BINDING, newbuf);
323                 // Set num tex coords in use now
324                 mNumTexCoordsInBuffer = numLayers;
325             }
326 
327             // Get the tcoord buffer & lock
328             if (mNumTexCoordsInBuffer)
329             {
330                 HardwareVertexBufferSharedPtr vbuf =
331                     mRenderOp.vertexData->vertexBufferBinding->getBuffer(TEXCOORD_BINDING);
332                 HardwareBufferLockGuard vbufLock(vbuf, HardwareBuffer::HBL_DISCARD);
333                 float* pVBStart = static_cast<float*>(vbufLock.pData);
334 
335                 size_t uvSize = VertexElement::getTypeSize(VET_FLOAT2) / sizeof(float);
336                 size_t vertexSize = decl->getVertexSize(TEXCOORD_BINDING) / sizeof(float);
337                 for (ushort i = 0; i < numLayers; ++i)
338                 {
339                     // Calc upper tex coords
340                     Real upperX = mU2 * mTileX[i];
341                     Real upperY = mV2 * mTileY[i];
342 
343 
344                     /*
345                         0-----2
346                         |    /|
347                         |  /  |
348                         |/    |
349                         1-----3
350                     */
351                     // Find start offset for this set
352                     float* pTex = pVBStart + (i * uvSize);
353 
354                     pTex[0] = mU1;
355                     pTex[1] = mV1;
356 
357                     pTex += vertexSize; // jump by 1 vertex stride
358                     pTex[0] = mU1;
359                     pTex[1] = upperY;
360 
361                     pTex += vertexSize;
362                     pTex[0] = upperX;
363                     pTex[1] = mV1;
364 
365                     pTex += vertexSize;
366                     pTex[0] = upperX;
367                     pTex[1] = upperY;
368                 }
369             }
370         }
371     }
372     //-----------------------------------------------------------------------
addBaseParameters(void)373     void PanelOverlayElement::addBaseParameters(void)
374     {
375         OverlayContainer::addBaseParameters();
376         ParamDictionary* dict = getParamDictionary();
377 
378         dict->addParameter(ParameterDef("uv_coords",
379            "The texture coordinates for the texture. 1 set of uv values."
380            , PT_STRING),
381            &msCmdUVCoords);
382 
383         dict->addParameter(ParameterDef("tiling",
384             "The number of times to repeat the background texture."
385             , PT_STRING),
386             &msCmdTiling);
387 
388         dict->addParameter(ParameterDef("transparent",
389             "Sets whether the panel is transparent, i.e. invisible itself "
390             "but it's contents are still displayed."
391             , PT_BOOL),
392             &msCmdTransparent);
393     }
394     //-----------------------------------------------------------------------
395     // Command objects
396     //-----------------------------------------------------------------------
doGet(const void * target) const397     String PanelOverlayElement::CmdTiling::doGet(const void* target) const
398     {
399         // NB only returns 1st layer tiling
400         String ret = "0 " + StringConverter::toString(
401             static_cast<const PanelOverlayElement*>(target)->getTileX() );
402         ret += " " + StringConverter::toString(
403             static_cast<const PanelOverlayElement*>(target)->getTileY() );
404         return ret;
405     }
doSet(void * target,const String & val)406     void PanelOverlayElement::CmdTiling::doSet(void* target, const String& val)
407     {
408         // 3 params: <layer> <x_tile> <y_tile>
409         // Param count is validated higher up
410         std::vector<String> vec = StringUtil::split(val);
411         ushort layer = (ushort)StringConverter::parseUnsignedInt(vec[0]);
412         Real x_tile = StringConverter::parseReal(vec[1]);
413         Real y_tile = StringConverter::parseReal(vec[2]);
414 
415         static_cast<PanelOverlayElement*>(target)->setTiling(x_tile, y_tile, layer);
416     }
417     //-----------------------------------------------------------------------
doGet(const void * target) const418     String PanelOverlayElement::CmdTransparent::doGet(const void* target) const
419     {
420         return StringConverter::toString(
421             static_cast<const PanelOverlayElement*>(target)->isTransparent() );
422     }
doSet(void * target,const String & val)423     void PanelOverlayElement::CmdTransparent::doSet(void* target, const String& val)
424     {
425         static_cast<PanelOverlayElement*>(target)->setTransparent(
426             StringConverter::parseBool(val));
427     }
428     //-----------------------------------------------------------------------
doGet(const void * target) const429     String PanelOverlayElement::CmdUVCoords::doGet(const void* target) const
430     {
431         Real u1, v1, u2, v2;
432 
433         static_cast<const PanelOverlayElement*>(target)->getUV(u1, v1, u2, v2);
434         String ret = " " + StringConverter::toString(u1) + " "
435              + StringConverter::toString(v1) + " " + StringConverter::toString(u2) + " "
436              + StringConverter::toString(v2);
437 
438         return ret;
439     }
doSet(void * target,const String & val)440     void PanelOverlayElement::CmdUVCoords::doSet(void* target, const String& val)
441     {
442         std::vector<String> vec = StringUtil::split(val);
443 
444         static_cast<PanelOverlayElement*>(target)->setUV(
445             StringConverter::parseReal(vec[0]),
446             StringConverter::parseReal(vec[1]),
447             StringConverter::parseReal(vec[2]),
448             StringConverter::parseReal(vec[3])
449             );
450     }
451 
452 }
453 
454 
455 
456