2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
10 **************************************************************************/
12 #include <cstdio> // FILE
13 #include <cstring> // strncmp
30 //static int power_of_two(int input)
34 //while (value < input)
41 unsigned image::global_object_
= 0;
44 image::image(const std::string
& path
) :
47 min_filter_(GL_NEAREST
),
48 mag_filter_(GL_NEAREST
),
54 FILE* fp
= resource::open_file(path
);
55 if (!fp
) throw std::runtime_error("image not found at " + path
);
57 png_byte signature
[8];
60 png_infop pngInfo
= 0;
61 png_infop pngInfoEnd
= 0;
62 png_structp pngObj
= 0;
72 bytesRead
= fread(signature
, 1, sizeof(signature
), fp
);
73 if (bytesRead
< sizeof(signature
) ||
74 png_sig_cmp(signature
, 0, sizeof(signature
)) != 0) goto cleanup
;
76 pngObj
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, 0, 0, 0);
77 if (!pngObj
) goto cleanup
;
79 pngInfo
= png_create_info_struct(pngObj
);
80 if (!pngInfo
) goto cleanup
;
82 pngInfoEnd
= png_create_info_struct(pngObj
);
83 if (!pngInfoEnd
) goto cleanup
;
85 if (setjmp(png_jmpbuf(pngObj
))) goto cleanup
;
87 png_init_io(pngObj
, fp
);
88 png_set_sig_bytes(pngObj
, sizeof(signature
));
89 png_read_info(pngObj
, pngInfo
);
91 bpp
= png_get_bit_depth(pngObj
, pngInfo
);
92 colors
= png_get_color_type(pngObj
, pngInfo
);
95 case PNG_COLOR_TYPE_PALETTE
:
96 png_set_palette_to_rgb(pngObj
);
99 case PNG_COLOR_TYPE_GRAY
:
100 if (bpp
< 8) png_set_expand(pngObj
);
103 case PNG_COLOR_TYPE_GRAY_ALPHA
:
104 png_set_gray_to_rgb(pngObj
);
108 if (bpp
== 16) png_set_strip_16(pngObj
);
110 png_read_update_info(pngObj
, pngInfo
);
112 bpp
= png_get_bit_depth(pngObj
, pngInfo
);
113 channels_
= png_get_channels(pngObj
, pngInfo
);
114 depth_
= bpp
* channels_
;
117 png_get_text(pngObj
, pngInfo
, &texts
, &nutext_s
);
118 for (int i
= 0; i
< nutext_s
; ++i
)
120 if (strncmp(texts
[i
].key
, "TextureInfo", 11) == 0)
122 set_texture_info(texts
[i
].text
);
127 width_
= png_get_image_width(pngObj
, pngInfo
);
128 height_
= png_get_image_height(pngObj
, pngInfo
);
130 pitch_
= png_get_rowbytes(pngObj
, pngInfo
);
131 pixels_
= new char[width_
* pitch_
];
133 rows
= new png_bytep
[height_
];
134 for (int i
= 0; i
< height_
; ++i
)
136 rows
[i
] = (png_bytep
)(pixels_
+ i
* channels_
* width_
);
139 png_read_image(pngObj
, rows
);
140 png_read_end(pngObj
, 0);
145 png_destroy_read_struct(pngObj
? &pngObj
: 0,
146 pngInfo
? &pngInfo
: 0,
147 pngInfoEnd
? &pngInfoEnd
: 0);
158 void image::set_as_icon() const
162 SDL_Surface
* context
= SDL_CreateRGBSurfaceFrom
169 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
182 SDL_WM_SetIcon(context
, 0);
184 SDL_FreeSurface(context
);
188 bool image::tile_coordinates(int index
, scalar coords
[8]) const
190 // make sure the index represents a real tile
191 if (index
< 0 && index
>= tile_width_
* tile_height_
) return false;
193 scalar w
= 1.0 / scalar(tile_width_
);
194 scalar h
= 1.0 / scalar(tile_height_
);
196 coords
[0] = scalar(index
% tile_width_
) * w
;
197 coords
[1] = (scalar(tile_height_
- 1) - scalar(index
/ tile_width_
)) * h
;
198 coords
[2] = coords
[0] + w
;
199 coords
[3] = coords
[1];
200 coords
[4] = coords
[2];
201 coords
[5] = coords
[1] + h
;
202 coords
[6] = coords
[0];
203 coords
[7] = coords
[5];
209 void image::bind() const
211 ASSERT(video::current() && "should have a video context set");
217 if (object_
!= global_object_
)
219 glBindTexture(GL_TEXTURE_2D
, (GLuint
)object_
);
220 global_object_
= object_
;
224 void image::reset_binding()
226 ASSERT(video::current() && "should have a video context set");
228 glBindTexture(GL_TEXTURE_2D
, 0);
234 * Upload the image to GL so that it will be accessible by a much more
235 * manageable handle and hopefully reside in video memory.
237 void image::upload_to_gl() const
245 glGenTextures(1, (GLuint
*)&object_
);
246 glBindTexture(GL_TEXTURE_2D
, (GLuint
)object_
);
249 if (channels_
== 3) mode
= GL_RGB
;
269 // we want to know when the GL context is recreated
270 //dispatcher& dispatcher = dispatcher::global();
271 //new_context_ = dispatcher.add_target("video.newcontext",
272 //boost::bind(&image::context_recreated, this));
273 // FIXME this has const issues
276 void image::unload_from_gl() const
280 if (object_
== global_object_
)
285 glDeleteTextures(1, (GLuint
*)&object_
);
290 void image::context_recreated()
292 object_
= global_object_
= 0;
297 * Sets some texture properties such as the filters and external
298 * coordinate behavior.
300 void image::set_properties() const
302 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
303 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
304 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
305 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
309 void image::set_texture_info(const std::string
& info
)
314 script::slot g
= script
.globals();
315 g
.set_field("CLAMP", GL_CLAMP
);
316 g
.set_field("REPEAT", GL_REPEAT
);
317 g
.set_field("LINEAR", GL_LINEAR
);
318 g
.set_field("NEAREST", GL_NEAREST
);
319 g
.set_field("LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR
);
320 g
.set_field("LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST
);
321 g
.set_field("NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR
);
322 g
.set_field("NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST
);
324 if (script
.do_string(info
) != script::success
)
332 log_info("loading texture information...");
334 script::slot globals
= script
.globals();
335 globals
.get(tile_width_
, "tiles_s");
336 globals
.get(tile_height_
, "tiles_t");
337 globals
.get(min_filter_
, "min_filter");
338 globals
.get(mag_filter_
, "mag_filter");
339 globals
.get(wrap_s_
, "wrap_s");
340 globals
.get(wrap_t_
, "wrap_t");
345 class image_resource_loader
349 image_resource_loader()
351 resource::register_type
<image
>("png");
354 ~image_resource_loader()
356 resource::unregister_type("png");
360 static image_resource_loader loader
;