/* * This source file is part of RmlUi, the HTML/CSS Interface Middleware * * For the latest information, see http://github.com/mikke89/RmlUi * * Copyright (c) 2008-2010 Nuno Silva * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ #include #include "RenderInterfaceSFML.h" #ifndef GL_CLAMP_TO_EDGE #define GL_CLAMP_TO_EDGE 0x812F #endif #ifdef ENABLE_GLEW class RmlUiSFMLRendererGeometryHandler { public: GLuint VertexID, IndexID; int NumVertices; Rml::Core::TextureHandle Texture; RmlUiSFMLRendererGeometryHandler() : VertexID(0), IndexID(0), Texture(0), NumVertices(0) { }; ~RmlUiSFMLRendererGeometryHandler() { if(VertexID) glDeleteBuffers(1, &VertexID); if(IndexID) glDeleteBuffers(1, &IndexID); VertexID = IndexID = 0; }; }; #endif struct RmlUiSFMLRendererVertex { sf::Vector2f Position, TexCoord; sf::Color Color; }; RmlUiSFMLRenderer::RmlUiSFMLRenderer() { } void RmlUiSFMLRenderer::SetWindow(sf::RenderWindow *Window) { MyWindow = Window; Resize(); }; sf::RenderWindow *RmlUiSFMLRenderer::GetWindow() { return MyWindow; }; void RmlUiSFMLRenderer::Resize() { static sf::View View; View.setViewport(sf::FloatRect(0, (float)MyWindow->getSize().x, (float)MyWindow->getSize().y, 0)); MyWindow->setView(View); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, MyWindow->getSize().x, MyWindow->getSize().y, 0, -1, 1); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, MyWindow->getSize().x, MyWindow->getSize().y); }; // Called by RmlUi when it wants to render geometry that it does not wish to optimise. void RmlUiSFMLRenderer::RenderGeometry(Rml::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::Core::TextureHandle texture, const Rml::Core::Vector2f& translation) { MyWindow->pushGLStates(); glTranslatef(translation.x, translation.y, 0); std::vector Positions(num_vertices); std::vector Colors(num_vertices); std::vector TexCoords(num_vertices); for(int i = 0; i < num_vertices; i++) { Positions[i] = vertices[i].position; Colors[i] = vertices[i].colour; TexCoords[i] = vertices[i].tex_coord; }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, &Positions[0]); glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Colors[0]); glTexCoordPointer(2, GL_FLOAT, 0, &TexCoords[0]); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); sf::Texture *sfTexture = (sf::Texture *)texture; if(sfTexture) { sf::Texture::bind(sfTexture); } else { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glBindTexture(GL_TEXTURE_2D, 0); }; glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glColor4f(1, 1, 1, 1); MyWindow->popGLStates(); } // Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future. Rml::Core::CompiledGeometryHandle RmlUiSFMLRenderer::CompileGeometry(Rml::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::Core::TextureHandle texture) { #ifdef ENABLE_GLEW std::vector Data(num_vertices); for(unsigned long i = 0; i < Data.size(); i++) { Data[i].Position = *(sf::Vector2f*)&vertices[i].position; Data[i].TexCoord = *(sf::Vector2f*)&vertices[i].tex_coord; Data[i].Color = sf::Color(vertices[i].colour.red, vertices[i].colour.green, vertices[i].colour.blue, vertices[i].colour.alpha); }; RmlUiSFMLRendererGeometryHandler *Geometry = new RmlUiSFMLRendererGeometryHandler(); Geometry->NumVertices = num_indices; glGenBuffers(1, &Geometry->VertexID); glBindBuffer(GL_ARRAY_BUFFER, Geometry->VertexID); glBufferData(GL_ARRAY_BUFFER, sizeof(RmlUiSFMLRendererVertex) * num_vertices, &Data[0], GL_STATIC_DRAW); glGenBuffers(1, &Geometry->IndexID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Geometry->IndexID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * num_indices, indices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); Geometry->Texture = texture; return (Rml::Core::CompiledGeometryHandle)Geometry; #else return (Rml::Core::CompiledGeometryHandle)NULL; #endif } // Called by RmlUi when it wants to render application-compiled geometry. void RmlUiSFMLRenderer::RenderCompiledGeometry(Rml::Core::CompiledGeometryHandle geometry, const Rml::Core::Vector2f& translation) { #ifdef ENABLE_GLEW RmlUiSFMLRendererGeometryHandler *RealGeometry = (RmlUiSFMLRendererGeometryHandler *)geometry; MyWindow->pushGLStates(); glTranslatef(translation.x, translation.y, 0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); sf::Texture *texture = (sf::Texture *)RealGeometry->Texture; if(texture) { sf::Texture::bind(texture); } else { glBindTexture(GL_TEXTURE_2D, 0); }; glEnable(GL_VERTEX_ARRAY); glEnable(GL_TEXTURE_COORD_ARRAY); glEnable(GL_COLOR_ARRAY); #define BUFFER_OFFSET(x) ((char*)0 + x) glBindBuffer(GL_ARRAY_BUFFER, RealGeometry->VertexID); glVertexPointer(2, GL_FLOAT, sizeof(RmlUiSFMLRendererVertex), BUFFER_OFFSET(0)); glTexCoordPointer(2, GL_FLOAT, sizeof(RmlUiSFMLRendererVertex), BUFFER_OFFSET(sizeof(sf::Vector2f))); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(RmlUiSFMLRendererVertex), BUFFER_OFFSET(sizeof(sf::Vector2f[2]))); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RealGeometry->IndexID); glDrawElements(GL_TRIANGLES, RealGeometry->NumVertices, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisable(GL_COLOR_ARRAY); glDisable(GL_TEXTURE_COORD_ARRAY); glDisable(GL_VERTEX_ARRAY); glColor4f(1, 1, 1, 1); MyWindow->popGLStates(); #else RMLUI_ASSERT(false); #endif } // Called by RmlUi when it wants to release application-compiled geometry. void RmlUiSFMLRenderer::ReleaseCompiledGeometry(Rml::Core::CompiledGeometryHandle geometry) { #ifdef ENABLE_GLEW delete (RmlUiSFMLRendererGeometryHandler *)geometry; #else RMLUI_ASSERT(false); #endif } // Called by RmlUi when it wants to enable or disable scissoring to clip content. void RmlUiSFMLRenderer::EnableScissorRegion(bool enable) { if (enable) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); } // Called by RmlUi when it wants to change the scissor region. void RmlUiSFMLRenderer::SetScissorRegion(int x, int y, int width, int height) { glScissor(x, MyWindow->getSize().y - (y + height), width, height); } // Called by RmlUi when a texture is required by the library. bool RmlUiSFMLRenderer::LoadTexture(Rml::Core::TextureHandle& texture_handle, Rml::Core::Vector2i& texture_dimensions, const Rml::Core::String& source) { Rml::Core::FileInterface* file_interface = Rml::Core::GetFileInterface(); Rml::Core::FileHandle file_handle = file_interface->Open(source); if (!file_handle) return false; file_interface->Seek(file_handle, 0, SEEK_END); size_t buffer_size = file_interface->Tell(file_handle); file_interface->Seek(file_handle, 0, SEEK_SET); char* buffer = new char[buffer_size]; file_interface->Read(buffer, buffer_size, file_handle); file_interface->Close(file_handle); sf::Texture *texture = new sf::Texture(); if(!texture->loadFromMemory(buffer, buffer_size)) { delete[] buffer; delete texture; return false; }; delete[] buffer; texture_handle = (Rml::Core::TextureHandle) texture; texture_dimensions = Rml::Core::Vector2i(texture->getSize().x, texture->getSize().y); return true; } // Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels. bool RmlUiSFMLRenderer::GenerateTexture(Rml::Core::TextureHandle& texture_handle, const Rml::Core::byte* source, const Rml::Core::Vector2i& source_dimensions) { sf::Texture *texture = new sf::Texture(); if (!texture->create(source_dimensions.x, source_dimensions.y)) { delete texture; return false; } texture->update(source, source_dimensions.x, source_dimensions.y, 0, 0); texture_handle = (Rml::Core::TextureHandle)texture; return true; } // Called by RmlUi when a loaded texture is no longer required. void RmlUiSFMLRenderer::ReleaseTexture(Rml::Core::TextureHandle texture_handle) { delete (sf::Texture *)texture_handle; }