1/*!
2 * Adapted from: WRATHSDLImageSupport.cpp of WRATH:
3 *
4 * Copyright 2013 by Nomovok Ltd.
5 * Contact: info@nomovok.com
6 * This Source Code Form is subject to the
7 * terms of the Mozilla Public License, v. 2.0.
8 * If a copy of the MPL was not distributed with
9 * this file, You can obtain one at
10 * http://mozilla.org/MPL/2.0/.
11 *
12 * \author Kevin Rogovin <kevin.rogovin@nomovok.com>
13 * \author Kevin Rogovin <kevin.rogovin@gmail.com>
14 */
15
16#include <iostream>
17#include <cstring>
18#include <fastuidraw/gl_backend/gl_context_properties.hpp>
19#include <fastuidraw/gl_backend/texture_image_gl.hpp>
20#include "ImageLoader.hpp"
21
22namespace
23{
24 fastuidraw::ivec2
25 load_image_worker(SDL_Surface *img, std::vector<fastuidraw::u8vec4> &bits_data, bool flip)
26 {
27 SDL_PixelFormat *fmt;
28
29 fmt = img->format;
30 // Store some useful variables
31 SDL_LockSurface(img);
32
33 int w(img->w), h(img->h);
34 int pitch(img->pitch);
35 int bytes_per_pixel(img->format->BytesPerPixel);
36
37 const unsigned char *surface_data;
38 surface_data = reinterpret_cast<const unsigned char*>(img->pixels);
39
40 // Resize the vector holding the bit data
41 bits_data.resize(w * h);
42
43 for(int y=0; y<h; ++y)
44 {
45 int source_y = (flip) ? h-1-y : y;
46
47 for(int x =0 ; x < w; ++x)
48 {
49 int src_L, dest_L;
50 Uint8 red, green, blue, alpha;
51 Uint32 temp, pixel;
52
53 src_L = source_y * pitch + x * bytes_per_pixel;
54 dest_L = y * w + x;
55
56 pixel = *reinterpret_cast<const Uint32*>(surface_data + src_L);
57
58 /* Get Alpha component */
59 temp = pixel & fmt->Amask;
60 temp = temp >> fmt->Ashift;
61 temp = temp << fmt->Aloss;
62 alpha = (Uint8)temp;
63
64 temp = pixel & fmt->Rmask;
65 temp = temp >> fmt->Rshift;
66 temp = temp << fmt->Rloss;
67 red = temp;
68
69 temp = pixel & fmt->Gmask;
70 temp = temp >> fmt->Gshift;
71 temp = temp << fmt->Gloss;
72 green = temp;
73
74 temp = pixel & fmt->Bmask;
75 temp = temp >> fmt->Bshift;
76 temp = temp << fmt->Bloss;
77 blue = temp;
78
79 bits_data[dest_L][0] = red;
80 bits_data[dest_L][1] = green;
81 bits_data[dest_L][2] = blue;
82 bits_data[dest_L][3] = alpha;
83 }
84 }
85 SDL_UnlockSurface(img);
86 return fastuidraw::ivec2(w, h);
87 }
88
89 bool
90 compute_use_tex_storage(void)
91 {
92 #ifdef FASTUIDRAW_GL_USE_GLES
93 {
94 return true;
95 }
96 #else
97 {
98 fastuidraw::gl::ContextProperties ctx;
99
100 return ctx.version() >= fastuidraw::ivec2(4, 2)
101 || ctx.has_extension("GL_ARB_texture_storage");
102 }
103 #endif
104 }
105
106 void
107 tex_storage2d_rgba8(int w, int h, int m)
108 {
109 static bool use_tex_storage(compute_use_tex_storage());
110 if (use_tex_storage)
111 {
112 fastuidraw_glTexStorage2D(GL_TEXTURE_2D, m, GL_RGBA8, w, h);
113 }
114 else
115 {
116 for (unsigned int i = 0; i < m; ++i, w /= 2, h /= 2)
117 {
118 fastuidraw_glTexImage2D(GL_TEXTURE_2D,
119 i,
120 GL_RGBA8,
121 fastuidraw::t_max(w, 1),
122 fastuidraw::t_max(h, 1),
123 0,
124 GL_RGBA,
125 GL_UNSIGNED_BYTE,
126 nullptr);
127 }
128 }
129 }
130
131}
132
133fastuidraw::ivec2
134load_image_to_array(const SDL_Surface *img,
135 std::vector<fastuidraw::u8vec4> &out_bytes,
136 bool flip)
137{
138 SDL_Surface *q;
139 fastuidraw::ivec2 R;
140
141 if (!img)
142 {
143 return fastuidraw::ivec2(0,0);
144 }
145 q = SDL_ConvertSurfaceFormat(const_cast<SDL_Surface*>(img), SDL_PIXELFORMAT_RGBA8888, 0);
146 R = load_image_worker(q, out_bytes, flip);
147 SDL_FreeSurface(q);
148 return R;
149}
150
151
152fastuidraw::ivec2
153load_image_to_array(const std::string &pfilename,
154 std::vector<fastuidraw::u8vec4> &out_bytes,
155 bool flip)
156{
157 fastuidraw::ivec2 R;
158
159 SDL_Surface *img;
160 img = IMG_Load(pfilename.c_str());
161 R = load_image_to_array(img, out_bytes, flip);
162 SDL_FreeSurface(img);
163 return R;
164}
165
166void
167create_mipmap_level(fastuidraw::ivec2 sz,
168 fastuidraw::c_array<const fastuidraw::u8vec4> in_data,
169 std::vector<fastuidraw::u8vec4> &out_data)
170{
171 int w, h;
172
173 w = fastuidraw::t_max(1, sz.x() / 2);
174 h = fastuidraw::t_max(1, sz.y() / 2);
175 out_data.resize(w * h);
176
177 for (int dst_y = 0; dst_y < h; ++dst_y)
178 {
179 int sy0, sy1;
180
181 sy0 = fastuidraw::t_min(2 * dst_y, sz.y() - 1);
182 sy1 = fastuidraw::t_min(2 * dst_y + 1, sz.y() - 1);
183 for (int dst_x = 0; dst_x < w; ++dst_x)
184 {
185 int sx0, sx1;
186 fastuidraw::vec4 p00, p01, p10, p11, p;
187
188 sx0 = fastuidraw::t_min(2 * dst_x, sz.x() - 1);
189 sx1 = fastuidraw::t_min(2 * dst_x + 1, sz.x() - 1);
190
191 p00 = fastuidraw::vec4(in_data[sx0 + sy0 * sz.x()]);
192 p01 = fastuidraw::vec4(in_data[sx0 + sy1 * sz.x()]);
193 p10 = fastuidraw::vec4(in_data[sx1 + sy0 * sz.x()]);
194 p11 = fastuidraw::vec4(in_data[sx1 + sy1 * sz.x()]);
195
196 p = 0.25f * (p00 + p01 + p10 + p11);
197
198 for (unsigned int c = 0; c < 4; ++c)
199 {
200 float q;
201 q = fastuidraw::t_min(p[c], 255.0f);
202 q = fastuidraw::t_max(q, 0.0f);
203 out_data[dst_x + dst_y * w][c] = static_cast<unsigned int>(q);
204 }
205 }
206 }
207}
208
209ImageLoaderData::
210ImageLoaderData(const std::string &pfilename, bool flip):
211 m_dimensions(0, 0)
212{
213 fastuidraw::ivec2 dims;
214 std::vector<fastuidraw::u8vec4> data;
215
216 dims = load_image_to_array(pfilename, data, flip);
217 if (dims.x() <= 0 || dims.y() <= 0)
218 {
219 return;
220 }
221
222 m_dimensions = fastuidraw::uvec2(dims);
223 m_mipmap_levels.push_back(std::vector<fastuidraw::u8vec4>());
224 m_mipmap_levels.back().swap(data);
225
226 while(dims.x() >= 2 && dims.y() >= 2)
227 {
228 fastuidraw::ivec2 wh;
229
230 wh.x() = fastuidraw::t_max(dims.x(), 1);
231 wh.y() = fastuidraw::t_max(dims.y(), 1);
232 create_mipmap_level(wh,
233 cast_c_array(m_mipmap_levels.back()),
234 data);
235 m_mipmap_levels.push_back(std::vector<fastuidraw::u8vec4>());
236 m_mipmap_levels.back().swap(data);
237 dims /= 2;
238 }
239
240 m_data_as_arrays.resize(m_mipmap_levels.size());
241 for (unsigned int i = 0; i < m_data_as_arrays.size(); ++i)
242 {
243 m_data_as_arrays[i] = cast_c_array(m_mipmap_levels[i]);
244 }
245}
246