1 /*
2 * This source file is part of libRocket, the HTML/CSS Interface Middleware
3 *
4 * For the latest information, see http://www.librocket.com
5 *
6 * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 *
26 */
27
28 #include "precompiled.h"
29 #include "DecoratorTiledBox.h"
30 #include "TextureResource.h"
31 #include "../../Include/Rocket/Core/Element.h"
32 #include "../../Include/Rocket/Core/Geometry.h"
33
34 namespace Rocket {
35 namespace Core {
36
37 struct DecoratorTiledBoxData
38 {
DecoratorTiledBoxDataRocket::Core::DecoratorTiledBoxData39 DecoratorTiledBoxData(Element* host_element)
40 {
41 for (int i = 0; i < 9; ++i)
42 geometry[i] = new Geometry(host_element);
43 }
44
~DecoratorTiledBoxDataRocket::Core::DecoratorTiledBoxData45 ~DecoratorTiledBoxData()
46 {
47 for (int i = 0; i < 9; ++i)
48 delete geometry[i];
49 }
50
51 Geometry* geometry[9];
52 };
53
DecoratorTiledBox()54 DecoratorTiledBox::DecoratorTiledBox()
55 {
56 }
57
~DecoratorTiledBox()58 DecoratorTiledBox::~DecoratorTiledBox()
59 {
60 }
61
62 // Initialises the tiles for the decorator.
Initialise(const Tile * _tiles,const String * _texture_names,const String * _rcss_paths)63 bool DecoratorTiledBox::Initialise(const Tile* _tiles, const String* _texture_names, const String* _rcss_paths)
64 {
65 // Load the textures.
66 for (int i = 0; i < 9; i++)
67 {
68 if (!_texture_names[i].Empty())
69 {
70 tiles[i] = _tiles[i];
71 tiles[i].texture_index = LoadTexture(_texture_names[i], _rcss_paths[i]);
72 if (tiles[i].texture_index < 0)
73 return false;
74 }
75 }
76
77 // If only one side of the left / right edges have been configured, then mirror the tile for the other side.
78 if (tiles[LEFT_EDGE].texture_index == -1 && tiles[RIGHT_EDGE].texture_index > -1)
79 {
80 tiles[LEFT_EDGE] = tiles[RIGHT_EDGE];
81 tiles[LEFT_EDGE].orientation = FLIP_HORIZONTAL;
82 }
83 else if (tiles[RIGHT_EDGE].texture_index == -1 && tiles[LEFT_EDGE].texture_index > -1)
84 {
85 tiles[RIGHT_EDGE] = tiles[LEFT_EDGE];
86 tiles[RIGHT_EDGE].orientation = FLIP_HORIZONTAL;
87 }
88 else if (tiles[LEFT_EDGE].texture_index == -1 && tiles[RIGHT_EDGE].texture_index == -1)
89 return false;
90
91 // If only one side of the top / bottom edges have been configured, then mirror the tile for the other side.
92 if (tiles[TOP_EDGE].texture_index == -1 && tiles[BOTTOM_EDGE].texture_index > -1)
93 {
94 tiles[TOP_EDGE] = tiles[BOTTOM_EDGE];
95 tiles[TOP_EDGE].orientation = FLIP_VERTICAL;
96 }
97 else if (tiles[BOTTOM_EDGE].texture_index == -1 && tiles[TOP_EDGE].texture_index > -1)
98 {
99 tiles[BOTTOM_EDGE] = tiles[TOP_EDGE];
100 tiles[BOTTOM_EDGE].orientation = FLIP_VERTICAL;
101 }
102 else if (tiles[TOP_EDGE].texture_index == -1 && tiles[BOTTOM_EDGE].texture_index == -1)
103 return false;
104
105 // Check that the centre tile has been specified.
106 if (tiles[CENTRE].texture_index < 0)
107 return false;
108
109 return true;
110 }
111
112 // Called on a decorator to generate any required per-element data for a newly decorated element.
GenerateElementData(Element * element)113 DecoratorDataHandle DecoratorTiledBox::GenerateElementData(Element* element)
114 {
115 // Initialise the tiles for this element.
116 for (int i = 0; i < 9; i++)
117 {
118 if (tiles[i].texture_index >= 0)
119 tiles[i].CalculateDimensions(element, *GetTexture(tiles[i].texture_index));
120 }
121
122 Vector2f padded_size = element->GetBox().GetSize(Box::PADDING);
123
124 // Calculate the size for the top row of tiles.
125 Vector2f top_left_dimensions = tiles[TOP_LEFT_CORNER].GetDimensions(element);
126 Vector2f top_dimensions = tiles[TOP_EDGE].GetDimensions(element);
127 Vector2f top_right_dimensions = tiles[TOP_RIGHT_CORNER].GetDimensions(element);
128
129 // Calculate the size for the bottom row of tiles.
130 Vector2f bottom_left_dimensions = tiles[BOTTOM_LEFT_CORNER].GetDimensions(element);
131 Vector2f bottom_dimensions = tiles[BOTTOM_EDGE].GetDimensions(element);
132 Vector2f bottom_right_dimensions = tiles[BOTTOM_RIGHT_CORNER].GetDimensions(element);
133
134 // The size of the left and right tiles.
135 Vector2f left_dimensions = tiles[LEFT_EDGE].GetDimensions(element);
136 Vector2f right_dimensions = tiles[RIGHT_EDGE].GetDimensions(element);
137
138 // Scale the top corners down if appropriate. If they are scaled, then the left and right edges are also scaled
139 // if they shared a width with their corner. Best solution? Don't know.
140 if (padded_size.x < top_left_dimensions.x + top_right_dimensions.x)
141 {
142 float minimum_width = top_left_dimensions.x + top_right_dimensions.x;
143
144 top_left_dimensions.x = padded_size.x * (top_left_dimensions.x / minimum_width);
145 if (tiles[TOP_LEFT_CORNER].GetDimensions(element).x == tiles[LEFT_EDGE].GetDimensions(element).x)
146 left_dimensions.x = top_left_dimensions.x;
147
148 top_right_dimensions.x = padded_size.x * (top_right_dimensions.x / minimum_width);
149 if (tiles[TOP_RIGHT_CORNER].GetDimensions(element).x == tiles[RIGHT_EDGE].GetDimensions(element).x)
150 right_dimensions.x = top_right_dimensions.x;
151 }
152
153 // Scale the bottom corners down if appropriate. If they are scaled, then the left and right edges are also scaled
154 // if they shared a width with their corner. Best solution? Don't know.
155 if (padded_size.x < bottom_left_dimensions.x + bottom_right_dimensions.x)
156 {
157 float minimum_width = bottom_left_dimensions.x + bottom_right_dimensions.x;
158
159 bottom_left_dimensions.x = padded_size.x * (bottom_left_dimensions.x / minimum_width);
160 if (tiles[BOTTOM_LEFT_CORNER].GetDimensions(element).x == tiles[LEFT_EDGE].GetDimensions(element).x)
161 left_dimensions.x = bottom_left_dimensions.x;
162
163 bottom_right_dimensions.x = padded_size.x * (bottom_right_dimensions.x / minimum_width);
164 if (tiles[BOTTOM_RIGHT_CORNER].GetDimensions(element).x == tiles[RIGHT_EDGE].GetDimensions(element).x)
165 right_dimensions.x = bottom_right_dimensions.x;
166 }
167
168 // Scale the left corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled
169 // if they shared a width with their corner. Best solution? Don't know.
170 if (padded_size.y < top_left_dimensions.y + bottom_left_dimensions.y)
171 {
172 float minimum_height = top_left_dimensions.y + bottom_left_dimensions.y;
173
174 top_left_dimensions.y = padded_size.y * (top_left_dimensions.y / minimum_height);
175 if (tiles[TOP_LEFT_CORNER].GetDimensions(element).y == tiles[TOP_EDGE].GetDimensions(element).y)
176 top_dimensions.y = top_left_dimensions.y;
177
178 bottom_left_dimensions.y = padded_size.y * (bottom_left_dimensions.y / minimum_height);
179 if (tiles[BOTTOM_LEFT_CORNER].GetDimensions(element).y == tiles[BOTTOM_EDGE].GetDimensions(element).y)
180 bottom_dimensions.y = bottom_left_dimensions.y;
181 }
182
183 // Scale the right corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled
184 // if they shared a width with their corner. Best solution? Don't know.
185 if (padded_size.y < top_right_dimensions.y + bottom_right_dimensions.y)
186 {
187 float minimum_height = top_right_dimensions.y + bottom_right_dimensions.y;
188
189 top_right_dimensions.y = padded_size.y * (top_right_dimensions.y / minimum_height);
190 if (tiles[TOP_RIGHT_CORNER].GetDimensions(element).y == tiles[TOP_EDGE].GetDimensions(element).y)
191 top_dimensions.y = top_right_dimensions.y;
192
193 bottom_right_dimensions.y = padded_size.y * (bottom_right_dimensions.y / minimum_height);
194 if (tiles[BOTTOM_RIGHT_CORNER].GetDimensions(element).y == tiles[BOTTOM_EDGE].GetDimensions(element).y)
195 bottom_dimensions.y = bottom_right_dimensions.y;
196 }
197
198 DecoratorTiledBoxData* data = new DecoratorTiledBoxData(element);
199
200 // Generate the geometry for the top-left tile.
201 tiles[TOP_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_LEFT_CORNER].texture_index]->GetVertices(),
202 data->geometry[tiles[TOP_LEFT_CORNER].texture_index]->GetIndices(),
203 element,
204 Vector2f(0, 0),
205 top_left_dimensions,
206 top_left_dimensions);
207 // Generate the geometry for the top edge tiles.
208 tiles[TOP_EDGE].GenerateGeometry(data->geometry[tiles[TOP_EDGE].texture_index]->GetVertices(),
209 data->geometry[tiles[TOP_EDGE].texture_index]->GetIndices(),
210 element,
211 Vector2f(top_left_dimensions.x, 0),
212 Vector2f(padded_size.x - (top_left_dimensions.x + top_right_dimensions.x), top_dimensions.y),
213 top_dimensions);
214 // Generate the geometry for the top-right tile.
215 tiles[TOP_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_RIGHT_CORNER].texture_index]->GetVertices(),
216 data->geometry[tiles[TOP_RIGHT_CORNER].texture_index]->GetIndices(),
217 element,
218 Vector2f(padded_size.x - top_right_dimensions.x, 0),
219 top_right_dimensions,
220 top_right_dimensions);
221
222 // Generate the geometry for the left side.
223 tiles[LEFT_EDGE].GenerateGeometry(data->geometry[tiles[LEFT_EDGE].texture_index]->GetVertices(),
224 data->geometry[tiles[LEFT_EDGE].texture_index]->GetIndices(),
225 element,
226 Vector2f(0, top_left_dimensions.y),
227 Vector2f(left_dimensions.x, padded_size.y - (top_left_dimensions.y + bottom_left_dimensions.y)),
228 left_dimensions);
229
230 // Generate the geometry for the right side.
231 tiles[RIGHT_EDGE].GenerateGeometry(data->geometry[tiles[RIGHT_EDGE].texture_index]->GetVertices(),
232 data->geometry[tiles[RIGHT_EDGE].texture_index]->GetIndices(),
233 element,
234 Vector2f((padded_size.x - right_dimensions.x), top_right_dimensions.y),
235 Vector2f(right_dimensions.x, padded_size.y - (top_right_dimensions.y + bottom_right_dimensions.y)),
236 right_dimensions);
237
238 // Generate the geometry for the bottom-left tile.
239 tiles[BOTTOM_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index]->GetVertices(),
240 data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index]->GetIndices(),
241 element,
242 Vector2f(0, padded_size.y - bottom_left_dimensions.y),
243 bottom_left_dimensions,
244 bottom_left_dimensions);
245 // Generate the geometry for the bottom edge tiles.
246 tiles[BOTTOM_EDGE].GenerateGeometry(data->geometry[tiles[BOTTOM_EDGE].texture_index]->GetVertices(),
247 data->geometry[tiles[BOTTOM_EDGE].texture_index]->GetIndices(),
248 element,
249 Vector2f(bottom_left_dimensions.x, padded_size.y - bottom_dimensions.y),
250 Vector2f(padded_size.x - (bottom_left_dimensions.x + bottom_right_dimensions.x), bottom_dimensions.y),
251 bottom_dimensions);
252 // Generate the geometry for the bottom-right tile.
253 tiles[BOTTOM_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index]->GetVertices(),
254 data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index]->GetIndices(),
255 element,
256 Vector2f(padded_size.x - bottom_right_dimensions.x, padded_size.y - bottom_right_dimensions.y),
257 bottom_right_dimensions,
258 bottom_right_dimensions);
259
260 // Generate the centre geometry.
261 if (tiles[CENTRE].texture_index >= 0)
262 {
263 Vector2f centre_dimensions = tiles[CENTRE].GetDimensions(element);
264 Vector2f centre_surface_dimensions(padded_size.x - (left_dimensions.x + right_dimensions.x),
265 padded_size.y - (top_dimensions.y + bottom_dimensions.y));
266
267 tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index]->GetVertices(),
268 data->geometry[tiles[CENTRE].texture_index]->GetIndices(),
269 element,
270 Vector2f(left_dimensions.x, top_dimensions.y),
271 centre_surface_dimensions,
272 centre_dimensions);
273 }
274
275 // Set the textures on the geometry.
276 const Texture* texture = NULL;
277 int texture_index = 0;
278 while ((texture = GetTexture(texture_index)) != NULL)
279 data->geometry[texture_index++]->SetTexture(texture);
280
281 return reinterpret_cast<DecoratorDataHandle>(data);
282 }
283
284 // Called to release element data generated by this decorator.
ReleaseElementData(DecoratorDataHandle element_data)285 void DecoratorTiledBox::ReleaseElementData(DecoratorDataHandle element_data)
286 {
287 delete reinterpret_cast< DecoratorTiledBoxData* >(element_data);
288 }
289
290 // Called to render the decorator on an element.
RenderElement(Element * element,DecoratorDataHandle element_data)291 void DecoratorTiledBox::RenderElement(Element* element, DecoratorDataHandle element_data)
292 {
293 Vector2f translation = element->GetAbsoluteOffset(Box::PADDING);
294 DecoratorTiledBoxData* data = reinterpret_cast< DecoratorTiledBoxData* >(element_data);
295
296 for (int i = 0; i < 9; i++)
297 data->geometry[i]->Render(translation);
298 }
299
300 }
301 }
302