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