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 Nuno Silva
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 <Rocket/Core/Core.h>
29 #include "RenderInterfaceSFML.h"
30 
31 #ifndef GL_CLAMP_TO_EDGE
32 #define GL_CLAMP_TO_EDGE 0x812F
33 #endif
34 
35 #ifdef ENABLE_GLEW
36 class RocketSFMLRendererGeometryHandler
37 {
38 public:
39 	GLuint VertexID, IndexID;
40 	int NumVertices;
41 	Rocket::Core::TextureHandle Texture;
42 
RocketSFMLRendererGeometryHandler()43 	RocketSFMLRendererGeometryHandler() : VertexID(0), IndexID(0), Texture(0), NumVertices(0)
44 	{
45 	};
46 
~RocketSFMLRendererGeometryHandler()47 	~RocketSFMLRendererGeometryHandler()
48 	{
49 		if(VertexID)
50 			glDeleteBuffers(1, &VertexID);
51 
52 		if(IndexID)
53 			glDeleteBuffers(1, &IndexID);
54 
55 		VertexID = IndexID = 0;
56 	};
57 };
58 #endif
59 
60 struct RocketSFMLRendererVertex
61 {
62 	sf::Vector2f Position, TexCoord;
63 	sf::Color Color;
64 };
65 
RocketSFMLRenderer()66 RocketSFMLRenderer::RocketSFMLRenderer()
67 {
68 }
69 
SetWindow(sf::RenderWindow * Window)70 void RocketSFMLRenderer::SetWindow(sf::RenderWindow *Window)
71 {
72 	MyWindow = Window;
73 
74 	Resize();
75 };
76 
GetWindow()77 sf::RenderWindow *RocketSFMLRenderer::GetWindow()
78 {
79 	return MyWindow;
80 };
81 
Resize()82 void RocketSFMLRenderer::Resize()
83 {
84 	static sf::View View;
85 	View.setViewport(sf::FloatRect(0, (float)MyWindow->getSize().x, (float)MyWindow->getSize().y, 0));
86 	MyWindow->setView(View);
87 
88 	glMatrixMode(GL_PROJECTION);
89 	glLoadIdentity();
90 	glOrtho(0, MyWindow->getSize().x, MyWindow->getSize().y, 0, -1, 1);
91 	glMatrixMode(GL_MODELVIEW);
92 
93 	glViewport(0, 0, MyWindow->getSize().x, MyWindow->getSize().y);
94 };
95 
96 // Called by Rocket when it wants to render geometry that it does not wish to optimise.
RenderGeometry(Rocket::Core::Vertex * vertices,int num_vertices,int * indices,int num_indices,const Rocket::Core::TextureHandle texture,const Rocket::Core::Vector2f & translation)97 void RocketSFMLRenderer::RenderGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation)
98 {
99 	MyWindow->pushGLStates();
100 	glTranslatef(translation.x, translation.y, 0);
101 
102 	std::vector<Rocket::Core::Vector2f> Positions(num_vertices);
103 	std::vector<Rocket::Core::Colourb> Colors(num_vertices);
104 	std::vector<Rocket::Core::Vector2f> TexCoords(num_vertices);
105 
106 	for(int i = 0; i < num_vertices; i++)
107 	{
108 		Positions[i] = vertices[i].position;
109 		Colors[i] = vertices[i].colour;
110 		TexCoords[i] = vertices[i].tex_coord;
111 	};
112 
113 	glEnableClientState(GL_VERTEX_ARRAY);
114 	glEnableClientState(GL_COLOR_ARRAY);
115 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
116 
117 	glVertexPointer(2, GL_FLOAT, 0, &Positions[0]);
118 	glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Colors[0]);
119 	glTexCoordPointer(2, GL_FLOAT, 0, &TexCoords[0]);
120 
121 	glEnable(GL_BLEND);
122 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
123 
124 	sf::Texture *sfTexture = (sf::Texture *)texture;
125 
126 	if(sfTexture)
127 	{
128 		sf::Texture::bind(sfTexture);
129 	}
130 	else
131 	{
132 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
133 		glBindTexture(GL_TEXTURE_2D, 0);
134 	};
135 
136 	glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices);
137 
138 	glDisableClientState(GL_VERTEX_ARRAY);
139 	glDisableClientState(GL_COLOR_ARRAY);
140 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
141 
142 	glColor4f(1, 1, 1, 1);
143 
144 	MyWindow->popGLStates();
145 }
146 
147 // Called by Rocket when it wants to compile geometry it believes will be static for the forseeable future.
CompileGeometry(Rocket::Core::Vertex * vertices,int num_vertices,int * indices,int num_indices,const Rocket::Core::TextureHandle texture)148 Rocket::Core::CompiledGeometryHandle RocketSFMLRenderer::CompileGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rocket::Core::TextureHandle texture)
149 {
150 #ifdef ENABLE_GLEW
151 	std::vector<RocketSFMLRendererVertex> Data(num_vertices);
152 
153 	for(unsigned long i = 0; i < Data.size(); i++)
154 	{
155 		Data[i].Position = *(sf::Vector2f*)&vertices[i].position;
156 		Data[i].TexCoord = *(sf::Vector2f*)&vertices[i].tex_coord;
157 		Data[i].Color = sf::Color(vertices[i].colour.red, vertices[i].colour.green,
158 			vertices[i].colour.blue, vertices[i].colour.alpha);
159 	};
160 
161 	RocketSFMLRendererGeometryHandler *Geometry = new RocketSFMLRendererGeometryHandler();
162 	Geometry->NumVertices = num_indices;
163 
164 	glGenBuffers(1, &Geometry->VertexID);
165 	glBindBuffer(GL_ARRAY_BUFFER, Geometry->VertexID);
166 	glBufferData(GL_ARRAY_BUFFER, sizeof(RocketSFMLRendererVertex) * num_vertices, &Data[0],
167 		GL_STATIC_DRAW);
168 
169 	glGenBuffers(1, &Geometry->IndexID);
170 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Geometry->IndexID);
171 	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * num_indices, indices, GL_STATIC_DRAW);
172 
173 	glBindBuffer(GL_ARRAY_BUFFER, 0);
174 
175 	Geometry->Texture = texture;
176 
177 	return (Rocket::Core::CompiledGeometryHandle)Geometry;
178 #else
179 	return (Rocket::Core::CompiledGeometryHandle)NULL;
180 #endif
181 }
182 
183 // Called by Rocket when it wants to render application-compiled geometry.
RenderCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry,const Rocket::Core::Vector2f & translation)184 void RocketSFMLRenderer::RenderCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry, const Rocket::Core::Vector2f& translation)
185 {
186 #ifdef ENABLE_GLEW
187 	RocketSFMLRendererGeometryHandler *RealGeometry = (RocketSFMLRendererGeometryHandler *)geometry;
188 
189 	MyWindow->pushGLStates();
190 	glTranslatef(translation.x, translation.y, 0);
191 	glEnable(GL_BLEND);
192 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
193 
194 	sf::Texture *texture = (sf::Texture *)RealGeometry->Texture;
195 
196 	if(texture)
197 	{
198 		sf::Texture::bind(texture);
199 	}
200 	else
201 	{
202 		glBindTexture(GL_TEXTURE_2D, 0);
203 	};
204 
205 	glEnable(GL_VERTEX_ARRAY);
206 	glEnable(GL_TEXTURE_COORD_ARRAY);
207 	glEnable(GL_COLOR_ARRAY);
208 
209 	#define BUFFER_OFFSET(x) ((char*)0 + x)
210 
211 	glBindBuffer(GL_ARRAY_BUFFER, RealGeometry->VertexID);
212 	glVertexPointer(2, GL_FLOAT, sizeof(RocketSFMLRendererVertex), BUFFER_OFFSET(0));
213 	glTexCoordPointer(2, GL_FLOAT, sizeof(RocketSFMLRendererVertex), BUFFER_OFFSET(sizeof(sf::Vector2f)));
214 	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(RocketSFMLRendererVertex), BUFFER_OFFSET(sizeof(sf::Vector2f[2])));
215 
216 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RealGeometry->IndexID);
217 	glDrawElements(GL_TRIANGLES, RealGeometry->NumVertices, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
218 
219 	glBindBuffer(GL_ARRAY_BUFFER, 0);
220 
221 	glDisable(GL_COLOR_ARRAY);
222 	glDisable(GL_TEXTURE_COORD_ARRAY);
223 	glDisable(GL_VERTEX_ARRAY);
224 
225 	glColor4f(1, 1, 1, 1);
226 
227 	MyWindow->popGLStates();
228 #else
229 	ROCKET_ASSERT(false);
230 #endif
231 }
232 
233 // Called by Rocket when it wants to release application-compiled geometry.
ReleaseCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry)234 void RocketSFMLRenderer::ReleaseCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry)
235 {
236 #ifdef ENABLE_GLEW
237 	delete (RocketSFMLRendererGeometryHandler *)geometry;
238 #else
239 	ROCKET_ASSERT(false);
240 #endif
241 }
242 
243 // Called by Rocket when it wants to enable or disable scissoring to clip content.
EnableScissorRegion(bool enable)244 void RocketSFMLRenderer::EnableScissorRegion(bool enable)
245 {
246 	if (enable)
247 		glEnable(GL_SCISSOR_TEST);
248 	else
249 		glDisable(GL_SCISSOR_TEST);
250 }
251 
252 // Called by Rocket when it wants to change the scissor region.
SetScissorRegion(int x,int y,int width,int height)253 void RocketSFMLRenderer::SetScissorRegion(int x, int y, int width, int height)
254 {
255 	glScissor(x, MyWindow->getSize().y - (y + height), width, height);
256 }
257 
258 // Called by Rocket when a texture is required by the library.
LoadTexture(Rocket::Core::TextureHandle & texture_handle,Rocket::Core::Vector2i & texture_dimensions,const Rocket::Core::String & source)259 bool RocketSFMLRenderer::LoadTexture(Rocket::Core::TextureHandle& texture_handle, Rocket::Core::Vector2i& texture_dimensions, const Rocket::Core::String& source)
260 {
261 	Rocket::Core::FileInterface* file_interface = Rocket::Core::GetFileInterface();
262 	Rocket::Core::FileHandle file_handle = file_interface->Open(source);
263 	if (file_handle == NULL)
264 		return false;
265 
266 	file_interface->Seek(file_handle, 0, SEEK_END);
267 	size_t buffer_size = file_interface->Tell(file_handle);
268 	file_interface->Seek(file_handle, 0, SEEK_SET);
269 
270 	char* buffer = new char[buffer_size];
271 	file_interface->Read(buffer, buffer_size, file_handle);
272 	file_interface->Close(file_handle);
273 
274 	sf::Texture *texture = new sf::Texture();
275 
276 	if(!texture->loadFromMemory(buffer, buffer_size))
277 	{
278 		delete buffer;
279 		delete texture;
280 
281 		return false;
282 	};
283 	delete buffer;
284 
285 	texture_handle = (Rocket::Core::TextureHandle) texture;
286 	texture_dimensions = Rocket::Core::Vector2i(texture->getSize().x, texture->getSize().y);
287 
288 	return true;
289 }
290 
291 // Called by Rocket when a texture is required to be built from an internally-generated sequence of pixels.
GenerateTexture(Rocket::Core::TextureHandle & texture_handle,const Rocket::Core::byte * source,const Rocket::Core::Vector2i & source_dimensions)292 bool RocketSFMLRenderer::GenerateTexture(Rocket::Core::TextureHandle& texture_handle, const Rocket::Core::byte* source, const Rocket::Core::Vector2i& source_dimensions)
293 {
294 	sf::Texture *texture = new sf::Texture();
295 
296 	if (!texture->create(source_dimensions.x, source_dimensions.y)) {
297 		delete texture;
298 		return false;
299 	}
300 
301 	texture->update(source, source_dimensions.x, source_dimensions.y, 0, 0);
302 	texture_handle = (Rocket::Core::TextureHandle)texture;
303 
304 	return true;
305 }
306 
307 // Called by Rocket when a loaded texture is no longer required.
ReleaseTexture(Rocket::Core::TextureHandle texture_handle)308 void RocketSFMLRenderer::ReleaseTexture(Rocket::Core::TextureHandle texture_handle)
309 {
310 	delete (sf::Texture *)texture_handle;
311 }
312