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 | |
22 | namespace |
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 | |
133 | fastuidraw::ivec2 |
134 | load_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 | |
152 | fastuidraw::ivec2 |
153 | load_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 | |
166 | void |
167 | create_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 | |
209 | ImageLoaderData:: |
210 | ImageLoaderData(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 | |