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 <SDL_image.h>
30 
31 #include "RenderInterfaceSDL2.h"
32 
33 #if !(SDL_VIDEO_RENDER_OGL)
34     #error "Only the opengl sdl backend is supported. To add support for others, see http://mdqinc.com/blog/2013/01/integrating-librocket-with-sdl-2/"
35 #endif
36 
RocketSDL2Renderer(SDL_Renderer * renderer,SDL_Window * screen)37 RocketSDL2Renderer::RocketSDL2Renderer(SDL_Renderer* renderer, SDL_Window* screen)
38 {
39     mRenderer = renderer;
40     mScreen = screen;
41 }
42 
43 // 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)44 void RocketSDL2Renderer::RenderGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation)
45 {
46     // SDL uses shaders that we need to disable here
47     glUseProgramObjectARB(0);
48     glPushMatrix();
49     glTranslatef(translation.x, translation.y, 0);
50 
51     std::vector<Rocket::Core::Vector2f> Positions(num_vertices);
52     std::vector<Rocket::Core::Colourb> Colors(num_vertices);
53     std::vector<Rocket::Core::Vector2f> TexCoords(num_vertices);
54     float texw, texh;
55 
56     SDL_Texture* sdl_texture = NULL;
57     if(texture)
58     {
59         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
60         sdl_texture = (SDL_Texture *) texture;
61         SDL_GL_BindTexture(sdl_texture, &texw, &texh);
62     }
63 
64     for(int  i = 0; i < num_vertices; i++) {
65         Positions[i] = vertices[i].position;
66         Colors[i] = vertices[i].colour;
67         if (sdl_texture) {
68             TexCoords[i].x = vertices[i].tex_coord.x * texw;
69             TexCoords[i].y = vertices[i].tex_coord.y * texh;
70         }
71         else TexCoords[i] = vertices[i].tex_coord;
72     };
73 
74     glEnableClientState(GL_VERTEX_ARRAY);
75     glEnableClientState(GL_COLOR_ARRAY);
76     glVertexPointer(2, GL_FLOAT, 0, &Positions[0]);
77     glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Colors[0]);
78     glTexCoordPointer(2, GL_FLOAT, 0, &TexCoords[0]);
79 
80     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
81     glEnable(GL_BLEND);
82     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
83     glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices);
84     glDisableClientState(GL_VERTEX_ARRAY);
85     glDisableClientState(GL_COLOR_ARRAY);
86 
87     if (sdl_texture) {
88         SDL_GL_UnbindTexture(sdl_texture);
89         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
90     }
91 
92     glColor4f(1.0, 1.0, 1.0, 1.0);
93     glPopMatrix();
94     /* Reset blending and draw a fake point just outside the screen to let SDL know that it needs to reset its state in case it wants to render a texture */
95     glDisable(GL_BLEND);
96     SDL_SetRenderDrawBlendMode(mRenderer, SDL_BLENDMODE_NONE);
97     SDL_RenderDrawPoint(mRenderer, -1, -1);
98 }
99 
100 
101 // Called by Rocket when it wants to enable or disable scissoring to clip content.
EnableScissorRegion(bool enable)102 void RocketSDL2Renderer::EnableScissorRegion(bool enable)
103 {
104     if (enable)
105         glEnable(GL_SCISSOR_TEST);
106     else
107         glDisable(GL_SCISSOR_TEST);
108 }
109 
110 // Called by Rocket when it wants to change the scissor region.
SetScissorRegion(int x,int y,int width,int height)111 void RocketSDL2Renderer::SetScissorRegion(int x, int y, int width, int height)
112 {
113     int w_width, w_height;
114     SDL_GetWindowSize(mScreen, &w_width, &w_height);
115     glScissor(x, w_height - (y + height), width, height);
116 }
117 
118 // 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)119 bool RocketSDL2Renderer::LoadTexture(Rocket::Core::TextureHandle& texture_handle, Rocket::Core::Vector2i& texture_dimensions, const Rocket::Core::String& source)
120 {
121 
122     Rocket::Core::FileInterface* file_interface = Rocket::Core::GetFileInterface();
123     Rocket::Core::FileHandle file_handle = file_interface->Open(source);
124     if (!file_handle)
125         return false;
126 
127     file_interface->Seek(file_handle, 0, SEEK_END);
128     size_t buffer_size = file_interface->Tell(file_handle);
129     file_interface->Seek(file_handle, 0, SEEK_SET);
130 
131     char* buffer = new char[buffer_size];
132     file_interface->Read(buffer, buffer_size, file_handle);
133     file_interface->Close(file_handle);
134 
135     size_t i;
136     for(i = source.Length() - 1; i > 0; i--)
137     {
138         if(source[i] == '.')
139             break;
140     }
141 
142     Rocket::Core::String extension = source.Substring(i+1, source.Length()-i);
143 
144     SDL_Surface* surface = IMG_LoadTyped_RW(SDL_RWFromMem(buffer, buffer_size), 1, extension.CString());
145 
146     if (surface) {
147         SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer, surface);
148 
149         if (texture) {
150             texture_handle = (Rocket::Core::TextureHandle) texture;
151             texture_dimensions = Rocket::Core::Vector2i(surface->w, surface->h);
152             SDL_FreeSurface(surface);
153         }
154         else
155         {
156             return false;
157         }
158 
159         return true;
160     }
161 
162     return false;
163 }
164 
165 // 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)166 bool RocketSDL2Renderer::GenerateTexture(Rocket::Core::TextureHandle& texture_handle, const Rocket::Core::byte* source, const Rocket::Core::Vector2i& source_dimensions)
167 {
168     #if SDL_BYTEORDER == SDL_BIG_ENDIAN
169         Uint32 rmask = 0xff000000;
170         Uint32 gmask = 0x00ff0000;
171         Uint32 bmask = 0x0000ff00;
172         Uint32 amask = 0x000000ff;
173     #else
174         Uint32 rmask = 0x000000ff;
175         Uint32 gmask = 0x0000ff00;
176         Uint32 bmask = 0x00ff0000;
177         Uint32 amask = 0xff000000;
178     #endif
179 
180     SDL_Surface *surface = SDL_CreateRGBSurfaceFrom ((void*) source, source_dimensions.x, source_dimensions.y, 32, source_dimensions.x*4, rmask, gmask, bmask, amask);
181     SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer, surface);
182     SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
183     SDL_FreeSurface(surface);
184     texture_handle = (Rocket::Core::TextureHandle) texture;
185     return true;
186 }
187 
188 // Called by Rocket when a loaded texture is no longer required.
ReleaseTexture(Rocket::Core::TextureHandle texture_handle)189 void RocketSDL2Renderer::ReleaseTexture(Rocket::Core::TextureHandle texture_handle)
190 {
191     SDL_DestroyTexture((SDL_Texture*) texture_handle);
192 }
193