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