openlayer-2.1.orig/0000700000175000017500000000000012262355751014505 5ustar georgeskgeorgeskopenlayer-2.1.orig/utils/0000700000175000017500000000000012262355751015645 5ustar georgeskgeorgeskopenlayer-2.1.orig/utils/glyphkeeper/0000700000175000017500000000000012262355751020164 5ustar georgeskgeorgeskopenlayer-2.1.orig/utils/glyphkeeper/license.txt0000644000175000017500000001145310567602066022365 0ustar georgeskgeorgesk Glyph Keeper license -------------------- Glyph Keeper - a text-rendering library version 0.32 (February 6, 2007) Copyright (c) 2003-2007 Kirill Kryukov This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Kirill Kryukov Bundled 3-rd party software --------------------------- Glyph Keeper source distribution contains a number of files that are not created by me: - FreeType library source code, under "freetype" directory. It is required for compiling Glyph Keeper, although you may use your own copy of FreeType instead. I use and distribute it in agreement with FreeType license located in "freetype/FTL.txt" file. See the "freetype/readme.Kirr-mod.txt" file for the list of my modifications. - Example font "DejaVu Sans" version 2.14, located in "fonts/DejaVuSans.ttf" file. Check its the readme "fonts/DejaVu readme.txt" and license "fonts/DejaVu licene.txt" for more information about it. - Allegro font "fonts/demofont.pcx". It is used by Allegro benchmark program, a part of Glyph Keeper benchmark suite. To say the truth I don't remember where it came from. I believe it came from Allegro library examples which is a giftware. Corerect me if I am wrong. - AllegroFont 1.9.2 library in "benchmark/alfont.c" file (slightly modified). It is used by a benchmark program to compare performance of Glyph Keeper with AllegoFont. It is created by Javier Gonzalez, and distributed under FreeType license. (See the source for copyright info). FreeType note ------------- As using Glyph Keeper requires you to use FreeType, you must also comply with FreeType license. Glyph Keeper license does not substitute FreeType license for you! Please check the FreeType license located in "freetype/license.txt" file in Glyph Keeper source archive if you are using FreeType bundled with Glyph Keeper. If you are using FreeType already installed on your system, refer to its license instead. I include FreeType 2.2.1 source with Glyph Keeper source distribution. It is located in "freetype" directory. I did not write any code there. I include it for convenience of those who don't have FreeType installed on their system. I use and distribute it together with Glyph Keeper under the terms of FreeType license, located in "freetype/FTL.txt" file. Patent note 1 ------------- There is an important potential patent issue involved in using FreeType, and therefore Glyph Keeper. It is best explained on FreeType project web-site here: http://www.freetype.org/patents.html Briefly, you should be careful if you are using TrueType bytecode interpreter patented by Apple. It is disabled (turned OFF) by default in FreeType bundled with Glyph Keeper. This means Glyph Keeper will not render some fonts as beautifully as they are rendered by MacOS or Windows. To activate bytecode interpreter (at your own risk) do the following: Open header file "include/freetype/config/ftoption.h", and find this line: /* #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ (It is commented out, which means bytecode interpreter is disabled and you are safe, but some fonts may look bad) To activate bytecode interpreter, change that line to: #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER And re-compile FreeType and Glyph Keeper (and your program if you are linking statically). Then bytecode interpreter will be enabled, and some fonts may look better. Patent note 2 ------------- My FreeType build has sub-pixel rendering (a.k.a. LCD rendering, or ClearType) disabled by default. It is patented by Microsoft, so you should be careful with it. If you want to activate it, open the header file "include/freetype/config/ftoption.h", find this line that sais: /* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ and change it to #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING Don't forget to re-compile FreeType and Glyph Keeper if you change it. Note that Glyph Keeper does not use sub-pixel rendering at the moment, but it may change in future. openlayer-2.1.orig/utils/glyphkeeper/src/0000700000175000017500000000000012262355751020753 5ustar georgeskgeorgeskopenlayer-2.1.orig/utils/glyphkeeper/src/glyph_main.c0000644000175000017500000003134610567602066023267 0ustar georgeskgeorgesk/* * glyph_main.c - Glyph Keeper main routines * (initialization/cleanup, rendering text). * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c /* * Init/cleanup functions */ void gk_library_init() { int error; FT_Int amajor,aminor,apatch; if (ftlib) return; #ifdef GLYPH_LOG if (!glyph_log) { glyph_log = fopen("glyph.log","w"); if (!glyph_log) { _gk_msg("Error: gk_library_init(): Can't create a log-file \"glyph.log\"\n"); exit(1); } /* It's a log-file, nothing should be lost. */ setbuf(glyph_log,0); fprintf(glyph_log,"glyph.log started\n"); } #endif error = FT_Init_FreeType(&ftlib); if (error || !ftlib) { _gk_msg("Error: gk_library_init(): can't initialize FreeType\n"); ftlib = 0; return; } FT_Library_Version(ftlib,&amajor,&aminor,&apatch); _gk_msg("FreeType %d.%d.%d initialized\n",amajor,aminor,apatch); FT_Bitmap_New(&_gk_workout_bitmap); _gk_install_exit_handler(); } void gk_library_cleanup(void) { #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_library_cleanup() begin\n"); #endif while (first_renderer) gk_done_renderer(first_renderer); while (first_keeper) gk_done_keeper(first_keeper); while (first_face) gk_unload_face(first_face); if (ftlib) { if (_gk_workout_bitmap.buffer) { FT_Bitmap_Done(ftlib,&_gk_workout_bitmap); } FT_Done_FreeType(ftlib); ftlib = 0; } if (rle_buffer) { _gk_free(rle_buffer); rle_buffer = 0; } rle_buffer_size = 0; #ifdef GLYPH_DEBUG_FT_MEMORY if (_gk_allocated_by_ft || _gk_overhead_by_ft) _gk_msg( "Memory leak! FreeType leaked %d + %d bytes!\n", _gk_allocated_by_ft, _gk_overhead_by_ft ); else _gk_msg( "FreeType shutdown clean\n" ); #endif #ifdef GLYPH_DEBUG_GK_MEMORY if (_gk_allocated_by_gk || _gk_overhead_by_gk) _gk_msg( "Memory leak! Glyph Keeper leaked %d + %d bytes!\n", _gk_allocated_by_gk, _gk_overhead_by_gk ); else _gk_msg("Glyph Keeper shutdown clean\n"); #endif #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_library_cleanup() end\n"); if (glyph_log) { fclose(glyph_log); glyph_log = 0; } #endif } /* * Checks how many bytes are allocated by Glyph Keeper. * (FreeType memory is not counted) */ size_t gk_bytes_allocated() { int n = 0; GLYPH_FACE *a; GLYPH_KEEP *b; GLYPH_REND *c; for (a = first_face; a; a=a->next) n += a->allocated; for (b = first_keeper; b; b=b->next) n += b->allocated; for (c = first_renderer; c; c=c->next) n += sizeof(GLYPH_REND); n += rle_buffer_size; return n; } /* * Precaching. */ void gk_precache_char(GLYPH_REND* const rend,const unsigned unicode) { GLYPH *glyph; if (!rend || !rend->index) return; if (rend->before_rend) gk_precache_char(rend->before_rend,unicode); glyph = _gk_rend_render(rend,unicode); if (glyph && !glyph->index) _gk_unload_glyph(glyph); if (rend->after_rend) gk_precache_char(rend->after_rend,unicode); } void gk_precache_range(GLYPH_REND* const rend, const unsigned range_start,const unsigned range_end) { unsigned code; if (!rend || !rend->index) return; for (code=range_start; code<=range_end; code++) gk_precache_char(rend,code); } void gk_precache_set_utf8(GLYPH_REND* const rend,const char* const char_set) { const char* c = char_set; unsigned code; if (!rend || !rend->index) return; while ( (code = _gk_utf8_getx(&c)) ) gk_precache_char(rend,code); } void gk_precache_set_utf16(GLYPH_REND* const rend,const unsigned short* const char_set) { const unsigned short* c = char_set; unsigned code; if (!rend || !rend->index) return; _gk_utf16_start_decoding(&c); while ( (code = _gk_utf16_decode(&c)) ) gk_precache_char(rend,code); } void gk_precache_set_utf32(GLYPH_REND* const rend,const unsigned* const char_set) { const unsigned* c = char_set; unsigned code; if (!rend || !rend->index) return; _gk_utf32_start_decoding(&c); while ( (code = _gk_utf32_decode(&c)) ) gk_precache_char(rend,code); } /* * Draws background rectangle. * pen_x and pen_y are in puxels. * adv_x and adv_y should not be both zero. */ #ifdef GLYPH_TARGET_HAS_RECTFILL static void _gk_draw_background_rectangle(GLYPH_TARGET_SURFACE* const bmp,GLYPH_REND* const rend, const int pen_x,const int pen_y,const int adv_x,const int adv_y) { if (rend->text_angle != 0) { #ifdef GLYPH_TARGET_HAS_RECTFILL_ANGLED int xlt,ylt,xlb,ylb,xrt,yrt,xrb,yrb; _gk_text_rectangle_by_advance(rend,adv_x,adv_y,&xlt,&ylt,&xlb,&ylb,&xrt,&yrt,&xrb,&yrb); _gk_driver_rectfill_angled(bmp,xlt+pen_x,ylt+pen_y,xrt+pen_x,yrt+pen_y, xrb+pen_x,yrb+pen_y,xlb+pen_x,ylb+pen_y,rend->back_color); #endif } else { int ascender = gk_rend_ascender(rend); int descender = gk_rend_descender(rend); int xl = pen_x << 6; int xr = xl + adv_x; if (rend->italic_angle != 0) { int da = ascender ? (tan(rend->italic_angle) * ascender) : 0; int dd = descender ? (tan(rend->italic_angle) * descender) : 0; if (rend->italic_angle > 0) { xl += dd; xr += da; } else { xl += da; xr += dd; } } /*_gk_driver_rectfill(bmp,pen_x,pen_y-(ascender>>6),pen_x+((adv_x+63)>>6),pen_y-(descender>>6),rend->back_color);*/ _gk_driver_rectfill(bmp,(xl+31)>>6,pen_y-(ascender>>6),(xr+31)>>6,pen_y-(descender>>6),rend->back_color); } } #endif void gk_put_char(GLYPH_TARGET_SURFACE* const bmp,GLYPH_REND* const rend, const unsigned unicode,const int x,const int y) { GLYPH *glyph = 0; if (!bmp || !rend) return; glyph = _gk_rend_render(rend,unicode); if (glyph) { if (rend->before_rend) gk_put_char_center(bmp,rend->before_rend,unicode, x + glyph->width/2 + rend->before_dx, y + glyph->height/2 + rend->before_dy); _gk_prepare_to_draw(bmp,rend); _gk_put_glyph(glyph,x,y); _gk_done_drawing(); if (rend->after_rend) gk_put_char_center(bmp,rend->after_rend,unicode, x + glyph->width/2 + rend->after_dx, y + glyph->height/2 + rend->after_dy); } } void gk_put_char_center(GLYPH_TARGET_SURFACE* const bmp,GLYPH_REND* const rend,const unsigned unicode, const int x,const int y) { GLYPH *glyph; if (!bmp || !rend) return; glyph = _gk_rend_render(rend,unicode); if (glyph) { if (rend->before_rend) gk_put_char_center(bmp,rend->before_rend,unicode,x+rend->before_dx,y+rend->before_dy); _gk_prepare_to_draw(bmp,rend); _gk_put_glyph(glyph, x - glyph->center_x + glyph->left, y + glyph->center_y - glyph->top); _gk_done_drawing(); if (rend->after_rend) gk_put_char_center(bmp,rend->after_rend,unicode,x+rend->after_dx,y+rend->after_dy); } } /* * 'rend' must be not 0. * 'pen_x' and 'pen_y' are expressed in 26.6 pixels here. */ static void _gk_internal_render_char(GLYPH_REND* const rend,const unsigned unicode,int *pen_x,int *pen_y) { GLYPH* glyph; int adv_x,adv_y; CARE(rend); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_internal_render_char()\n"); #endif glyph = _gk_rend_render(rend,unicode); if (!glyph) return; adv_x = glyph->advance_x; adv_y = glyph->advance_y; _gk_put_glyph(glyph,((*pen_x+31)>>6)+glyph->left,((*pen_y+31)>>6)-glyph->top); *pen_x += adv_x; *pen_y -= adv_y; } void gk_render_char(GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend,const unsigned unicode, int* const pen_x,int* const pen_y) { GLYPH* glyph; int adv_x,adv_y; int draw_x,draw_y; if (!bmp || !rend || !pen_x || !pen_y) return; glyph = _gk_rend_render(rend,unicode); if (!glyph) return; adv_x = glyph->advance_x; adv_y = glyph->advance_y; draw_x = ((*pen_x+31)>>6)+glyph->left; draw_y = ((*pen_y+31)>>6)-glyph->top; #ifdef GLYPH_TARGET_HAS_RECTFILL if (rend->back_color >= 0) { int ax,ay; gk_char_advance(rend,unicode,&ax,&ay); if (ax || ay) _gk_draw_background_rectangle(bmp,rend,*pen_x,*pen_y,ax,ay); } #endif if (rend->before_rend) gk_put_char_center(bmp,rend->before_rend,unicode, ((*pen_x+31)>>6) + glyph->center_x + rend->before_dx, ((*pen_y+31)>>6) - glyph->center_y + rend->before_dy); _gk_prepare_to_draw(bmp,rend); _gk_put_glyph(glyph,draw_x,draw_y); _gk_done_drawing(); if (rend->after_rend) gk_put_char_center(bmp,rend->after_rend,unicode, ((*pen_x+31)>>6) + glyph->center_x + rend->after_dx, ((*pen_y+31)>>6) - glyph->center_y + rend->after_dy); *pen_x += adv_x; *pen_y -= adv_y; } void gk_render_char_center(GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend,const unsigned unicode, const int x,const int y) { GLYPH *glyph; if (!bmp || !rend) return; glyph = _gk_rend_render(rend,unicode); if (glyph) { int asc = gk_rend_ascender_pixels(rend); _gk_prepare_to_draw(bmp,rend); _gk_put_glyph(glyph,x-glyph->width/2,y - rend->text_height_pixels/2 + asc - glyph->top); _gk_done_drawing(); } } void gk_render_line_utf8(GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend,const char* const text, const int pen_x,const int pen_y) { int x,y; const char* c = text; unsigned code; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_render_line_utf8() begin\n"); #endif if (!bmp || !rend || !text) return; #ifdef GLYPH_TARGET_HAS_RECTFILL if (rend->back_color >= 0) { int ax,ay; gk_text_advance_subpixel_utf8(rend,text,&ax,&ay); if (ax || ay) _gk_draw_background_rectangle(bmp,rend,pen_x,pen_y,ax,ay); } #endif x = pen_x<<6; y = pen_y<<6; if (rend->before_rend || rend->after_rend) { while ( (code = _gk_utf8_getx(&c)) ) gk_render_char(bmp,rend,code,&x,&y); } else { _gk_prepare_to_draw(bmp,rend); while ( (code = _gk_utf8_getx(&c)) ) _gk_internal_render_char(rend,code,&x,&y); _gk_done_drawing(); } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_render_line_utf8() end\n"); #endif } void gk_render_line_utf16(GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend,const unsigned short* const text, const int pen_x,const int pen_y) { int x,y; const unsigned short* c = text; unsigned code; if (!bmp || !rend || !text) return; #ifdef GLYPH_TARGET_HAS_RECTFILL if (rend->back_color >= 0) { int ax,ay; gk_text_advance_subpixel_utf16(rend,text,&ax,&ay); if (ax || ay) _gk_draw_background_rectangle(bmp,rend,pen_x,pen_y,ax,ay); } #endif x = pen_x<<6; y = pen_y<<6; _gk_utf16_start_decoding(&c); if (rend->before_rend || rend->after_rend) { while ( (code = _gk_utf16_decode(&c)) ) gk_render_char(bmp,rend,code,&x,&y); } else { _gk_prepare_to_draw(bmp,rend); while ( (code = _gk_utf16_decode(&c)) ) _gk_internal_render_char(rend,code,&x,&y); _gk_done_drawing(); } } void gk_render_line_utf32(GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend,const unsigned* const text, const int pen_x,const int pen_y) { int x,y; const unsigned* c = text; unsigned code; if (!bmp || !rend || !text) return; #ifdef GLYPH_TARGET_HAS_RECTFILL if (rend->back_color >= 0) { int ax,ay; gk_text_advance_subpixel_utf32(rend,text,&ax,&ay); if (ax || ay) _gk_draw_background_rectangle(bmp,rend,pen_x,pen_y,ax,ay); } #endif x = pen_x<<6; y = pen_y<<6; _gk_utf32_start_decoding(&c); if (rend->before_rend || rend->after_rend) { while ( (code = _gk_utf32_decode(&c)) ) gk_render_char(bmp,rend,code,&x,&y); } else { _gk_prepare_to_draw(bmp,rend); while ( (code = _gk_utf32_decode(&c)) ) _gk_internal_render_char(rend,code,&x,&y); _gk_done_drawing(); } } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_memory.c0000644000175000017500000002272210567602066023651 0ustar georgeskgeorgesk/* * glyph_memory.h - Glyph Keeper memory manager for debugging. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c size_t gk_total_gk_allocated_bytes() { return _gk_allocated_by_gk; } size_t gk_total_gk_overhead_bytes() { return _gk_overhead_by_gk; } size_t gk_total_ft_allocated_bytes() { return _gk_allocated_by_ft; } size_t gk_total_ft_overhead_bytes() { return _gk_overhead_by_ft; } #ifdef GLYPH_DEBUG_GK_MEMORY void* _gk_malloc(size_t size) { void *buf; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_malloc(%d) (now %d + %d allocated) : ", size, _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif buf = malloc( size + sizeof(size_t) ); if (buf) { *(size_t*)buf = size; _gk_allocated_by_gk += size; _gk_overhead_by_gk += sizeof(size_t); #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Success (%p), now %d + %d allocated\n", (void*)((size_t*)buf + 1), _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif return (size_t*)buf + 1; } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Failure!\n" ); #endif _gk_msg( "Error: _gk_malloc() failed to allocate %d bytes!\n", size ); return 0; } } void* _gk_calloc(size_t num_elements, size_t size) { size_t bytes = num_elements * size; void *buf; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_calloc(%d,%d) (now %d + %d allocated) : ", num_elements, size, _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif buf = malloc( bytes + sizeof(size_t) ); if (buf) { memset( buf, 0, bytes + sizeof(size_t) ); *(size_t*)buf = bytes; _gk_allocated_by_gk += bytes; _gk_overhead_by_gk += sizeof(size_t); #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Success (%p), now %d + %d bytes allocated\n", (void*)((size_t*)buf + 1), _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif return (size_t*)buf + 1; } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Failure!\n" ); #endif _gk_msg( "Error: _gk_calloc() failed to allocate %d bytes!\n", bytes ); return 0; } } void* _gk_realloc(void *ptr, size_t size) { size_t old_size; size_t* real_ptr; void *buf; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_realloc(%p,%d) (now %d + %d allocated) : ", ptr, size, _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif if (ptr) real_ptr = (size_t*)ptr - 1; else real_ptr = 0; if (real_ptr) old_size = *real_ptr; else old_size = 0; buf = realloc( real_ptr, size + sizeof(size_t) ); if (buf) { *(size_t*)buf = size; _gk_allocated_by_gk += size - old_size; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Success (%p), now %d + %d bytes allocated\n", (void*)((size_t*)buf + 1), _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif return (size_t*)buf + 1; } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Failure!\n" ); #endif _gk_msg( "Error: _gk_realloc() failed to allocate %d bytes!\n", size ); return 0; } } void _gk_free(void *ptr) { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_free(%p) (now %d + %d allocated) : ", ptr, _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif if (ptr) { size_t size = *((size_t*)ptr - 1); free( (size_t*)ptr - 1 ); _gk_allocated_by_gk -= size; _gk_overhead_by_gk -= sizeof(size_t); #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Freed %d bytes (now %d + %d allocated)\n", size, _gk_allocated_by_gk, _gk_overhead_by_gk ); #endif } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_GK_MEMORY) if (glyph_log) fprintf( glyph_log, "Trying to free a 0 pointer!\n" ); #endif _gk_msg( "Error: trying to _gk_free() a 0 pointer\n" ); } } #endif /* GLYPH_DEBUG_GK_MEMORY */ #ifdef GLYPH_DEBUG_FT_MEMORY void* _gk_for_ft_malloc(size_t size) { void *buf; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_for_ft_malloc(%d) (now %d + %d allocated) : ", size, _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif buf = malloc( size + sizeof(size_t) ); if (buf) { *(size_t*)buf = size; _gk_allocated_by_ft += size; _gk_overhead_by_ft += sizeof(size_t); #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Success (%p), now %d + %d allocated\n", (void*)((size_t*)buf + 1), _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif return (size_t*)buf + 1; } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Failure!\n" ); #endif _gk_msg( "Error: _gk_for_ft_malloc() failed to allocate %d bytes!\n", size ); return 0; } } void* _gk_for_ft_calloc(size_t num_elements, size_t size) { size_t bytes = num_elements * size; void *buf; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_for_ft_calloc(%d,%d) (now %d + %d allocated) : ", num_elements, size, _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif buf = malloc( bytes + sizeof(size_t) ); if (buf) { memset( buf, 0, bytes + sizeof(size_t) ); *(size_t*)buf = bytes; _gk_allocated_by_ft += bytes; _gk_overhead_by_ft += sizeof(size_t); #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Success (%p), now %d + %d bytes allocated\n", (void*)((size_t*)buf + 1), _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif return (size_t*)buf + 1; } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Failure!\n" ); #endif _gk_msg( "Error: _gk_for_ft_calloc() failed to allocate %d bytes!\n", bytes ); return 0; } } void* _gk_for_ft_realloc(void *ptr, size_t size) { size_t old_size; size_t* real_ptr; void *buf; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_for_ft_realloc(%p,%d) (now %d + %d allocated) : ", ptr, size, _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif if (ptr) real_ptr = (size_t*)ptr - 1; else real_ptr = 0; if (real_ptr) old_size = *real_ptr; else old_size = 0; buf = realloc( real_ptr, size + sizeof(size_t) ); if (buf) { *(size_t*)buf = size; _gk_allocated_by_ft += size - old_size; #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Success (%p), now %d + %d bytes allocated\n", (void*)((size_t*)buf + 1), _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif return (size_t*)buf + 1; } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Failure!\n" ); #endif _gk_msg( "Error: _gk_for_ft_realloc() failed to allocate %d bytes!\n", size ); return 0; } } void _gk_for_ft_free(void *ptr) { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "_gk_for_ft_free(%p) (now %d + %d allocated) : ", ptr, _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif if (ptr) { size_t size = *((size_t*)ptr - 1); free( (size_t*)ptr - 1 ); _gk_allocated_by_ft -= size; _gk_overhead_by_ft -= sizeof(size_t); #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Freed %d bytes (now %d + %d allocated)\n", size, _gk_allocated_by_ft, _gk_overhead_by_ft ); #endif } else { #if defined(GLYPH_LOG) && defined(GLYPH_LOG_FT_MEMORY) if (glyph_log) fprintf( glyph_log, "Trying to free a 0 pointer!\n" ); #endif _gk_msg( "Error: trying to _gk_for_ft_free() a 0 pointer\n" ); } } #endif /* GLYPH_DEBUG_FT_MEMORY */ #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_to_allegro.c0000644000175000017500000006762510567602066024503 0ustar georgeskgeorgesk/* * glyph_to_allegro.c - part of Glyph Keeper Allegro driver. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c #define included_from_glyph_to_allegro_c #ifndef MAKE_VERSION #if (ALLEGRO_SUB_VERSION&1) #define MAKE_VERSION(a, b, c) (((a)<<16)|((b)<<8)|(c)) #else #define MAKE_VERSION(a, b, c) (((a)<<16)|((b)<<8)) #endif #endif /* MAKE_VERSION */ #ifdef GLYPH_TARGET_HAS_RECTFILL static void _gk_driver_rectfill(BITMAP* const bmp,const int x1,const int y1,const int x2,const int y2,const int color) { int cd = bitmap_color_depth(bmp); int c = makecol_depth(cd,(color>>16)&0xFF,(color>>8)&0xFF,color&0xFF); rectfill(bmp,x1,y1,x2,y2,c); } #ifdef GLYPH_TARGET_HAS_RECTFILL_ANGLED static void _gk_driver_rectfill_angled(BITMAP* const bmp,const int x1,const int y1, const int x2,const int y2,const int x3,const int y3,const int x4,const int y4,const int color) { int cd = bitmap_color_depth(bmp); int c = makecol_depth(cd,(color>>16)&0xFF,(color>>8)&0xFF,color&0xFF); triangle(bmp,x1,y1,x2,y2,x3,y3,c); triangle(bmp,x1,y1,x3,y3,x4,y4,c); } #endif /* GLYPH_TARGET_HAS_RECTFILL_ANGLED */ #endif /* GLYPH_TARGET_HAS_RECTFILL */ static BITMAP* bmp = 0; static int bitmap_acquired; static GLYPH_REND* rend = 0; static int coldepth; static int ct,cb,cl,cr; static unsigned alpha_color; static int alpha; static unsigned text_color; static int _gk_driver_back_color; /*int r,g,b*/ static unsigned _gk_driver_last_text_alpha_color; static int _gk_driver_last_back_color; static int _gk_driver_back_to_front[256]; static void (*drawer)(const GLYPH* const glyph,const int x0,const int y0) = 0; #ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK static unsigned last_monotrans_alpha_color = 0; static unsigned char rtrans[256], gtrans[256], btrans[256]; #endif /* GLYPH_TARGET_KNOWS_MONO_BITPACK */ #include "glyph_to_allegro_mono.c" #include "glyph_to_allegro_aa.c" static void _gk_prepare_to_draw(BITMAP* const new_bmp,GLYPH_REND* const new_rend) { CARE(new_bmp); CARE(new_rend); #ifdef GLYPH_LOG /*if (glyph_log) fprintf(glyph_log,"prepare_to_draw() begin\n");*/ #endif alpha_color = new_rend->text_alpha_color; alpha = alpha_color >> 24; if (!alpha) return; rend = new_rend; bmp = new_bmp; coldepth = bitmap_color_depth(bmp); if (bmp->clip) { ct = bmp->ct; cb = bmp->cb; cl = bmp->cl; cr = bmp->cr; } else { ct = 0; cb = bmp->h; cl = 0; cr = bmp->w; } /*int r = (alpha_color>>16)&0xFF; int g = (alpha_color>>8)&0xFF; int b = alpha_color&0xFF; text_color = makecol_depth(coldepth,r,g,b);*/ text_color = makecol_depth(coldepth,(alpha_color>>16)&0xFF,(alpha_color>>8)&0xFF,alpha_color&0xFF); if (rend->back_color >= 0) _gk_driver_back_color = makecol_depth(coldepth,(rend->back_color>>16)&0xFF,(rend->back_color>>8)&0xFF,rend->back_color&0xFF); else _gk_driver_back_color = -1; #ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK if (rend->render_mode == FT_RENDER_MODE_MONO) { if (alpha==255) { if (coldepth==32) drawer = &put_glyph_mono_opaque_32; else if (coldepth==16) drawer = &put_glyph_mono_opaque_16; else if (coldepth==8) drawer = &put_glyph_mono_opaque_8; else drawer = &put_glyph_mono; } else { if (coldepth==32) drawer = &put_glyph_mono_transparent_32; else if (coldepth==16) drawer = &put_glyph_mono_transparent_16; else drawer = &put_glyph_mono; } } else #endif { if ( (_gk_driver_back_color >= 0) && (coldepth > 8) && (alpha_color != _gk_driver_last_text_alpha_color || _gk_driver_back_color != _gk_driver_last_back_color) ) { int r = (alpha_color>>16)&0xFF; int g = (alpha_color>>8)&0xFF; int b = alpha_color&0xFF; int back_r = (_gk_driver_back_color>>16)&0xFF; int back_g = (_gk_driver_back_color>>8)&0xFF; int back_b = _gk_driver_back_color&0xFF; int i_r = ((r - back_r)<<16)/255; int i_g = ((g - back_g)<<16)/255; int i_b = ((b - back_b)<<16)/255; int rr = (back_r << 16) + 0x7FFF; int gg = (back_g << 16) + 0x7FFF; int bb = (back_b << 16) + 0x7FFF; int i; _gk_driver_back_to_front[0] = makecol_depth(coldepth,rr>>16,gg>>16,bb>>16); for (i=1; i<=255; i++) { rr += i_r; gg += i_g; bb += i_b; _gk_driver_back_to_front[i] = makecol_depth(coldepth,rr>>16,gg>>16,bb>>16); } _gk_driver_last_text_alpha_color = alpha_color; _gk_driver_last_back_color = _gk_driver_back_color; } if (coldepth==32) drawer = (_gk_driver_back_color == -1) ? &put_glyph_aa_32 : &put_glyph_aa_32_back; else if (coldepth==16) drawer = &put_glyph_aa_16; else if (coldepth==8) drawer = &put_glyph_aa_8; else drawer = &put_glyph_aa; } acquire_bitmap(bmp); bitmap_acquired = 1; #ifdef GLYPH_LOG /*if (glyph_log) fprintf(glyph_log,"prepare_to_draw() end\n");*/ #endif } static void _gk_done_drawing() { #ifdef GLYPH_LOG /*if (glyph_log) fprintf(glyph_log,"done_drawing() begin\n");*/ #endif if (bitmap_acquired) { release_bitmap(bmp); bitmap_acquired = 0; } #ifdef GLYPH_LOG /*if (glyph_log) fprintf(glyph_log,"done_drawing() end\n");*/ #endif } /* * This function must unload the glyph, if it is not cached */ static void _gk_put_glyph(GLYPH* const glyph,const int x,const int y) { CARE(glyph); CARE(bmp); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"put_glyph() begin: U+%04X\n",glyph->unicode); #endif if (glyph->bmp && (x < cr) && (y < cb) && (x+glyph->width > cl) && (y+glyph->height > ct) && (alpha) ) { #ifdef GLYPH_LOG if (glyph_log) { unsigned char format = *glyph->bmp; if (format==GLYPH_UNCOMPRESSED) { fprintf(glyph_log," \n"); } #ifdef GLYPH_TARGET_KNOWS_RLEAA else if (format==GLYPH_RLEAA) { fprintf(glyph_log," \n"); } #endif #ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK else if (format==GLYPH_MONO_BITPACK) { fprintf(glyph_log," \n"); } #endif #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 else if (format==GLYPH_MONO_RLE7) { fprintf(glyph_log," \n"); } #endif else fprintf(glyph_log," \n"); } #endif CARE(glyph->bmpsize); drawer(glyph,x,y); } if (!glyph->index) _gk_unload_glyph(glyph); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"put_glyph() end\n"); #endif } /*************************************************************************************** * * The following code is producing and handling Allegro FONT and VTABLE structures. */ static int gk_text_width_allegro(GLYPH_REND* const rend,AL_CONST char* const text) { int px = 0; AL_CONST char* c = text; unsigned code; if (!rend || !text) return 0; while ( (code = ugetxc(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; if (!glyph->index) _gk_unload_glyph(glyph); } } if (rend->text_angle == 0) { return (px + 63) >> 6; } else { return (abs(px) + abs((int)(sin(rend->text_angle)*rend->text_height)) + 63) >> 6; } } static void gk_text_advance_subpixel_allegro(GLYPH_REND* const rend,AL_CONST char* const text,int* const adv_x,int* const adv_y) { int px = 0, py = 0; AL_CONST char* c = text; unsigned code; if (!adv_x || !adv_y) return; if (!rend || !text) { *adv_x = *adv_y = 0; return; } while ( (code = ugetxc(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } *adv_x = px; *adv_y = py; } /*static void gk_text_advance_allegro(GLYPH_REND* const rend,AL_CONST char* const text,int* const adv_x,int* const adv_y) { gk_text_advance_subpixel_allegro(rend,text,adv_x,adv_y); *adv_x = (*adv_x+31)>>6; *adv_y = (*adv_y+31)>>6; }*/ static int _gk_vtable_font_height(AL_CONST FONT *f) { CARE(f); return f->height; } static int _gk_vtable_char_length(AL_CONST FONT *f,int ch) { CARE(f); if (!f->data) return 0; return gk_char_width((GLYPH_REND*)f->data,ch); } static int _gk_vtable_text_length(AL_CONST FONT *f,AL_CONST char *text) { GLYPH_REND* r; CARE(f && text); r = (GLYPH_REND*)f->data; if (!r) return 0; return gk_text_width_allegro(r,text); } static int _gk_vtable_render_char(AL_CONST FONT *f,int ch,int fg,int bg,BITMAP *bmp,int x,int y) { int adv = 0; int pen_x = x, pen_y = y, asc; GLYPH_REND* r; CARE(f && bmp); if (!f->data) return 0; r = (GLYPH_REND*)f->data; asc = gk_rend_ascender_pixels(r); gk_rend_set_text_color_rgb(r,getr(fg),getg(fg),getb(fg)); if (bg>=0) gk_rend_set_back_color(r,(getr(bg)<<16)|(getg(bg)<<8)|getb(bg)); else gk_rend_set_back_color(r,-1); if (r->text_angle == 0) { pen_y += asc; } else { pen_x += (int)(sin(r->text_angle)*asc); pen_y += (int)(cos(r->text_angle)*asc); } _gk_prepare_to_draw(bmp,r); #ifdef GLYPH_TARGET_HAS_RECTFILL if (r->back_color >= 0) { int ax,ay; gk_char_advance_subpixel(r,ch,&ax,&ay); if (ax || ay) _gk_draw_background_rectangle(bmp,r,pen_x,pen_y,ax,ay); } #endif pen_x <<= 6; pen_x <<= 6; _gk_internal_render_char(rend,ch,&pen_x,&pen_y); _gk_done_drawing(); /*glyph = _gk_rend_render(rend,ch); if (glyph) { adv = (glyph->advance_x+63)>>6; if (bg>=0 && r->text_angle==0) rectfill(bmp,x,y,x+adv,y+r->text_height_pixels-1,bg); put_glyph(glyph,x+glyph->left,y-glyph->top+gk_rend_ascender_pixels(r)); }*/ return adv; } static void _gk_vtable_render(AL_CONST FONT *f,AL_CONST char* text,int fg,int bg,BITMAP *bmp,int x,int y) { AL_CONST char* p = text; int ch = 0; GLYPH_REND* r; int tx,ty,asc; int pen_x = x, pen_y = y; CARE(f && text && bmp); if (!f->data) return; r = (GLYPH_REND*)f->data; asc = gk_rend_ascender_pixels(r); gk_rend_set_text_color_rgb(r,getr(fg),getg(fg),getb(fg)); if (bg>=0) gk_rend_set_back_color(r,(getr(bg)<<16)|(getg(bg)<<8)|getb(bg)); else gk_rend_set_back_color(r,-1); if (r->text_angle == 0) { pen_y += asc; } else { pen_x += (int)(r->text_angle_sin*asc); pen_y += (int)(r->text_angle_cos*asc); } _gk_prepare_to_draw(bmp,r); #ifdef GLYPH_TARGET_HAS_RECTFILL if (r->back_color >= 0) { int ax,ay; gk_text_advance_subpixel_allegro(r,text,&ax,&ay); if (ax || ay) _gk_draw_background_rectangle(bmp,r,pen_x,pen_y,ax,ay); } #endif tx = pen_x<<6; ty = pen_y<<6; while ( (ch = ugetxc(&p)) ) _gk_internal_render_char(rend,ch,&tx,&ty); _gk_done_drawing(); } /* * This function only destroys the FONT structure, not the renderer. */ static void _gk_vtable_destroy(FONT *f) { if (f) { if (f->data) ((GLYPH_REND*)f->data)->target_info = 0; free(f); } } #if MAKE_VERSION(ALLEGRO_VERSION,ALLEGRO_SUB_VERSION,ALLEGRO_WIP_VERSION) > MAKE_VERSION(4,1,18) static struct FONT_VTABLE font_vtable_gk = { _gk_vtable_font_height, _gk_vtable_char_length, _gk_vtable_text_length, _gk_vtable_render_char, _gk_vtable_render, _gk_vtable_destroy, 0, /*_gk_get_font_ranges,*/ 0, 0, 0, 0, 0 }; #elif MAKE_VERSION(ALLEGRO_VERSION,ALLEGRO_SUB_VERSION,ALLEGRO_WIP_VERSION) == MAKE_VERSION(4,1,18) static struct FONT_VTABLE font_vtable_gk = { _gk_vtable_font_height, _gk_vtable_char_length, _gk_vtable_text_length, _gk_vtable_render_char, _gk_vtable_render, _gk_vtable_destroy, 0, /*_gk_get_font_ranges,*/ 0, 0, 0, 0 }; #else /* MAKE_VERSION(...) < MAKE_VERSION(4,1,18) */ static struct FONT_VTABLE font_vtable_gk = { _gk_vtable_font_height, _gk_vtable_char_length, _gk_vtable_text_length, _gk_vtable_render_char, _gk_vtable_render, _gk_vtable_destroy }; #endif /* MAKE_VERSION(...) */ FONT* gk_create_allegro_font(GLYPH_REND* const rend) { FONT* f; if (!rend) return 0; if (rend->target_info) return rend->target_info; f = (FONT*)malloc(sizeof(FONT)); if (!f) return 0; f->data = rend; rend->target_info = f; f->height = rend->text_height_pixels; f->vtable = &font_vtable_gk; return f; } FONT* gk_create_allegro_bitmap_font_for_range(GLYPH_REND* const rend, const int range_start,const int range_end,const int color_depth) { FONT* f; double temp_text_angle; int temp_undefined_char, temp_error_char; int gk_back_color, gk_alpha; unsigned gk_text_alpha_color; int max_height_up = 0, max_height_down = 0, max_height = 0; int max_width_left = 0, max_width_right = 0, max_width = 0; int asc, desc; int i; BITMAP* temp_bmp = 0; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_create_allegro_bitmap_font_for_range() begin\n"); #endif if (!rend) return 0; if (range_end < range_start) return 0; f = (FONT*)malloc(sizeof(FONT)); if (!f) return 0; f->height = 0; f->data = 0; f->vtable = 0; /* Setting renderer for horizontal text, no error chars. */ temp_text_angle = rend->text_angle; if (rend->text_angle != 0) gk_rend_set_angle_in_radians(rend,0); temp_undefined_char = rend->undefined_char; gk_rend_set_undefined_char(rend,0); temp_error_char = rend->error_char; gk_rend_set_error_char(rend,0); gk_back_color = gk_rend_get_back_color(rend); gk_text_alpha_color = gk_rend_get_text_alpha_color(rend); gk_alpha = (gk_text_alpha_color >> 24) & 0xFF; asc = gk_rend_ascender_pixels(rend); desc = gk_rend_descender_pixels(rend); if (asc > max_height_up) max_height_up = asc; if (-desc > max_height_down) max_height_down = -desc; /* Finding max glyph size. */ for (i=range_start; i<=range_end; i++) { if (gk_rend_has_character(rend,i)) { GLYPH* glyph = _gk_rend_render(rend,i); if (glyph) { if (-glyph->left > max_width_left) max_width_left = -glyph->left; if (glyph->left + glyph->width > max_width_right) max_width_right = glyph->left + glyph->width; if (((glyph->advance_x+31)>>6) > max_width_right) max_width_right = ((glyph->advance_x+31)>>6); if (glyph->top > max_height_up) max_height_up = glyph->top; if (glyph->height - glyph->top > max_height_down) max_height_down = glyph->height - glyph->top; if (glyph && !glyph->index) _gk_unload_glyph(glyph); } } } max_width = max_width_left + max_width_right; max_height = max_height_up + max_height_down; f->height = max_height; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," max glyph size: %d x %d\n",max_width,max_height); #endif temp_bmp = create_bitmap_ex(32,max_width,max_height); if (!temp_bmp) { if (f) free(f); return 0; } if ( (rend->render_mode == FT_RENDER_MODE_MONO) && (gk_alpha == 0xFF) ) { FONT_MONO_DATA* first_data = 0; FONT_MONO_DATA* prev_data = 0; FONT_MONO_DATA* cur_data = 0; int c = range_start; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," making mono font\n"); #endif _gk_msg(" Creating a monochrome FONT\n"); gk_rend_set_text_alpha_color(rend,0xFFFFFFFF); gk_rend_set_back_color(rend,0); while (c <= range_end) { int begin, end; while (c <= range_end && !gk_rend_has_character(rend,c)) c++; if (c > range_end) break; begin = end = c; while (end <= range_end && gk_rend_has_character(rend,end)) end++; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Range: %d .. %d\n",begin,end-1); #endif /*_gk_msg(" Range: %d .. %d\n",begin,end-1);*/ cur_data = (FONT_MONO_DATA*)calloc(sizeof(FONT_MONO_DATA),1); if (!cur_data) break; cur_data->begin = begin; cur_data->end = end; cur_data->glyphs = (FONT_GLYPH**)calloc(end-begin,sizeof(FONT_GLYPH*)); cur_data->next = 0; for (c = begin; c < end; c++) { FONT_GLYPH* alglyph = 0; GLYPH* glyph = 0; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Char: %d\n",c); #endif /*_gk_msg(" Char: %d\n",c);*/ glyph = _gk_rend_render(rend,c); if (glyph) { int wl=0,wr=0,w,h,sx,j,k; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," rendered glyph: size = %d x %d, pos = (%d,%d)\n",glyph->width,glyph->height,glyph->left,glyph->top); #endif /*_gk_msg(" rendered %dx%d glyph\n",glyph->width,glyph->height);*/ if (-glyph->left > wl) wl = -glyph->left; if (glyph->left + glyph->width > wr) wr = glyph->left + glyph->width; if (((glyph->advance_x+31)>>6) > wr) wr = ((glyph->advance_x+31)>>6); w = wl + wr; h = max_height; sx = ((w + 7) / 8); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," output glyph size: %d x %d\n",w,h); if (glyph_log) fprintf(glyph_log," glyph data is %d bytes\n",sx*h); #endif /*_gk_msg(" effective size: %dx%d\n",w,h);*/ alglyph = (FONT_GLYPH*)calloc(sizeof(FONT_GLYPH) + sx * h, 1); if (!alglyph) { #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," can't allocate memory for alglyph\n"); #endif exit(1); } alglyph->w = w; alglyph->h = h; /*_gk_msg(" alglyph created\n");*/ clear(temp_bmp); /*_gk_msg(" bitmap cleared\n");*/ if (glyph->bmp) { /*_gk_msg(" printing a glyph\n");*/ _gk_prepare_to_draw(temp_bmp,rend); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," printing a %dx%d glyph at (%d,%d)\n",glyph->width,glyph->height,glyph->left+wl,max_height_up-glyph->top); #endif _gk_put_glyph(glyph,glyph->left+wl,max_height_up-glyph->top); _gk_done_drawing(); /*_gk_msg(" printed!\n");*/ } else { if (glyph && !glyph->index) _gk_unload_glyph(glyph); } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," printed\n"); #endif /*_gk_msg(" converting\n");*/ for (j=0; jdat[j] = 0; /*_gk_msg(" target cleared\n");*/ for (j=0; jdat[(j*sx)+(k/8)] |= 0x80 >> (k & 7); } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," converted\n"); #endif /*_gk_msg(" converted!\n");*/ } else { int j; _gk_msg(" no glyph!\n"); alglyph = (FONT_GLYPH*)malloc(sizeof(FONT_GLYPH) + 8); alglyph->w = 8; alglyph->h = 8; for (j=0; j<8; j++) alglyph->dat[j] = 0; } cur_data->glyphs[c-begin] = alglyph; } if (prev_data) prev_data->next = cur_data; else { first_data = cur_data; } prev_data = cur_data; cur_data = 0; } f->data = first_data; f->vtable = font_vtable_mono; } else { FONT_COLOR_DATA* first_data = 0; FONT_COLOR_DATA* prev_data = 0; FONT_COLOR_DATA* cur_data = 0; int c = range_start; int al_back_color; int gk_text_r, gk_text_g, gk_text_b; int transparent = (color_depth == 32) && ((rend->back_color < 0) || (gk_alpha < 0xFF)); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," making color font\n"); #endif if (transparent) _gk_msg(" Creating a color transparent FONT\n"); else _gk_msg(" Creating a color opaque FONT\n"); al_back_color = makecol_depth(color_depth,(gk_back_color>>16)&0xFF,(gk_back_color>>8)&0xFF,gk_back_color&0xFF); gk_text_r = (gk_text_alpha_color >> 16) & 0xFF; gk_text_g = (gk_text_alpha_color >> 8) & 0xFF; gk_text_b = gk_text_alpha_color & 0xFF; if (transparent) { gk_rend_set_text_alpha_color( rend, gk_text_alpha_color | 0xFFFFFF ); gk_rend_set_back_color(rend,0); } while (c <= range_end) { int begin, end; while (c <= range_end && !gk_rend_has_character(rend,c)) c++; if (c > range_end) break; begin = end = c; while (end <= range_end && gk_rend_has_character(rend,end)) end++; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Range: %d .. %d\n",begin,end-1); #endif /*_gk_msg(" Range: %d .. %d\n",begin,end-1);*/ /*cur_data = (FONT_COLOR_DATA*)calloc(sizeof(FONT_COLOR_DATA),1);*/ cur_data = (FONT_COLOR_DATA*)_AL_MALLOC(sizeof(FONT_COLOR_DATA)); if (!cur_data) { _gk_msg("Can't allocate memory for FONT_COLOR_DATA!\n"); break; } cur_data->begin = begin; cur_data->end = end; /*cur_data->bitmaps = (BITMAP**)calloc(end-begin,sizeof(BITMAP*));*/ cur_data->bitmaps = (BITMAP**)_AL_MALLOC( (end-begin) * sizeof(BITMAP*) ); if (!cur_data->bitmaps) { _gk_msg("Can't allocate memory for array of bitmaps!\n"); break; } memset( cur_data->bitmaps, 0, (end-begin) * sizeof(BITMAP*) ); cur_data->next = 0; for (c = begin; c < end; c++) { BITMAP* albmp = 0; GLYPH* glyph = 0; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Char: %d\n",c); #endif /*_gk_msg(" Char: %d\n",c);*/ glyph = _gk_rend_render(rend,c); if (glyph) { int wl=0,wr=0,w,h; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," rendered glyph: size = %d x %d, pos = (%d,%d)\n",glyph->width,glyph->height,glyph->left,glyph->top); #endif if (-glyph->left > wl) wl = -glyph->left; if (glyph->left + glyph->width > wr) wr = glyph->left + glyph->width; if (((glyph->advance_x+31)>>6) > wr) wr = ((glyph->advance_x+31)>>6); w = wl + wr; h = max_height; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," output glyph size: %d x %d\n",w,h); #endif albmp = create_bitmap_ex(color_depth,w,h); if (!albmp) { _gk_msg("Can't create allegro bitmap!\n"); break; } if (transparent) clear_to_color(albmp,0); else clear_to_color(albmp,al_back_color); if (glyph->bmp) { _gk_prepare_to_draw(albmp,rend); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," printing a %dx%d glyph at (%d,%d)\n",glyph->width,glyph->height,glyph->left+wl,max_height_up-glyph->top); #endif _gk_put_glyph(glyph,glyph->left+wl,max_height_up-glyph->top); _gk_done_drawing(); if (transparent) { int x,y; for (y=0; yindex) _gk_unload_glyph(glyph); } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," printed\n"); #endif } else { albmp = create_bitmap_ex(color_depth,8,8); if (!albmp) { _gk_msg("Can't create allegro bitmap!\n"); break; } clear_to_color(albmp,al_back_color); } cur_data->bitmaps[c-begin] = albmp; } if (prev_data) prev_data->next = cur_data; else { first_data = cur_data; } prev_data = cur_data; cur_data = 0; } f->data = first_data; if (transparent) f->vtable = font_vtable_trans; else f->vtable = font_vtable_color; } if (temp_text_angle) gk_rend_set_angle_in_radians(rend,temp_text_angle); gk_rend_set_undefined_char(rend,temp_undefined_char); gk_rend_set_error_char(rend,temp_error_char); gk_rend_set_text_alpha_color(rend,gk_text_alpha_color); gk_rend_set_back_color(rend,gk_back_color); if (temp_bmp) { destroy_bitmap(temp_bmp); temp_bmp = 0; } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_create_allegro_bitmap_font_for_range() end\n"); #endif return f; } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_global_vars.c0000644000175000017500000000524710567602066024637 0ustar georgeskgeorgesk/* * glyph_global_vars.c - Glyph Keeper global variables. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c /* * Version guard. */ static const int _gk_version_major = 0; static const int _gk_version_minor = 32; static const int _gk_version_patch = 0; static const int _gk_target = GLYPH_TARGET; /* * Log-file, */ #ifdef GLYPH_LOG static FILE* glyph_log = 0; #endif /* * Messenger function. */ static void (*_gk_messenger)(const char* const) = 0; /* * Font path */ static const char* _gk_font_path = 0; /* * Name of currently working routine, used for error reporting. * (FIXME: It is actually bad way to report errors.) */ static char* funcname = ""; /* * This variable is set to 1, if gk_library_cleanup() * shutdown handler is already installed with atexit(). */ static int _gk_atexit_installed = 0; /* * Internal buffer used for RLE compression. */ static unsigned char* rle_buffer = 0; static unsigned rle_buffer_size = 0; /* * FT_Bitmap for processing glyph rendered by FreeType. */ static FT_Bitmap _gk_workout_bitmap; /* * Endianness flag for UTF-16 decoding. * 0 if UTF-16 string being processed currently has same * byte order with the machine the program's running on. * 1 if the UTF-16 string being decoded currently has * wrong byte order, and need byte swapping. */ static int _gk_utf16_opposite_byte_sex = 0; /* * Endianness flag for UTF-32 decoding. */ static int _gk_utf32_opposite_byte_sex = 0; /* * FreeType library instance handle. */ static FT_Library ftlib = 0; /* * Number of currently used GLYPH_FACE objects. */ static unsigned face_count = 0; /* * First face ID number available. */ static unsigned face_first_free_id = 1; /* * Global list of GLYPH_FACE objects. */ static GLYPH_FACE *first_face = 0, *last_face = 0; /* * Global list of renderers. */ static GLYPH_REND *first_renderer = 0, *last_renderer = 0; /* * Global list of GLYPH_KEEP objects. */ static GLYPH_KEEP *first_keeper = 0, *last_keeper = 0; /* * Default return string for unavailable font properties. */ static const char _gk_na[] = "UNAVAILABLE"; /* * True measures of memory allocated by Glyph Keeper and FreeType. */ size_t _gk_allocated_by_gk = 0; size_t _gk_overhead_by_gk = 0; size_t _gk_allocated_by_ft = 0; size_t _gk_overhead_by_ft = 0; #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_dimensions.c0000644000175000017500000004656410567602066024523 0ustar georgeskgeorgesk/* * glyph_dimensions.c - Glyph Keeper routines for finding text size. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c /* * Advance is subpixel, returned coordinates are integer pixels. */ static void _gk_text_rectangle_by_advance(GLYPH_REND* const rend,const int adv_x,const int adv_y, int* const xlt,int* const ylt,int* const xlb,int* const ylb, int* const xrt,int* const yrt,int* const xrb,int* const yrb) { int asc = gk_rend_ascender(rend); int desc = gk_rend_descender(rend); int up_x, up_y; up_x = (int)(-rend->text_angle_sin * rend->text_height); up_y = (int)(-rend->text_angle_cos * rend->text_height); *xlb = (int)(rend->text_angle_sin * -desc); *ylb = (int)(rend->text_angle_cos * -desc); *xrb = *xlb + adv_x; *yrb = *ylb + adv_y; if (rend->italic_angle != 0) { double da = asc ? (tan(rend->italic_angle) * asc) : 0; double dd = desc ? (tan(rend->italic_angle) * desc) : 0; if (rend->italic_angle > 0) { *xlb += dd * rend->text_angle_cos; *ylb -= dd * rend->text_angle_sin; *xrb += da * rend->text_angle_cos; *yrb -= da * rend->text_angle_sin; } else { *xlb += da * rend->text_angle_cos; *ylb -= da * rend->text_angle_sin; *xrb += dd * rend->text_angle_cos; *yrb -= dd * rend->text_angle_sin; } } *xlt = (*xlb + up_x + 31) >> 6; *ylt = (*ylb + up_y + 31) >> 6; *xlb = (*xlb + 31) >> 6; *ylb = (*ylb + 31) >> 6; *xrt = (*xrb + up_x + 31) >> 6; *yrt = (*yrb + up_y + 31) >> 6; *xrb = (*xrb + 31) >> 6; *yrb = (*yrb + 31) >> 6; } /* * Advance is subpixel. */ static void _gk_text_dimensions_by_advance_angled(GLYPH_REND* const rend,const int adv_x,const int adv_y, int* const size_x,int* const size_y,int* const origin_x,int* const origin_y) { int xmin,ymin,xmax,ymax; int xlb,ylb,xrt,yrt,xrb,yrb; _gk_text_rectangle_by_advance(rend,adv_x,adv_y,&xmin,&ymin,&xlb,&ylb,&xrt,&yrt,&xrb,&yrb); xmax = xmin; ymax = ymin; if (xlb < xmin) xmin = xlb; if (xlb > xmax) xmax = xlb; if (ylb < ymin) ymin = ylb; if (ylb > ymax) ymax = ylb; if (xrt < xmin) xmin = xrt; if (xrt > xmax) xmax = xrt; if (yrt < ymin) ymin = yrt; if (yrt > ymax) ymax = yrt; if (xrb < xmin) xmin = xrb; if (xrb > xmax) xmax = xrb; if (yrb < ymin) ymin = yrb; if (yrb > ymax) ymax = yrb; *size_x = xmax-xmin+1; *size_y = ymax-ymin+1; *origin_x = -xmin; *origin_y = -ymin; } /* * Advance is subpixel. */ static void _gk_text_dimensions_by_advance_horizontal(GLYPH_REND* const rend,const int adv_x, int* const size_x,int* const size_y,int* const origin_x,int* const origin_y) { int sx = adv_x; int ox = 0; if (rend->italic_angle != 0) { sx += abs(tan(rend->italic_angle) * rend->text_height); if (rend->italic_angle > 0) ox -= tan(rend->italic_angle) * gk_rend_descender(rend); else ox -= tan(rend->italic_angle) * gk_rend_ascender(rend); } *size_x = (sx + 31) >> 6; *size_y = rend->text_height_pixels; *origin_x = (ox + 31) >> 6; *origin_y = (gk_rend_ascender(rend) + 31) >> 6; } /* * This function is useful to determine size in pixels of rendered text. * Smallest possible rectangle, containing rendered text, is constructed. * Size of this rectangle is written to 'size_x' and 'size_y'. * Position of text origin point, relative to the top left corner of rectangle, * is written to 'origin_x' and 'origin_y'. */ void gk_text_dimensions_utf8(GLYPH_REND* const rend,const char* const text, int* const size_x,int* const size_y,int* const origin_x,int* const origin_y) { int adv_x,adv_y; if (!rend || !text) { *size_x = *size_y = *origin_x = *origin_y = 0; return; } gk_text_advance_subpixel_utf8(rend,text,&adv_x,&adv_y); if (rend->text_angle != 0) { _gk_text_dimensions_by_advance_angled(rend,adv_x,adv_y,size_x,size_y,origin_x,origin_y); } else { _gk_text_dimensions_by_advance_horizontal(rend,adv_x,size_x,size_y,origin_x,origin_y); } } void gk_text_dimensions_utf16(GLYPH_REND* const rend,const unsigned short* const text, int* const size_x,int* const size_y,int* const origin_x,int* const origin_y) { int adv_x,adv_y; if (!rend || !text) { *size_x = *size_y = *origin_x = *origin_y = 0; return; } gk_text_advance_subpixel_utf16(rend,text,&adv_x,&adv_y); if (rend->text_angle != 0) { _gk_text_dimensions_by_advance_angled(rend,adv_x,adv_y,size_x,size_y,origin_x,origin_y); } else { _gk_text_dimensions_by_advance_horizontal(rend,adv_x,size_x,size_y,origin_x,origin_y); } } void gk_text_dimensions_utf32(GLYPH_REND* const rend,const unsigned* const text, int* const size_x,int* const size_y,int* const origin_x,int* const origin_y) { int adv_x,adv_y; if (!rend || !text) { *size_x = *size_y = *origin_x = *origin_y = 0; return; } gk_text_advance_subpixel_utf32(rend,text,&adv_x,&adv_y); if (rend->text_angle != 0) { _gk_text_dimensions_by_advance_angled(rend,adv_x,adv_y,size_x,size_y,origin_x,origin_y); } else { _gk_text_dimensions_by_advance_horizontal(rend,adv_x,size_x,size_y,origin_x,origin_y); } } /*************************************************************************** * * gk_text_size... */ void gk_glyph_size(GLYPH_REND* const rend,const unsigned unicode,int *const width,int* const height) { GLYPH *glyph; if (!width || !height) return; if (!rend || !unicode) { *width = *height = 0; return; } glyph = _gk_rend_render(rend,unicode); if (glyph) { *width = glyph->width; *height = glyph->height; if (!glyph->index) _gk_unload_glyph(glyph); } else { *width = 0; *height = 0; } } void gk_char_size(GLYPH_REND* const rend,const unsigned unicode,int *const width,int* const height) { GLYPH *glyph; if (!width || !height) return; if (!rend || !unicode) { *width = *height = 0; return; } glyph = _gk_rend_render(rend,unicode); if (glyph) { if (rend->text_angle == 0) { *width = (glyph->advance_x + 63) >> 6; *height = rend->text_height_pixels; } else { *width = (abs(glyph->advance_x) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; *height = (abs(glyph->advance_y) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; } if (!glyph->index) _gk_unload_glyph(glyph); } else { *width = 0; *height = 0; } } void gk_text_size_utf8(GLYPH_REND* const rend,const char* const text,int* const width,int* const height) { int px = 0, py = 0; const char* c = text; unsigned code; if (!width || !height) return; if (!rend || !text) { *width = *height = 0; return; } while ( (code = _gk_utf8_getx(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } if (rend->text_angle == 0) { *width = (px + 63) >> 6; *height = rend->text_height_pixels; } else { *width = (abs(px) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; *height = (abs(py) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; } } void gk_text_size_utf16(GLYPH_REND* const rend,const unsigned short* const text,int* const width,int* const height) { int px = 0, py = 0; const unsigned short* c = text; unsigned code; if (!width || !height) return; if (!rend || !text) { *width = *height = 0; return; } _gk_utf16_start_decoding(&c); while ( (code = _gk_utf16_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } if (rend->text_angle == 0) { *width = (px + 63) >> 6; *height = rend->text_height_pixels; } else { *width = (abs(px) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; *height = (abs(py) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; } } void gk_text_size_utf32(GLYPH_REND* const rend,const unsigned* const text,int* const width,int* const height) { int px = 0, py = 0; const unsigned* c = text; unsigned code; if (!width || !height) return; if (!rend || !text) { *width = *height = 0; return; } _gk_utf32_start_decoding(&c); while ( (code = _gk_utf32_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } if (rend->text_angle == 0) { *width = (px + 63) >> 6; *height = rend->text_height_pixels; } else { *width = (abs(px) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; *height = (abs(py) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; } } /*************************************************************************** * * gk_text_width... */ int gk_glyph_width(GLYPH_REND* const rend,const unsigned unicode) { GLYPH *glyph; int w = 0; if (!rend || !unicode) { return 0; } glyph = _gk_rend_render(rend,unicode); if (glyph) { w = glyph->width; if (!glyph->index) _gk_unload_glyph(glyph); } return w; } int gk_char_width(GLYPH_REND* const rend,const unsigned unicode) { GLYPH *glyph; int w = 0; if (!rend || !unicode) { return 0; } glyph = _gk_rend_render(rend,unicode); if (glyph) { if (rend->text_angle == 0) w = (glyph->advance_x + 63) >> 6; else w = (abs(glyph->advance_x) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; if (!glyph->index) _gk_unload_glyph(glyph); } return w; } int gk_text_width_utf8(GLYPH_REND* const rend,const char* const text) { int px = 0; const char* c = text; unsigned code; if (!rend || !text) return 0; while ( (code = _gk_utf8_getx(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; if (!glyph->index) _gk_unload_glyph(glyph); } } if (rend->text_angle == 0) { return (px + 63) >> 6; } else { return (abs(px) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; } } int gk_text_width_utf16(GLYPH_REND* const rend,const unsigned short* const text) { int px = 0; const unsigned short* c = text; unsigned code; if (!rend || !text) return 0; _gk_utf16_start_decoding(&c); while ( (code = _gk_utf16_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; if (!glyph->index) _gk_unload_glyph(glyph); } } if (rend->text_angle == 0) { return (px + 63) >> 6; } else { return (abs(px) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; } } int gk_text_width_utf32(GLYPH_REND* const rend,const unsigned* const text) { int px = 0; const unsigned* c = text; unsigned code; if (!rend || !text) { return 0; } _gk_utf32_start_decoding(&c); while ( (code = _gk_utf32_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; if (!glyph->index) _gk_unload_glyph(glyph); } } if (rend->text_angle == 0) { return (px + 63) >> 6; } else { return (abs(px) + abs((int)(rend->text_angle_sin*rend->text_height)) + 63) >> 6; } } /*************************************************************************** * * gk_text_height... */ int gk_glyph_height(GLYPH_REND* const rend,const unsigned unicode) { GLYPH *glyph; int h = 0; if (!rend || !unicode) { return 0; } glyph = _gk_rend_render(rend,unicode); if (glyph) { h = glyph->height; if (!glyph->index) _gk_unload_glyph(glyph); } return h; } int gk_char_height(GLYPH_REND* const rend,const unsigned unicode) { GLYPH *glyph; int h = 0; if (!rend || !unicode) { return 0; } glyph = _gk_rend_render(rend,unicode); if (glyph) { if (rend->text_angle == 0) h = rend->text_height_pixels; else h = (abs(glyph->advance_y) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; if (!glyph->index) _gk_unload_glyph(glyph); } return h; } int gk_text_height_utf8(GLYPH_REND* const rend,const char* const text) { if (!rend || !text) return 0; if (rend->text_angle == 0) { return rend->text_height_pixels; } else { int py = 0; const char* c = text; unsigned code; while ( (code = _gk_utf8_getx(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } return (abs(py) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; } } int gk_text_height_utf16(GLYPH_REND* const rend,const unsigned short* const text) { if (!rend || !text) return 0; if (rend->text_angle == 0) { return rend->text_height_pixels; } else { int py = 0; const unsigned short* c = text; unsigned code; _gk_utf16_start_decoding(&c); while ( (code = _gk_utf16_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } return (abs(py) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; } } int gk_text_height_utf32(GLYPH_REND* const rend,const unsigned* const text) { if (!rend || !text) return 0; if (rend->text_angle == 0) { return rend->text_height_pixels; } else { int py = 0; const unsigned* c = text; unsigned code; _gk_utf32_start_decoding(&c); while ( (code = _gk_utf32_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } return (abs(py) + abs((int)(rend->text_angle_cos*rend->text_height)) + 63) >> 6; } } /*************************************************************************** * * gk_text_advance_subpixel... */ void gk_char_advance_subpixel(GLYPH_REND* const rend,const unsigned unicode,int* const adv_x,int* const adv_y) { GLYPH *glyph; if (!adv_x || !adv_y) return; if (!rend || !unicode) { *adv_x = *adv_y = 0; return; } glyph = _gk_rend_render(rend,unicode); if (glyph) { *adv_x = glyph->advance_x; *adv_y = -glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } else { *adv_x = 0; *adv_y = 0; } } void gk_text_advance_subpixel_utf8(GLYPH_REND* const rend,const char* const text,int* const adv_x,int* const adv_y) { int px = 0, py = 0; const char* c = text; unsigned code; if (!adv_x || !adv_y) return; if (!rend || !text) { *adv_x = *adv_y = 0; return; } while ( (code = _gk_utf8_getx(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } *adv_x = px; *adv_y = py; } void gk_text_advance_subpixel_utf16(GLYPH_REND* const rend,const unsigned short* const text,int* const adv_x,int* const adv_y) { int px = 0, py = 0; const unsigned short* c = text; unsigned code; if (!adv_x || !adv_y) return; if (!rend || !text) { *adv_x = *adv_y = 0; return; } _gk_utf16_start_decoding(&c); while ( (code = _gk_utf16_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } *adv_x = px; *adv_y = py; } void gk_text_advance_subpixel_utf32(GLYPH_REND* const rend,const unsigned* const text,int* const adv_x,int* const adv_y) { int px = 0, py = 0; const unsigned* c = text; unsigned code; if (!adv_x || !adv_y) return; if (!rend || !text) { *adv_x = *adv_y = 0; return; } _gk_utf32_start_decoding(&c); while ( (code = _gk_utf32_decode(&c)) ) { GLYPH* glyph = _gk_rend_render(rend,code); if (glyph) { px += glyph->advance_x; py -= glyph->advance_y; if (!glyph->index) _gk_unload_glyph(glyph); } } *adv_x = px; *adv_y = py; } /*************************************************************************** * * gk_text_advance... */ void gk_char_advance(GLYPH_REND* const rend,const unsigned unicode,int* const adv_x,int* const adv_y) { gk_char_advance_subpixel(rend,unicode,adv_x,adv_y); *adv_x = (*adv_x+31)>>6; *adv_y = (*adv_y+31)>>6; } void gk_text_advance_utf8(GLYPH_REND* const rend,const char* const text,int* const adv_x,int* const adv_y) { gk_text_advance_subpixel_utf8(rend,text,adv_x,adv_y); *adv_x = (*adv_x+31)>>6; *adv_y = (*adv_y+31)>>6; } void gk_text_advance_utf16(GLYPH_REND* const rend,const unsigned short* const text,int* const adv_x,int* const adv_y) { gk_text_advance_subpixel_utf16(rend,text,adv_x,adv_y); *adv_x = (*adv_x+31)>>6; *adv_y = (*adv_y+31)>>6; } void gk_text_advance_utf32(GLYPH_REND* const rend,const unsigned* const text,int* const adv_x,int* const adv_y) { gk_text_advance_subpixel_utf32(rend,text,adv_x,adv_y); *adv_x = (*adv_x+31)>>6; *adv_y = (*adv_y+31)>>6; } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_memory.h0000644000175000017500000000177610567602066023664 0ustar georgeskgeorgesk/* * glyph_memory.h - Glyph Keeper header for memory manager. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef GLYPH_DEBUG_GK_MEMORY void* _gk_malloc(size_t size); void* _gk_calloc(size_t num_elements, size_t size); void* _gk_realloc(void *ptr, size_t size); void _gk_free(void *ptr); #else #define _gk_malloc malloc #define _gk_calloc calloc #define _gk_realloc realloc #define _gk_free free #endif #ifdef GLYPH_DEBUG_FT_MEMORY void* _gk_for_ft_malloc(size_t size); void* _gk_for_ft_calloc(size_t num_elements, size_t size); void* _gk_for_ft_realloc(void *ptr, size_t size); void _gk_for_ft_free(void *ptr); #else #define _gk_for_ft_malloc malloc #define _gk_for_ft_calloc calloc #define _gk_for_ft_realloc realloc #define _gk_for_ft_free free #endif openlayer-2.1.orig/utils/glyphkeeper/src/glyph_to_allegro_mono.c0000644000175000017500000005150710567602066025523 0ustar georgeskgeorgesk/* * glyph_to_allegro_mono.c - part of Glyph Keeper Allegro driver. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_to_allegro_c #ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK /* * General case code for printing a monochrome glyph to Allegro bitmap. */ static void put_glyph_mono(const GLYPH* const glyph,const int x0,const int y0) { if ( (alpha == 0xFF) || (coldepth <= 8) ) { solid_mode(); } else { drawing_mode(DRAW_MODE_TRANS,0,0,0); set_trans_blender(0,0,0,alpha); } #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 if (glyph->bmp[0]==GLYPH_MONO_RLE7) { int by = y0; int bxend = x0 + glyph->width; int byend = y0 + glyph->height; unsigned char* rlepos = glyph->bmp+1; if (byend>cb) byend = cb; while (bybmp[0]==GLYPH_MONO_BITPACK)*/ #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { int pitch = (glyph->width+7)>>3; int y = (y0 >= ct) ? y0 : ct; int yend = y0 + glyph->height; int xend = x0 + glyph->width; if (yend > cb) yend = cb; for (; ybmp + 1 + pitch*(y-y0); unsigned char* aend = a + pitch; while (aheight; int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; if (xr > cr) xr = cr; if (byend>cb) byend = cb; bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 if (glyph->bmp[0]==GLYPH_MONO_RLE7) { int by = y0; unsigned char* rlepos = glyph->bmp+1; for (; bywidth; while (bxwidth; while (addr=addr_l && addrbmp[0]==GLYPH_MONO_BITPACK)*/ #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { int pitch = (glyph->width+7)>>3; int by = (y0 >= ct) ? y0 : ct; for (; bybmp + 1 + pitch*(by-y0); unsigned char* aend = a + pitch; while (a=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addrheight; int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; if (xr > cr) xr = cr; if (byend>cb) byend = cb; bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 if (glyph->bmp[0]==GLYPH_MONO_RLE7) { int by = y0; unsigned char* rlepos = glyph->bmp+1; for (; bywidth; while (bxwidth; while (addr=addr_l && addrbmp[0]==GLYPH_MONO_BITPACK)*/ #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { int pitch = (glyph->width+7)>>3; int by = (y0 >= ct) ? y0 : ct; for (; bybmp + 1 + pitch*(by-y0); unsigned char* aend = a + pitch; while (a=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addrheight; int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; if (xr > cr) xr = cr; if (byend>cb) byend = cb; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"put_glyph_mono_opaque_8() begin\n"); #endif bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 if (glyph->bmp[0]==GLYPH_MONO_RLE7) { int by = y0; unsigned char* rlepos = glyph->bmp+1; for (; bywidth; while (bxwidth; while (addr=addr_l && addrbmp[0]==GLYPH_MONO_BITPACK)*/ #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { int pitch = (glyph->width+7)>>3; int by = (y0 >= ct) ? y0 : ct; for (; bybmp + 1 + pitch*(by-y0); unsigned char* aend = a + pitch; while (a=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addrheight; int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; if (xr > cr) xr = cr; if (byend>cb) byend = cb; if (last_monotrans_alpha_color!=alpha_color) { int alpha1 = (255-alpha)*257; int r = (alpha_color>>16)&0xFF; int g = (alpha_color>>8)&0xFF; int b = alpha_color&0xFF; int r_a = r*alpha*257+256; int g_a = g*alpha*257+256; int b_a = b*alpha*257+256; int n = 0; for (; n<256; n++) { rtrans[n] = (n*alpha1 + r_a)>>16; gtrans[n] = (n*alpha1 + g_a)>>16; btrans[n] = (n*alpha1 + b_a)>>16; } last_monotrans_alpha_color = alpha_color; } bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 if (glyph->bmp[0]==GLYPH_MONO_RLE7) { int by = y0; unsigned char* rlepos = glyph->bmp+1; for (; bywidth; while (addr=addr_l && addrbmp[0]==GLYPH_MONO_BITPACK)*/ #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { int pitch = (glyph->width+7)>>3; int by = (y0 >= ct) ? y0 : ct; for (; bybmp + 1 + pitch*(by-y0); unsigned char* aend = a + pitch; unsigned int v; while (a=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addrheight; int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; if (xr > cr) xr = cr; if (byend>cb) byend = cb; if (last_monotrans_alpha_color!=alpha_color) { int alpha1 = (255-alpha)*257; int r = (alpha_color>>16)&0xFF; int g = (alpha_color>>8)&0xFF; int b = alpha_color&0xFF; int r_a = r*alpha*257+256; int g_a = g*alpha*257+256; int b_a = b*alpha*257+256; int n = 0; for (; n<256; n++) { rtrans[n] = (n*alpha1 + r_a)>>16; gtrans[n] = (n*alpha1 + g_a)>>16; btrans[n] = (n*alpha1 + b_a)>>16; } last_monotrans_alpha_color = alpha_color; } bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 if (glyph->bmp[0]==GLYPH_MONO_RLE7) { int by = y0; unsigned char* rlepos = glyph->bmp+1; for (; bywidth; while (addr=addr_l && addrbmp[0]==GLYPH_MONO_BITPACK)*/ #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { int pitch = (glyph->width+7)>>3; int by = (y0 >= ct) ? y0 : ct; for (; bybmp + 1 + pitch*(by-y0); unsigned char* aend = a + pitch; unsigned short v; while (a=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr=addr_l && addr 128 -> 128 * I need to explain what it is. */ GLYPH ****pages; /* * What kind of glyphs are indexed. * These values are derived from the renderer - GLYPH_REND object. * Includes: font face, loading and rendering settings, * font size and angle settings. * Notice that this does not include any color information. */ unsigned face_id; unsigned load_flags; FT_Render_Mode render_mode; unsigned synth_flags; unsigned hsize,vsize; double text_angle; double italic_angle; int bold_strength; /* GLYPH_KEEP object, using this index */ GLYPH_KEEP *keeper; /* * List of GLYPH_REND objects, using this index * Once this object is dismissed, they will all be set to 'no cache' mode. */ GLYPH_REND *first_renderer,*last_renderer; /* list of indexes, corresponding to same GLYPH_KEEP object */ struct GLYPH_INDEX *prev,*next; } GLYPH_INDEX; /* * GLYPH_KEEP structure - a glyph cache entity. */ struct GLYPH_KEEP { /* * Maximum number of glyphs this cache can store. * 0 means no limit. */ int max_glyphs; /* * Maximum number of bytes this cache can use. * This includes the memory used by GLYPH_KEEP structure. * Set to 0 to disable memory limit. */ int max_memory; /* Number of currently cached glyphs. */ int num_glyphs; /* * Amount of memory in current use by this cache, in bytes. * This includes size of this GLYPH_KEEP structure, size of all * GLYPH_INDEX structures associated with this cache, * and also size of all glyphs cached currently. */ int allocated; /* * Head and tail of the double-linked list of GLYPH_INDEX objects. */ GLYPH_INDEX *first_index,*last_index; /* * Head and tail of the list of cached glyphs. */ GLYPH *head,*tail; /* * Global list of GLYPH_KEEP objects. * This is used for cleanup. */ struct GLYPH_KEEP *prev,*next; }; /* * GLYPH_REND structure - a glyph renderer. * */ struct GLYPH_REND { /* * Font face. */ GLYPH_FACE *face; unsigned face_id; /* * Corresponding GLYPH_INDEX object, if there is a cache assigned * to this renderer. * 0 if this renderer works without cache. */ GLYPH_INDEX *index; /* * FT_Size object - FreeType's size object. * It is necessary, since Glyph Keeper can share the same font face * among several renderers. */ FT_Size size; /* * One of the following: * FT_LOAD_DEFAULT = 0 * FT_LOAD_NO_HINTING - no any hinting is applied * FT_LOAD_FORCE_AUTOHINT * FT_LOAD_NO_AUTOHINT */ unsigned hinting_mode; /* * One of the following: * FT_LOAD_TARGET_MONO - hint outline for monochrome or lcd displays * FT_LOAD_TARGET_NORMAL - hint and render for normal anti-aliased displays */ unsigned hinting_target; /* * Glyph outline loading settings - OR'd combination of flags: * FT_LOAD_DEFAULT = 0 * FT_LOAD_VERTICAL_LAYOUT * FT_LOAD_PEDANTIC - more careful checking, reject broken fonts. * FT_LOAD_NO_BITMAP - always used, ignore bitmaps defined in the * font file * Also, it gets OR'd in 'hinting_mode' and 'hinting_target'. */ unsigned load_flags; /* * FreeType rendering mode. Possible values: * FT_RENDER_MODE_NORMAL (default) - 256 grey tones. * FT_RENDER_MODE_LIGHT - I don't know what it is. * FT_RENDER_MODE_MONO - Monochrome rendering. */ FT_Render_Mode render_mode; /* * Font size settings. * 'hsize' and 'vsize' is a EM box size, in 1/64th of a pixel. */ unsigned hsize,vsize; /* * Substitution character for any 'undefined' character - not defined in * font. '?' is default (U+003F). */ unsigned undefined_char; /* * Sometimes the character glyph is defined in font face, but some error * happens when trying to render it. In such case 'error_char' will appear * instead of the failed character. */ unsigned error_char; /* Spacing between two lines of text, in 1/64th of a pixel. */ unsigned line_spacing; /* Spacing between two lines of text, in pixels. */ unsigned line_spacing_pixels; /* Maximum height of text in 1/64th of a pixel. */ unsigned text_height; /* Maximum height of text in pixels. */ /* Calculated as (ascender + descender) */ unsigned text_height_pixels; /* Text rotation angle, in radians */ double text_angle; /* Sine and cosine of the angle to not re-compute them */ double text_angle_cos; double text_angle_sin; /* Italicizing angle, in radians */ double italic_angle; /* Strength of emboldening */ int bold_strength; /* True if this renderer uses glyph transformation */ int do_matrix_transform; /* Transformation matrix */ FT_Matrix matrix; /*long matrix[4];*/ /* Text alpha and color - (a<<24) | (r<<16) | (g<<8) | b */ unsigned text_alpha_color; /* Background color. Normally -1 which means transparent. */ /* Otherwise depth-independent value: (r<<16) | (g<<8) | b */ int back_color; /* * Renderers to be automatically used to render the same character before, and after the * character is rendered with this renderer. */ GLYPH_REND *before_rend, *after_rend; /* * Offset of the glyph rendered before and after. Offset is relative to the test origin * point, so positive x axis goes right, positive y axis goes up. */ int before_dx, before_dy, after_dx, after_dy; /* * Points to the target-specific info used for better integration with the target. * Currently only Allegro target is using this. */ void* target_info; /* * Global list of GLYPH_REND objects. */ GLYPH_REND *prev,*next; /* * List of GLYPH_REND objects rendering characters in the same font face. */ GLYPH_REND *prev_for_same_face,*next_for_same_face; /* * List of GLYPH_REND objects sharing the same GLYPH_INDEX. */ GLYPH_REND *prev_for_same_index,*next_for_same_index; }; #endif openlayer-2.1.orig/utils/glyphkeeper/src/glyph_face.c0000644000175000017500000004363110567602066023241 0ustar georgeskgeorgesk/* * glyph_face.c - Glyph Keeper routines dealing with the font face objects. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c static void _gk_find_mapping(GLYPH_FACE* const face1,unsigned code1,GLYPH_FACE** face2,unsigned* code2); const char* gk_face_family(const GLYPH_FACE* const f) { return (f && f->face && f->face->family_name) ? f->face->family_name : _gk_na; } const char* gk_face_style(const GLYPH_FACE* const f) { return (f && f->face && f->face->style_name) ? f->face->style_name : _gk_na; } const char* gk_face_postscript_name(const GLYPH_FACE* const f) { const char* ps_name; if (!f || !f->face) return _gk_na; ps_name = FT_Get_Postscript_Name(f->face); return ps_name ? ps_name : _gk_na; } const char* gk_face_driver_name(const GLYPH_FACE* const f) { if (!f || !f->face) return _gk_na; /* return (f && f->face && f->face->driver && f->face->driver->root.clazz && f->face->driver->root.clazz->module_name) ? f->face->driver->root.clazz->module_name : _gk_na;*/ return _gk_na; } int gk_face_get_number_of_charmaps(const GLYPH_FACE* const f) { if (!f || !f->face) return 0; return f->face->num_charmaps; } int gk_face_is_scalable(const GLYPH_FACE* const f) { return (f && f->face) ? FT_IS_SCALABLE(f->face) : 0; } int gk_face_is_horizontal(const GLYPH_FACE* const f) { return (f && f->face) ? FT_HAS_HORIZONTAL(f->face) : 0; } int gk_face_is_vertical(const GLYPH_FACE* const f) { return (f && f->face) ? FT_HAS_VERTICAL(f->face) : 0; } int gk_face_ascender(const GLYPH_FACE* const f) { return (f && f->face) ? f->face->ascender : 0; } int gk_face_descender(const GLYPH_FACE* const f) { return (f && f->face) ? f->face->descender : 0; } int gk_face_line_spacing(const GLYPH_FACE* const f) { return (f && f->face) ? f->face->height : 0; } int gk_face_number_of_glyphs(const GLYPH_FACE* const f) { return (f && f->face) ? f->face->num_glyphs : 0; } /* This code is slow, but theoretically more safe */ /*int gk_face_number_of_characters_safe(const GLYPH_FACE* const f) { unsigned i,num=0; if (!f || !f->face) return 0; for (i=0; i<=GK_MAX_UNICODE; i++) if (FT_Get_Char_Index(f->face,i)) num++; return num; }*/ int gk_face_number_of_own_characters(GLYPH_FACE* const f) { if (!f || !f->face) return 0; if (f->number_of_own_characters < 0) { FT_ULong charcode; FT_UInt gindex; unsigned num = 0; charcode = FT_Get_First_Char(f->face,&gindex); while (gindex != 0) { if (charcode <= 0xD7FF || (charcode >= 0xE000 && charcode <= GK_MAX_UNICODE) ) num++; charcode = FT_Get_Next_Char(f->face,charcode,&gindex); } f->number_of_own_characters = num; return num; } else { return f->number_of_own_characters; } } int gk_face_number_of_own_characters_in_range(GLYPH_FACE* const f,const unsigned start,const unsigned end) { FT_ULong charcode; FT_UInt gindex; unsigned num = 0; if (!f || !f->face) return 0; if (start>=end) return 0; charcode = FT_Get_First_Char(f->face,&gindex); while (gindex != 0) { if (charcode <= 0xD7FF || (charcode >= 0xE000 && charcode <= GK_MAX_UNICODE) ) if (charcode >= start && charcode < end) num++; charcode = FT_Get_Next_Char(f->face,charcode,&gindex); } return num; } int gk_face_number_of_characters(GLYPH_FACE* const face) { int num = 0; if (!face) return 0; if (!face->remap) return gk_face_number_of_own_characters(face); if (face->number_of_own_characters < 0) gk_face_number_of_own_characters(face); if (face->number_of_own_characters >= 0) num = face->number_of_own_characters; return num + face->remap_increment; } int gk_face_has_own_character(GLYPH_FACE* const face,const unsigned code) { if (!face || !face->face) return 0; if (code > GK_MAX_UNICODE) return 0; if (code >= 0xD800 && code <= 0xDFFF) return 0; return (FT_Get_Char_Index(face->face,code) != 0); } int gk_face_has_character(GLYPH_FACE* const face,const unsigned code) { GLYPH_FACE* actual_face; unsigned actual_code; if (!face) return 0; if (code > GK_MAX_UNICODE) return 0; _gk_find_mapping(face,code,&actual_face,&actual_code); if (!actual_face || !actual_face->face) return 0; if (actual_code > GK_MAX_UNICODE) return 0; if (actual_code >= 0xD800 && actual_code <= 0xDFFF) return 0; return (FT_Get_Char_Index(actual_face->face,actual_code) != 0); } GLYPH_FACE* gk_create_empty_face() { GLYPH_FACE* f; funcname = "gk_create_empty_face()"; f = (GLYPH_FACE*)_gk_malloc(sizeof(GLYPH_FACE)); if (!f) return 0; f->face = 0; f->own_size = 0; f->remap = 0; f->number_of_own_characters = 0; f->remap_increment = 0; f->first_renderer = 0; f->last_renderer = 0; f->allocated = sizeof(GLYPH_FACE); face_count++; f->id = face_first_free_id++; f->next = 0; f->prev = last_face; if (last_face) last_face->next = f; if (!first_face) first_face = f; last_face = f; return f; } GLYPH_FACE* _gk_load_face_from_file(const char* const fname,const int face_index, const int gk_header_version, const int gk_header_target ) { GLYPH_FACE* f; char buf[1000] = ""; funcname = "gk_load_face_from_file()"; if (gk_header_version != GK_MAKE_VERSION(_gk_version_major,_gk_version_minor,_gk_version_patch)) { _gk_msg("Error: Glyph Keeper library and header versions don't match\n"); return 0; } if (_gk_target != gk_header_target) { _gk_msg("Error: Glyph Keeper library and your program have different targets (GLYPH_TARGET)\n"); return 0; } if (!fname || !*fname || face_index<0) return 0; /* Trying to initialize FreeType. */ if (!ftlib) { gk_library_init(); if (!ftlib) { _gk_msg("Error: %s: Can't initialize FreeType\n",funcname); return 0; } } /* characters that are normally not contained in a filename */ /*if (strpbrk(fname,"\n\r\t\f\v\"*")) { _gk_msg("Error: %s: Can't load font face: invalid filename \"%s\"\n",funcname,fname); return 0; }*/ /* Checking if the file exists and is available to open */ { FILE* file = fopen(fname,"rb"); if (!file && _gk_font_path && *_gk_font_path) { int fname_length = strlen(fname); const char *c = _gk_font_path; while (!file && c && *c) { int dirname_length; char *c2 = strchr(c,';'); if (!c2) c2 = strchr(c,0); dirname_length = c2-c; if (dirname_length + fname_length < 1000) { strncpy(buf,c,dirname_length); strncpy(buf+dirname_length,fname,fname_length); buf[dirname_length+fname_length] = 0; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"Trying to open file :::%s:::\n",buf); #endif file = fopen(buf,"rb"); } if (!*c2) break; c = c2+1; } } if (!file) { _gk_msg("Error: %s: Can't find font file \"%s\"\n",funcname,fname); return 0; } fclose(file); } /* _gk_msg("loading font face %d from file \"%s\"\n",face_index,fname); */ f = (GLYPH_FACE*)_gk_malloc(sizeof(GLYPH_FACE)); if (!f) return 0; f->face = 0; f->own_size = 0; f->remap = 0; f->number_of_own_characters = -1; f->remap_increment = 0; f->first_renderer = 0; f->last_renderer = 0; f->allocated = sizeof(GLYPH_FACE); { int error = FT_New_Face(ftlib,*buf?buf:fname,face_index,&f->face); if (error || !f->face) { if (error == FT_Err_Unknown_File_Format) _gk_msg("Error: %s: Can't load font face from \"%s\": unknown file format\n",funcname,*buf?buf:fname); else _gk_msg("Error: %s: Can't load font face from \"%s\"\n",funcname,*buf?buf:fname); _gk_free(f); return 0; } } /*if (!FT_IS_SCALABLE(f->face)) { _gk_msg("Error: %s: Font face is not scalable\n",funcname); FT_Done_Face(f->face); _gk_free(f); return 0; } if (FT_Select_Charmap(f->face,ft_encoding_unicode)) { _gk_msg("Error: %s: Font face does not contain Unicode character map\n",funcname); FT_Done_Face(f->face); _gk_free(f); return 0; }*/ FT_Select_Charmap(f->face,ft_encoding_unicode); f->own_size = f->face->size; face_count++; f->id = face_first_free_id++; f->next = 0; f->prev = last_face; if (last_face) last_face->next = f; if (!first_face) first_face = f; last_face = f; _gk_msg("font face loaded from file \"%s\"\n",f->id,*buf?buf:fname); return f; } GLYPH_FACE* _gk_load_face_from_memory(const unsigned char* const data,const int size,const int face_index, const int gk_header_version,const int gk_header_target) { GLYPH_FACE* f; funcname = "gk_load_face_from_memory()"; if (gk_header_version != GK_MAKE_VERSION(_gk_version_major,_gk_version_minor,_gk_version_patch)) { _gk_msg("Error: Glyph Keeper library and header versions don't match\n"); return 0; } if (_gk_target != gk_header_target) { _gk_msg("Error: Glyph Keeper library and your program have different targets (GLYPH_TARGET)\n"); return 0; } if (!data || !size || face_index<0) return 0; if (!ftlib) gk_library_init(); if (!ftlib) { _gk_msg("Error: %s: Can't initialize FreeType\n",funcname); return 0; } f = (GLYPH_FACE*)_gk_malloc(sizeof(GLYPH_FACE)); if (!f) return 0; f->face = 0; f->own_size = 0; f->remap = 0; f->number_of_own_characters = -1; f->remap_increment = 0; f->first_renderer = 0; f->last_renderer = 0; f->allocated = sizeof(GLYPH_FACE); { int error = FT_New_Memory_Face(ftlib,data,size,face_index,&f->face); if (error || !f->face) { if (error == FT_Err_Unknown_File_Format) _gk_msg("Error: %s: Can't load font face - unknown data format\n",funcname); else _gk_msg("Error: %s: Can't load font face\n",funcname); _gk_free(f); return 0; } } /*if (!FT_IS_SCALABLE(f->face)) { _gk_msg("Error: %s: Font face is not scalable\n",funcname); FT_Done_Face(f->face); _gk_free(f); return 0; } if (FT_Select_Charmap(f->face,ft_encoding_unicode)) { _gk_msg("Error: %s: Font face does not contain Unicode character map\n",funcname); FT_Done_Face(f->face); _gk_free(f); return 0; }*/ FT_Select_Charmap(f->face,ft_encoding_unicode); f->own_size = f->face->size; face_count++; f->id = face_first_free_id++; f->next = 0; f->prev = last_face; if (last_face) last_face->next = f; if (!first_face) first_face = f; last_face = f; _gk_msg("font face loaded from memory\n",f->id); return f; } void gk_unload_face(GLYPH_FACE* const f) { unsigned id; if (!f) return; id = f->id; if (f->remap) { int a,b; for (a=0; a<68; a++) if (f->remap[a]) { GLYPH_REMAP** page_b = f->remap[a]; for (b=0; b<128; b++) if (page_b[b]) _gk_free(page_b[b]); _gk_free(page_b); } _gk_free(f->remap); } while (f->first_renderer) { GLYPH_REND* r = f->first_renderer; f->first_renderer = f->first_renderer->next_for_same_face; gk_rend_set_face(r,0); } if (f->face) { FT_Done_Face(f->face); f->face = 0; } if (f==first_face) first_face = f->next; if (f==last_face) last_face = f->prev; if (f->next) f->next->prev = f->prev; if (f->prev) f->prev->next = f->next; face_count--; _gk_free(f); _gk_msg("font face unloaded\n",id); } /* * Remapping. * This function finds a substitution character and font face. * 'face1', 'face2' and 'code2' must be not 0. * 'code1' must be in range 0..GK_MAX_UNICODE. */ static void _gk_find_mapping(GLYPH_FACE* const face1,unsigned code1,GLYPH_FACE** face2,unsigned* code2) { CARE(face1 && face2 && code2); CARE(code1<=GK_MAX_UNICODE); if (face1->remap) { GLYPH_REMAP** page_b = face1->remap[code1 >> 14]; if (page_b) { GLYPH_REMAP* page_c = page_b[(code1 & 0x3FFF) >> 7]; if (page_c) { GLYPH_REMAP* remap_entry = &page_c[code1 & 0x7F]; if (remap_entry->face) { *face2 = remap_entry->face; *code2 = remap_entry->code; return; } } } } *face2 = face1; *code2 = code1; } /* * Adds a mapping so that whenever face1.code1 character is requested, * face2.code2 glyph will be rendered instead. */ void gk_remap_character(GLYPH_FACE* const face1,const unsigned code1,GLYPH_FACE* const face2,const unsigned code2) { GLYPH_FACE* new_face = face2; unsigned new_code = code2; int a_index, b_index; int a_size = 0, b_size = 0, c_size = 0; GLYPH_REMAP** b_page; GLYPH_REMAP* c_page; GLYPH_REMAP* remap_entry; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_remap_character(%d,%d,%d,%d) begin\n", (int)face1,code1,(int)face2,code2); #endif funcname = "gk_remap_character()"; if (!face1) return; if (code1>GK_MAX_UNICODE) return; if (code1>=0xD800 && code1<=0xDFFF) return; if (new_code>GK_MAX_UNICODE || (new_code>=0xD800 && new_code<=0xDFFF)) { new_face = 0; new_code = 0; } if (!new_face) { gk_unmap_character(face1,code1); return; } if (!face1->remap) { a_size = 68*sizeof(void*) + sizeof(int); face1->remap = (GLYPH_REMAP***)_gk_malloc(a_size); if (!face1->remap) return; memset(face1->remap,0,a_size); } a_index = code1 >> 14; if (!face1->remap[a_index]) { const int b_size = 128*sizeof(void*) + sizeof(int); face1->remap[a_index] = (GLYPH_REMAP**)_gk_malloc(b_size); if (!face1->remap[a_index]) { if (a_size) { _gk_free(face1->remap); face1->remap = 0; } return; } (*(int*)(face1->remap+68))++; memset(face1->remap[a_index],0,b_size); } b_page = face1->remap[a_index]; b_index = (code1 & 0x3FFF) >> 7; if (!b_page[b_index]) { const int c_size = 128*sizeof(GLYPH_REMAP) + sizeof(int); b_page[b_index] = (GLYPH_REMAP*)_gk_malloc(c_size); if (!b_page[b_index]) { if (b_size) { _gk_free(b_page); face1->remap[a_index] = 0; (*(int*)(face1->remap+68))--; } if (a_size) { _gk_free(face1->remap); face1->remap = 0; } return; } (*(int*)(b_page+128))++; memset(b_page[b_index],0,c_size); } face1->allocated += a_size + b_size + c_size; c_page = b_page[b_index]; remap_entry = &c_page[code1 & 0x7F]; if (remap_entry->face == 0) { (*(int*)(c_page+128))++; if (!gk_face_has_own_character(face1,code1)) face1->remap_increment++; } remap_entry->face = new_face; remap_entry->code = new_code; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_remap_character(%d,%d,%d,%d) success\n", (int)face1,code1,(int)face2,code2); #endif } void gk_unmap_character(GLYPH_FACE* const face,const unsigned code) { GLYPH_REMAP **b_page, *c_page, *remap_entry; int a_index, b_index, c_index; if (!face || code>GK_MAX_UNICODE) return; if (!face->remap) return; a_index = code >> 14; b_page = face->remap[a_index]; if (!b_page) return; b_index = (code & 0x3FFF) >> 7; c_page = b_page[b_index]; if (!c_page) return; c_index = code & 0x7F; remap_entry = &c_page[c_index]; /* Not remapped, nothing to do. */ if (remap_entry->face == 0) return; if (!gk_face_has_own_character(face,code)) face->remap_increment--; remap_entry->face = 0; remap_entry->code = 0; (*(int*)(c_page+128))--; if (*(int*)(c_page+128) > 0) return; _gk_free(c_page); b_page[b_index] = 0; face->allocated -= 128*sizeof(GLYPH_REMAP) + sizeof(int); (*(int*)(b_page+128))--; if (*(int*)(b_page+128) > 0) return; _gk_free(b_page); face->remap[a_index] = 0; face->allocated -= 128*sizeof(void*) + sizeof(int); (*(int*)(face->remap+68))--; if (*(int*)(face->remap+68) > 0) return; _gk_free(face->remap); face->remap = 0; face->allocated -= 68*sizeof(void*) + sizeof(int); } void gk_remap_range(GLYPH_FACE* const face1,const unsigned code1, GLYPH_FACE* const face2,const unsigned code2,const unsigned range_size) { unsigned i; for (i=0; (i>16)&0xFF; unsigned g = (color>>8)&0xFF; unsigned b = (color)&0xFF; boxColor(bmp,x1,y1,x2,y2,(r<<24)|(g<<16)|(b<<8)|255); if (x1 < _gk_x_min) _gk_x_min = x1; if (x2 < _gk_x_min) _gk_x_min = x2; if (x1 > _gk_x_max) _gk_x_max = x1; if (x2 > _gk_x_max) _gk_x_max = x2; if (y1 < _gk_y_min) _gk_y_min = y1; if (y2 < _gk_y_min) _gk_y_min = y2; if (y1 > _gk_y_max) _gk_y_max = y1; if (y2 > _gk_y_max) _gk_y_max = y2; } #ifdef GLYPH_TARGET_HAS_RECTFILL_ANGLED static void _gk_driver_rectfill_angled(SDL_Surface* const bmp,const int x1,const int y1, const int x2,const int y2,const int x3,const int y3,const int x4,const int y4,const int color) { unsigned r = (color>>16)&0xFF; unsigned g = (color>>8)&0xFF; unsigned b = (color)&0xFF; short vx[4], vy[4]; vx[0] = x1; vx[1] = x2; vx[2] = x3; vx[3] = x4; vy[0] = y1; vy[1] = y2; vy[2] = y3; vy[3] = y4; filledPolygonColor(bmp,vx,vy,4,(r<<24)|(g<<16)|(b<<8)|255); if (x1 < _gk_x_min) _gk_x_min = x1; if (x2 < _gk_x_min) _gk_x_min = x2; if (x3 < _gk_x_min) _gk_x_min = x3; if (x4 < _gk_x_min) _gk_x_min = x4; if (x1 > _gk_x_max) _gk_x_max = x1; if (x2 > _gk_x_max) _gk_x_max = x2; if (x3 > _gk_x_max) _gk_x_max = x3; if (x4 > _gk_x_max) _gk_x_max = x4; if (y1 < _gk_y_min) _gk_y_min = y1; if (y2 < _gk_y_min) _gk_y_min = y2; if (y3 < _gk_y_min) _gk_y_min = y3; if (y4 < _gk_y_min) _gk_y_min = y4; if (y1 > _gk_y_max) _gk_y_max = y1; if (y2 > _gk_y_max) _gk_y_max = y2; if (y3 > _gk_y_max) _gk_y_max = y3; if (y4 > _gk_y_max) _gk_y_max = y4; } #endif #endif static void (*_gk_driver_drawer)(const GLYPH* const glyph,const int x0,const int y0) = 0; static void _gk_put_glyph_any(const GLYPH* const glyph,const int x0,const int y0) { int bxend = x0 + glyph->width; int byend = y0 + glyph->height; if (byend > _gk_clip_bottom) byend = _gk_clip_bottom; CARE(glyph); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_put_glyph_any() begin\n"); #endif { int by = (y0 >= _gk_clip_top) ? y0 : _gk_clip_top; for (; bybmp + 1 + glyph->width*(by-y0); while (bx0) { pixelRGBA(_gk_bmp,bx,by,_gk_r,_gk_g,_gk_b,a); } bx++; } } } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_put_glyph_any() end\n"); #endif } static void _gk_prepare_to_draw(SDL_Surface* const new_bmp,GLYPH_REND* const new_rend) { #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_prepare_to_draw() begin\n"); #endif _gk_bmp = 0; CARE(new_bmp); CARE(new_rend); if (!new_bmp->format) return; _gk_alpha_color = new_rend->text_alpha_color; _gk_alpha = _gk_alpha_color >> 24; if (!_gk_alpha) return; if (SDL_MUSTLOCK(new_bmp)) if (SDL_LockSurface(new_bmp) < 0) return; _gk_rend = new_rend; _gk_bmp = new_bmp; _gk_driver_coldepth = new_bmp->format->BitsPerPixel; _gk_driver_bytes_per_pixel = new_bmp->format->BytesPerPixel; _gk_clip_left = _gk_bmp->clip_rect.x; _gk_clip_right = _gk_clip_left + _gk_bmp->clip_rect.w; _gk_clip_top = _gk_bmp->clip_rect.y; _gk_clip_bottom = _gk_clip_top + _gk_bmp->clip_rect.h; _gk_r_mask = _gk_bmp->format->Rmask; _gk_g_mask = _gk_bmp->format->Gmask; _gk_b_mask = _gk_bmp->format->Bmask; _gk_a_mask = _gk_bmp->format->Amask; _gk_x_min = _gk_bmp->w; _gk_y_min = _gk_bmp->h; _gk_x_max = 0; _gk_y_max = 0; _gk_r = (_gk_alpha_color>>16)&0xFF; _gk_g = (_gk_alpha_color>>8)&0xFF; _gk_b = (_gk_alpha_color)&0xFF; _gk_color = SDL_MapRGBA(_gk_bmp->format,_gk_r,_gk_g,_gk_b,255); if (_gk_last_alpha_used != _gk_alpha) { int a1 = (_gk_alpha<<16)/255; int i=0; for (; i<256; i++) { _gk_alpha_gradient[i] = (i*a1)>>16; } _gk_last_alpha_used = _gk_alpha; } _gk_driver_drawer = &_gk_put_glyph_any; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_prepare_to_draw() end\n"); #endif } static void _gk_done_drawing() { #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_done_drawing() begin\n"); #endif if (_gk_bmp) { if (SDL_MUSTLOCK(_gk_bmp)) { SDL_UnlockSurface(_gk_bmp); } if (_gk_x_min < _gk_clip_left) _gk_x_min = _gk_clip_left; if (_gk_x_max > _gk_clip_right) _gk_x_max = _gk_clip_right; if (_gk_y_min < _gk_clip_top) _gk_y_min = _gk_clip_top; if (_gk_y_max > _gk_clip_bottom) _gk_y_max = _gk_clip_bottom; if ( (_gk_x_min < _gk_x_max) && (_gk_y_min < _gk_y_max) ) { SDL_UpdateRect(_gk_bmp, _gk_x_min, _gk_y_min, _gk_x_max-_gk_x_min, _gk_y_max-_gk_y_min); } _gk_bmp = 0; } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_done_drawing() end\n"); #endif } static void _gk_put_glyph(GLYPH* const glyph,const int x,const int y) { CARE(glyph); /*CARE(_gk_bmp);*/ #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"\n_gk_put_glyph() begin\n"); if (glyph_log) fprintf(glyph_log," glyph U+%04X [%dx%d] --> (%d,%d)\n", glyph->unicode,glyph->width,glyph->height,x,y); #endif if (glyph->bmp && _gk_bmp && (x < _gk_clip_right) && (y < _gk_clip_bottom) && (x + glyph->width > _gk_clip_left) && (y + glyph->height > _gk_clip_top) && _gk_alpha) { CARE(glyph->bmpsize); _gk_driver_drawer(glyph,x,y); if (x < _gk_x_min) _gk_x_min = x; if (y < _gk_y_min) _gk_y_min = y; if (x + glyph->width > _gk_x_max) _gk_x_max = x + glyph->width; if (y + glyph->height > _gk_y_max) _gk_y_max = y + glyph->height; } if (!glyph->index) _gk_unload_glyph(glyph); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_put_glyph() end\n"); #endif } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_workout.c0000644000175000017500000006153210567602066024055 0ustar georgeskgeorgesk/* * glyph_workout.c - Glyph Keeper routines rendering a character glyph. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c /* * Compress monochrome glyph with RLE7 to ensure fastest output. */ #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 static unsigned _gk_make_RLE7(const unsigned char* const src,const int width,const int height,const int pitch) { unsigned char *rlepos; int x, y; unsigned max_rlesize = width*height+1; if (rle_buffer_size < max_rlesize) { if (rle_buffer) { _gk_free(rle_buffer); rle_buffer = 0; } rle_buffer_size = 0; rle_buffer = (unsigned char*)_gk_malloc(max_rlesize*2); if (!rle_buffer) return 0; rle_buffer_size = max_rlesize*2; } rlepos = rle_buffer; *rlepos++ = GLYPH_MONO_RLE7; for (y=0; y>7) ? 255 : 0; for (x=1; x>= 1; if (!mask) { mask = 128; s++; } } *rlepos++ = (color&128)|run; } return rlepos - rle_buffer; } #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ /* * RLE-compress anti-aliased glyph. */ #ifdef GLYPH_TARGET_KNOWS_RLEAA static unsigned _gk_make_RLEAA(const unsigned char* const src,const int width,const int height) { unsigned char *rlepos; const unsigned char *srcpos, *srcend; unsigned max_rlesize = 1+2*width*height; if (rle_buffer_size < max_rlesize) { if (rle_buffer) { _gk_free(rle_buffer); rle_buffer = 0; } rle_buffer_size = 0; rle_buffer = (unsigned char*)_gk_malloc(max_rlesize*2); if (!rle_buffer) return 0; rle_buffer_size = max_rlesize*2; } rlepos = rle_buffer; *rlepos++ = GLYPH_RLEAA; srcpos = src; srcend = src + width*height; while (srcpos < srcend) { const unsigned char *lineend = srcpos + width; while (srcpos < lineend) { if (*srcpos>0 && *srcpos<255) { *rlepos++ = *srcpos++; } else { int n = 1, c = *srcpos++; *rlepos++ = c; while (srcpospoints; for ( c = 0; c < outline->n_contours; c++ ) { int last = outline->contours[c]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; for ( n = first; n <= last; n++ ) { FT_Vector in, out; FT_Angle angle_diff; FT_Pos d; FT_Fixed scale; if ( n < last ) v_next = points[n + 1]; else v_next = v_first; /* compute the in and out vectors */ in.x = v_cur.x - v_prev.x; in.y = v_cur.y - v_prev.y; out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; angle_in = FT_Atan2( in.x, in.y ); angle_out = FT_Atan2( out.x, out.y ); angle_diff = FT_Angle_Diff( angle_in, angle_out ); scale = FT_Cos( angle_diff / 2 ); if ( scale < 0x4000L && scale > -0x4000L ) in.x = in.y = 0; else { d = FT_DivFix( strength, scale ); FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); } outline->points[n].x = v_cur.x + strength + in.x; outline->points[n].y = v_cur.y + strength + in.y; if (v_cur.x < min_x) min_x = v_cur.x; if (v_cur.x > max_x) max_x = v_cur.x; if (v_cur.y < min_y) min_y = v_cur.y; if (v_cur.y > max_y) max_y = v_cur.y; if (outline->points[n].x < new_min_x) new_min_x = outline->points[n].x; if (outline->points[n].x > new_max_x) new_max_x = outline->points[n].x; if (outline->points[n].y < new_min_y) new_min_y = outline->points[n].y; if (outline->points[n].y > new_max_y) new_max_y = outline->points[n].y; v_prev = v_cur; v_cur = v_next; } first = last + 1; } *x_left = min_x - new_min_x; *x_right = new_max_x - max_x; *y_top = new_max_y - max_y; *y_bottom = min_y - new_min_y; #ifdef GLYPH_LOG if (glyph_log) { fprintf(glyph_log," (%d..%d x %d..%d) -> (%d..%d x %d..%d)\n", min_x,max_x,min_y,max_y,new_min_x,new_max_x,new_min_y,new_max_y); } #endif } /* * Renders a glyph immediately, then tries to puts it into cache. * rend and rend->face must be not 0 */ static GLYPH* _gk_rend_workout(GLYPH_REND* const rend,const unsigned unicode) { unsigned glyph_index; int bmp_size; int error; int center_x = 0,center_y = 0; FT_Glyph ft_glyph = 0; GLYPH* glyph; GLYPH_FACE* actual_face; unsigned actual_code; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_rend_workout(%p,%d) begin\n",(void*)rend,unicode); #endif CARE(rend && rend->face); CARE(unicode > 0); CARE(unicode <= GK_MAX_UNICODE); funcname = "_gk_rend_workout()"; _gk_find_mapping(rend->face,unicode,&actual_face,&actual_code); if (!actual_face || !actual_code) return 0; if (!actual_face->face) return 0; glyph_index = FT_Get_Char_Index(actual_face->face,actual_code); if (!glyph_index) { if (unicode==rend->undefined_char || unicode==rend->error_char) return 0; else return _gk_rend_render(rend,rend->undefined_char); } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," glyph_index is %u\n",glyph_index); #endif /* Preparing for glyph loading: setting size */ /*FT_Activate_Size(size);*/ if (actual_face == rend->face) { error = (rend->size == 0); if (!error) actual_face->face->size = rend->size; } else { error = (actual_face->own_size == 0); if (!error) { actual_face->face->size = actual_face->own_size; error = FT_Set_Char_Size(actual_face->face,rend->hsize,rend->vsize,72,72); } } #ifdef GLYPH_LOG if (error) { if (glyph_log) fprintf(glyph_log," Failed to select size\n"); } else { if (glyph_log) fprintf(glyph_log," Size selected successfully\n"); } #endif /* Loading a glyph with FreeType */ if (!error) { error = FT_Load_Glyph(actual_face->face,glyph_index,rend->load_flags); if (error) _gk_msg("Error: %s: FT_Load_Glyph() bugs on glyph (#%d) for character U+%04X\n",funcname,glyph_index,unicode); else { error = (actual_face->face->glyph == 0); if (error) _gk_msg("Error: %s: Empty glyph slot after FT_Load_Glyph()\n",funcname); } /*#ifdef GLYPH_LOG if (error) { if (glyph_log) fprintf(glyph_log," Could not load a glyph with FT_Load_Glyph()\n"); } else { if (glyph_log) fprintf(glyph_log," Loaded a glyph with FT_Load_Glyph()\n"); } #endif*/ } /* Getting center coordinates (MEGA-HACK) */ /* This whole idea should be re-made in more optimal way */ if (!error) { /*#ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Getting a center point\n"); #endif*/ FT_Glyph g = 0; error = FT_Get_Glyph(actual_face->face->glyph, &g); /*#ifdef GLYPH_LOG if (glyph_log) { if (error) fprintf(glyph_log," FT_Get_Glyph() failed\n"); else fprintf(glyph_log," FT_Get_Glyph() succeeded\n"); if (g) fprintf(glyph_log," FT_Get_Glyph() returned not 0\n"); else fprintf(glyph_log," FT_Get_Glyph() returned 0\n"); } #endif*/ error = error || !g; if (!error && g->format==FT_GLYPH_FORMAT_OUTLINE) { /*#ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Calling FT_Glyph_To_Bitmap()\n"); #endif*/ error = FT_Glyph_To_Bitmap(&g,rend->render_mode,0,1); /*#ifdef GLYPH_LOG if (glyph_log) { if (error) fprintf(glyph_log," FT_Glyph_To_Bitmap() failed\n"); else fprintf(glyph_log," FT_Glyph_To_Bitmap() succeeded\n"); } #endif*/ if (!error) { center_x = 64 * ((FT_BitmapGlyph)g)->left + 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2; center_y = 64 * ((FT_BitmapGlyph)g)->top - 64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2; /*center_x = 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2; center_y = -64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;*/ } } if (g) { /*#ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Calling FT_Done_Glyph()\n"); #endif*/ FT_Done_Glyph(g); } /*#ifdef GLYPH_LOG if (glyph_log) { if (error) fprintf(glyph_log," Could not find a center point\n"); else fprintf(glyph_log," Computed a center point\n"); } #endif*/ } /* Emboldening the glyph */ if (!error) { if (rend->bold_strength && actual_face->face->glyph->format==FT_GLYPH_FORMAT_OUTLINE) { int xstr, ystr, xstr2, ystr2; int xmin,xmax,ymin,ymax; int center_dx, center_dy; FT_GlyphSlot slot = actual_face->face->glyph; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Emboldening the glyph by %d\n",rend->bold_strength); #endif xstr = rend->bold_strength * FT_MulFix( actual_face->face->units_per_EM, actual_face->face->size->metrics.y_scale ) / 2400; ystr = xstr; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xstr = %d, ystr = %d\n",xstr,ystr); #endif GK_Outline_Embolden(&slot->outline,xstr,&xmin,&xmax,&ymin,&ymax); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xmin = %d, xmax = %d\n",xmin,xmax); if (glyph_log) fprintf(glyph_log," ymin = %d, ymax = %d\n",ymin,ymax); #endif /*xstr = xstr * 2; ystr = xstr;*/ #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xstr = %d, ystr = %d\n",xstr,ystr); #endif xstr2 = xmin+xmax; ystr2 = ymin+ymax; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xstr2 = %d, ystr2 = %d\n",xstr2,ystr2); if (glyph_log) fprintf(glyph_log," xscale = %.5f\n",((double)actual_face->face->size->metrics.x_scale)/65536); if (glyph_log) fprintf(glyph_log," yscale = %.5f\n",((double)actual_face->face->size->metrics.y_scale)/65536); #endif if (slot->advance.x) slot->advance.x += xstr; if (slot->advance.y) slot->advance.y += ystr; slot->metrics.width += xstr * 2; slot->metrics.height += ystr * 2; /*slot->metrics.horiBearingX -= xmin;*/ slot->metrics.horiBearingY += ystr * 2; slot->metrics.horiAdvance += xstr * 2; slot->metrics.vertBearingX -= xstr; slot->metrics.vertBearingY += ystr * 2; slot->metrics.vertAdvance += ystr * 2; /*center_dx = (int)( (double)xstr / 2 * (double)actual_face->face->size->metrics.x_scale / (80000) ); center_dy = (int)( (double)ystr / 2 * (double)actual_face->face->size->metrics.y_scale / (65536) );*/ center_dx = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.x_ppem / 80); center_dy = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.y_ppem / 80); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," center_x += %.1f\n",((double)center_dx)/64); if (glyph_log) fprintf(glyph_log," center_y += %.1f\n",((double)center_dx)/64); #endif center_x += center_dx; center_y += center_dy; /*center_x += xstr;*/ /*center_y += ymin;*/ /*FT_GlyphSlot_Embolden(slot);*/ } } /* Getting a glyph from FreeType */ if (!error) { error = FT_Get_Glyph(actual_face->face->glyph, &ft_glyph); error = error || !ft_glyph; if (error) _gk_msg("Error: %s: Can't get a glyph with FT_Get_Glyph() call. Glyph (#%d) for character U+%04X\n", funcname,glyph_index,unicode); } /* Transforming the glyph to apply rotation and italics */ if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE && rend->do_matrix_transform) { error = FT_Glyph_Transform(ft_glyph,&rend->matrix,0); if (!error) { FT_Vector c; c.x = center_x; c.y = center_y; FT_Vector_Transform(&c,&rend->matrix); center_x = c.x; center_y = c.y; } } /* Converting glyph to bitmap */ if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE) { error = FT_Glyph_To_Bitmap(&ft_glyph,rend->render_mode,0,1); if (error) _gk_msg("Error: %s: FT_Glyph_To_Bitmap() bugs on character U+%04X\n",funcname,unicode); } /* Checking if we have bitmap now */ if (!error) { error = (ft_glyph->format!=FT_GLYPH_FORMAT_BITMAP); if (error) _gk_msg("Error: %s: Glyph is not FT_GLYPH_FORMAT_BITMAP after rendering with FT_Glyph_To_Bitmap()\n",funcname); } #ifdef GLYPH_LOG /* { if (glyph_log) { fprintf(glyph_log," We got a bitmap glyph from FreeType!\n"); if (ft_glyph->format==FT_GLYPH_FORMAT_BITMAP) { fprintf(glyph_log," Format: FT_GLYPH_FORMAT_BITMAP\n"); fprintf(glyph_log," Size: %dx%d, pitch: %d\n", ((FT_BitmapGlyph)ft_glyph)->bitmap.width, ((FT_BitmapGlyph)ft_glyph)->bitmap.rows, ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch); if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_MONO) { int x,y; int pitch = ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch; fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_MONO\n"); fprintf(glyph_log," Buffer:\n"); for (y=0; y < ((FT_BitmapGlyph)ft_glyph)->bitmap.rows; y++) { fprintf(glyph_log," "); for (x=0; x < ((FT_BitmapGlyph)ft_glyph)->bitmap.width; x++) { unsigned char byte = ((unsigned char*)((FT_BitmapGlyph)ft_glyph)->bitmap.buffer)[y*pitch+x]; unsigned char mask = 128 >> (x%8); fprintf(glyph_log,"%s",(byte&mask)?" *":" ."); } fprintf(glyph_log,"\n"); } } else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_GRAY\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY2) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_GRAY2\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY4) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_GRAY4\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_LCD\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD_V) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_LCD_V\n"); } else if (ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE) { fprintf(glyph_log," Format: FT_GLYPH_FORMAT_OUTLINE\n"); } fprintf(glyph_log," Advance: ( %.1f , %.1f ) pixels\n", ((double)ft_glyph->advance.x)/0x10000,((double)ft_glyph->advance.y)/0x10000); } }*/ #endif if (!error) { error = ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch < 0 ); if (error) _gk_msg("Error: rend_workout(): Rendered glyph has negative pitch value, can't handle\n"); /* FIXME */ } if (!error) { glyph = (GLYPH*)_gk_malloc(sizeof(GLYPH)); error = (glyph == 0); } if (error || !ft_glyph) { if (ft_glyph) FT_Done_Glyph(ft_glyph); if (unicode==rend->error_char) return 0; else return _gk_rend_render(rend,rend->error_char); } glyph->unicode = unicode; glyph->width = ((FT_BitmapGlyph)ft_glyph)->bitmap.width; glyph->height = ((FT_BitmapGlyph)ft_glyph)->bitmap.rows; glyph->left = ((FT_BitmapGlyph)ft_glyph)->left; glyph->top = ((FT_BitmapGlyph)ft_glyph)->top; glyph->advance_x = ft_glyph->advance.x >> 10; glyph->advance_y = ft_glyph->advance.y >> 10; glyph->center_x = (center_x + 31) / 64; glyph->center_y = (center_y + 31) / 64; glyph->index = 0; glyph->prev = 0; glyph->next = 0; glyph->bmp = 0; glyph->bmpsize = 0; _gk_msg("rendering character '%c'\n",unicode); bmp_size = glyph->width*glyph->height; if (!bmp_size) /* empty glyph, like space (' ') character */ { if (rend->index) _gk_glyph_index_add_glyph(rend->index,glyph); FT_Done_Glyph(ft_glyph); return glyph; } if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { #ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK int pitch1 = (glyph->width+7)>>3; int bitpack_size = glyph->height*pitch1; #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 int rle_size = 0; if (rend->index) rle_size = _gk_make_RLE7( ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer, glyph->width, glyph->height, ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch); if (rle_size>0 && rle_size<=bitpack_size) { glyph->bmp = (unsigned char*)_gk_malloc(rle_size); if (!glyph->bmp) { _gk_free(glyph); return 0; } memcpy(glyph->bmp,rle_buffer,rle_size); glyph->bmpsize = rle_size; } else #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { glyph->bmp = (unsigned char*)_gk_malloc(bitpack_size+1); if (!glyph->bmp) { _gk_free(glyph); return 0; } glyph->bmp[0] = GLYPH_MONO_BITPACK; if ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch == pitch1 ) memcpy( glyph->bmp+1, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer, bitpack_size ); else { unsigned char *d = glyph->bmp+1; int y = 0; for (; yheight; y++,d+=pitch1) memcpy( d, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch, pitch1 ); } glyph->bmpsize = bitpack_size+1; } #else /* GLYPH_TARGET_KNOWS_MONO_BITPACK */ { int y = 0; unsigned char* b; glyph->bmp = (unsigned char*)_gk_malloc(bmp_size+1); if (!glyph->bmp) { _gk_free(glyph); return 0; } glyph->bmp[0] = GLYPH_UNCOMPRESSED; glyph->bmpsize = bmp_size+1; b = glyph->bmp + 1; for (; yheight; y++) { int x = 0; unsigned char* a = ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch; while (xwidth) { if (x < glyph->width) { *b++ = *a&0x80 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x40 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x20 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x10 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x08 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x04 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x02 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x01 ? 255 : 0; x++; } a++; } } } #endif /* GLYPH_TARGET_KNOWS_MONO_BITPACK */ } else /* if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) */ { #ifdef GLYPH_TARGET_KNOWS_RLEAA int rle_size = 0; #endif FT_Bitmap *ft_bmp; if (((FT_BitmapGlyph)ft_glyph)->bitmap.num_grays!=256) { FT_Bitmap_Convert(ftlib,&((FT_BitmapGlyph)ft_glyph)->bitmap,&_gk_workout_bitmap,4); ft_bmp = &_gk_workout_bitmap; } else { ft_bmp = &((FT_BitmapGlyph)ft_glyph)->bitmap; } /* FIXME: handle case when ((FT_BitmapGlyph)ft_glyph)->bitmap.num_grays is not 256 */ /*CARE(((FT_BitmapGlyph)ft_glyph)->bitmap.num_grays==256);*/ #ifdef GLYPH_TARGET_KNOWS_RLEAA if (rend->index) rle_size = _gk_make_RLEAA(ft_bmp->buffer,glyph->width,glyph->height); if (rle_size>0 && rle_sizebmp = (unsigned char*)_gk_malloc(rle_size); if (!glyph->bmp) { _gk_free(glyph); return 0; } memcpy(glyph->bmp,rle_buffer,rle_size); glyph->bmpsize = rle_size; } else #endif { glyph->bmp = (unsigned char*)_gk_malloc(bmp_size+1); if (!glyph->bmp) { _gk_free(glyph); return 0; } glyph->bmp[0] = GLYPH_UNCOMPRESSED; memcpy(glyph->bmp+1,ft_bmp->buffer,bmp_size); glyph->bmpsize = bmp_size+1; } } if (rend->index) _gk_glyph_index_add_glyph(rend->index,glyph); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_rend_workout(%p,%d) end\n",(void*)rend,unicode); #endif FT_Done_Glyph(ft_glyph); return glyph; } static GLYPH* _gk_rend_render(GLYPH_REND* const rend,const unsigned unicode) { GLYPH *glyph = 0; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_rend_render(%p,%d) begin\n",(void*)rend,unicode); #endif if (!unicode || unicode>GK_MAX_UNICODE) return 0; if (!rend || !rend->face) return 0; /* First look in cache */ if (rend->index) glyph = glyph_index_find_glyph(rend->index,unicode); /* Then try to render */ if (!glyph) glyph = _gk_rend_workout(rend,unicode); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_rend_render(%p,%d) end\n",(void*)rend,unicode); #endif return glyph; } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_index.c0000644000175000017500000003672510567602066023460 0ustar georgeskgeorgesk/* * glyph_index.c - Glyph Keeper routines implementing glyph cache. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c static int _gk_keeper_make_space(GLYPH_KEEP* const keeper,const int bytes); static int _gk_glyph_index_ok_for_renderer(const GLYPH_INDEX* const index, const GLYPH_REND* const rend) { CARE(index); CARE(rend); return (index->face_id == rend->face_id && index->load_flags == rend->load_flags && index->render_mode == rend->render_mode && index->hsize == rend->hsize && index->vsize == rend->vsize && index->text_angle == rend->text_angle && index->italic_angle == rend->italic_angle && index->bold_strength == rend->bold_strength); } static void _gk_glyph_index_init(GLYPH_INDEX* const index, const GLYPH_REND* const rend) { CARE(index); CARE(rend); index->face_id = rend->face_id; index->load_flags = rend->load_flags; index->render_mode = rend->render_mode; index->hsize = rend->hsize; index->vsize = rend->vsize; index->text_angle = rend->text_angle; index->italic_angle = rend->italic_angle; index->bold_strength = rend->bold_strength; } /* Callers: gk_rend_debug. */ static int _gk_glyph_index_size(const GLYPH_INDEX* const index) { int size,a,b; CARE(index); size = sizeof(GLYPH_INDEX); if (!index->pages) return size; size += 69*sizeof(void*); if ((long)index->pages[68]) { for (a=0; a<68; a++) { if (!index->pages[a]) continue; size += 129*sizeof(void*); if ((long)index->pages[a][128]) { for (b=0; b<128; b++) { if (index->pages[a][b]) size += 129*sizeof(void*); } } } } return size; } /* the only way to create GLYPH_INDEX object */ /* callers: gk_rend_set_keeper */ static GLYPH_INDEX* _gk_glyph_index_create(GLYPH_KEEP* const keeper, GLYPH_REND* const rend) { GLYPH_INDEX* index; funcname = "_gk_glyph_index_create()"; CARE(keeper); CARE(rend); if (!_gk_keeper_make_space(keeper,sizeof(GLYPH_INDEX))) return 0; index = (GLYPH_INDEX*)_gk_malloc(sizeof(GLYPH_INDEX)); if (!index) return 0; index->pages = 0; _gk_glyph_index_init(index,rend); index->keeper = keeper; index->prev = 0; index->next = keeper->first_index; if (keeper->first_index) keeper->first_index->prev = index; if (!keeper->last_index) keeper->last_index = index; keeper->first_index = index; index->first_renderer = 0; index->last_renderer = 0; keeper->allocated += sizeof(GLYPH_INDEX); return index; } /* callers: gk_done_keeper */ static void _gk_glyph_index_done(GLYPH_INDEX* const index) { GLYPH_KEEP* keeper; GLYPH_REND* renderer; int a,b,c; CARE(index); keeper = index->keeper; for (renderer = index->first_renderer; renderer; renderer = renderer->next_for_same_index) gk_rend_set_keeper(renderer,0); if (index->pages) { for (a=0; a<68; a++) { if (index->pages[a]) { for (b=0; b<128; b++) { if (index->pages[a][b]) { for (c=0; c<128; c++) { if (index->pages[a][b][c]) { GLYPH *glyph = index->pages[a][b][c]; index->pages[a][b][c] = 0; if (glyph == keeper->head) keeper->head = keeper->head->next; if (glyph == keeper->tail) keeper->tail = keeper->tail->prev; if (glyph->prev) glyph->prev->next = glyph->next; if (glyph->next) glyph->next->prev = glyph->prev; keeper->num_glyphs--; keeper->allocated -= glyph_size_in_bytes(glyph); if (glyph->bmp) _gk_free(glyph->bmp); _gk_free(glyph); } } _gk_free(index->pages[a][b]); index->pages[a][b] = 0; keeper->allocated -= 129*sizeof(void*); } } _gk_free(index->pages[a]); index->pages[a] = 0; keeper->allocated -= 129*sizeof(void*); } } _gk_free(index->pages); index->pages = 0; keeper->allocated -= 69*sizeof(void*); } if (index == keeper->first_index) keeper->first_index = index->next; if (index == keeper->last_index) keeper->last_index = index->prev; if (index->next) index->next->prev = index->prev; if (index->prev) index->prev->next = index->next; _gk_free(index); keeper->allocated -= sizeof(GLYPH_INDEX); } /* Uncaches one glyph, and releases all its memory. */ /* If the glyph was the last one, referenced in it's index page, */ /* the page will also removed. All higher level pages, including root page, */ /* will be removed as well, if they appear to be empty after glyph deletion. */ /* If all index pages were deleted and GLYPH_INDEX object itself is not */ /* referenced by any GLYPH_REND objects, GLYPH_INDEX object is also deleted. */ static void _gk_unload_glyph(GLYPH* const glyph) { GLYPH_INDEX *index; GLYPH_KEEP *keeper; GLYPH ***page_b,**page_c; int a_index,b_index,c_index; if (!glyph) return; /* if glyph is not being kept by keeper, just _gk_free() it. */ if (!glyph->index) { if (glyph->bmp) _gk_free(glyph->bmp); _gk_free(glyph); return; } index = glyph->index; keeper = index->keeper; CARE(keeper); /* if GLYPH_INDEX has no pages, it means it can't keep any glyphs, crash */ CARE(index->pages); a_index = glyph->unicode/16384; c_index = glyph->unicode - a_index*16384; page_b = index->pages[a_index]; CARE(page_b); b_index = c_index/128; page_c = page_b[b_index]; CARE(page_c); c_index -= b_index*128; /* check if the index actually keeps the same glyph we are uncaching */ CARE(page_c[c_index]==glyph); /* unlinking the glyph from index */ page_c[c_index] = 0; (*(long*)(page_c+128))--; /* uninking the glyph from keeper's list */ if (glyph == keeper->head) keeper->head = keeper->head->next; if (glyph == keeper->tail) keeper->tail = keeper->tail->prev; if (glyph->prev) glyph->prev->next = glyph->next; if (glyph->next) glyph->next->prev = glyph->prev; /* releasing glyph's memory */ keeper->num_glyphs--; keeper->allocated -= glyph_size_in_bytes(glyph); if (glyph->bmp) _gk_free(glyph->bmp); _gk_free(glyph); /* releasing unnecessary index pages, and index itself */ if (((long)page_c[128])<=0) { _gk_free(page_c); page_b[b_index] = 0; keeper->allocated -= 129*sizeof(void*); (*(long*)(page_b+128))--; if (((long)page_b[128])<=0) { _gk_free(page_b); index->pages[a_index] = 0; keeper->allocated -= 129*sizeof(void*); (*(long*)(index->pages+68))--; if (((long)index->pages[68])<=0) { _gk_free(index->pages); index->pages = 0; keeper->allocated -= 69*sizeof(void*); /* no any glyphs left, no renderers.. -> kill the index object */ if (!index->first_renderer) { if (index == keeper->first_index) keeper->first_index = index->next; if (index == keeper->last_index) keeper->last_index = index->prev; if (index->next) index->next->prev = index->prev; if (index->prev) index->prev->next = index->next; _gk_free(index); keeper->allocated -= sizeof(GLYPH_INDEX); } } } } } /* Adds 'glyph' into cache. */ /* Returns 1 if glyph is saved, 0 if glyph is not saved. */ /* Callers: rend_workout. */ static int _gk_glyph_index_add_glyph(GLYPH_INDEX* const index,GLYPH* const glyph) { GLYPH_KEEP *keeper; GLYPH ***page_b,**page_c; int a_index,b_index,c_index; int bytes; funcname = "_gk_glyph_index_add_glyph()"; CARE(index); CARE(glyph); keeper = index->keeper; /* If the keeper has limitation on number of glyphs, */ /* make sure to not exceed the limit, by removing most long-ago-used glyphs. */ if (keeper->max_glyphs) { while ((keeper->num_glyphs >= keeper->max_glyphs) && keeper->tail) _gk_unload_glyph(keeper->tail); if (keeper->num_glyphs >= keeper->max_glyphs) return 0; } /* Asking for memory */ bytes = glyph_size_in_bytes(glyph); if (!_gk_keeper_make_space(keeper,bytes+(129+129+69)*sizeof(void*))) return 0; /* creating root directory, if not exist */ if (!index->pages) { index->pages = (GLYPH****)_gk_malloc(69*sizeof(void*)); if (!index->pages) return 0; memset(index->pages,0,69*sizeof(void*)); keeper->allocated += 69*sizeof(void*); } a_index = glyph->unicode/16384; c_index = glyph->unicode - a_index*16384; if (!index->pages[a_index]) { index->pages[a_index] = (GLYPH***)_gk_malloc(129*sizeof(void*)); if (!index->pages[a_index]) return 0; (*(long*)(index->pages+68))++; memset(index->pages[a_index],0,129*sizeof(void*)); keeper->allocated += 129*sizeof(void*); } page_b = index->pages[a_index]; b_index = c_index/128; if (!page_b[b_index]) { page_b[b_index] = (GLYPH**)_gk_malloc(129*sizeof(void*)); if (!page_b[b_index]) return 0; (*(long*)(page_b+128))++; memset(page_b[b_index],0,129*sizeof(void*)); keeper->allocated += 129*sizeof(void*); } page_c = page_b[b_index]; c_index -= b_index*128; /* There should be NO glyph at this place at this moment */ CARE(page_c[c_index]==0); page_c[c_index] = glyph; (*(int*)(page_c+128))++; glyph->index = index; glyph->prev = 0; glyph->next = keeper->head; if (keeper->head) keeper->head->prev = glyph; if (!keeper->tail) keeper->tail = glyph; keeper->head = glyph; keeper->allocated += bytes; keeper->num_glyphs++; return 1; } /* Finds the glyph for a given unicode. */ /* Callers: rend_render. */ static GLYPH* glyph_index_find_glyph(GLYPH_INDEX* const index,const unsigned unicode) { GLYPH *glyph; GLYPH_KEEP *keeper; GLYPH ***page_b,**page_c; int a_index,b_index,c_index; CARE(index); CARE(unicode<=GK_MAX_UNICODE); if (!index->pages) return 0; /*a_index = unicode/16384;*/ a_index = unicode >> 14; /*c_index = unicode - a_index*16384;*/ c_index = unicode - (a_index << 14); page_b = index->pages[a_index]; if (!page_b) return 0; /*b_index = c_index/128;*/ b_index = c_index >> 7; page_c = page_b[b_index]; if (!page_c) return 0; /*c_index -= b_index*128;*/ c_index -= b_index << 7; if (!page_c[c_index]) return 0; glyph = page_c[c_index]; keeper = index->keeper; if (glyph!=keeper->head) { if (glyph->prev) glyph->prev->next = glyph->next; if (glyph->next) glyph->next->prev = glyph->prev; if (keeper->tail==glyph) keeper->tail = glyph->prev; if (keeper->head) keeper->head->prev = glyph; glyph->next = keeper->head; glyph->prev = 0; keeper->head = glyph; } return glyph; } /* * GLYPH_KEEP routines */ /* Tries to make free memory, to store 'bytes' bytes */ /* without exceeding 'max_memory' limit. */ /* Returns 1 on success, 0 on failure. */ /* Callers: _gk_glyph_index_create, _gk_glyph_index_add_glyph */ static int _gk_keeper_make_space(GLYPH_KEEP* const keeper,const int bytes) { CARE(keeper); /* no need to do anything, the memory is not limited */ if (!keeper->max_memory) return 1; /* trying to release glyphs, until enough memory is free older glyphs are released first */ while ( (keeper->allocated + bytes > keeper->max_memory) && keeper->tail) _gk_unload_glyph(keeper->tail); if (keeper->allocated + bytes <= keeper->max_memory) return 1; return 0; } GLYPH_KEEP* gk_create_keeper(const unsigned max_glyphs,const unsigned max_memory) { GLYPH_KEEP *keeper; funcname = "gk_create_keeper()"; keeper = (GLYPH_KEEP*)_gk_malloc(sizeof(GLYPH_KEEP)); if (!keeper) return 0; keeper->head = 0; keeper->tail = 0; keeper->num_glyphs = 0; keeper->allocated = sizeof(GLYPH_KEEP); keeper->max_glyphs = max_glyphs; keeper->max_memory = max_memory; keeper->first_index = 0; keeper->last_index = 0; keeper->next = 0; keeper->prev = last_keeper; if (last_keeper) last_keeper->next = keeper; if (!first_keeper) first_keeper = keeper; last_keeper = keeper; _gk_install_exit_handler(); _gk_msg("glyph keeper created\n"); return keeper; } void gk_done_keeper(GLYPH_KEEP* const keeper) { int mem; if (!keeper) return; while (keeper->head) _gk_unload_glyph(keeper->head); while (keeper->first_index) _gk_glyph_index_done(keeper->first_index); if (keeper==first_keeper) first_keeper = keeper->next; if (keeper==last_keeper) last_keeper = keeper->prev; if (keeper->next) keeper->next->prev = keeper->prev; if (keeper->prev) keeper->prev->next = keeper->next; mem = keeper->allocated - sizeof(GLYPH_KEEP); _gk_free(keeper); _gk_msg("glyph keeper destroyed, (%d bytes leak)\n",mem); } int gk_keeper_glyph_count(const GLYPH_KEEP* const keeper) { return keeper ? keeper->num_glyphs : 0; } int gk_keeper_glyph_limit(const GLYPH_KEEP* const keeper) { return keeper ? keeper->max_glyphs : 0; } int gk_keeper_byte_count(const GLYPH_KEEP* const keeper) { return keeper ? keeper->allocated : 0; } int gk_keeper_byte_limit(const GLYPH_KEEP* const keeper) { return keeper ? keeper->max_memory : 0; } void gk_keeper_debug(const GLYPH_KEEP* const keeper) { GLYPH_INDEX *index; GLYPH_REND *rend; int ni = 0, nr = 0; _gk_msg("GLYPH_KEEP object (address:%p):\n",keeper); if (!keeper) return; _gk_msg(" can keep %d glyphs, currently keeping %d\n",keeper->max_glyphs,keeper->num_glyphs); _gk_msg(" can use %d bytes of memory, now using %d bytes\n",keeper->max_memory,keeper->allocated); for (index=keeper->first_index;index;index=index->next) { ni++; for (rend=index->first_renderer;rend;rend=rend->next_for_same_index) nr++; } _gk_msg(" this keeper has %d GLYPH_INDEX objects, used by %d renderers\n",ni,nr); } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_to_allegro_aa.c0000644000175000017500000004135610567602066025135 0ustar georgeskgeorgesk/* * glyph_to_allegro_aa.c - part of Glyph Keeper Allegro driver. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_to_allegro_c static int last_aa_alpha_used = -1; static unsigned char gradient[256]; /* * General case code for printing an anti-aliased glyph to Allegro bitmap. */ static void put_glyph_aa(const GLYPH* const glyph,const int x0,const int y0) { int bxend = x0 + glyph->width; int byend = y0 + glyph->height; if (byend>cb) byend = cb; if (last_aa_alpha_used != alpha) { int a1 = (alpha<<16)/255; int i=0; for (; i<256; i++) gradient[i] = (i*a1)>>16; last_aa_alpha_used = alpha; } #ifdef GLYPH_TARGET_KNOWS_RLEAA if (glyph->bmp[0]==GLYPH_RLEAA) { unsigned char* rlepos = glyph->bmp + 1; int by = y0; for (; bywidth; while (bx= ct) ? y0 : ct; for (; bybmp + 1 + glyph->width*(by-y0); while (bx0) putpixel(bmp,bx,by,text_color); bx++; } } } solid_mode(); } /* * Fast code for printing an anti-aliased glyph to 32-bit bitmap. */ static void put_glyph_aa_32(const GLYPH* const glyph,const int x0,const int y0) { int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; int byend = y0 + glyph->height; int r = (alpha_color>>16)&0xFF; int g = (alpha_color>>8)&0xFF; int b = alpha_color&0xFF; if (xr > cr) xr = cr; if (byend>cb) byend = cb; if (last_aa_alpha_used != alpha) { int a1 = (alpha<<16)/255; int i=0; for (; i<256; i++) gradient[i] = (i*a1)>>16; last_aa_alpha_used = alpha; } bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_RLEAA if (glyph->bmp[0]==GLYPH_RLEAA) { int alpha1 = (255-alpha)*257; int r_a = r*alpha*257+256; int g_a = g*alpha*257+256; int b_a = b*alpha*257+256; unsigned char* rlepos = glyph->bmp + 1; int by = y0; for (; bywidth; while (bxwidth; while (addr=addr_l && addr=addr_l && addr>16, (getg32(value)*alpha1+g_a)>>16, (getb32(value)*alpha1+b_a)>>16)); } addr++; } rlepos++; } else { rlepos++; if (addr>=addr_l && addr>16, (getg32(value)*a1+g_a1)>>16, (getb32(value)*a1+b_a1)>>16)); } addr++; } } } } } else #endif /* GLYPH_TARGET_KNOWS_RLEAA */ { int by = (y0 >= ct) ? y0 : ct; for (; bybmp + 1 + glyph->width*(by-y0) + (xl-x0); while (addr0) { int a1 = (255-a)*257; int r_a1 = r*a*257+256; int g_a1 = g*a*257+256; int b_a1 = b*a*257+256; unsigned int value = bmp_read32(addr); bmp_write32(addr,makecol32((getr32(value)*a1+r_a1)>>16, (getg32(value)*a1+g_a1)>>16, (getb32(value)*a1+b_a1)>>16)); } addr++; } } } bmp_unwrite_line(bmp); } /* * Printing an anti-aliased glyph to 32-bit bitmap with known background color. */ static void put_glyph_aa_32_back(const GLYPH* const glyph,const int x0,const int y0) { int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; int byend = y0 + glyph->height; if (xr > cr) xr = cr; if (byend>cb) byend = cb; bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_RLEAA if (glyph->bmp[0]==GLYPH_RLEAA) { unsigned char* rlepos = glyph->bmp + 1; int by = y0; for (; bywidth; while (bxwidth; while (addr=addr_l && addr=addr_l && addr= ct) ? y0 : ct; for (; bybmp + 1 + glyph->width*(by-y0) + (xl-x0); while (addr0) bmp_write32(addr,_gk_driver_back_to_front[a]); addr++; } } } bmp_unwrite_line(bmp); } /* * Fast code for printing an anti-aliased glyph to 16-bit bitmap. */ static void put_glyph_aa_16(const GLYPH* const glyph,const int x0,const int y0) { int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; int byend = y0 + glyph->height; int r = (alpha_color>>16)&0xFF; int g = (alpha_color>>8)&0xFF; int b = alpha_color&0xFF; if (xr > cr) xr = cr; if (byend>cb) byend = cb; if (last_aa_alpha_used != alpha) { int a1 = (alpha<<16)/255; int i=0; for (; i<256; i++) gradient[i] = (i*a1)>>16; last_aa_alpha_used = alpha; } bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_RLEAA if (glyph->bmp[0]==GLYPH_RLEAA) { int alpha1 = (255-alpha)*257; int r_a = r*alpha*257+256; int g_a = g*alpha*257+256; int b_a = b*alpha*257+256; unsigned char* rlepos = glyph->bmp + 1; int by = y0; for (; bywidth; while (bxwidth; while (addr=addr_l && addr=addr_l && addr>16, (getg16(value)*alpha1+g_a)>>16, (getb16(value)*alpha1+b_a)>>16)); } addr++; } rlepos++; } else { rlepos++; if (addr>=addr_l && addr>16, (getg16(value)*a1+g_a1)>>16, (getb16(value)*a1+b_a1)>>16)); } addr++; } } } } } else #endif /* GLYPH_TARGET_KNOWS_RLEAA */ { int by = (y0 >= ct) ? y0 : ct; for (; bybmp + 1 + glyph->width*(by-y0) + (xl-x0); while (addr0) { int a1 = (255-a)*257; int r_a1 = r*a*257+256; int g_a1 = g*a*257+256; int b_a1 = b*a*257+256; unsigned short value = bmp_read16(addr); bmp_write16(addr,makecol16((getr16(value)*a1+r_a1)>>16, (getg16(value)*a1+g_a1)>>16, (getb16(value)*a1+b_a1)>>16)); } addr++; } } } bmp_unwrite_line(bmp); } /* * Fast code for printing an anti-aliased glyph to 8-bit bitmap. */ static void put_glyph_aa_8(const GLYPH* const glyph,const int x0,const int y0) { int xl = (x0 >= cl) ? x0 : cl; int xr = x0 + glyph->width; int byend = y0 + glyph->height; if (xr > cr) xr = cr; if (byend>cb) byend = cb; bmp_select(bmp); #ifdef GLYPH_TARGET_KNOWS_RLEAA if (glyph->bmp[0]==GLYPH_RLEAA) { unsigned char* rlepos = glyph->bmp + 1; int by = y0; for (; bywidth; while (bxwidth; while (addr=addr_l && addr127 && addr>=addr_l && addr= ct) ? y0 : ct; for (; bybmp + 1 + glyph->width*(by-y0) + (xl-x0); while (addr127) bmp_write8(addr,text_color); bmppos++; addr++; } } } bmp_unwrite_line(bmp); } #endif /* included_from_glyph_to_allegro_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_to_text.c0000644000175000017500000001075010567602066024025 0ustar georgeskgeorgesk/* * glyph_to_text.c - Glyph Keeper driver for FILE stream IO. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c static FILE* file = 0; static void put_glyph_mono(const GLYPH* const glyph) { char c = '*'; int y = 0; if (glyph->bmp[0]==GLYPH_MONO_RLE7) { unsigned char* rlepos = glyph->bmp+1; for (; yheight; y++) { int x = 0; while (xwidth) { int cc = (*rlepos)&128 ? c : ' '; int x2 = x + ((*rlepos)&127); for (; xwidth+7)>>3; for (; yheight; y++) { int x = 0; unsigned char* a = glyph->bmp + 1 + pitch*y; unsigned char* aend = a + pitch; while (awidth) { if (*a&0x80) fputc(c,file); else fputc(' ',file); x++; if (*a&0x40) fputc(c,file); else fputc(' ',file); x++; if (*a&0x20) fputc(c,file); else fputc(' ',file); x++; if (*a&0x10) fputc(c,file); else fputc(' ',file); x++; if (*a&0x08) fputc(c,file); else fputc(' ',file); x++; if (*a&0x04) fputc(c,file); else fputc(' ',file); x++; if (*a&0x02) fputc(c,file); else fputc(' ',file); x++; if (*a&0x01) fputc(c,file); else fputc(' ',file); x++; a++; } fputc('\n',file); } } } /* * This function prints out the glyph as a text into the FILE* stream. * Although in text mode, the glyph is still antialiased (kind of). * * Parameters 'text_color' and 'back_color' are actually not used. */ static void put_glyph_aa(const GLYPH* const glyph) { int y = 0; if (glyph->bmp[0]==GLYPH_RLEAA) { unsigned char* rlepos = glyph->bmp + 1; for (; yheight; y++) { int x = 0; while (xwidth) { if (*rlepos==0 || *rlepos==255) { char c = *rlepos ? '@' : ' '; int x2; rlepos++; x2 = x + *rlepos; for (; xbmp + 1; for (; yheight; y++) { int x = 0; for (; xwidth; x++) { if (*rlepos==0) fputc(' ',file); else if (*rlepos<64) fputc('.',file); else if (*rlepos<128) fputc(':',file); else if (*rlepos<192) fputc('+',file); else if (*rlepos<255) fputc('a',file); else fputc('@',file); rlepos++; } fputc('\n',file); } } } static void _gk_prepare_to_draw(FILE* const bmp,GLYPH_REND* const rend) { CARE(bmp); CARE(rend); file = bmp; if (rend) {} } static void _gk_done_drawing() { } /* * This function simply prints the given glyph to the output FILE* stream. * The coordinates 'x' and 'y' are not used at all. */ static void _gk_put_glyph(GLYPH* const glyph,const int x,const int y) { CARE(file); CARE(glyph); if (x || y) {} fprintf(file,"--------- glyph for character U+%04X ---------\n",glyph->unicode); if (glyph->bmp) { CARE(glyph->bmpsize); if (glyph->bmp[0] >= GLYPH_MONO) put_glyph_mono(glyph); else put_glyph_aa(glyph); } if (!glyph->index) _gk_unload_glyph(glyph); } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_to_opengl.c0000644000175000017500000003243010567602066024324 0ustar georgeskgeorgesk/* OpenGL Add On to Glyph Keeper * by Esa Tanskanen * */ #ifdef included_from_glyph_c #if (GLYPH_TARGET == GLYPH_TARGET_ALLEGGL) #include #elif (GLYPH_TARGET == GLYPH_TARGET_OPENGL) #include #endif /* Used to extract the color components from GLYPH_REND::text_alpha_color */ #define GLYPH_GETR( color ) ((color >> 16) & 0xff) #define GLYPH_GETG( color ) ((color >> 8) & 0xff) #define GLYPH_GETB( color ) ((color) & 0xff) #define GLYPH_GETA( color ) ((color >> 24) & 0xff) typedef unsigned char GLYPH_GL_PIXELTYPE; /* Texture data storage */ struct GLYPH_TEXTURE { /* OpenGL "pointers" to the associated texture and display lists */ GLuint textureId; GLuint displayListStart; GLuint displayListBase; /* Glyph information, creates its own copy of the glyphs */ int numGlyphs; GLYPH **glyphs; GLYPH_GL_PIXELTYPE *pixeldata; /* Width and height of the pixel data */ int w, h; int splits; int glyphsPerSplit; int splitHeight; /* Amount of memory consumed by the texture */ int neededMemory; GLYPH_REND *rend; }; /* Several internal function definitions */ GLuint _gk_load_texture( const GLYPH_GL_PIXELTYPE *pixeldata, int w, int h ); int gk_reload_texture( GLYPH_TEXTURE *texture ); void gk_send_texture_to_gpu( GLYPH_TEXTURE *texture ); void _gk_set_orthographic_projection(); void _gk_reset_projection(); static int iabs( int num ) { return (num < 0)? -num : num; } static int _glyphs_per_line( int numGlyphs, int splitCount ) { return numGlyphs/splitCount+1; } /* * Creates the CLYPH_TEXTURE object, but doesn't * output anything to OpenGL or the gfx card */ GLYPH_TEXTURE *_gk_glyphs_to_texture( GLYPH_REND *rend, GLYPH **glyphs, int numGlyphs, GLuint displayListBase ) { GLYPH_TEXTURE *texture = 0; int totalWidth = 0; int maxHeight = 0; int glyphx; //int x; int y; unsigned char *srcptr; GLYPH_GL_PIXELTYPE *dstptr; int index; int splitCount; int chosenSplitcount; int minDiff; int currentDiff; int line; int maxiumWidth; int currentWidth; int currentLineEnd; int textureW; int textureH; int lineBaseIndex; CARE( first ); CARE( last ); texture = (GLYPH_TEXTURE *) malloc( sizeof( GLYPH_TEXTURE )); texture->displayListBase = displayListBase; texture->textureId = -1; texture->numGlyphs = numGlyphs; texture->glyphs = glyphs; texture->rend = rend; /* Find the width and height of the texture */ for( index = 0; index < numGlyphs; index++ ) { totalWidth += glyphs[index]->width; if( glyphs[index]->height > maxHeight ) maxHeight = glyphs[index]->height; } /* Find the smallest texture size */ texture->w = 1; texture->h = 1; while( texture->w < totalWidth ) texture->w <<= 1; while( texture->h < maxHeight ) texture->h <<= 1; splitCount = 0; chosenSplitcount = splitCount; minDiff = iabs( texture->w - texture->h ); do { ++splitCount; if( numGlyphs/splitCount < 10 ) { break; } maxiumWidth = 0; index = 0; for( line = 0; line < splitCount; line++ ) { currentWidth = 0; currentLineEnd = index + _glyphs_per_line( numGlyphs, splitCount ); for(; index < currentLineEnd && index < numGlyphs; index++ ) { currentWidth += glyphs[index]->width; } if( currentWidth > maxiumWidth ) { maxiumWidth = currentWidth; } } if( maxiumWidth < maxHeight * splitCount/2 ) { break; } textureW = 1; textureH = 1; while( textureW < maxiumWidth ) textureW <<= 1; while( textureH < maxHeight * splitCount ) textureH <<= 1; currentDiff = iabs( textureW - textureH ); if( currentDiff < minDiff ) { minDiff = currentDiff; chosenSplitcount = splitCount; texture->w = textureW; texture->h = textureH; } } while( 1 ); if( chosenSplitcount > 0 ) { texture->glyphsPerSplit = _glyphs_per_line( numGlyphs, chosenSplitcount ); } else { texture->glyphsPerSplit = numGlyphs; } texture->splits = chosenSplitcount; texture->splitHeight = maxHeight; texture->neededMemory = texture->w * texture->h * sizeof( GLYPH_GL_PIXELTYPE )*100; /* Copy the pixel data */ texture->pixeldata = (GLYPH_GL_PIXELTYPE *) malloc( texture->neededMemory ); memset( texture->pixeldata, 0, texture->neededMemory ); CARE( texture->pixeldata ); index = 0; /* Copy glyph bitmap data to the texture buffer */ for( line = 0; line < texture->splits; line++ ) { glyphx = 0; currentLineEnd = index + _glyphs_per_line( numGlyphs, texture->splits ); lineBaseIndex = line * texture->splitHeight * texture->w; for(; index < currentLineEnd && index < numGlyphs; index++ ) { srcptr = glyphs[index]->bmp+1; for( y = 0; y < glyphs[index]->height; y++ ) { /* Copy one line of the glyph to the texture buffer */ dstptr = lineBaseIndex + texture->pixeldata + y * texture->w + glyphx; memcpy( dstptr, srcptr, glyphs[index]->width ); srcptr += glyphs[index]->width; } glyphx += glyphs[index]->width; } } return texture; } /* * Creates the display lists which is later used * to output the glyphs to the screen */ void _gk_create_display_lists( GLYPH_TEXTURE *texture ) { int index; int textureX = 0; int textureY = 0; double textureCoX; double textureCoY; double textureW, textureH; int line = 0; int lineEnd = texture->glyphsPerSplit; GLYPH *currentGlyph; CARE( texture ); texture->displayListStart = glGenLists( texture->numGlyphs ); for( index = 0; index < texture->numGlyphs; index++ ) { if( index >= lineEnd ) { lineEnd += texture->glyphsPerSplit; line++; textureX = 0; textureY += texture->splitHeight; } currentGlyph = texture->glyphs[index]; textureCoX = (double) textureX/texture->w; textureW = (double) currentGlyph->width/texture->w; textureCoY = (double) textureY/texture->h; textureH = (double) currentGlyph->height/texture->h; glNewList( texture->displayListStart + index, GL_COMPILE ); /* Adjust the quad position according to the anchor */ glTranslated( currentGlyph->left, -currentGlyph->top, 0 ); glBegin( GL_QUADS ); /* Bottom-left */ glTexCoord2f( textureCoX, textureCoY + textureH ); glVertex2i( 0, currentGlyph->height ); /* Bottom-right */ glTexCoord2f( textureCoX + textureW, textureCoY + textureH ); glVertex2i( currentGlyph->width, currentGlyph->height ); /* Top-right */ glTexCoord2f( textureCoX + textureW, textureCoY ); glVertex2i( currentGlyph->width, 0 ); /* Top-left */ glTexCoord2f( textureCoX, textureCoY ); glVertex2i( 0, 0 ); glEnd(); /* Revert the anchor displacement and advance the orign such that */ /* the next glyph drawn at the correct place */ glTranslated( -currentGlyph->left + (double) (currentGlyph->advance_x)/(double) (1<<6), currentGlyph->top - (double) (currentGlyph->advance_y)/(double) (1<<6), 0 ); glEndList(); textureX += currentGlyph->width; } }; /* * Creates the texture using a GLYPH_REND */ GLYPH_TEXTURE *gk_create_texture( GLYPH_REND *rend, int rangeStart, int rangeLength ) { GLYPH_TEXTURE *texture = 0; GLYPH **glyphs = 0; GLYPH *returned = 0; int index; CARE( rend ); CARE( rangeStart > 0 && rangeStart + rangeLength <= 255 ); glyphs = (GLYPH **) malloc( sizeof( GLYPH* ) * rangeLength ); for( index = 0; index < rangeLength; index++ ) { returned = _gk_rend_render( rend, rangeStart + index ); /* Create a copy of the glyph so that we don't have to care of what happens to the original */ glyphs[index] = returned;//(GLYPH *) malloc( sizeof( GLYPH )); //memcpy( glyphs[index], returned, sizeof( GLYPH )); } texture = _gk_glyphs_to_texture( rend, glyphs, rangeLength, rangeStart ); CARE( texture ); _gk_create_display_lists( texture ); return texture; } void gk_destroy_texture( GLYPH_TEXTURE *texture ) { int i; CARE( texture ); if( texture->textureId != 0 ) gk_unload_texture_from_gpu( texture ); for( i = 0; i < texture->numGlyphs; i++ ) { free( texture->glyphs[i] ); } free( texture->glyphs ); free( texture->pixeldata ); free( texture ); } /* * Renders a display list from a texture, printing the text to screen * This function doesn't take a top-left position for the text, as it * should already be set in the modelview matrix */ void _gk_render_display_list( const GLYPH_TEXTURE *texture, const char *text ) { CARE( texture ); /* Store the user display list settings so that we don't mess them up */ glPushAttrib( GL_LIST_BIT ); /* Select the base of character rendering */ glListBase( texture->displayListStart - texture->displayListBase ); /* Send the display lists to gfx card according to our text input */ glCallLists( strlen( text ), GL_UNSIGNED_BYTE, text ); /* Restore the previous display list settings */ glPopAttrib(); } /* * Renders the text to screen */ void gk_render_line_gl_utf8( GLYPH_TEXTURE *texture, const char *text, int x, int y ) { int textColor; CARE( texture ); if( texture->textureId == (unsigned)-1 ) gk_send_texture_to_gpu( texture ); _gk_set_orthographic_projection(); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, texture->textureId ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glPushMatrix(); glTranslated( x, y, 0.0 ); textColor = texture->rend->text_alpha_color; glColor4f( GLYPH_GETR( textColor )/255.0, GLYPH_GETG( textColor )/255.0, GLYPH_GETB( textColor )/255.0, GLYPH_GETA( textColor )/255.0 ); _gk_render_display_list( texture, text ); glPopMatrix(); _gk_reset_projection(); } /* * Load or reload the texture to the gfx card */ void gk_send_texture_to_gpu( GLYPH_TEXTURE *texture ) { CARE( texture ); texture->textureId = _gk_load_texture( texture->pixeldata, texture->w, texture->h ); } /* * Unload the texture in the gfx card */ void gk_unload_texture_from_gpu( GLYPH_TEXTURE *texture ) { CARE( texture ); glDeleteTextures( 1, &texture->textureId ); texture->textureId = 0; } /* Load bitmap information to gfx card as a texture, returns the texture id */ GLuint _gk_load_texture( const GLYPH_GL_PIXELTYPE *pixeldata, int w, int h ) { GLuint textureId; #if (GLYPH_TARGET == GLYPH_TARGET_ALLEGGL) BITMAP *temp; int i; /* Unfortunately, we currenly need to make a copy of the pixel data */ temp = create_bitmap_ex( 8, w, h ); for( i = 0; i < w*h; i++ ) putpixel( temp, i%w, i/w, pixeldata[i] ); allegro_gl_use_alpha_channel( TRUE ); allegro_gl_use_mipmapping(FALSE); allegro_gl_set_texture_format( GL_ALPHA8 ); textureId = allegro_gl_make_texture_ex( AGL_TEXTURE_ALPHA_ONLY, temp, GL_ALPHA8 ); destroy_bitmap( temp ); #else glGenTextures( 1, &textureId ); glBindTexture( GL_TEXTURE_2D, textureId ); glTexImage2D( GL_TEXTURE_2D, 0, 1, w, h, 0, GL_ALPHA8, GL_UNSIGNED_BYTE, pixeldata ); #endif return textureId; } /* Selects orthographic projection to allow pixel-based placements */ void _gk_set_orthographic_projection() { glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); glOrtho( 0, SCREEN_W, 0, SCREEN_H, -1, 1000 ); glScalef( 1, -1, 1 ); glTranslatef( 0, -SCREEN_H, 0 ); glMatrixMode( GL_MODELVIEW ); glDisable(GL_DEPTH_TEST); } /* Resets the previous projection matrix, stored by _gk_set_orthographic_projection */ void _gk_reset_projection() { glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); } /* The following Glyph Keeper functions are currently defined empty in this context */ static void _gk_prepare_to_draw(GLYPH_TARGET_SURFACE* const new_bmp,GLYPH_REND* const new_rend) {} static void _gk_put_glyph(GLYPH* const glyph,const int x,const int y) {} static void _gk_done_drawing() {} #endif /* included_from_glyph_c */openlayer-2.1.orig/utils/glyphkeeper/src/glyph_rend.c0000644000175000017500000006051310567602066023271 0ustar georgeskgeorgesk/* * glyph_rend.c - Glyph Keeper routines dealing with renderer objects. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c #define DEFAULT_LOAD_FLAGS (FT_LOAD_NO_BITMAP) #define rend_set_hinting_mode(r,mode) \ { \ (r)->hinting_mode = (mode); \ (r)->load_flags = DEFAULT_LOAD_FLAGS | (r)->hinting_mode | (r)->hinting_target; \ } /* * This function resets all parameters of a renderer to default values * for unscalable font face. */ static void _gk_rend_reset_to_fixed(GLYPH_REND* const rend) { CARE(rend); rend->hinting_target = FT_LOAD_TARGET_MONO; rend->load_flags = DEFAULT_LOAD_FLAGS | rend->hinting_mode | rend->hinting_target; rend->render_mode = FT_RENDER_MODE_MONO; rend->text_angle = 0; rend->text_angle_sin = 0; rend->text_angle_cos = 1; rend->italic_angle = 0; rend->bold_strength = 0; rend->do_matrix_transform = 0; rend->matrix.xx = 0x10000l; rend->matrix.xy = 0; rend->matrix.yx = 0; rend->matrix.yy = 0x10000l; } void gk_rend_set_text_alpha_color(GLYPH_REND* const rend,const unsigned alpha_color) { if (rend) rend->text_alpha_color = alpha_color; } unsigned gk_rend_get_text_alpha_color(const GLYPH_REND* const rend) { return rend ? rend->text_alpha_color : 0; } void gk_rend_set_text_color_rgb(GLYPH_REND* const rend, const unsigned char r,const unsigned char g,const unsigned char b) { if (rend) rend->text_alpha_color = (rend->text_alpha_color&0xFF000000) | (r<<16) | (g<<8) | b; } void gk_rend_set_text_color_combined(GLYPH_REND* const rend, const int color) { if (rend) rend->text_alpha_color = (rend->text_alpha_color&0xFF000000) | (color & 0x00FFFFFF); } int gk_rend_get_text_color(const GLYPH_REND* const rend) { return rend ? (rend->text_alpha_color&0x00FFFFFF) : 0; } void gk_rend_set_text_alpha(GLYPH_REND* const rend,const unsigned char alpha) { if (rend) rend->text_alpha_color = (rend->text_alpha_color&0x00FFFFFF) | (alpha<<24); } unsigned gk_rend_get_text_alpha(const GLYPH_REND* const rend) { return rend ? (rend->text_alpha_color>>24) : 0; } void gk_rend_set_back_color(GLYPH_REND* const rend,const int new_back_color) { if (rend) rend->back_color = (new_back_color < 0) ? -1 : (new_back_color & 0x00FFFFFF); } int gk_rend_get_back_color(GLYPH_REND* const rend) { return rend ? rend->back_color : -1; } int gk_rend_ascender(const GLYPH_REND* const rend) { return (rend && rend->size) ? rend->size->metrics.ascender : 0; } int gk_rend_ascender_pixels(const GLYPH_REND* const rend) { return (rend && rend->size) ? (rend->size->metrics.ascender+63)>>6 : 0; } int gk_rend_descender(const GLYPH_REND* const rend) { return (rend && rend->size) ? rend->size->metrics.descender : 0; } int gk_rend_descender_pixels(const GLYPH_REND* const rend) { return (rend && rend->size) ? (rend->size->metrics.descender+63)>>6 : 0; } int gk_rend_spacing(const GLYPH_REND* const rend) { return rend ? rend->line_spacing : 0; } int gk_rend_spacing_pixels(const GLYPH_REND* const rend) { return rend ? rend->line_spacing_pixels : 0; } int gk_rend_height(const GLYPH_REND* const rend) { return rend ? rend->text_height : 0; } int gk_rend_height_pixels(const GLYPH_REND* const rend) { return rend ? rend->text_height_pixels : 0; } void gk_rend_set_hinting_off(GLYPH_REND* const rend) { if (!rend) return; rend_set_hinting_mode(rend,FT_LOAD_NO_HINTING); if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } void gk_rend_set_hinting_default(GLYPH_REND* const rend) { if (!rend) return; rend_set_hinting_mode(rend,0); if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } void gk_rend_set_hinting_force_autohint(GLYPH_REND* const rend) { if (!rend) return; rend_set_hinting_mode(rend,FT_LOAD_FORCE_AUTOHINT); if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } void gk_rend_set_hinting_no_autohint(GLYPH_REND* const rend) { if (!rend) return; rend_set_hinting_mode(rend,FT_LOAD_NO_AUTOHINT); if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } void gk_rend_set_antialiasing_on(GLYPH_REND* const rend) { if (!rend) return; if (!rend->face || !rend->face->face || (rend->face && rend->face->face && FT_IS_SCALABLE(rend->face->face)) ) { rend->hinting_target = FT_LOAD_TARGET_NORMAL; rend->load_flags = DEFAULT_LOAD_FLAGS | rend->hinting_mode | rend->hinting_target; rend->render_mode = FT_RENDER_MODE_NORMAL; if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } } void gk_rend_set_antialiasing_off(GLYPH_REND* const rend) { if (!rend) return; rend->hinting_target = FT_LOAD_TARGET_MONO; rend->load_flags = DEFAULT_LOAD_FLAGS | rend->hinting_mode | rend->hinting_target; rend->render_mode = FT_RENDER_MODE_MONO; if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } /*void rend_set_render_mode_light(GLYPH_REND* const rend) { if (!rend) return; rend->hinting_target = FT_LOAD_TARGET_NORMAL; rend->load_flags = DEFAULT_LOAD_FLAGS | rend->hinting_mode | rend->hinting_target; rend->render_mode = FT_RENDER_MODE_LIGHT; if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); }*/ void gk_rend_set_undefined_char(GLYPH_REND* const rend,const unsigned new_undefined_char) { if (rend) rend->undefined_char = (new_undefined_char<=GK_MAX_UNICODE) ? new_undefined_char : 0; } void gk_rend_set_error_char(GLYPH_REND* const rend,const unsigned new_error_char) { if (rend) rend->error_char = (new_error_char<=GK_MAX_UNICODE) ? new_error_char : 0; } static void _gk_rend_remove_size_object(GLYPH_REND* const rend) { CARE(rend); if (rend->size) { FT_Done_Size(rend->size); rend->size = 0; } } /* * If calling to set the same keeper which is already set for this renderer, * this function still should uncache all glyphs and set the keeper anew. */ void gk_rend_set_keeper(GLYPH_REND* const rend,GLYPH_KEEP* const new_keeper) { if (!rend) return; if (rend->index) { GLYPH_INDEX *index = rend->index; /* No need to do anything, appropriate index is already assigned. */ if (index->keeper == new_keeper && _gk_glyph_index_ok_for_renderer(index,rend)) return; /* Unlink renderer and index from each other */ if (index->first_renderer==rend) index->first_renderer = rend->next_for_same_index; if (index->last_renderer==rend) index->last_renderer = rend->prev_for_same_index; if (rend->prev_for_same_index) rend->prev_for_same_index->next_for_same_index = rend->next_for_same_index; if (rend->next_for_same_index) rend->next_for_same_index->prev_for_same_index = rend->prev_for_same_index; rend->index = 0; rend->prev_for_same_index = 0; rend->next_for_same_index = 0; /* If dropped index has no other renderers and doesn't index any glyphs, */ /* it should be deleted. */ if (!index->first_renderer && !index->pages) _gk_glyph_index_done(index); } if (new_keeper) { GLYPH_INDEX *index; for (index = new_keeper->first_index; index; index = index->next) { if (_gk_glyph_index_ok_for_renderer(index,rend)) break; } if (!index) index = _gk_glyph_index_create(new_keeper,rend); if (!index) return; rend->index = index; rend->prev_for_same_index = 0; rend->next_for_same_index = index->first_renderer; if (index->first_renderer) index->first_renderer->prev_for_same_index = rend; if (!index->last_renderer) index->last_renderer = rend; index->first_renderer = rend; } } void gk_rend_set_face(GLYPH_REND* const rend,GLYPH_FACE* const new_face) { #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_rend_set_face() begin\n"); #endif if (!rend) return; if (new_face == rend->face) return; _gk_rend_remove_size_object(rend); if (rend->face) { if (rend->face->first_renderer==rend) rend->face->first_renderer = rend->next_for_same_face; if (rend->face->last_renderer==rend) rend->face->last_renderer = rend->prev_for_same_face; if (rend->prev_for_same_face) rend->prev_for_same_face->next_for_same_face = rend->next_for_same_face; if (rend->next_for_same_face) rend->next_for_same_face->prev_for_same_face = rend->prev_for_same_face; rend->face = 0; rend->prev_for_same_face = 0; rend->next_for_same_face = 0; } if (!new_face || !new_face->face) return; rend->face = new_face; /* If the face is not scalable, then we can't produce AA glyphs */ if (!FT_IS_SCALABLE(rend->face->face)) _gk_rend_reset_to_fixed(rend); /* Creating new size object and setting initial size */ { FT_New_Size(rend->face->face,&rend->size); if (!rend->size) { rend->face = 0; _gk_msg("Error: gk_rend_set_face(): can't create size object\n"); return; } if (!gk_rend_set_size_subpixel(rend,rend->hsize,rend->vsize)) { _gk_rend_remove_size_object(rend); rend->face = 0; _gk_msg("Error: gk_rend_set_face(): can't set initial size\n"); return; } } rend->face_id = rend->face->id; rend->prev_for_same_face = 0; rend->next_for_same_face = rend->face->first_renderer; if (rend->next_for_same_face) rend->next_for_same_face->prev_for_same_face = rend; if (!rend->face->last_renderer) rend->face->last_renderer = rend; rend->face->first_renderer = rend; if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_rend_set_face() end\n"); #endif } int gk_rend_set_size_subpixel(GLYPH_REND* const rend,const unsigned new_hsize,const unsigned new_vsize) { int error; if (!rend || !rend->face || !rend->face->face || !rend->size) return 0; funcname = "gk_rend_set_size_subpixel()"; error = FT_Activate_Size(rend->size); if (error) { _gk_msg("Error: %s: Can't activate size object\n",funcname); return 0; } if (FT_IS_SCALABLE(rend->face->face)) { error = FT_Set_Char_Size(rend->face->face,new_hsize,new_vsize,72,72); if (error) { _gk_msg("Error: %s: Can't set font size to %.3f x %.3f pixels\n", funcname, ((double)new_hsize)/64, ((double)new_vsize)/64 ); return 0; } rend->hsize = new_hsize; rend->vsize = new_vsize; } else { int try_smaller_size = (new_vsize+32)/64; int try_larger_size = (new_vsize+32)/64; int result_hsize, result_vsize; error = FT_Set_Pixel_Sizes(rend->face->face, (new_hsize+32)/64, (new_vsize+32)/64 ); if (error) error = FT_Set_Pixel_Sizes(rend->face->face, 0, (new_vsize+32)/64 ); while (error && --try_smaller_size>1) error = FT_Set_Pixel_Sizes(rend->face->face,0,try_smaller_size); while (error && ++try_larger_size<100) error = FT_Set_Pixel_Sizes(rend->face->face,0,try_larger_size); if (error) { _gk_msg("Error: %s: Can't select font pixel size to match %.3f x %.3f pixels\n", funcname, ((double)new_hsize)/64, ((double)new_vsize)/64 ); return 0; } result_hsize = rend->size->metrics.x_ppem; result_vsize = rend->size->metrics.y_ppem; rend->hsize = result_hsize * 64; rend->vsize = result_vsize * 64; _gk_rend_reset_to_fixed(rend); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"Pixel size of %d x %d is selected\n",result_hsize,result_vsize); #endif } rend->line_spacing = rend->face->face->size->metrics.height; rend->line_spacing_pixels = (rend->line_spacing+63)>>6; rend->text_height = gk_rend_ascender(rend) - gk_rend_descender(rend); rend->text_height_pixels = ((gk_rend_ascender(rend)+63)>>6) - ((gk_rend_descender(rend)+63)>>6); if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); #if (GLYPH_TARGET == GLYPH_TARGET_ALLEGRO) if (rend->target_info) ((FONT*)rend->target_info)->height = rend->text_height_pixels; #endif return 1; } int gk_rend_set_size_pixels(GLYPH_REND* const rend,const unsigned new_pixel_hsize,const unsigned new_pixel_vsize) { return gk_rend_set_size_subpixel(rend,new_pixel_hsize<<6,new_pixel_vsize<<6); } static void _gk_rend_update_matrix(GLYPH_REND* const rend) { rend->do_matrix_transform = (rend->text_angle != 0 || rend->italic_angle != 0); if (rend->do_matrix_transform) { FT_Matrix a; rend->matrix.xx = 0x10000; rend->matrix.xy = (FT_Fixed)(sin(rend->italic_angle)*(GK_SQRT2*0x10000)); rend->matrix.yx = 0; rend->matrix.yy = 0x10000; a.xx = (FT_Fixed)( rend->text_angle_cos*0x10000); a.xy = (FT_Fixed)(-rend->text_angle_sin*0x10000); a.yx = (FT_Fixed)( rend->text_angle_sin*0x10000); a.yy = (FT_Fixed)( rend->text_angle_cos*0x10000); FT_Matrix_Multiply(&a,&rend->matrix); } } void gk_rend_set_angle_in_radians(GLYPH_REND* const rend,const double new_text_angle) { if (!rend) return; if (!rend->face || !rend->face->face || (rend->face && rend->face->face && FT_IS_SCALABLE(rend->face->face)) ) { if (rend->text_angle != new_text_angle) { rend->text_angle = new_text_angle; rend->text_angle_sin = sin(new_text_angle); rend->text_angle_cos = cos(new_text_angle); _gk_rend_update_matrix(rend); if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } } } void gk_rend_set_angle_in_degrees(GLYPH_REND* const rend,const double new_text_angle) { gk_rend_set_angle_in_radians(rend,new_text_angle*GK_PI/180); } double gk_rend_get_angle_in_radians(const GLYPH_REND* const rend) { return rend ? rend->text_angle : 0; } double gk_rend_get_angle_in_degrees(const GLYPH_REND* const rend) { return rend ? rend->text_angle*180/GK_PI : 0; } void gk_rend_set_italic_angle_in_radians(GLYPH_REND* const rend,const double new_italic_angle) { if (!rend) return; if (new_italic_angle < -GK_PI/4 || new_italic_angle > GK_PI*4) return; if (!rend->face || !rend->face->face || (rend->face && rend->face->face && FT_IS_SCALABLE(rend->face->face)) ) { if (rend->italic_angle != new_italic_angle) { rend->italic_angle = new_italic_angle; _gk_rend_update_matrix(rend); if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); /*_gk_msg("new italic angle set: %.3f\n",new_italic_angle);*/ } } } void gk_rend_set_italic_angle_in_degrees(GLYPH_REND* const rend,const double new_italic_angle) { gk_rend_set_italic_angle_in_radians(rend,new_italic_angle*GK_PI/180); } double gk_get_italic_angle_in_radians(const GLYPH_REND* const rend) { return rend ? rend->italic_angle : 0; } double gk_get_italic_angle_in_degrees(const GLYPH_REND* const rend) { return rend ? rend->italic_angle*180/GK_PI : 0; } void gk_rend_set_bold_strength(GLYPH_REND* const rend,const int new_bold_strength) { if (!rend) return; if (!rend->face || !rend->face->face || (rend->face && rend->face->face && FT_IS_SCALABLE(rend->face->face)) ) { rend->bold_strength = new_bold_strength; if (rend->index) gk_rend_set_keeper(rend,rend->index->keeper); } } int gk_rend_get_bold_strength(const GLYPH_REND* const rend) { return rend ? rend->bold_strength : 0; } void gk_rend_set_before_renderer ( GLYPH_REND* const rend, GLYPH_REND* const new_before_rend, const int new_before_dx, const int new_before_dy ) { if (!rend) return; rend->before_rend = new_before_rend; rend->before_dx = new_before_dx; rend->before_dy = new_before_dy; } void gk_rend_set_after_renderer ( GLYPH_REND* const rend, GLYPH_REND* const new_after_rend, const int new_after_dx, const int new_after_dy ) { if (!rend) return; rend->after_rend = new_after_rend; rend->after_dx = new_after_dx; rend->after_dy = new_after_dy; } void gk_rend_debug(const GLYPH_REND* const rend) { _gk_msg("GLYPH_REND object (%d):\n",rend); if (!rend) return; if (rend->face) _gk_msg(" there is a font_face object associated, id is %d\n",rend->face->id); else _gk_msg(" no font_face object associated\n"); if (rend->size) { _gk_msg(" there is a size object associated:\n"); _gk_msg(" EM size in pixels is %dx%d\n",rend->size->metrics.x_ppem,rend->size->metrics.y_ppem); _gk_msg(" ascender is %d\n",rend->size->metrics.ascender>>6); _gk_msg(" descender is %d\n",rend->size->metrics.descender>>6); _gk_msg(" line interval is %d\n",rend->size->metrics.height>>6); } else _gk_msg(" no size object associated\n"); if (rend->index) { _gk_msg(" there is a GLYPH_INDEX / GLYPH_KEEP object associated:\n"); _gk_msg(" GLYPH_INDEX object (%d):\n",rend->index); _gk_msg(" index size is %d bytes\n",_gk_glyph_index_size(rend->index)); _gk_msg(" rend->prev_for_same_index is %d\n",rend->prev_for_same_index); _gk_msg(" rend->next_for_same_index is %d\n",rend->next_for_same_index); _gk_msg(" GLYPH_KEEP object (%d):\n",rend->index->keeper); if (gk_keeper_glyph_limit(rend->index->keeper)) _gk_msg(" keeping %d glyphs, can keep %d glyphs maximum\n", gk_keeper_glyph_count(rend->index->keeper),gk_keeper_glyph_limit(rend->index->keeper)); else _gk_msg(" keeping %d glyphs, not limited in glyph number\n", gk_keeper_glyph_count(rend->index->keeper)); if (gk_keeper_byte_limit(rend->index->keeper)) _gk_msg(" using %d bytes of memory, can use %d bytes maximum\n", gk_keeper_byte_count(rend->index->keeper),gk_keeper_byte_limit(rend->index->keeper)); else _gk_msg(" using %d bytes of memory, not limited in memory usage\n", gk_keeper_byte_count(rend->index->keeper)); } else _gk_msg(" no GLYPH_INDEX / GLYPH_KEEP object associated\n"); _gk_msg(" ascender is %.3f pixels\n",((double)gk_rend_ascender(rend))/64); _gk_msg(" descender is %.3f pixels\n",((double)gk_rend_descender(rend))/64); _gk_msg(" line spacing is %.3f ~ %d pixels\n", ((double)(rend->line_spacing))/64,rend->line_spacing_pixels); _gk_msg(" text_height is %.3f ~ %d pixels\n", ((double)(rend->text_height))/64,rend->text_height_pixels); } int gk_rend_has_character(const GLYPH_REND* const rend,const unsigned code) { if (!rend || !rend->face || !rend->face->face || code>GK_MAX_UNICODE || !code) return 0; if (FT_Get_Char_Index(rend->face->face,code)!=0) return 1; else return 0; } int gk_rend_has_glyph(GLYPH_REND* const rend,const unsigned code) { GLYPH *glyph; int has_glyph; if (!gk_rend_has_character(rend,code)) return 0; glyph = _gk_rend_render(rend,code); if (!glyph) return 0; has_glyph = (glyph->bmp) ? 1 : 0; if (!glyph->index) _gk_unload_glyph(glyph); return has_glyph; } GLYPH_REND* gk_create_renderer(GLYPH_FACE* const face,GLYPH_KEEP* const keeper) { GLYPH_REND *rend; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_create_renderer() begin\n"); #endif funcname = "gk_create_renderer()"; rend = (GLYPH_REND*)_gk_malloc(sizeof(GLYPH_REND)); if (!rend) return 0; rend->face = 0; rend->size = 0; rend->index = 0; rend->hinting_mode = 0; rend->hinting_target = FT_LOAD_TARGET_NORMAL; rend->load_flags = DEFAULT_LOAD_FLAGS | rend->hinting_mode | rend->hinting_target; rend->render_mode = FT_RENDER_MODE_NORMAL; rend->hsize = rend->vsize = 16<<6; rend->undefined_char = '?'; rend->error_char = 0; rend->line_spacing = rend->line_spacing_pixels = 0; rend->text_height = rend->text_height_pixels = 0; rend->text_angle = 0; rend->text_angle_sin = 0; rend->text_angle_cos = 1; rend->italic_angle = 0; rend->bold_strength = 0; rend->do_matrix_transform = 0; rend->matrix.xx = 0x10000l; rend->matrix.xy = 0; rend->matrix.yx = 0; rend->matrix.yy = 0x10000l; rend->text_alpha_color = 0xFF0000FF; rend->back_color = -1; rend->before_rend = 0; rend->before_dx = 0; rend->before_dy = 0; rend->after_rend = 0; rend->after_dx = 0; rend->after_dy = 0; rend->prev_for_same_face = rend->next_for_same_face = 0; rend->prev_for_same_index = rend->next_for_same_index = 0; rend->target_info = 0; gk_rend_set_face(rend,face); gk_rend_set_keeper(rend,keeper); rend->next = 0; rend->prev = last_renderer; if (last_renderer) last_renderer->next = rend; if (!first_renderer) first_renderer = rend; last_renderer = rend; _gk_install_exit_handler(); _gk_msg("glyph renderer created\n"); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_create_renderer() end\n"); #endif return rend; } GLYPH_REND* gk_create_copy_of_renderer(GLYPH_REND* const rend) { GLYPH_REND *new_rend; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_create_copy_of_renderer() begin\n"); #endif if (!rend) return 0; new_rend = gk_create_renderer(rend->face,0); if (!new_rend) return 0; new_rend->text_alpha_color = rend->text_alpha_color; new_rend->back_color = rend->back_color; new_rend->undefined_char = rend->undefined_char; new_rend->error_char = rend->error_char; new_rend->hinting_mode = rend->hinting_mode; new_rend->hinting_target = rend->hinting_target; new_rend->load_flags = rend->load_flags; new_rend->render_mode = rend->render_mode; new_rend->target_info = rend->target_info; new_rend->text_angle = rend->text_angle; new_rend->text_angle_sin = rend->text_angle_sin; new_rend->text_angle_cos = rend->text_angle_cos; new_rend->italic_angle = rend->italic_angle; new_rend->bold_strength = rend->bold_strength; new_rend->do_matrix_transform = rend->do_matrix_transform; new_rend->matrix.xx = rend->matrix.xx; new_rend->matrix.xy = rend->matrix.xy; new_rend->matrix.yx = rend->matrix.yx; new_rend->matrix.yy = rend->matrix.yy; gk_rend_set_size_subpixel(new_rend,rend->hsize,rend->vsize); if (rend->index) gk_rend_set_keeper(new_rend,rend->index->keeper); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_create_copy_of_renderer() end\n"); #endif return new_rend; } void gk_done_renderer(GLYPH_REND* const rend) { #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_done_renderer() begin\n"); #endif if (!rend) return; gk_rend_set_keeper(rend,0); gk_rend_set_face(rend,0); #if (GLYPH_TARGET == GLYPH_TARGET_ALLEGRO) if (rend->target_info) _gk_free(rend->target_info); #endif if (rend==first_renderer) first_renderer = rend->next; if (rend==last_renderer) last_renderer = rend->prev; if (rend->next) rend->next->prev = rend->prev; if (rend->prev) rend->prev->next = rend->next; _gk_free(rend); _gk_msg("glyph renderer destroyed\n"); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"gk_done_renderer() end\n"); #endif } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_to_sdl_rect.c0000644000175000017500000002244710461545476024652 0ustar georgeskgeorgesk/* * glyph_to_sdl.c - part of Glyph Keeper SDL driver. * * Copyright (c) 2003-2005 Kirill Kryukov * * This file uses code from SDL_gfx library, written by Andreas Schiffler. * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_to_sdl_c #ifdef GLYPH_TARGET_HAS_RECTFILL void _gk_sdl_box_color(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) { Sint16 left, right, top, bottom; Uint8 *pixel, *pixellast; int x, dx; int dy; int pixx, pixy; Sint16 w, h, tmp; Uint8 *colorptr; left = dst->clip_rect.x; right = dst->clip_rect.x + dst->clip_rect.w - 1; top = dst->clip_rect.y; bottom = dst->clip_rect.y + dst->clip_rect.h - 1; if ((x1right) && (x2>right)) return; if ((y1bottom) && (y2>bottom)) return; if (x1right) { x1=right; } if (x2right) { x2=right; } if (y1bottom) { y1=bottom; } if (y2bottom) { y2=bottom; } if (x1 > x2) { tmp = x1; x1 = x2; x2 = tmp; } if (y1 > y2) { tmp = y1; y1 = y2; y2 = tmp; } w = x2 - x1; h = y2 - y1; colorptr = (Uint8 *) & color; if (SDL_BYTEORDER == SDL_BIG_ENDIAN) color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); else color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); dx = w; dy = h; pixx = dst->format->BytesPerPixel; pixy = dst->pitch; pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1; pixellast = pixel + pixx * dx + pixy * dy; dx++; switch (dst->format->BytesPerPixel) { case 1: for (; pixel <= pixellast; pixel += pixy) { memset(pixel, (Uint8) color, dx); } break; case 2: pixy -= (pixx * dx); for (; pixel <= pixellast; pixel += pixy) for (x = 0; x < dx; x++) { *(Uint16 *) pixel = color; pixel += pixx; } break; case 3: pixy -= (pixx * dx); for (; pixel <= pixellast; pixel += pixy) { for (x = 0; x < dx; x++) { if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { pixel[0] = (color >> 16) & 0xff; pixel[1] = (color >> 8) & 0xff; pixel[2] = color & 0xff; } else { pixel[0] = color & 0xff; pixel[1] = (color >> 8) & 0xff; pixel[2] = (color >> 16) & 0xff; } pixel += pixx; } } break; default: pixy -= (pixx * dx); for (; pixel <= pixellast; pixel += pixy) for (x = 0; x < dx; x++) { *(Uint32 *) pixel = color; pixel += pixx; } break; } } static void _gk_driver_rectfill(SDL_Surface* const bmp,const int x1,const int y1,const int x2,const int y2,const int color) { unsigned r = (color>>16)&0xFF; unsigned g = (color>>8)&0xFF; unsigned b = (color)&0xFF; _gk_sdl_box_color(bmp,x1,y1,x2,y2,(r<<24)|(g<<16)|(b<<8)); if (x1 < _gk_x_min) _gk_x_min = x1; if (x2 < _gk_x_min) _gk_x_min = x2; if (x1 > _gk_x_max) _gk_x_max = x1; if (x2 > _gk_x_max) _gk_x_max = x2; if (y1 < _gk_y_min) _gk_y_min = y1; if (y2 < _gk_y_min) _gk_y_min = y2; if (y1 > _gk_y_max) _gk_y_max = y1; if (y2 > _gk_y_max) _gk_y_max = y2; } #ifdef GLYPH_TARGET_HAS_RECTFILL_ANGLED void _gk_sdl_hline_color(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) { Sint16 left, right, top, bottom; Uint8 *pixel, *pixellast; int dx; int pixx, pixy; Sint16 w; Sint16 xtmp; Uint8 *colorptr; left = dst->clip_rect.x; right = dst->clip_rect.x + dst->clip_rect.w - 1; top = dst->clip_rect.y; bottom = dst->clip_rect.y + dst->clip_rect.h - 1; if ((x1right) && (x2>right)) { return; } if ((ybottom)) { return; } if (x1 < left) { x1 = left; } if (x2 > right) { x2 = right; } if (x1 > x2) { xtmp = x1; x1 = x2; x2 = xtmp; } w = x2 - x1; if (w < 0) { return; } colorptr = (Uint8 *) & color; if (SDL_BYTEORDER == SDL_BIG_ENDIAN) color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]); else color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]); dx = w; pixx = dst->format->BytesPerPixel; pixy = dst->pitch; pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y; switch (dst->format->BytesPerPixel) { case 1: memset(pixel, color, dx); break; case 2: pixellast = pixel + dx + dx; for (; pixel <= pixellast; pixel += pixx) { *(Uint16 *) pixel = color; } break; case 3: pixellast = pixel + dx + dx + dx; for (; pixel <= pixellast; pixel += pixx) { if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { pixel[0] = (color >> 16) & 0xff; pixel[1] = (color >> 8) & 0xff; pixel[2] = color & 0xff; } else { pixel[0] = color & 0xff; pixel[1] = (color >> 8) & 0xff; pixel[2] = (color >> 16) & 0xff; } } break; default: dx = dx + dx; pixellast = pixel + dx + dx; for (; pixel <= pixellast; pixel += pixx) { *(Uint32 *) pixel = color; } break; } } int _gk_sdl_compare_ints(const void *a, const void *b) { return (*(const int *) a) - (*(const int *) b); } static int *_gk_sdl_poly_ints = 0; static int _gk_sdl_poly_allocated = 0; void _gk_sdl_filled_polygon_color(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color) { int i; int y, xa, xb; int miny, maxy; int x1, y1; int x2, y2; int ind1, ind2; int ints; if (n < 3) { return; } if (!_gk_sdl_poly_allocated) { _gk_sdl_poly_ints = (int *) malloc(sizeof(int) * n); _gk_sdl_poly_allocated = n; } else { if (_gk_sdl_poly_allocated < n) { _gk_sdl_poly_ints = (int *) realloc(_gk_sdl_poly_ints, sizeof(int) * n); _gk_sdl_poly_allocated = n; } } miny = vy[0]; maxy = vy[0]; for (i = 1; (i < n); i++) { if (vy[i] < miny) miny = vy[i]; else if (vy[i] > maxy) maxy = vy[i]; } for (y = miny; (y <= maxy); y++) { ints = 0; for (i = 0; (i < n); i++) { if (!i) { ind1 = n - 1; ind2 = 0; } else { ind1 = i - 1; ind2 = i; } y1 = vy[ind1]; y2 = vy[ind2]; if (y1 < y2) { x1 = vx[ind1]; x2 = vx[ind2]; } else if (y1 > y2) { y2 = vy[ind1]; y1 = vy[ind2]; x2 = vx[ind1]; x1 = vx[ind2]; } else { continue; } if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) { _gk_sdl_poly_ints[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1); } } qsort(_gk_sdl_poly_ints, ints, sizeof(int), _gk_sdl_compare_ints); for (i = 0; (i < ints); i += 2) { xa = _gk_sdl_poly_ints[i] + 1; xa = (xa >> 16) + ((xa & 32768) >> 15); xb = _gk_sdl_poly_ints[i+1] - 1; xb = (xb >> 16) + ((xb & 32768) >> 15); _gk_sdl_hline_color(dst, xa, xb, y, color); } } } static void _gk_driver_rectfill_angled(SDL_Surface* const bmp,const int x1,const int y1, const int x2,const int y2,const int x3,const int y3,const int x4,const int y4,const int color) { unsigned r = (color>>16)&0xFF; unsigned g = (color>>8)&0xFF; unsigned b = (color)&0xFF; short vx[4] = { x1, x2, x3, x4 }; short vy[4] = { y1, y2, y3, y4 }; _gk_sdl_filled_polygon_color(bmp,vx,vy,4,(r<<24)|(g<<16)|(b<<8)); if (x1 < _gk_x_min) _gk_x_min = x1; if (x2 < _gk_x_min) _gk_x_min = x2; if (x3 < _gk_x_min) _gk_x_min = x3; if (x4 < _gk_x_min) _gk_x_min = x4; if (x1 > _gk_x_max) _gk_x_max = x1; if (x2 > _gk_x_max) _gk_x_max = x2; if (x3 > _gk_x_max) _gk_x_max = x3; if (x4 > _gk_x_max) _gk_x_max = x4; if (y1 < _gk_y_min) _gk_y_min = y1; if (y2 < _gk_y_min) _gk_y_min = y2; if (y3 < _gk_y_min) _gk_y_min = y3; if (y4 < _gk_y_min) _gk_y_min = y4; if (y1 > _gk_y_max) _gk_y_max = y1; if (y2 > _gk_y_max) _gk_y_max = y2; if (y3 > _gk_y_max) _gk_y_max = y3; if (y4 > _gk_y_max) _gk_y_max = y4; } #endif /* GLYPH_TARGET_HAS_RECTFILL_ANGLED */ #endif /* GLYPH_TARGET_HAS_RECTFILL */ #endif /* included_from_glyph_to_sdl_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph.c0000644000175000017500000000203410567602066022253 0ustar georgeskgeorgesk/* * glyph.c - Glyph Keeper source container, includes all other files. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #define included_from_glyph_c /* Internal header. */ #include "glyph_internal.h" /* Memory manager header. */ #include "glyph_memory.h" /* Global variables. */ #include "glyph_global_vars.c" /* Memory manager. */ #include "glyph_memory.c" /* Simple routines. */ #include "glyph_utils.c" /* GLYPH_FACE routines. */ #include "glyph_face.c" /* GLYPH_INDEX and GLYPH_KEEP routines. */ #include "glyph_index.c" /* GLYPH_REND routines. */ #include "glyph_rend.c" /* Rendering a glyph. */ #include "glyph_workout.c" /* Routines finding text size. */ #include "glyph_dimensions.c" /* Main routines. */ #include "glyph_main.c" /* Driver code. */ #include GK_DRIVER_CODE openlayer-2.1.orig/utils/glyphkeeper/src/glyph_utils.c0000644000175000017500000000671310567602066023503 0ustar georgeskgeorgesk/* * glyph_utils.c - Glyph Keeper basic support routines. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifdef included_from_glyph_c /* * Passing messages from Glyph Keeper to the application. */ void gk_set_messenger(void (*func)(const char* const)) { _gk_messenger = func; } static void _gk_msg(const char* const format,...) { va_list arg; static char buf[1000] = "[glyph] "; if (!_gk_messenger) return; va_start(arg,format); vsprintf(buf+8,format,arg); va_end(arg); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"msg: %s\n",buf); #endif _gk_messenger(buf); } /* * Setting font search path */ void gk_set_font_path(const char* const path) { _gk_font_path = path; } /* * Setting exit handler. */ static void _gk_install_exit_handler() { if (!_gk_atexit_installed) { if (atexit(gk_library_cleanup)==0) _gk_atexit_installed = 1; else _gk_msg("Error: Can't install exit handler with atexit().\n"); } } /* * Returns size in bytes of one glyph. * Both size of GLYPH structure and size of glyph bitmap are counted. */ static size_t glyph_size_in_bytes(const GLYPH* const g) { return sizeof(GLYPH) + g->bmpsize; } /* * UTF-8 decoder. * (taken from Allegro) */ static unsigned _gk_utf8_getx(const char** s) { int c; CARE(s); c = *((unsigned char *)((*s)++)); if (c&0x80) { int n = 1; while (c&(0x80>>n)) n++; c &= (1<<(8-n))-1; while (--n>0) { int t = *((unsigned char *)((*s)++)); if ((!(t&0x80))||(t&0x40)) { (*s)--; return '?'; } c = (c<<6)|(t&0x3F); } } return c; } /* * UTF-16 decoding functions. * 's' and '*s' must be not null. */ static void _gk_utf16_start_decoding(const unsigned short** s) { unsigned short a = **s; if (a == 0xFFFE) { _gk_utf16_opposite_byte_sex = 1; (*s)++; return; } _gk_utf16_opposite_byte_sex = 0; if (a == 0xFEFF) { (*s)++; } } static unsigned _gk_utf16_decode(const unsigned short** s) { unsigned short a,b; const unsigned short* ss = *s; a = *ss; ss++; if (_gk_utf16_opposite_byte_sex) a = ((a&0xFF)<<8)|(a>>8); if (a <= 0xD7FF || a >= 0xE000) { *s = ss; return a; } if (a > 0xDBFF) { return 0; } b = *ss; ss++; if (_gk_utf16_opposite_byte_sex) b = ((b&0xFF)<<8)|(b>>8); if (b < 0xDC00 || b > 0xDFFF) { return 0; } return 0x10000 + ( (((int)a&0x3FF)<<10) | ((int)b&0x3FF) ); } /* * UTF-32 decoding functions. * 's' and '*s' must be not null. */ static void _gk_utf32_start_decoding(const unsigned int** s) { unsigned int a = **s; if (a == 0xFFFE0000) { _gk_utf32_opposite_byte_sex = 1; (*s)++; return; } _gk_utf32_opposite_byte_sex = 0; if (a == 0x0000FEFF) { (*s)++; } } static unsigned _gk_utf32_decode(const unsigned int** s) { unsigned int a = **s; if (_gk_utf32_opposite_byte_sex) { a = ((a&0x000000FF)<<24) | ((a&0x0000FF00)<<8) | ((a&0x00FF0000)>>8) | (a>>24); } if (a <= 0xD7FF || a >= 0xE000) { (*s)++; return a; } else { return 0; } } #endif /* included_from_glyph_c */ openlayer-2.1.orig/utils/glyphkeeper/src/glyph_internal.h0000644000175000017500000000515110567602066024157 0ustar georgeskgeorgesk/* * glyph_internal.h - Glyph Keeper internal header file. * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifndef glyph_internal_h_included #define glyph_internal_h_included #include #include #include #include #include #include FT_FREETYPE_H #include FT_BITMAP_H #include FT_GLYPH_H #include FT_SIZES_H #include FT_SYNTHESIS_H #include FT_OUTLINE_H #include FT_TRIGONOMETRY_H #include "../include/glyph.h" #include "glyph_structs.h" #define GK_PI 3.14159265358979323846 #define GK_SQRT2 1.41421356237309504880 #define GK_MIN(a,b) ((a)<(b)?(a):(b)) #define GK_MAX(a,b) ((a)>(b)?(a):(b)) /* * This macro should be used to check internal consistensy only. * All things coming from user through API should be checked in some other way. * (Because this checking can be turned on/off by GLYPH_SAFE macro) */ #ifdef GLYPH_SAFE #define CARE(thing) \ { if (!(thing)) { _gk_msg("Error: some really bad thing happened: %s, line %d\n",__FILE__,__LINE__); exit(1); } } #else #define CARE(thing) {} #endif #define GLYPH_UNCOMPRESSED 0 #ifdef GLYPH_TARGET_KNOWS_RLEAA #define GLYPH_RLEAA 1 #endif #define GLYPH_MONO 2 #ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK #define GLYPH_MONO_BITPACK 2 #endif #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 #define GLYPH_MONO_RLE7 3 #endif /* * Functions that must be defined by the target driver code. */ #ifdef GLYPH_TARGET_HAS_RECTFILL static void _gk_driver_rectfill(GLYPH_TARGET_SURFACE* const bmp, const int x1,const int y1,const int x2,const int y2,const int color); #ifdef GLYPH_TARGET_HAS_RECTFILL_ANGLED static void _gk_driver_rectfill_angled(GLYPH_TARGET_SURFACE* const bmp,const int x1,const int y1, const int x2,const int y2,const int x3,const int y3,const int x4,const int y4,const int color); #endif /* GLYPH_TARGET_HAS_RECTFILL_ANGLED */ #endif /* GLYPH_TARGET_HAS_RECTFILL */ static void _gk_prepare_to_draw(GLYPH_TARGET_SURFACE* const new_bmp,GLYPH_REND* const new_rend); static void _gk_put_glyph(GLYPH* const glyph,const int x,const int y); static void _gk_done_drawing(); /* * End of target driver's functions. */ static void _gk_unload_glyph(GLYPH* const glyph); static GLYPH* _gk_rend_render(GLYPH_REND* const rend,const unsigned unicode); static void _gk_msg(const char* const format,...); #endif openlayer-2.1.orig/utils/glyphkeeper/readme.txt0000644000175000017500000000425610567602066022203 0ustar georgeskgeorgesk _____ _ _ _ __ / ____| | | | | |/ / | | __| |_ _ _ __ | |__ | ' / ___ ___ _ __ ___ _ __ | | |_ | | | | | '_ \| '_ \ | < / _ \/ _ \ '_ \ / _ \ '__| | |__| | | |_| | |_) | | | | | . \ __/ __/ |_) | __/ | \_____|_|\__, | .__/|_| |_| |_|\_\___|\___| .__/ \___|_| __/ | | | | |___/|_| |_| 0.32 Introduction ------------ Glyph Keeper is a text rendering library written in C. In can enable your program to load a font from file, render character glyphs, and output them to the target surface. Glyph Keeper should work on any platform which has C compiler, FreeType, and your target library (Allegro or SDL). See installation instructions in "install.txt" file. More information is available on Glyph Keeper web-site: http://kd.lab.nig.ac.jp/glyph-keeper/ Files, included in this package: -------------------------------- behcnmark/ - Benchmark programs for testing Glyph Keeper performance. docs/* - Documentation. examples/ - Glyph Keeper Examples. fonts/ - Example fonts. freetype/ - FreeType source code. include/glyph.h - Glyph Keeper header file, you may want to copy it to your compiler 'include' directory. obj/ - Empty directory, where object and lib files will be produced. src/ - Glyph Keeper source. If you compile Glyph Keeper manually, you only need to compile "src/glyph.c", as it #includes all other files. authors.txt - List of people contributed to Glyph Keeper development. changes.txt - Glyph Keeper version history. install.txt - Installation instructions. license.txt - Glyph Keeper license. *.bat - Batch files for compiling and installing Glyph Keeper. Makefile.* - Makefiles for compiling and installing Glyph Keeper. quotes.txt - What people say about Glyph Keeper. releng.txt - How to prepare a new release of Glyph Keeper. readme.txt - This file. to-do.txt - List of first priority things to do. openlayer-2.1.orig/utils/glyphkeeper/CMakeLists.txt0000644000175000017500000000430710567602066022742 0ustar georgeskgeorgesk# ------------------------------------------------------- # GlyphKeeper cmake build script if not using internal # renderer # Written by: juvinious # ------------------------------------------------------- # ------------------------------------------------------- # project name # ------------------------------------------------------- project (GlyphKeeper) # ------------------------------------------------------- # Including needed macros # ------------------------------------------------------- find_package(FREETYPE REQUIRED) find_package(ALLEGROGL REQUIRED) if(NOT MSVC) add_definitions(-DGK_NO_LEGACY -DGLYPH_TARGET=GLYPH_TARGET_ALLEGGL) else(NOT MSVC) add_definitions(/DGK_NO_LEGACY /DGLYPH_TARGET=GLYPH_TARGET_ALLEGGL) endif(NOT MSVC) # ------------------------------------------------------- # Source directory containing all the necessary .cpp files # ------------------------------------------------------- set(GK_SOURCES src/glyph.c src/glyph_global_vars.c src/glyph_rend.c src/glyph_to_allegro_mono.c src/glyph_dimensions.c src/glyph_index.c src/glyph_to_allegro_aa.c src/glyph_to_opengl.c src/glyph_face.c src/glyph_main.c src/glyph_to_allegro.c src/glyph_utils.c src/glyph_memory.c src/glyph_workout.c) # ------------------------------------------------------- # Include directory # ------------------------------------------------------- include_directories(include src ${FREETYPE_INCLUDE_DIR}) # ------------------------------------------------------- # OpenLayer Library # ------------------------------------------------------- add_library (glyph-agl ${CREATE_STATIC_LIBRARY} ${GK_SOURCES}) # ------------------------------------------------------- # Create the library # ------------------------------------------------------- target_link_libraries(glyph-agl) configure_file(include/glyph.h ${CMAKE_BINARY_DIR}/include/glyph.h COPYONLY) # ------------------------------------------------------- # Installation # ------------------------------------------------------- if(NOT MSVC) install(FILES ${CMAKE_BINARY_DIR}/include/glyph.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include) install(TARGETS glyph-agl DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) endif(NOT MSVC) openlayer-2.1.orig/utils/glyphkeeper/include/0000700000175000017500000000000012262355751021607 5ustar georgeskgeorgeskopenlayer-2.1.orig/utils/glyphkeeper/include/glyph.h0000644000175000017500000011327210567602066023123 0ustar georgeskgeorgesk/* * glyph.h - Glyph Keeper API header file * * Copyright (c) 2003-2007 Kirill Kryukov * * This file is part of Glyph Keeper library, and may only be used, * modified, and distributed under the terms of the Glyph Keeper * license, located in the file 'license.txt' within this package. */ #ifndef glyph_h_included #define glyph_h_included /* * Glyph Keeper identification */ #define GK_VERSION_MAJOR 0 #define GK_VERSION_MINOR 32 #define GK_VERSION_PATCH 0 #define GK_VERSION_STR "0.32.0" #define GK_DATE_STR "2007-02-06" /* * Define this macro to enable more safety checks. * Useful for debugging, but results in a little slower code. * * Note: Defining this macro will affect Glyph Keeper, not your program. * Enabling/disabling this macro has effect only after recompiling the * Glyph Keeper library. */ /*#define GLYPH_SAFE*/ /* * Define this macro to enable Glyph Keeper internal logging. * This is used for debugging Glyph Keeper library, so use it only if you * want to debug Glyph Keeper, or to understand how it works. * * When you run a program linked to Glyph Keeper compiled with GLYPH_LOG * defined, a logfile "glyph.log" will be created in the curent directory. * Many things then will be written to that file, as your program calls * Glyph Keeper rountines. * * Note that enabling this option slows down the Glyph Keeper dramatically, * so don't attempt to run a benchmark with this option on. */ /*#define GLYPH_LOG*/ /* * Debugging Glyph Keeper and FreeType memory usage. */ /*#define GLYPH_DEBUG_GK_MEMORY*/ /*#define GLYPH_LOG_GK_MEMORY*/ /*#define GLYPH_DEBUG_FT_MEMORY*/ /*#define GLYPH_LOG_FT_MEMORY*/ /* * If you want to make Glyph Keeper DLL you should * define GLYPH_DLL when compiling Glyph Keeper. * This will give __declspec(dllexport) to all Glyph Keeper API fuctions. * * Feel free to modify this if your compiler wants some other declaration. * But in that case please send me back your changes, so I can include them * in next version. */ #undef GLYPH_DECLSPEC #ifdef GLYPH_DLL #define GLYPH_DECLSPEC __declspec(dllexport) #else #define GLYPH_DECLSPEC #endif /* * Glyph Keeper supports three rendering target systems: * * 1 - Pure text mode. No any graphics library is involved. * All you can do is render character glyphs one by one and write them * to the FILE* stream. Kind of ASCII art. * * This mode is useful to isolate problems related to Glyph Keeper only. * It is also convenient to check if Glyph Keeper works with your * FreeType installation, without introducing extra dependencies. * * 2 - Rendering target is Allegro's BITMAP. * You have to supply Allegro headers and link with Allegro lib. * * 3 - Rendering target is SDL's SDL_Surface. * Requires SDL and SDL_gfx libraries. * * You have to define GLYPH_TARGET to be one of these targets. * To do this, add line like this (for example): * #define GLYPH_TARGET = GLYPH_TARGET_ALLEGRO * to your program _BEFORE_ including "glyph.h" * * Also, you should define this macro to the same thing when compiling * Glyph Keeper itself. It's better to do in compiler's command line, * like this: " -DGLYPH_TARGET=GLYPH_TARGET_ALLEGRO " * It is also OK to do it in command line for all your project files, * so that you don't need to #define it in the source. * * You can't mix two targets in one program. * * If you don't define GLYPH_TARGET to anything, * "glyph.h" will define it to GLYPH_TARGET_TEXT, the default target. */ #define GLYPH_TARGET_TEXT 1 #define GLYPH_TARGET_ALLEGRO 2 #define GLYPH_TARGET_SDL 3 #define GLYPH_TARGET_OPENGL 4 #define GLYPH_TARGET_ALLEGGL 5 /* * Checking for defined target. * Aliasing the target bitmap structure with GLYPH_TARGET_SURFACE * and including target-specific headers. * GLYPH_TARGET_TEXT is the default target. */ #if (GLYPH_TARGET == GLYPH_TARGET_ALLEGGL) || (GLYPH_TARGET == GLYPH_TARGET_OPENGL) #define GLYPH_TARGET_STR "OpenGL" #define GK_DRIVER_CODE "glyph_to_opengl.c" #define GLYPH_TARGET_SURFACE GLYPH_TEXTURE typedef struct GLYPH_TEXTURE GLYPH_TEXTURE; #elif (GLYPH_TARGET == GLYPH_TARGET_ALLEGRO) #include #include #define GLYPH_TARGET_STR "Allegro" #define GLYPH_TARGET_SURFACE BITMAP #define GLYPH_TARGET_KNOWS_RLEAA #define GLYPH_TARGET_KNOWS_MONO_BITPACK #define GLYPH_TARGET_KNOWS_MONO_RLE7 #define GLYPH_TARGET_HAS_RECTFILL #define GLYPH_TARGET_HAS_RECTFILL_ANGLED #define GK_DRIVER_CODE "glyph_to_allegro.c" #elif (GLYPH_TARGET == GLYPH_TARGET_SDL) #include #define GLYPH_TARGET_STR "SDL" #define GLYPH_TARGET_SURFACE SDL_Surface #define GLYPH_TARGET_HAS_RECTFILL #define GLYPH_TARGET_HAS_RECTFILL_ANGLED #define GK_DRIVER_CODE "glyph_to_sdl.c" #elif (GLYPH_TARGET == GLYPH_TARGET_TEXT) #include #define GLYPH_TARGET_STR "Text" #define GLYPH_TARGET_SURFACE FILE #define GLYPH_TARGET_KNOWS_RLEAA #define GLYPH_TARGET_KNOWS_MONO_BITPACK #define GLYPH_TARGET_KNOWS_MONO_RLE7 #define GK_DRIVER_CODE "glyph_to_text.c" #endif /* GLYPH_TARGET */ /* * Glyph Keeper objects, that your program will create and use. * Your program should not make any assumption about their content layout. * You will normally only work with pointers to them. * All handling of this data should be done by Glyph Keeper API calls. */ typedef struct GLYPH_FACE GLYPH_FACE; typedef struct GLYPH_KEEP GLYPH_KEEP; typedef struct GLYPH_REND GLYPH_REND; /* Maximum possible Unicode code point. */ #define GK_MAX_UNICODE 0x10FFFFu /* * Constructing color values. */ #ifdef GLYPH_SAFE #define gk_makecol(r,g,b) ( ((((int)(r))&0xFF)<<16) | ((((int)(g))&0xFF)<<8) | (((int)(b))&0xFF) ) #define gk_makeacol(a,r,g,b) ( ((((int)(a))&0xFF)<<24) | ((((int)(r))&0xFF)<<16) | (((((int)(g))&0xFF)<<8) | (((int)(b))&0xFF) ) #else #define gk_makecol(r,g,b) ( ((r)<<16) | ((g)<<8) | (b) ) #define gk_makeacol(a,r,g,b) ( ((a)<<24) | ((r)<<16) | ((g)<<8) | (b) ) #endif /* * Packing version into one integer value. */ #define GK_MAKE_VERSION(a,b,c) (((a)<<20)|((b)<<10)|(c)) #ifdef __cplusplus extern "C" { #endif /* * This function sets user-provided messenger function. * User-provided messenger function will be called by Glyph Keeper library * routines every time when some routine wants to say out some message, * usually in case of an error. * If no messenger function is provided, no text feedback or error messages * will come out of Glyph Keeper. * * Set to 0 to 'unset' the messenger function. */ GLYPH_DECLSPEC void gk_set_messenger ( void (*func)(const char* const) ); /* * Sets font search path - a list of directories where * a font files will be searched. */ GLYPH_DECLSPEC void gk_set_font_path ( const char* const path ); /* * Glyph Keeper initialization. * There is no need to call this function in your program - * it will be called automatically when loading first font. * This function initializes FreeType. So use it, when you want to separate * FreeType initialization from loading first font for some reason. */ GLYPH_DECLSPEC void gk_library_init(); /* * Glyph Keeper shutdown function. * Basically it does nothing more than complete cleanup. * All data allocated by Glyph Keeper will be disposed. * I mean all objects of type GLYPH, GLYPH_FACE, GLYPH_INDEX, GLYPH_KEEP * and GLYPH_REND will be gone, all pointers to them will become invalid. * FreeType library will be also dismissed. * * It is OK to call this function and later load some new font and start * using Glyph Keeper again in the same program session. * Just be careful not to use any old pointers after this call. * * Actually you are not required to call this function in your program. * Glyph Keeper initialization will register this function with the atexit(), * and it will be called in the end of your program anyway. * * There is no problem to call this function twice or any number of times. * So, you can still call it at the end, if you like. Or if you want to * control the order of things happening. */ GLYPH_DECLSPEC void gk_library_cleanup(void); /* * Returns number of bytes allocated by Glyph Keeper. * FreeType memory is not counted. * * To see the real 'raw' memory usage of Glyph Keeper and FreeType, compile * both Glyph Keeper and FreeType with -DGLYPH_DEBUG_GK_MEMORY and * -DGLYPH_DEBUG_FT_MEMORY and use the functions below. */ GLYPH_DECLSPEC size_t gk_bytes_allocated(); /* * Functions for debugging Glyph Keeper and FreeType memory usage. * Don't use them in your project normally. * Note that they will give meaningful output only if you compile Glyph Keeper * and FreeType with -DGLYPH_DEBUG_GK_MEMORY and -DGLYPH_DEBUG_FT_MEMORY. * * ..._allocated_bytes() - returns amount of memory allocated and used. This * will be the correct memory usage numbers when you switch memory debugging * off. When memory debugging is on, the actual allocated memory is larger * because there is debugging overhead. * * ..._overhead_bytes() - returns debugging overhead. This is extra memory * allocated to enable memory debugging. Overhead will be 0 when you switch * off the debugging. */ GLYPH_DECLSPEC size_t gk_total_gk_allocated_bytes(); GLYPH_DECLSPEC size_t gk_total_gk_overhead_bytes(); GLYPH_DECLSPEC size_t gk_total_ft_allocated_bytes(); GLYPH_DECLSPEC size_t gk_total_ft_overhead_bytes(); /************************************************************************* * * GLYPH_FACE routines */ /* * Loads font face from a file 'fname'. * One file may contain several font faces, use 'face_index' to specify wich * one to load. Use 'face_index' = 0 to load first font face, or if there is * only one font face in the file. * This function returns 0 on failure. */ GLYPH_DECLSPEC GLYPH_FACE* _gk_load_face_from_file ( const char* const fname, const int face_index, const int gk_header_version, const int gk_header_target ); #define gk_load_face_from_file(a,b) \ _gk_load_face_from_file(a,b,GK_MAKE_VERSION(GK_VERSION_MAJOR,GK_VERSION_MINOR,GK_VERSION_PATCH),GLYPH_TARGET) /* * Loads font face from a memory buffer * Returns 0 on failure. */ GLYPH_DECLSPEC GLYPH_FACE* _gk_load_face_from_memory ( const unsigned char* const data, const int size, const int face_index, const int gk_header_version, const int gk_header_target ); #define gk_load_face_from_memory(a,b,c) \ _gk_load_face_from_memory(a,b,c,GK_MAKE_VERSION(GK_VERSION_MAJOR,GK_VERSION_MINOR,GK_VERSION_PATCH),GLYPH_TARGET) /* * You can manually dispose GLYPH_FACE object with this function. * All renderers using is will automatically become unuseful until you * set them to use another font face. * All currently loaded font faces can be also disposed with * 'gk_library_cleanup()'. */ GLYPH_DECLSPEC void gk_unload_face ( GLYPH_FACE* const f ); /* * These functions extract various information from font face. * Don't free() the char* after using. */ GLYPH_DECLSPEC const char* gk_face_family ( const GLYPH_FACE* const f ); GLYPH_DECLSPEC const char* gk_face_style ( const GLYPH_FACE* const f ); GLYPH_DECLSPEC const char* gk_face_postscript_name ( const GLYPH_FACE* const f ); GLYPH_DECLSPEC const char* gk_face_driver_name ( const GLYPH_FACE* const f ); /* * Returns number of charmaps a given face has. */ GLYPH_DECLSPEC int gk_face_get_number_of_charmaps ( const GLYPH_FACE* const f ); /* * Returns non-zero of the face is scalable. */ GLYPH_DECLSPEC int gk_face_is_scalable ( const GLYPH_FACE* const f ); /* * These functions check the directions supported by the font face. * 'is_horisontal' and 'is_vertical' can be both true at the same time. */ GLYPH_DECLSPEC int gk_face_is_horizontal ( const GLYPH_FACE* const f ); GLYPH_DECLSPEC int gk_face_is_vertical ( const GLYPH_FACE* const f ); /* * Vertical distance from the baseline to the topmost point of any glyph in the face. * positive, expressed in font units. */ GLYPH_DECLSPEC int gk_face_ascender ( const GLYPH_FACE* const f ); /* * Vertical distance from the baseline to the bottommost point of any glyph in the face. * negative, expressed in font units. */ GLYPH_DECLSPEC int gk_face_descender ( const GLYPH_FACE* const f ); /* * Vertical distance from one baseline to the next one when writing several * lines of text. Always positive, expressed in font units. */ GLYPH_DECLSPEC int gk_face_line_spacing ( const GLYPH_FACE* const f ); /* * Total number of glyphs in a font face. * This is not necessarily the same with the number of characters, * available to render with that font face. */ GLYPH_DECLSPEC int gk_face_number_of_glyphs ( const GLYPH_FACE* const f ); /* * Returns total number of characters, that can be rendered * with this font face. */ GLYPH_DECLSPEC int gk_face_number_of_characters ( GLYPH_FACE* const f ); /* * Returns total number of characters, that are actually defined * in this font face, without remapping. */ GLYPH_DECLSPEC int gk_face_number_of_own_characters ( GLYPH_FACE* const f ); GLYPH_DECLSPEC int gk_face_number_of_own_characters_in_range(GLYPH_FACE* const f, const unsigned start, const unsigned end); /* * This function checks if the face has character 'code'. * Remapped characters are included. */ GLYPH_DECLSPEC int gk_face_has_character ( GLYPH_FACE* const face, const unsigned code ); /* * This function checks if the face has character 'code' * among its own characters, without remapping. */ GLYPH_DECLSPEC int gk_face_has_own_character ( GLYPH_FACE* const face, const unsigned code ); /* * Remapping */ GLYPH_DECLSPEC void gk_remap_character ( GLYPH_FACE* const face1, const unsigned code1, GLYPH_FACE* const face2, const unsigned code2 ); GLYPH_DECLSPEC void gk_unmap_character ( GLYPH_FACE* const face, const unsigned code ); GLYPH_DECLSPEC void gk_remap_range ( GLYPH_FACE* const face1, const unsigned code1, GLYPH_FACE* const face2, const unsigned code2, const unsigned range_size ); GLYPH_DECLSPEC void gk_unmap_range ( GLYPH_FACE* const face, const unsigned code, const unsigned range_size ); /************************************************************************* * * GLYPH_KEEP routines */ /* * Creates new GLYPH_KEEP object, limited to keep not more than 'max_glyphs' * glyphs and to use not more than 'max_memory' bytes in memory. * You can set 'max_glyphs' or/and 'max_memory' to 0 to have no limit. * This function returns 0 on failure. */ GLYPH_DECLSPEC GLYPH_KEEP* gk_create_keeper ( const unsigned max_glyphs, const unsigned max_memory ); /* * This function is useful to destroy GLYPH_KEEP object. * Normally there is no particular need to call it - all GLYPH_KEEP * objects will be automatically destroyed by 'gk_library_cleanup()' * Note that you can safely destroy GLYPH_KEEP object, even if some * renderer (GLYPH_REND object) is using it. Renderer will just switch * to work without cache. * But don't use in any way pointer to the destroyed keeper. The keeper is * gone, the pointer leads nowhere. */ GLYPH_DECLSPEC void gk_done_keeper ( GLYPH_KEEP* const keeper ); /* * Returns number of glyphs currently cached by the keeper. */ GLYPH_DECLSPEC int gk_keeper_glyph_count ( const GLYPH_KEEP* const keeper ); /* * Returns maximum number of glyphs a keeper can keep. */ GLYPH_DECLSPEC int gk_keeper_glyph_limit ( const GLYPH_KEEP* const keeper ); /* * Returns number of bytes used by a keeper. * This includes keeper, its indexes and all cached glyphs. */ GLYPH_DECLSPEC int gk_keeper_byte_count ( const GLYPH_KEEP* const keeper ); /* * Returns maximum number of bytes this keeper may use in memory. */ GLYPH_DECLSPEC int gk_keeper_byte_limit(const GLYPH_KEEP* const keeper); /* * Prints some information about keeper's current state. * Printing goes through the messenger function. */ GLYPH_DECLSPEC void gk_keeper_debug(const GLYPH_KEEP* const keeper); /************************************************************************* * * GLYPH_REND routines */ /* * Creates new renderer - GLYPH_REND object. * * Renderer is set to use font face 'face' and glyph cache 'keeper'. * If 'keeper' is 0, renderer will still work fine, just without glyph * caching. Caching can be turned on later by introducing a keeper with * gk_rend_set_keeper(). * If 'face' is 0, renderer will be still created, but can't be used until * some font face is specified with gk_rend_set_face(). * * Antialiasing is on by default. * '?' (U+003F) is the default undefined character. */ GLYPH_DECLSPEC GLYPH_REND* gk_create_renderer ( GLYPH_FACE* const face, GLYPH_KEEP* const keeper ); /* * Creates a copy of renderer 'rend'. */ GLYPH_DECLSPEC GLYPH_REND* gk_create_copy_of_renderer ( GLYPH_REND* const rend ); /* * Deletes GLYPH_REND object from memory. Don't use in any way a pointer * to destroyed renderer, it will crash your program. */ GLYPH_DECLSPEC void gk_done_renderer(GLYPH_REND* const rend); /* * Assigns a particular GLYPH_KEEP object to this renderer. * In fact one GLYPH_KEEP object can cache glyphs for several renderers * at the same time. * If 'new_keeper' is 0, glyph caching will be off for this renderer. */ GLYPH_DECLSPEC void gk_rend_set_keeper ( GLYPH_REND* const rend, GLYPH_KEEP* const new_keeper ); /* * Assigns a new font face for this renderer. All rendered glyphs * will be of that face. * If 'new_face' is 0, the renderer will become unuseful - it can't render * anything. */ GLYPH_DECLSPEC void gk_rend_set_face ( GLYPH_REND* const rend, GLYPH_FACE* const new_face ); /* * Sets new text size - size of EM square, in 1/64th of a pixel. * Returns 1 on success, 0 on failure. */ GLYPH_DECLSPEC int gk_rend_set_size_subpixel ( GLYPH_REND* const rend, const unsigned new_hsize, const unsigned new_vsize ); /* * Sets new text size in integer pixels. * Returns 1 on success, 0 on failure. */ GLYPH_DECLSPEC int gk_rend_set_size_pixels ( GLYPH_REND* const rend, const unsigned new_pixel_hsize, const unsigned new_pixel_vsize ); /* * Set and get angle of text rotation. * Increasing the angle will rotate the text counter-clockwise. */ GLYPH_DECLSPEC void gk_rend_set_angle_in_radians ( GLYPH_REND* const rend, const double new_text_angle ); GLYPH_DECLSPEC void gk_rend_set_angle_in_degrees ( GLYPH_REND* const rend, const double new_text_angle ); GLYPH_DECLSPEC double gk_rend_get_angle_in_radians ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC double gk_rend_get_angle_in_degrees ( const GLYPH_REND* const rend ); /* * Set and get angle of text obliqueness. Allowed angles are * from -PI/4 to PI/4 (or -45 to 45 with _in_degrees version). * Negative angle means text is oblique to the left, 0 means text is straight * normal, positive angle means text is oblique to the right. * Use PI/15 (12 degrees) to get common italic text. */ GLYPH_DECLSPEC void gk_rend_set_italic_angle_in_radians ( GLYPH_REND* const rend, const double new_italic_angle ); GLYPH_DECLSPEC void gk_rend_set_italic_angle_in_degrees ( GLYPH_REND* const rend, const double new_italic_angle ); GLYPH_DECLSPEC double gk_rend_get_italic_angle_in_radians ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC double gk_rend_get_italic_angle_in_degrees ( const GLYPH_REND* const rend ); /* * Set and get strength of emboldening. * 0 means no emboldening, positive value will produce bold text. * Negative values will shrink the letters making them thinner. * 100 is moderately bold text. */ GLYPH_DECLSPEC void gk_rend_set_bold_strength ( GLYPH_REND* const rend, const int new_bold_strength ); GLYPH_DECLSPEC int gk_rend_get_bold_strength ( const GLYPH_REND* const rend ); /* * Sets renderer and offset to render the same character before and after that * character is rendered with the renderer 'rend'. */ GLYPH_DECLSPEC void gk_rend_set_before_renderer ( GLYPH_REND* const rend, GLYPH_REND* const new_before_rend, const int new_before_dx, const int new_before_dy ); GLYPH_DECLSPEC void gk_rend_set_after_renderer ( GLYPH_REND* const rend, GLYPH_REND* const new_after_rend, const int new_after_dx, const int new_after_dy ); /* * Return renderer's ascender and descender in 1/64th of a pixel. * ..._pixels - version returning same thing in integer pixels. * Note, that ascender is positive, while descender is usually negative. */ GLYPH_DECLSPEC int gk_rend_ascender ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC int gk_rend_ascender_pixels ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC int gk_rend_descender ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC int gk_rend_descender_pixels ( const GLYPH_REND* const rend ); /* * Returns vertical distance between lines, in 1/64th of a pixel. * Spacing returned by this function is not affected by changing * renderer's angle setting. */ GLYPH_DECLSPEC int gk_rend_spacing ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC int gk_rend_spacing_pixels ( const GLYPH_REND* const rend ); /* * Returns 'text height' = ascender - descender */ GLYPH_DECLSPEC int gk_rend_height ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC int gk_rend_height_pixels ( const GLYPH_REND* const rend ); /* * These functions control whether this renderer will perform hinting. */ GLYPH_DECLSPEC void gk_rend_set_hinting_off ( GLYPH_REND* const rend ); GLYPH_DECLSPEC void gk_rend_set_hinting_default ( GLYPH_REND* const rend ); GLYPH_DECLSPEC void gk_rend_set_hinting_force_autohint ( GLYPH_REND* const rend ); GLYPH_DECLSPEC void gk_rend_set_hinting_no_autohint ( GLYPH_REND* const rend ); /* * Control rendering mode. * 'light' mode does not seem to work, need to investigate (FIXME). */ GLYPH_DECLSPEC void gk_rend_set_antialiasing_on ( GLYPH_REND* const rend ); GLYPH_DECLSPEC void gk_rend_set_antialiasing_off ( GLYPH_REND* const rend ); /*GLYPH_DECLSPEC void gk_rend_set_antialiasing_light ( GLYPH_REND* const rend );*/ /* * You can specify which character will show up instead of the character, * not present in font. Default is '?'. * Setting it to 0 will prevent anything shown instead of undefined characters. */ GLYPH_DECLSPEC void gk_rend_set_undefined_char ( GLYPH_REND* const rend, const unsigned new_undefined_char ); /* * You can specify which character will show up when FreeType * can't render a character. * Default is 0 - nothing is shown. */ GLYPH_DECLSPEC void gk_rend_set_error_char ( GLYPH_REND* const rend, const unsigned new_error_char ); /* * Returns 1, if renderer can render a character 'code', * otherwise returns 0. * Note: a character's glyph may be empty, like for space character, * in such case this function still returns 1. */ GLYPH_DECLSPEC int gk_rend_has_character ( const GLYPH_REND* const rend, const unsigned code ); /* * Returns 1, if renderer can render a non-empty glyph for character 'code', * otherwise returns 0. */ GLYPH_DECLSPEC int gk_rend_has_glyph ( GLYPH_REND* const rend, const unsigned code ); /* * Setting and querying text alpha transparency and color. * 'alpha_color' is (A<<24)+(R<<16)+(G<<8)+B, * A, R, G and B are in 0..255 range. */ GLYPH_DECLSPEC void gk_rend_set_text_alpha_color ( GLYPH_REND* const rend, const unsigned alpha_color ); GLYPH_DECLSPEC unsigned gk_rend_get_text_alpha_color ( const GLYPH_REND* const rend ); /* * Setting color and alpha separately. */ GLYPH_DECLSPEC void gk_rend_set_text_color_rgb ( GLYPH_REND* const rend, const unsigned char r, const unsigned char g, const unsigned char b ); GLYPH_DECLSPEC void gk_rend_set_text_color_combined ( GLYPH_REND* const rend, const int color ); GLYPH_DECLSPEC int gk_rend_get_text_color ( const GLYPH_REND* const rend ); GLYPH_DECLSPEC void gk_rend_set_text_alpha ( GLYPH_REND* const rend, const unsigned char alpha ); GLYPH_DECLSPEC unsigned gk_rend_get_text_alpha ( const GLYPH_REND* const rend ); /* * Setting and checking background color. */ GLYPH_DECLSPEC void gk_rend_set_back_color ( GLYPH_REND* const rend, const int new_back_color ); GLYPH_DECLSPEC int gk_rend_get_back_color ( GLYPH_REND* const rend ); GLYPH_DECLSPEC void gk_rend_debug ( const GLYPH_REND* const rend ); /* * Returning text dimensions and origin point coordinates. */ GLYPH_DECLSPEC void gk_text_dimensions_utf8 ( GLYPH_REND* const rend, const char* const text, int* const size_x, int* const size_y, int* const origin_x, int* const origin_y ); GLYPH_DECLSPEC void gk_text_dimensions_utf16 ( GLYPH_REND* const rend, const unsigned short* const text, int* const size_x, int* const size_y, int* const origin_x, int* const origin_y ); GLYPH_DECLSPEC void gk_text_dimensions_utf32 ( GLYPH_REND* const rend, const unsigned int* const text, int* const size_x, int* const size_y, int* const origin_x, int* const origin_y ); /* * Measuring a single glyph. */ GLYPH_DECLSPEC void gk_glyph_size ( GLYPH_REND* const rend, const unsigned unicode, int *const width, int* const height ); GLYPH_DECLSPEC int gk_glyph_width ( GLYPH_REND* const rend, const unsigned unicode ); GLYPH_DECLSPEC int gk_glyph_height ( GLYPH_REND* const rend, const unsigned unicode ); /* * Measuring a single character. */ GLYPH_DECLSPEC void gk_char_size ( GLYPH_REND* const rend, const unsigned unicode, int *const width, int* const height ); GLYPH_DECLSPEC int gk_char_width ( GLYPH_REND* const rend, const unsigned unicode ); GLYPH_DECLSPEC int gk_char_height ( GLYPH_REND* const rend, const unsigned unicode ); GLYPH_DECLSPEC void gk_char_advance ( GLYPH_REND* const rend, const unsigned unicode, int* const adv_x, int* const adv_y ); GLYPH_DECLSPEC void gk_char_advance_subpixel ( GLYPH_REND* const rend, const unsigned unicode, int* const adv_x, int* const adv_y ); /* * These functions calculate width and height of text, in pixels. * Width and height are written to '*width' and '*height'. */ GLYPH_DECLSPEC void gk_text_size_utf8 ( GLYPH_REND* const rend, const char* const text, int* const width, int* const height ); GLYPH_DECLSPEC void gk_text_size_utf16 ( GLYPH_REND* const rend, const unsigned short* const text, int* const width, int* const height ); GLYPH_DECLSPEC void gk_text_size_utf32 ( GLYPH_REND* const rend, const unsigned* const text, int* const width, int* const height ); /* * Returns width and height of text, produced by given renderer. * In integer pixels. */ GLYPH_DECLSPEC int gk_text_width_utf8 ( GLYPH_REND* const rend, const char* const text ); GLYPH_DECLSPEC int gk_text_width_utf16 ( GLYPH_REND* const rend, const unsigned short* const text ); GLYPH_DECLSPEC int gk_text_width_utf32 ( GLYPH_REND* const rend, const unsigned* const text ); GLYPH_DECLSPEC int gk_text_height_utf8 ( GLYPH_REND* const rend, const char* const text ); GLYPH_DECLSPEC int gk_text_height_utf16 ( GLYPH_REND* const rend, const unsigned short* const text ); GLYPH_DECLSPEC int gk_text_height_utf32 ( GLYPH_REND* const rend, const unsigned* const text ); /* * Return text advance, in integer pixels. */ GLYPH_DECLSPEC void gk_text_advance_utf8 ( GLYPH_REND* const rend, const char* const text, int* const adv_x, int* const adv_y ); GLYPH_DECLSPEC void gk_text_advance_utf16 ( GLYPH_REND* const rend, const unsigned short* const text, int* const adv_x, int* const adv_y); GLYPH_DECLSPEC void gk_text_advance_utf32 ( GLYPH_REND* const rend, const unsigned* const text, int* const adv_x, int* const adv_y ); /* * Return text advance, in 1/64th of a pixel. */ GLYPH_DECLSPEC void gk_text_advance_subpixel_utf8 ( GLYPH_REND* const rend, const char* const text, int* const adv_x, int* const adv_y ); GLYPH_DECLSPEC void gk_text_advance_subpixel_utf16 ( GLYPH_REND* const rend, const unsigned short* const text, int* const adv_x, int* const adv_y); GLYPH_DECLSPEC void gk_text_advance_subpixel_utf32 ( GLYPH_REND* const rend, const unsigned* const text, int* const adv_x, int* const adv_y ); /* * This function renders the character's glyph and adds it into the cache. * The rendered character is not printed anywhere. * If the glyph is already in the cache, it is not rendered again. * This function can be useful to 'prepare' the glyphs of some characters, * that you expect to be used soon. */ GLYPH_DECLSPEC void gk_precache_char ( GLYPH_REND* const rend, const unsigned unicode ); GLYPH_DECLSPEC void gk_precache_range ( GLYPH_REND* const rend, const unsigned range_start, const unsigned range_end ); GLYPH_DECLSPEC void gk_precache_set_utf8 ( GLYPH_REND* const rend, const char* const char_set ); GLYPH_DECLSPEC void gk_precache_set_utf16 ( GLYPH_REND* const rend, const unsigned short* const char_set ); GLYPH_DECLSPEC void gk_precache_set_utf32 ( GLYPH_REND* const rend, const unsigned* const char_set ); /* * Functions, rendering something to the target surface. */ #ifdef GLYPH_TARGET /* * Outputs a character 'unicode' to the 'bmp', using renderer 'rend'. * Character glyph's left top corner will appear at (x,y). */ GLYPH_DECLSPEC void gk_put_char ( GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend, const unsigned unicode, const int x, const int y ); /* * Outputs a character so that it's center is at (x,y). */ GLYPH_DECLSPEC void gk_put_char_center ( GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend, const unsigned unicode, const int x, const int y ); /* * Renders one character, starting with positioning pen at (*pen_x,*pen_y). * *pen_x and *pen_y will be incremented to become starting pen position for * the next character. */ GLYPH_DECLSPEC void gk_render_char ( GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend, const unsigned unicode, int* const pen_x, int* const pen_y ); GLYPH_DECLSPEC void gk_render_char_center ( GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend, const unsigned unicode, const int x, const int y ); /* * */ GLYPH_DECLSPEC void gk_render_line_utf8 ( GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend, const char* const text, const int pen_x, const int pen_y ); GLYPH_DECLSPEC void gk_render_line_utf16 ( GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend, const unsigned short* const text, const int pen_x, const int pen_y ); GLYPH_DECLSPEC void gk_render_line_utf32 ( GLYPH_TARGET_SURFACE* const bmp, GLYPH_REND* const rend, const unsigned* const text, const int pen_x, const int pen_y ); /* * Target-specific functions */ #if (GLYPH_TARGET == GLYPH_TARGET_ALLEGGL) || (GLYPH_TARGET == GLYPH_TARGET_OPENGL) GLYPH_DECLSPEC GLYPH_TEXTURE *gk_create_texture( GLYPH_REND *rend, int rangeStart, int rangeLength ); GLYPH_DECLSPEC void gk_send_texture_to_gpu( GLYPH_TEXTURE *texture ); GLYPH_DECLSPEC void gk_render_line_gl_utf8( GLYPH_TEXTURE *texture, const char *text, int x, int y ); GLYPH_DECLSPEC void gk_unload_texture_from_gpu( GLYPH_TEXTURE *texture ); GLYPH_DECLSPEC void gk_destroy_texture( GLYPH_TEXTURE *texture ); #endif #if (GLYPH_TARGET == GLYPH_TARGET_ALLEGRO) /* * Creates an Allegro FONT with Glyph Keeper's vtable. * The renderer 'rend' will be used for all text output with this font. * So don't dispose the renderer if you are still going to use the font. */ GLYPH_DECLSPEC FONT* gk_create_allegro_font ( GLYPH_REND* const rend ); /* * Creates a native Allegro FONT structure, with Allegro vtable. * In this case the renderer 'rend' is not used for output, so you can * safely dispose it. */ GLYPH_DECLSPEC FONT* gk_create_allegro_bitmap_font_for_range ( GLYPH_REND* const rend, const int range_start, const int range_end, const int color_depth ); #endif #endif /* GLYPH_TARGET */ #ifdef __cplusplus } #endif #undef GLYPH_DECLSPEC /* * Compatibility with old messy API. */ #ifndef GK_NO_LEGACY #define GK_LEGACY #endif #ifdef GK_LEGACY #define GLYPH_KEEPER_VERSION_MAJOR GK_VERSION_MAJOR #define GLYPH_KEEPER_VERSION_MINOR GK_VERSION_MINOR #define GLYPH_KEEPER_VERSION_PATCH GK_VERSION_PATCH #define GLYPH_KEEPER_VERSION_STR GK_VERSION_STR #define GLYPH_KEEPER_DATE_STR GK_DATE_STR #define glyph_keeper_set_messenger gk_set_messenger #define set_glyph_messenger gk_set_messenger #define glyph_keeper_library_init gk_library_init #define glyph_keeper_library_done gk_library_cleanup #define glyph_keeper_bytes_allocated gk_bytes_allocated #define load_face gk_load_face_from_file #define load_face_from_file gk_load_face_from_file #define load_face_from_memory gk_load_face_from_memory #define unload_face gk_unload_face #define face_family gk_face_family #define face_style gk_face_style #define face_postscript_name gk_face_postscript_name #define face_driver_name gk_face_driver_name #define face_is_horizontal gk_face_is_horizontal #define face_is_vertical gk_face_is_vertical #define face_ascender gk_face_ascender #define face_descender gk_face_descender #define face_line_spacing gk_face_line_spacing #define face_get_number_of_glyphs gk_face_number_of_glyphs #define face_get_number_of_characters gk_face_number_of_characters #define create_keeper gk_create_keeper #define glyph_keeper_create_keeper gk_create_keeper #define done_keeper gk_done_keeper #define glyph_keeper_done_keeper gk_done_keeper #define keeper_glyph_count gk_keeper_glyph_count #define keeper_glyph_limit gk_keeper_glyph_limit #define keeper_byte_count gk_keeper_byte_count #define keeper_byte_limit gk_keeper_byte_limit #define keeper_debug gk_keeper_debug #define create_renderer gk_create_renderer #define glyph_renderer_create gk_create_renderer #define done_renderer gk_done_renderer #define glyph_renderer_done gk_done_renderer #define rend_set_keeper gk_rend_set_keeper #define rend_set_face gk_rend_set_face #define rend_set_size gk_rend_set_size_subpixel #define gk_rend_set_size gk_rend_set_size_subpixel #define rend_set_size_pixels gk_rend_set_size_pixels #define rend_set_angle gk_rend_set_angle #define rend_ascender gk_rend_ascender #define rend_ascender_pixels gk_rend_ascender_pixels #define rend_descender gk_rend_descender #define rend_descender_pixels gk_rend_descender_pixels #define rend_spacing gk_rend_spacing #define rend_spacing_pixels gk_rend_spacing_pixels #define rend_height gk_rend_height #define rend_height_pixels gk_rend_height_pixels #define rend_set_hinting_off gk_rend_set_hinting_off #define rend_set_hinting_default gk_rend_set_hinting_default #define rend_set_hinting_force_autohint gk_rend_set_hinting_force_autohint #define rend_set_hinting_no_autohint gk_rend_set_hinting_no_autohint #define rend_set_render_mode_normal gk_rend_set_antialiasing_on #define rend_set_render_mode_mono gk_rend_set_antialiasing_off #define rend_set_italic gk_rend_set_italic #define rend_set_undefined gk_rend_set_undefined_char #define rend_set_undefined_char gk_rend_set_undefined_char #define rend_set_error_char gk_rend_set_error_char #define rend_has_character gk_rend_has_character #define rend_has_glyph gk_rend_has_glyph #define rend_set_text_alpha_color gk_rend_set_text_alpha_color #define rend_get_text_alpha_color gk_rend_get_text_alpha_color #define rend_set_text_color gk_rend_set_text_color_rgb #define gk_rend_set_text_color gk_rend_set_text_color_rgb #define rend_set_text_alpha gk_rend_set_text_alpha #define rend_precache_char gk_rend_precache_char #define create_allegro_font gk_create_allegro_font #define text_size_utf8 gk_text_size_utf8 #define text_size_utf32 gk_text_size_utf32 #define text_width_utf8 gk_text_width_utf8 #define text_width_utf32 gk_text_width_utf32 #define text_height_utf8 gk_text_height_utf8 #define text_height_utf32 gk_text_height_utf32 #define gk_rend_precache_char gk_precache_char #define put_char gk_put_char #define put_char_center gk_put_char_center #define render_char gk_render_char #define render_line_utf8 gk_render_line_utf8 #define render_line_utf32 gk_render_line_utf32 #define gk_rend_set_angle gk_rend_set_angle_in_radians #define gk_rend_set_italic gk_rend_set_italic_angle_in_degrees #define gk_rend_set_bold gk_rend_set_bold_strength #endif /* GK_LEGACY */ #endif openlayer-2.1.orig/utils/glyphkeeper/authors.txt0000644000175000017500000000267510567602066022436 0ustar georgeskgeorgesk Glyph Keeper is written and currently mantained by Kirill Kryukov These people contributed to Glyph Keeper development in various ways, including bug-reports, patches, suggestions and active discussion. Thanks a lot! (Contact me if you have any corrections, or if I forgot to mention someone) ------------------------- Daniel Schlyder reported text centering bug (fixed in 0.21.1), and gave me many other comments and suggestions. Esa Tanskanen (aka Fladimir da Gorf) spotted an italic glyph rendering bug (fixed in 0.19.1) and wrong "glyph.h" inclusion in glyph.c (fixed in 0.24). Besides that he contributed Glyph Keeper's OpenGL driver. Peter Wang helped making Glyph Keeper 64-bit safe. Ken Seergobin noticed a font path search bug (fixed in 0.21.3). Evert Glebbeek helped with better integration of Glyph Keeper and Allegro, providing advice about Allegro's FONT and FONT_VTABLE structures. Oscar Giner suggested to move target-specific includes out of extern "C" block. biscuitz reported a memory leak (fixed in 0.27). Hans de Goede helped making Glyph Keeper 64-bit safe and improved SDL header inclusion (merged in 0.30). Matthew Leverton reported a memory leak (fixed in 0.32). Also I recieved useful comments and suggestions from Steve Terry, Miran Amon, Serge Semashko, Elias Pschernig, Matt Smith, Robert Ohannessian and gnolam. openlayer-2.1.orig/utils/glyphkeeper/changes.txt0000644000175000017500000002433110567602066022352 0ustar georgeskgeorgesk 0.32 (February 6, 2007) - Glyph Keeper now can produce native Allegro FONT objects. This means that Glyph Keeper now can be used with AllegroGL. - DejaVu Sans 2.14 is now included as example font. - Fixed memory leak introduced in 0.30. - Added API to debug memory usage in Glyph Keeper and FreeType. - Stable centering: Glyph center remains the same when you rotate it. - Improved benchmarks. 0.31 (February 2, 2007) - Bundled FreeType updated to version 2.3.1. - Glyph Keeper now can work with bitmap (raster) fonts. - Bytecode interpreter and sublixel rendering are from now OFF by default. - gk_rend_set_angle() and gk_rend_set_italic() are deprecated. (They are still available if you don't define GK_NO_LEGACY when compiling your program). Instead four new functions are introduced: gk_rend_set_angle_in_radians(), gk_rend_set_angle_in_degrees(), gk_rend_set_italic_angle_in_radians() and gk_rend_set_italic_angle_in_degrees(). - New functions for getting renderer properties: gk_rend_get_italic_angle_in_radians(), gk_rend_get_italic_angle_in_degrees(), gk_rend_get_bold_strength(). - New function for creating a copy of a renderer object: gk_create_copy_of_renderer(). - New functions for finding text dimensions: gk_text_dimensions_utf8(), gk_text_dimensions_utf16(), gk_text_dimensions_utf32(). - Dimensions of italic text are now computed correctly. - All files use Windows end of line now. - Examples are improved. 0.30.1 - Removed fragments of SDL_gfx code. SDL_gfx is now required to compile Glyph Keeper with SDL. - Fixed compilation with SDL and MinGW. - Fixed angled bold text. - Added two functions: gk_rend_set_before_renderer() and gk_rend_set_after_renderer() for adding a renderer that will always render copy of same character. This can be used for shadows, outlines, underlines, etc. 0.30 (January 15, 2007) - Fixed compilation with FreeType 2.2.1. - Bundled FreeType is updated to version 2.2.1. - Applied 64-bit fixes by Hans de Goede. - New API: gk_rend_set_bold() for making bold text. - Added ability to change font boldness in compare_alleg.c example. - license.txt now includes info about bundled 3-rd party software. - Removed one C++ style variable declaration in OpenGL driver. - Fixed incorrect inclusion of FreeType header in examples/alfont.c, reported by gnolam. - Added 'delete.me' into the obj dirs, for those with buggy archievers. - Fixed "statement with no effect" warning in 'examples/bench_utils.c'. 0.29.1 (July 9, 2005) - Added example font (Bitstream Vera) to the examples/ directory. Hard-coded this font in text-mode and "Hello, World!" examples and set it as default for all other examples. - Added 'demofont.pcx' - example font for Allegro benchmark (bench_bare_alleg). - Minor fixes in Makefiles. 0.29 (July 03, 2005) - FreeType is now bundled with Glyph Keeper. - Added benchmark examples. - Many fixes and improvements in makefiles. 0.28 (June 27, 2005) - Added simple examples. - Updated documentation. - Added install.txt with installation instructions. - Added makefile for MinGW. - Added makefiles for MSVC 7.1 and 8.0. - Changed source indentation: 2 -> 4 spaces. (I did not have a big monitor when I started writing GK). 0.27 (June 14, 2005) - Hopefully fixed problem occuring in case if FreeType renders a 2 or 4-bit glyph (not tested). - Now FreeType v.2.1.10 is required to compile Glyph Keeper. - From now on you can't mix different versions of Glyph Keeper header and library anymore. It will compile and run, just it will never succeed to load a font. - If you manage to compile Glyph Keeper and your program with different targets, it will still not work - it will not load any fonts. - Fixed memory leak in _gk_unload_glyph(), reported by biscuitz. - From now it is necessary to specify GLYPH_TARGET in the command line to compile Glyph Keeper. It will not be set to GLYPH_TARGET_TEXT by default, as it was previously. - Fladimir da Gorf commented out debug macro and added missing glyph deletion in OpenGL driver. - New routine: gk_render_char_center(). - GK_MAX_UNICODE made public again. - Fixed gk_render_char() to match documentation. 0.26.2 (May 25, 2005) - Added API gk_face_number_of_own_characters_in_range(). - Fladimir da Gorf updated OpenGL driver to remove the limitation on glyph size (or at least making it much greater than it was). 0.26.1 (March 29, 2005) - Fladimir da Gorf fixed angled text output with OpenGL target. 0.26 (March 23, 2005) - Added OpenGL driver made by Fladimir da Gorf. This is work in progress release, OpenGL driver is not finished and has known problems. 0.25 (March 23, 2005) - Restructured source to make more easy to see what and where is included. (glyph.c now does not have any code, but only includes other files). 0.24 (March 22, 2005) - Fixed unclusion of "glyph.h" in glyph.c, pointed by Fladimir da Gorf. (Changed to "../include/glyph.h"). - Added more precaching functions, in hope to use them in OpenGL driver: gk_precache_range(), gk_precache_set_utf8(), gk_precache_set_utf16() and gk_precache_set_utf32(). - Fixed bug in gk_precache_char(). 0.23.1 (March 9, 2005) - Updated documentation. - Switched off GLYPH_SAFE and GLYPH_LOG macros, that should be only used for debugging. They should be off in released versions because they make Glyph Keeper slow. (Forgot to switch them off before the release). 0.23 (March 1, 2005) - It should be compatible with upcoming Allegro 4.2, that has changed FONT_VTABLE structure since 4.1.18. - New function: gk_face_number_of_own_characters(). - gk_face_number_of_characters() now does not count surrogates. - New functions: gk_face_has_character() and gk_face_has_own_character(). - Added character remapping with API: gk_remap_character(), gk_unmap_character(), gk_remap_range(), gk_unmap_range(). 0.22 (February 15, 2005) - SDL driver is fully functional again. - Moved target-specific includes out of extern "C" block, as suggested by Oscar Giner. - New function: gk_rend_set_color_combined(). - gk_rend_set_color() is renamed to gk_rend_set_color_rgb(), for clarity. - gk_rend_set_size() is renamed to gk_rend_set_size_subpixel(), so it will not be used with integer pixel sizes by mistake. - Added two macros: gk_makecol(r,g,b) and gk_makeacol(a,r,g,b). 0.21.4 (February 7, 2005) - Fixed font path search, finally. - Restored text target compilation. - Restored C89 compatibility. 0.21.3 (February 7, 2005) - Fixed font path search problem, reported by Ken Seergobin. 0.21.2 (February 6, 2005) - Added functions for measuring a single glyph / single character. - Added gk_set_font_path() function for setting a font search path. - Added background rectangle rendering, working for angled text also. - Optimized Allegro 32-bit antialiased output with background. - Added gk_text_advance_utf8/16/32 functions. - Added macros for enabling/disabling RLE and bitpack glyphs compression. From now a target driver is not required to handle RLE and bitpacked glyphs, linear 8-bit glyph support is enough. - UTF-32 decoder now knows about byte order mark. - Added GK_NO_LAGACY macro. - Minor fixes and changes. 0.21.1 (January 31, 2005) - UTF-16 support added. - Fixed some brain damage effect in "gk_load_face_from_file()", which caused function to fail most of times. (introduced in 0.21) - Centering and text width calculation is finally fixed. - Added GK_LEGACY macro for controlling compatibility defines. 0.21 (January 31, 2005) - All API functions got prefixed with "gk_". - Fixed text width calculation bug, reported by Daniel Schlyder. - Fixed (hopefully) 64-bit porting problems, following Peter Wang's suggestion. - Fixed overflow problem with glyph advance values for very large font sizes (around 1000 pixels). - Fixed Allegro driver's screen access with DJGPP compilation. - Fixed C89 compatibility, broken in 0.20. 0.20.1 (January 23, 2005) - height field of FONT object now can be used. - FONT support works with Allegro 4.1.18. - Increased speed of face_get_number_of_characters(). 0.20 (January 9, 2005) - Added support for creating Allegro FONT objects, as suggested by Evert Glebbeek, Serge Semashko, Miran, MattSmith and others. 0.19.1 (December 31, 2004) - Bug fixed: When there are two renderers using same font face, one italic and other not italic, sometimes non-italic renderer was producing italic glyphs. (Reported by Fladimir da Gorf) 0.19 (October 28, 2004) - Added italic text rendering, new API: rend_set_italic(). - Allegro driver was trying to release un-acquired bitmap if text alpha was set to 0. 0.18 (October 7, 2004) - Changed function of rend_set_size() and rend_set_size_pixels(). 0.17 (October 4, 2004) - Fix for rend_precache_char(). - New API function: rend_has_glyph(). - New API function: load_face_from_memory(). - New API function: rend_set_error_char(). 0.16 (September 30, 2004) - Improved drawing speed for Allegro screen bitmap. - Antialiased rendering to 8-bit Allegro bitmap does not crash anymore. - Removed some obsolete code. 0.15 (September 22, 2004) - Some API functions have got better names. - Removed text background rendering. It never worked for angled text anyway. - Added alpha transparency. - Added RLE-like compression for anti-aliased glyphs. - Optimized some of the Allegro-specific routines. - Added initial SDL support. Only monochrome opaque rendering. - Commenting, logging, etc. Version 0.14 was the first public release (August 22, 2004) It already had the following: - Works with FreeType 2.1.9 - Rendering directly to Allegro BITMAPS - Glyph caching - Angled text rendering - RLE compression of monochrome glyphs Before that I did not track the history. If you are curious you can download Glyph Keeper 0.12 or 0.10 and see what was there. openlayer-2.1.orig/default.cbd0000644000175000017500000002531610552417346016623 0ustar georgeskgeorgesk# Replacement to OpenLayers dying Makefile # check verbose output ifopt verbose verbose 1 # check for building utilities ifopt glyphkeeper invoke build/gk-build.cbd # Lets force configuration ifopt configure configure = "true" # Display Help do ifopt help echo "This builds the OpenLayer 2.0 library. To compile run:" do ifplat win32 echo "buildme.bat [OPT] ..." else echo "cbuild.c [OPT] ..." done echo " [OPTIONS] help - Prints this information verbose - Enable verbose output configure - Force configuration prompts clean - Clean up resources install - installs the library uninstall - uninstalls the library glyphkeeper - Builds (AllegroGL specific) glyphkeeper and installs" exit 0 done # Display Make help do ifopt makehelp echo "This builds the OpenLayer 2.0 library. To compile run: make [TARGET] [TARGETS] help - Prints this information verbose - Compiles the libray with verbose output clean - Clean up resources install - installs the library uninstall - uninstalls the library glyphkeeper - Builds (AllegroGL specific) glyphkeeper and installs" exit 0 done # need to setup variables and directories beforehand AR = ar AR_OPT = rcs OBJ_DIR = obj DEP_DIR = dep LIB_PRE = lib/ LIB_EXT = .a LIB_SOURCES = $(ls src) LIB_SOURCES -= src/ src_paths src # Goto target clean ifopt clean goto clean # Remove temporary cbuild file ifopt rmcbuild goto rmcbuild # Goto target install ifopt install goto install # Goto target uninstall ifopt uninstall goto uninstall # Check whether forcing configuration do if $(tolower ${'configure'})='true' goto checktarget done # If we have a prior configuration load it and commence build do ifexist build/options setinput build/options read tempstr CPPFLAGS = ${'tempstr'} read tempstr LDFLAGS = ${'tempstr'} read tempstr CONFIGFLAGS = ${'tempstr'} read tempstr CONFIGLIBS = ${'tempstr'} read tempstr DROPPNG = ${'tempstr'} read tempstr DROPTTF = ${'tempstr'} read tempstr USENEWTTF = ${'tempstr'} read tempstr DROPOLDAPI = ${'tempstr'} read tempstr DROPSTATECHANGE = ${'tempstr'} setinput goto build done # Platform precheck do ifplat linux echo "Seting up for linux environment" CPPFLAGS+=-O2 -Wall -Iinclude -Iinclude/OpenLayer `freetype-config --cflags` -fexpensive-optimizations LDFLAGS=-lglyph-agl `freetype-config --libs` `libpng-config --libs` -lagl `allegro-config --libs` -lGL -lGLU else ifplat win32 echo "Seting up for msys environment" do ifexist ${'MINGDIR'}/include/freetype2 CPPFLAGS+=-O2 -Wall -Iinclude -Iinclude/OpenLayer -I%MINGDIR%/include/freetype2 -fexpensive-optimizations else ifexist ${'MINGDIR'}/local/include/freetype2 CPPFLAGS+=-O2 -Wall -Iinclude -Iinclude/OpenLayer -I%MINGDIR%/local/include/freetype2 -fexpensive-optimizations else :gkloc echo "Can't find freetype do you have it installed?" echo "Please specify where its located:" echo "example: c:/\mingw (make sure lib/\libfreetype.a and include/\freetype2/\freetype exist in the directory)" echo "Enter ignore to disable ttf support or exit if you don't have it and quit setup." read LOCATION do if $(tolower ${'LOCATION'})='ignore' CPPFLAGS+=-O2 -Wall -Iinclude -Iinclude/OpenLayer -fexpensive-optimizations LDFLAGS=-lpng -lagl -lalleg -luser32 -lgdi32 -lglu32 -lopengl32 DROPTTF='true' goto NOPNG else if $(tolower ${'LOCATION'})='exit' exit 0 else if ${'LOCATION'}='' goto gkloc else ifexist ${'LOCATION'}/lib/libfreetype.a do ifexist ${'LOCATION'}/include/freetype2 CFLAGS+=-O2 -Wall -Iinclude/OpenLayer -I${'LOCATION'}/include/freetype2 -fexpensive-optimizations else ifnexist ${'LOCATION'}/include/freetype2 echo "${'LOCATION'} is an invalid library location." goto gkloc done else ifnexist ${'LOCATION'}/lib/libfreetype.a ifnexist ${'LOCATION'}/include/freetype2 echo "${'LOCATION'} is an invalid library location." goto gkloc done done LDFLAGS=-lglyph-agl -lfreetype -lpng -lz -lagl -lalleg -luser32 -lgdi32 -lglu32 -lopengl32 else ifplat macosx echo "Seting up for macosx environment" CPPFLAGS+=-O2 -Wall -Iinclude -Iinclude/OpenLayer `freetype-config --cflags` -fexpensive-optimizations LDFLAGS=-lglyph-agl `freetype-config --libs` `libpng-config --libs` -lagl `allegro-config --libs` -framework OpenGL -framework Carbon done # Prompt user for preprocessor support :NOTTF echo "Do you wish to drop TTF support? [y/N]" read TTF do if $(tolower ${'TTF'})='y' CPPFLAGS += " -DOL_NO_TTF" LDFLAGS -= "-lglyph-agl " CONFIGLIBS-="-lglyph-agl " DROPTTF='true' goto NOPNG else ifnot $(tolower ${'TTF'})='n' ifnot ${'TTF'}='' goto NOTTF done CONFIGFLAGS += "`freetype-config --cflags` " CONFIGLIBS += "`freetype-config --libs` -lglyph-agl " :NONEWTTF echo "Do you wish to use FreeType directly and drop GlyphKeeper? [y/N]" read NEWTTF do if $(tolower ${'NEWTTF'})='y' CPPFLAGS += " -DUSE_NEW_TTF" LDFLAGS -= "-lglyph-agl " CONFIGLIBS-="-lglyph-agl " USENEWTTF='true' else ifnot $(tolower ${'NEWTTF'})='n' ifnot ${'NEWTTF'}='' goto NONEWTTF done :NOPNG echo "Do you wish to drop PNG support? [y/N]" read PNG do if $(tolower ${'PNG'})='y' CPPFLAGS += " -DOL_NO_PNG" DROPPNG='true' else ifnot $(tolower ${'PNG'})='n' ifnot ${'PNG'}='' goto NOPNG done do if ${'DROPPNG'}='' CONFIGFLAGS += "`libpng-config --cflags` " CONFIGLIBS += "`libpng-config --libs` " done :NOOLDAPI echo "Do you wish to drop old API Support? [y/N]" read OLDAPI do if $(tolower ${'OLDAPI'})='y' CPPFLAGS += " -DOL_NO_OLD_API" DROPOLDAPI='true' else ifnot $(tolower ${'OLDAPI'})='n' ifnot ${'OLDAPI'}='' goto NOOLDAPI done :NOSTATECHANGE echo "Do you wish to drop State Changes? [y/N]" read STATECHANGE do if $(tolower ${'STATECHANGE'})='y' CPPFLAGS += " -DOL_NO_STATE_CHANGE" DROPSTATECHANGE='true' else ifnot $(tolower ${'STATECHANGE'})='n' ifnot ${'STATECHANGE'}='' goto NOSTATECHANGE done # Finishing touches on the openlayer-config script do ifplat linux CONFIGFLAGS += "`allegro-config --cflags` " CONFIGLIBS += "-lagl `allegro-config --libs` -lGL -lGLU " else ifplat macosx CONFIGFLAGS += "`allegro-config --cflags` " CONFIGLIBS += "-lagl `allegro-config --libs` -framework OpenGL -framework Carbon " done # Create options file and retain users choices writefile build/options ${'CPPFLAGS'} appendfile build/options ${'LDFLAGS'} appendfile build/options ${'CONFIGFLAGS'} appendfile build/options ${'CONFIGLIBS'} appendfile build/options ${'DROPPNG'} appendfile build/options ${'DROPTTF'} appendfile build/options ${'USENEWTTF'} appendfile build/options ${'DROPOLDAPI'} appendfile build/options ${'DROPSTATECHANGE'} goto build # Start building library :build echo "- Creating required directories -" ifnexist obj -mkdir obj ifnexist dep -mkdir dep ifnexist lib -mkdir lib echo "- Starting compilation -" compile ${LIB_SOURCES} echo "- Assembling library -" -rm lib/libopenlayer.a linklib libopenlayer # Do the header invoke build/header.cbd echo "- Compiling demos -" LIBFLAG = "lib/libopenlayer.a " LIBFLAG += ${LDFLAGS} LDFLAGS = ${LIBFLAG} CPPFLAGS -= "-DUSE_NEW_TTF" LD = g++ # Collision demo src_paths demos/collisiondemo -compile main.cpp -linkexec demos/collisiondemo/collisiondemo -rmobj main.cpp # gamedemo src_paths demos/gamedemo -compile Demo.cpp -linkexec demos/gamedemo/gamedemo -rmobj Demo.cpp # gameloop src_paths demos/gameloop -compile Main.cpp -linkexec demos/gameloop/gameloop -rmobj Main.cpp # Line strip demo src_paths demos/linestripdemo -compile Main.cpp -linkexec demos/linestripdemo/linestripdemo -rmobj Main.cpp # Render bitmap src_paths demos/renderbitmap -compile Main.cpp -linkexec demos/renderbitmap/renderbitmap -rmobj Main.cpp # Shape demo src_paths demos/shapedemo -compile Main.cpp -linkexec demos/shapedemo/shapedemo -rmobj Main.cpp # Text demo src_paths demos/textdemo -compile Main.cpp -linkexec demos/textdemo/textdemo -rmobj Main.cpp echo " - Compilation completed - You can now install the lib by passing install." exit 0 # Install library :install do ifexist lib/libopenlayer.a :installask echo "Where do you wish to install OpenLayer?" do ifplat win32 echo "example: c:\mingw (make sure lib and include exist in the directory)" else echo "example: /usr/local (make sure lib and include exist in the directory)" done echo "Enter exit or cancel if you don't want to install at this time." read LOCATION do if $(tolower ${'LOCATION'})='cancel' exit 0 else if $(tolower ${'LOCATION'})='exit' exit 0 else if ${'LOCATION'}='' goto installask else ifexist ${'LOCATION'}/lib ifexist ${'LOCATION'}/include echo "Installing OpenLayer to ${'LOCATION'}" LIB_HEADERS = $(ls include/OpenLayer/) -mkdir ${'LOCATION'}/include/OpenLayer ifnplat win32 -call chmod 755 ${'LOCATION'}/include/OpenLayer :copystart HEADER = $(word 1, ${LIB_HEADERS}) popfront LIB_HEADERS if ${'HEADER'}='' goto copyend copy ${'HEADER'} ${'LOCATION'}/include/OpenLayer/ goto copystart :copyend copy include/OpenLayer.hpp ${'LOCATION'}/include/ copy lib/libopenlayer.a ${'LOCATION'}/lib/ writefile installdir ${'LOCATION'} ifnplat win32 invoke build/ol-config.cbd :libinstallfinish echo "" echo "Install completed" exit 0 else ifnexist ${'LOCATION'}/lib ifnexist ${'LOCATION'}/include echo "" echo "${'LOCATION'} is an invalid install location." echo "" goto installask done else ifnexist lib/libopenlayer.a echo "Please compile OpenLayer first." exit 1 done exit 1 :uninstall do ifexist installdir setinput installdir read tempstr LOCATION = ${'tempstr'} setinput goto uninstallok done echo "It seems there is no install history." :uninstallask echo "Provide the location of where OpenLayer is installed. Enter exit or cancel if you don't want to uninstall at this time." read LOCATION do if $(tolower ${'LOCATION'})='exit' exit 0 else if $(tolower ${'LOCATION'})='cancel' exit 0 else ifnexist ${'LOCATION'}/lib/libopenlayer.a ifnexist ${'LOCATION'}/include/OpenLayer.hpp echo "" echo "There seems to be no OpenLayer installation at ${'LOCATION'}" echo "" goto uninstallask done :uninstallok echo "Uninstalling OpenLayer from ${'LOCATION'}" -rm ${'LOCATION'}/lib/libopenlayer.a -rm ${'LOCATION'}/include/OpenLayer.hpp HEADERS = $(ls ${'LOCATION'}/include/OpenLayer/) :uninststart HEADER = $(word 1, ${HEADERS}) popfront HEADERS if ${'HEADER'}='' goto uninstend -rm ${'HEADER'} goto uninststart :uninstend -rm ${'LOCATION'}/include/OpenLayer -rm ${'LOCATION'}/bin/openlayer-config -rm installdir exit 0 # clean up library :clean echo "- Cleaning up -" ifplat win32 EXE_EXT='.exe' -rmobj ${LIB_SOURCES} -rm lib/libopenlayer.a demos/collisiondemo/collisiondemo${'EXE_EXT'} demos/gamedemo/gamedemo${'EXE_EXT'} demos/gameloop/gameloop${'EXE_EXT'} demos/linestripdemo/linestripdemo${'EXE_EXT'} demos/renderbitmap/renderbitmap${'EXE_EXT'} demos/shapedemo/shapedemo${'EXE_EXT'} demos/textdemo/textdemo${'EXE_EXT'} build/options obj lib dep :rmcbuild @-rmexec cbuild exit 0 openlayer-2.1.orig/src/0000700000175000017500000000000012262355751015274 5ustar georgeskgeorgeskopenlayer-2.1.orig/src/RenderModes.cpp0000644000175000017500000002022610417230626020214 0ustar georgeskgeorgesk#include "RenderModes.hpp" #include "TextureInfo.hpp" #include "Bitmap.hpp" #include "Rgba.hpp" #include "Rectangle.hpp" using namespace ol; // RENDER MODES // // * GENERAL FUNCTIONS // ClippedMode:: ClippedMode( const Rect &clipArea ) : clipRect( clipArea.pos.x, clipArea.pos.y, clipArea.size.x, clipArea.size.y ) {} OlRect RenderMode:: GetRenderRect( OlRect current ) const { return current; } OlTexCoords RenderMode:: GetTexCoords( OlTexCoords current ) const { return current; } void RenderMode:: PrimarySetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoords, float w, float h ) { switch( coord ) { case OL_TC_TOPLEFT: glTexCoord2f( texCoords.convx1, texCoords.convy1 ); break; case OL_TC_TOPRIGHT: glTexCoord2f( texCoords.convx2, texCoords.convy1 ); break; case OL_TC_BOTTOMLEFT: glTexCoord2f( texCoords.convx1, texCoords.convy2 ); break; case OL_TC_BOTTOMRIGHT: glTexCoord2f( texCoords.convx2, texCoords.convy2 ); break; default: OlError( "Unknown enumeration in SetTextCoord!" ); } } void RenderMode:: SetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoordRect, float w, float h ) const { PrimarySetTexCoord( coord, renderRect, texCoordRect, w, h ); } // * TINT MODE // void TintMode:: Select() const { // Use linear interpolation // glFogi( GL_FOG_MODE, GL_LINEAR ); #ifdef NO_COLOR_CHANNELS float fogCol[] = { color.r, color.g, color.b, 1.0 }; #else Rgba channels = Transforms::GetColorChannels(); float fogCol[] = { channels.r * color.r, channels.g * color.g, channels.b * color.b, 1.0 }; #endif glFogfv( GL_FOG_COLOR, fogCol ); glFogf( GL_FOG_DENSITY, 1.0 ); glFogf( GL_FOG_START, -color.a ); glFogf( GL_FOG_END, (1.0 - color.a )); // We don't need per-pixel fog, per-verted will do the same // glHint( GL_FOG_HINT, GL_FASTEST ); glEnable( GL_FOG ); } void TintMode:: Unselect() const { glDisable( GL_FOG ); } // * GAIN ALPHA MODE // // Thanks to Graham Goring for submitting the following two functions // void GainAlphaMode:: Select() const { glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); alphaFrom.Select(); glActiveTexture(GL_TEXTURE0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); glActiveTexture(GL_TEXTURE1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS); glActiveTexture(GL_TEXTURE0); } void GainAlphaMode:: Unselect() const { glActiveTexture(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); glDisable( GL_TEXTURE_2D ); } void GainAlphaMode:: SetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoords, float w, float h ) const { OlRect otherTCR(( x < 0.0 )? -x/alphaFrom.Width() * alphaFrom.GetTextureEndX() : 0.0, ( y < 0.0 )? -y/alphaFrom.Height() * alphaFrom.GetTextureEndY() : 0.0, ( x + alphaFrom.Width() > w )? ( w - x )/alphaFrom.Width() * alphaFrom.GetTextureEndX() : alphaFrom.GetTextureEndX(), ( y + alphaFrom.Height() > h )? ( h - y )/alphaFrom.Height() * alphaFrom.GetTextureEndY() : alphaFrom.GetTextureEndY()); switch( coord ) { case OL_TC_TOPLEFT: glMultiTexCoord2f( GL_TEXTURE0, texCoords.convx1, texCoords.convy1 ); glMultiTexCoord2f( GL_TEXTURE1, otherTCR.x, 1.0 - otherTCR.y ); break; case OL_TC_TOPRIGHT: glMultiTexCoord2f( GL_TEXTURE0, texCoords.convx2, texCoords.convy1 ); glMultiTexCoord2f( GL_TEXTURE1, otherTCR.w, 1.0 - otherTCR.y ); break; case OL_TC_BOTTOMLEFT: glMultiTexCoord2f( GL_TEXTURE0, texCoords.convx1, texCoords.convy2 ); glMultiTexCoord2f( GL_TEXTURE1, otherTCR.x, 1.0 - ( otherTCR.h )); break; case OL_TC_BOTTOMRIGHT: glMultiTexCoord2f( GL_TEXTURE0, texCoords.convx2, texCoords.convy2 ); glMultiTexCoord2f( GL_TEXTURE1, otherTCR.w, 1.0 - ( otherTCR.h )); break; default: OlError( "Unknown enumeration in SetTextCoord!" ); } } OlRect GainAlphaMode:: GetRenderRect( OlRect current ) const { OlRect clipRect( x, y, alphaFrom.Width(), alphaFrom.Height() ); return current.ClippedTo( clipRect ); } OlTexCoords GainAlphaMode:: GetTexCoords( OlTexCoords current ) const { OlRect clipRect( x, y, alphaFrom.Width(), alphaFrom.Height() ); return current.ClippedTo( clipRect ); } // * SLICE MULTIPLY MODE // OlTexCoords SliceMultiplyMode:: GetTexCoords( OlTexCoords current ) const { switch( mode ) { case HORIZONTAL_SLICE: current.y1 += slicePos; current.y2 = current.y1; break; case VERTICAL_SLICE: current.x1 += slicePos; current.x2 = current.x1; break; default: OlError( "Unknown enumeration in SliceMultiplyMode::GetTexCoords!" ); } return current; } // * CLIPPED MODE // OlTexCoords ClippedMode:: GetTexCoords( OlTexCoords current ) const { return current.ClippedTo( clipRect ); } OlRect ClippedMode:: GetRenderRect( OlRect current ) const { return current.ClippedTo( clipRect ); } // * FLIPPED MODE // OlTexCoords FlippedMode:: GetTexCoords( OlTexCoords current ) const { switch( mode ) { case HORIZONTAL: current.FlipHorizontal(); break; case VERTICAL: current.FlipVertical(); break; case BOTH: current.FlipHorizontal(); current.FlipVertical(); break; default: OlError( "Unknown enumeration in FlippedMode::Select!" ); } return current; } // * GRADIENT MODE // OlTexCoords GradientMode:: GetTexCoords( OlTexCoords current ) const { current.SetColors( corners ); return current; } // * MULTI MODE // MultiMode RenderMode:: operator+( const RenderMode &other ) const { return MultiMode( *this, other ); } void MultiMode:: Select() const { mode1.Select(); mode2.Select(); } void MultiMode:: Unselect() const { mode1.Unselect(); mode2.Unselect(); } bool MultiMode:: SetsTexCoords() const { return mode1.SetsTexCoords() || mode2.SetsTexCoords(); } void MultiMode:: SetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoordRect, float w, float h ) const { if( mode1.SetsTexCoords() ) mode1.SetTexCoord( coord, renderRect, texCoordRect, w, h ); if( mode2.SetsTexCoords() ) mode2.SetTexCoord( coord, renderRect, texCoordRect, w, h ); } OlRect MultiMode:: GetRenderRect( OlRect current ) const { current = mode1.GetRenderRect( current ); return mode2.GetRenderRect( current ); } OlTexCoords MultiMode:: GetTexCoords( OlTexCoords current ) const { return mode2.GetTexCoords( mode1.GetTexCoords( current )); } openlayer-2.1.orig/src/Settings.cpp0000644000175000017500000000436610507747260017623 0ustar georgeskgeorgesk#include "Settings.hpp" #include "Includes.hpp" #include "General.hpp" #include "Internal.hpp" using namespace ol; // CONSTANTS // static const float OL_NEAR_ZERO = 0.000001; // STATIC CLASS VARIABLES // float Settings::circleAccuracy = 0.5; float Settings::collisionPolyAccuracy = 0.8; int Settings::collisionPolyAlphaLimit = 128; bool Settings::useAntiAlias = true; bool Settings::useTextures = true; bool Settings::storeMemoryBitmaps = false; // GENERAL FUNCTIONS // void Settings:: SetCollisionPolyAccuracy( float accuracy ) { if( accuracy > OL_NEAR_ZERO && accuracy <= 1.0 ) { collisionPolyAccuracy = accuracy; } else { OlError( std::string("Illegal accuracy value in SetCollisionPolyAccuracy: ") + ToString( accuracy )); } } float Settings:: GetCollisionPolyAccuracy() { return collisionPolyAccuracy; } void Settings:: SetAntialiasing( bool turnedOn ) { useAntiAlias = turnedOn; if( useAntiAlias ) { glEnable( GL_LINE_SMOOTH ); //glEnable( GL_POINT_SMOOTH ); //glEnable( GL_POLYGON_SMOOTH ); } else { glDisable( GL_LINE_SMOOTH ); glDisable( GL_POINT_SMOOTH ); //glDisable( GL_POLYGON_SMOOTH ); } } void Settings:: SetCircleAccuracy( float accuracy ) { if( accuracy > OL_NEAR_ZERO && accuracy <= 1.0 ) circleAccuracy = accuracy; } void Settings:: SetTextureMapping( bool turnedOn ) { useTextures = turnedOn; if( useTextures ) { glEnable( GL_TEXTURE_2D ); } else { glDisable( GL_TEXTURE_2D ); } } void Settings:: SetOrthographicProjection( int w, int h ) { glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); glOrtho( 0, w, 0, h, -1, 1000 ); glScalef( 1, -1, 1 ); glTranslatef( 0, -h, 0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glDisable( GL_DEPTH_TEST ); } void Settings:: RestoreOldProjection() { glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); } void Settings:: StoreMemoryBitmaps( bool turnedOn ) { storeMemoryBitmaps = turnedOn; } bool Settings:: MemoryBitmapsStored() { return storeMemoryBitmaps; } openlayer-2.1.orig/src/Line.cpp0000644000175000017500000000732210560135002016665 0ustar georgeskgeorgesk#include "Line.hpp" #include "Internal.hpp" #include "General.hpp" using namespace ol; std::string Line:: ToString() const { std::ostringstream str; str << "Line: Start: ( " << start.x << ", " << start.y << " ) End: ( " << end.x << ", " << end.y << " ) Origin: ( " << origin.x << ", " << origin.y << " )"; return str.str(); } void Line:: ExecDraw() const { glLineWidth( lineWidth ); glPushMatrix(); glTranslatef( origin.x, origin.y, 0.0 ); glBegin( GL_LINES ); glVertex2f( start.x, start.y ); glVertex2f( end.x, end.y ); glEnd(); glPopMatrix(); } void Line:: Draw( const Rgba &color1, const Rgba &color2 ) const { glLineWidth( lineWidth ); #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( origin.x, origin.y, 0.0 ); glBegin( GL_LINES ); color1.Select(); glVertex2f( start.x, start.y ); color2.Select(); glVertex2f( end.x, end.y ); glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } float Line:: GetShortestDistanceTo( const Vec2D &point ) { // Contributed by SiegeLord float A = point.x - start.x; float B = point.y - start.y; float C = end.x - start.x; float D = end.y - start.y; float dot = A * C + B * D; float len_sq = C * C + D * D; float param = dot / len_sq; float xx,yy; if(param < 0) { xx = start.x; yy = start.y; } else if(param > 1) { xx = end.x; yy = end.y; } else { xx = start.x + param * C; yy = start.y + param * D; } return sqrt((( point.x - xx ) * ( point.x - xx )) + (( point.y - yy ) * ( point.y - yy ))); } Vec2D Line:: GetIntersectionPoint( const Line &other ) const { Vec2D absStart = start + origin; Vec2D absEnd = end + origin; Vec2D otherStart = other.start + other.origin; Vec2D otherEnd = other.end + other.origin; float ua = (( otherEnd.x - otherStart.x ) * ( absStart.y - otherStart.y ) - ( otherEnd.y - otherStart.y ) * ( absStart.x - otherStart.x )) / (( otherEnd.y - otherStart.y ) * ( absEnd.x - absStart.x ) - ( otherEnd.x - otherStart.x ) * ( absEnd.y - absStart.y )); return Vec2D( absStart.x + ua * ( absEnd.x - absStart.x ), absStart.y + ua * ( absEnd.y - absStart.y )); } // Tests if the two line segments collide // bool Line:: Collides( const Vec2D &thisStart, const Vec2D &thisEnd, const Vec2D &otherOrigin, const Vec2D &otherStart, const Vec2D &otherEnd ) const { Vec2D absStart = thisStart + origin; Vec2D absEnd = thisEnd + origin; Vec2D otherAbsStart = otherStart + otherOrigin; Vec2D otherAbsEnd = otherEnd + otherOrigin; return IsCounterClockwise( absStart, absEnd, otherAbsStart ) != IsCounterClockwise( absStart, absEnd, otherAbsEnd ) && IsCounterClockwise( otherAbsStart, otherAbsEnd, absStart ) != IsCounterClockwise( otherAbsStart, otherAbsEnd, absEnd ); } bool Line:: Collides( const Line &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { Matrix2D thisTransform = thisPlacement.Get2DMatrix(); Matrix2D otherTransform = otherPlacement.Get2DMatrix(); Vec2D thisStart = thisTransform.Transform( start - thisPlacement.GetRotationPivot() ); Vec2D thisEnd = thisTransform.Transform( end - thisPlacement.GetRotationPivot() ); Vec2D otherStart = otherTransform.Transform( other.start - otherPlacement.GetRotationPivot() ); Vec2D otherEnd = otherTransform.Transform( other.end - otherPlacement.GetRotationPivot() ); return Collides( thisStart, thisEnd, other.origin, otherStart, otherEnd ); } openlayer-2.1.orig/src/Canvas.cpp0000644000175000017500000001766510517576304017244 0ustar georgeskgeorgesk#include "Canvas.hpp" #include "Framebuffer.hpp" #include "Blenders.hpp" #include "Setup.hpp" #include "Rectangle.hpp" #include "Includes.hpp" using namespace ol; // CONSTANTS // static unsigned int SCREENSHOT_BPP = 3; static int SCREENSHOT_FORMAT = GL_RGB; int Canvas:: GetScreenshotBPP() { return SCREENSHOT_BPP; } int Canvas:: GetScreenshotFormat() { return SCREENSHOT_FORMAT; } // STATIC CLASS VARIABLES // Canvas::SurfaceInfo Canvas::activeSurface( SCREEN_BACKBUF, 0, 0 ); std::map< RenderTarget, Canvas::SurfaceInfo > Canvas::storedSurfaces; std::stack< Canvas::SurfaceInfo > Canvas::pushedSurfaces; // GENERAL FUNCTIONS // void Canvas:: ReadBufferSizes() { activeSurface.SelectDefaultBufferSize(); for( std::map< RenderTarget, Canvas::SurfaceInfo > ::iterator iter = storedSurfaces.begin(); iter != storedSurfaces.end(); iter++ ) { iter->second.SelectDefaultBufferSize(); } } void Canvas::SurfaceInfo:: SelectDefaultBufferSize() { width = Setup::GetWindowWidth(); height = Setup::GetWindowHeight(); } void Canvas::SurfaceInfo:: SetPixelWriteMode( PixelWriteMode mode ) { writeMode = mode; ApplyPixelWriteMode(); } void Canvas:: ReleaseSurface() { switch( activeSurface.GetType() ) { case BITMAP_TARGET: Refresh(); FrameBuffer::GetInstance().Release(); break; case SCREEN_BACKBUF: case SCREEN_FRONTBUF: storedSurfaces[activeSurface.GetType()] = activeSurface; break; default: OlError( "Unknown rendering target in ReleaseSurface: " + ToString((int) activeSurface.GetType() )); } } void Canvas:: SetTo( const Bitmap &image ) { ReleaseSurface(); activeSurface = SurfaceInfo( BITMAP_TARGET, image.Width(), image.Height(), &image ); SelectImage( image ); FinishSurfaceSelection(); } void Canvas:: SetTo( RenderTarget buffer ) { if( buffer == BITMAP_TARGET ) { OlError( "Can't select BITMAP_TARGET as the active rendering target without using the overloaded version of Canvas::SetTo" ); return; } ReleaseSurface(); SelectBuffer( buffer ); if( storedSurfaces.find( buffer ) == storedSurfaces.end() ) activeSurface = SurfaceInfo( buffer, Setup::GetWindowWidth(), Setup::GetWindowHeight() ); else activeSurface = storedSurfaces[buffer]; FinishSurfaceSelection(); } void Canvas:: SetTo( const SurfaceInfo &info ) { ReleaseSurface(); activeSurface = info; switch( info.GetType() ) { case SCREEN_BACKBUF: case SCREEN_FRONTBUF: SelectBuffer( info.GetType() ); break; case BITMAP_TARGET: { const Bitmap *image = activeSurface.GetImage(); if( !image ) { OlError( "The selected Canvas with Bitmap information is incorrect - No Bitmap found" ); SetTo( SCREEN_BACKBUF ); return; } SelectImage( *image ); break; } default: OlError( "Unknown rendering target in Canvas::SetTo (private): " + ToString((int) info.GetType() )); } FinishSurfaceSelection(); } void Canvas:: SelectBuffer( RenderTarget buffer ) { switch( buffer ) { case SCREEN_BACKBUF: glDrawBuffer( GL_BACK ); glReadBuffer( GL_BACK ); break; case SCREEN_FRONTBUF: glDrawBuffer( GL_FRONT ); glReadBuffer( GL_FRONT ); break; default: OlError( "Unknown buffer in SelectBuffer: " + ToString((int) buffer )); } } void Canvas:: SelectImage( const Bitmap &image ) { FrameBuffer::GetInstance().BindToTexture( image.textureInfo ); } void Canvas:: FinishSurfaceSelection() { activeSurface.ApplySettings(); } void Canvas:: Refresh() { Transforms::ApplyTinting(); switch( activeSurface.GetType() ) { case BITMAP_TARGET: //SetPixelWriteMode( COLOR_AND_ALPHA ); FrameBuffer::GetInstance().RefreshSurface(); break; case SCREEN_BACKBUF: allegro_gl_flip(); break; case SCREEN_FRONTBUF: glFlush(); glFinish(); break; default: OlError( "Unknown rendering target in Canvas::Refresh: " + ToString((int) activeSurface.GetType() )); return; } Blenders::SelectBlender(); } void Canvas:: Fill( Rgba col, PixelWriteMode filledComponents ) { PixelWriteMode oldMode = GetPixelWriteMode(); SetPixelWriteMode( filledComponents ); glClearColor( col.r, col.g, col.b, col.a ); glClear( GL_COLOR_BUFFER_BIT ); SetPixelWriteMode( oldMode ); } void Canvas::SurfaceInfo:: SetClipping( int x, int y, int w, int h ) { glEnable( GL_SCISSOR_TEST ); OlRectangle< int > clippingRegion( 0, 0, width, height ); clippingRegions.push( OlRectangle< int >( x, y, w, h )); ApplyClipping(); } void Canvas::SurfaceInfo:: ApplySettings() { ApplyClipping(); ApplyPixelWriteMode(); } void Canvas::SurfaceInfo:: ApplyClipping() { if( clippingRegions.empty() ) { DisableClipping(); } else { const OlRectangle< int > &clippingRegion = clippingRegions.top(); glScissor( clippingRegion.x, height - (clippingRegion.y + clippingRegion.h), clippingRegion.w, clippingRegion.h ); glEnable( GL_SCISSOR_TEST ); } } void Canvas::SurfaceInfo:: ApplyPixelWriteMode() { switch( writeMode ) { case COLOR_AND_ALPHA: glColorMask( true, true, true, true ); break; case COLOR_ONLY: glColorMask( true, true, true, false ); break; case ALPHA_ONLY: glColorMask( false, false, false, true ); break; } } void Canvas::SurfaceInfo:: DisableClipping() { clippingRegions = std::stack< OlRectangle< int > > (); glDisable( GL_SCISSOR_TEST ); } Rect Canvas::SurfaceInfo:: GetClippingRegion() { if(!clippingRegions.empty()) { const OlRectangle< int > &clippingRegion = clippingRegions.top(); return Rect( clippingRegion.x, clippingRegion.y, clippingRegion.w, clippingRegion.h ); } return Rect( 0, 0, Width(), Height() ); } void Canvas::SurfaceInfo:: ChooseDefaultPixelWriteMode() { switch( target ) { case BITMAP_TARGET: writeMode = COLOR_AND_ALPHA; break; case SCREEN_BACKBUF: writeMode = COLOR_ONLY; break; default: OlError( "Unknown render target: " + ToString((int) target )); } } OL_MEMORY_IMG *Canvas:: GetMemoryBitmap() { int width = Canvas::Width(); int height = Canvas::Height(); unsigned char *pixelData = new unsigned char[width * height * SCREENSHOT_BPP]; glReadPixels( 0, 0, width, height, SCREENSHOT_FORMAT, GL_UNSIGNED_BYTE, pixelData ); OL_MEMORY_IMG *img = GlDriver::Get()->GetMemoryBitmap( width, height, SCREENSHOT_BPP, pixelData ); delete[] pixelData; return img; } void Canvas:: Save( std::string filename ) { switch( activeSurface.GetType() ) { case SCREEN_BACKBUF: case SCREEN_FRONTBUF: { OL_MEMORY_IMG *screenshotImg = GetMemoryBitmap(); GlDriver::Get()->SaveMemoryBitmap( screenshotImg, Setup::ToAbsolutePathname( filename ).c_str() ); GlDriver::Get()->DestroyMemoryBitmap( screenshotImg ); break; } case BITMAP_TARGET: { const Bitmap *image = activeSurface.GetImage(); if( !image ) { OlError( "The saved Canvas with Bitmap information is incorrect - No Bitmap found" ); SetTo( SCREEN_BACKBUF ); return; } image->SaveIfSurface( filename ); break; } default: OlError( "Unknown render target: " + ToString((int) activeSurface.GetType() )); } } openlayer-2.1.orig/src/Blenders.cpp0000644000175000017500000000324210402062460017533 0ustar georgeskgeorgesk#include "Blenders.hpp" #include "Includes.hpp" using namespace ol; // STATIC CLASS VARIABLES // Blenders::BlenderObj Blenders::activeBlender( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); std::stack< Blenders::BlenderObj > Blenders::blenderStack; // GENERAL FUNCTIONS // void Blenders:: Set( Blender blender ) { switch( blender ) { case ALPHA_BLENDER: activeBlender.source = GL_SRC_ALPHA; activeBlender.dest = GL_ONE_MINUS_SRC_ALPHA; break; case ADDITIVE_BLENDER: activeBlender.source = GL_SRC_ALPHA; activeBlender.dest = GL_ONE; break; case SUBTRACTIVE_BLENDER: activeBlender.source = GL_ZERO; activeBlender.dest = GL_ONE_MINUS_SRC_COLOR; break; case COPY_BLENDER: activeBlender.source = GL_ONE; activeBlender.dest = GL_ZERO; break; case FULL_ADDITIVE_BLENDER: activeBlender.source = GL_ONE; activeBlender.dest = GL_ONE; break; case CUSTOM: //Nothing break; } SelectBlender(); } void Blenders:: Set( GLenum sourceFactor, GLenum destFactor ) { activeBlender.source = sourceFactor; activeBlender.dest = destFactor; SelectBlender(); } void Blenders:: SelectBlender() { if( activeBlender.source == GL_ONE && activeBlender.dest == GL_ZERO ) { glDisable( GL_BLEND ); } else { glBlendFunc( activeBlender.source, activeBlender.dest ); glEnable( GL_BLEND ); } } void Blenders:: Pop() { activeBlender = blenderStack.top(); SelectBlender(); blenderStack.pop(); } openlayer-2.1.orig/src/regpng.c0000644000175000017500000000225210552323114016721 0ustar georgeskgeorgesk/* loadpng, Allegro wrapper routines for libpng * by Peter Wang (tjaden@users.sf.net). * * This file is hereby placed in the public domain. */ #include #include "loadpng.h" /* register_png_file_type: */ void register_png_file_type(void) { register_bitmap_file_type("png", load_png, save_png); } /* register_png_datafile_object: */ static void *load_datafile_png(PACKFILE *f, long size) { BITMAP *bmp; char *buffer; buffer = (char *)malloc(size); if (!buffer) return NULL; if (pack_fread(buffer, size, f) != size) { free(buffer); return NULL; } bmp = load_memory_png(buffer, size, NULL); free(buffer); return bmp; } static void destroy_datafile_png(void *data) { if (data) destroy_bitmap((BITMAP *)data); } void register_png_datafile_object(int id) { register_datafile_object(id, load_datafile_png, destroy_datafile_png); } /* loadpng_init: * This is supposed to resemble jpgalleg_init in JPGalleg 2.0. */ int loadpng_init(void) { register_png_datafile_object(DAT_ID('P','N','G',' ')); register_png_file_type(); return 0; } openlayer-2.1.orig/src/Rectangle.cpp0000644000175000017500000002226610471102216017710 0ustar georgeskgeorgesk#include "Rectangle.hpp" #include "VertexListCollision.hpp" #include using namespace ol; static const float OL_NEAR_ZERO = 0.00001; void Rect:: ExecDraw() const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif bool applyRotation = fabs( rotationAngle ) > OL_NEAR_ZERO; if( roundness <= OL_NEAR_ZERO ) { if( applyRotation ) { glPushMatrix(); RotateMatrix( rotationAngle ); } glBegin( GL_TRIANGLE_FAN ); glVertex2f( pos.x, pos.y+size.y ); glVertex2f( pos.x+size.x, pos.y+size.y ); glVertex2f( pos.x+size.x, pos.y ); glVertex2f( pos.x, pos.y ); glEnd(); if( applyRotation ) { glPopMatrix(); } } else { glPushMatrix(); if( applyRotation ) { RotateMatrix( rotationAngle ); } float topY = pos.y + roundness; float bottomY = pos.y + size.y - roundness; float leftX = pos.x + roundness; float rightX = pos.x + size.x - roundness; glBegin( GL_QUADS ); // Center // glVertex2f( pos.x, bottomY ); glVertex2f( pos.x+size.x, bottomY ); glVertex2f( pos.x+size.x, topY ); glVertex2f( pos.x, topY ); // Top // glVertex2f( leftX, topY ); glVertex2f( rightX, topY ); glVertex2f( rightX, pos.y ); glVertex2f( leftX, pos.y ); // Bottom // glVertex2f( leftX, pos.y + size.y ); glVertex2f( rightX, pos.y + size.y ); glVertex2f( rightX, bottomY ); glVertex2f( leftX, bottomY ); glEnd(); glTranslatef( pos.x + roundness, pos.y + roundness, GLfloat( 0.0 )); RenderCircleQuarter( AL_PI ); glTranslatef( size.x - 2 * roundness, 0.0, GLfloat( 0.0 )); RenderCircleQuarter( -AL_PI/2 ); glTranslatef( 0.0, size.y - 2 * roundness, GLfloat( 0.0 )); RenderCircleQuarter( 0.0 ); glTranslatef( -size.x + 2 * roundness, 0.0, GLfloat( 0.0 )); RenderCircleQuarter( AL_PI/2 ); glPopMatrix(); } #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void Rect:: RenderCircleQuarter( float angleStart ) const { float endAngle = angleStart + AL_PI/2; glBegin( GL_TRIANGLE_FAN ); glVertex2f( 0, 0 ); for( float a = angleStart; a < endAngle; a += angleIncrement ) { glVertex2f( cos(a) * roundness, sin(a) * roundness ); } glVertex2f( cos( endAngle ) * roundness, sin( endAngle ) * roundness ); glEnd(); } void Rect:: RenderThickCircleOutlineQuarter( float startAngle ) const { float endAngle = startAngle + AL_PI/2; float outerRad = roundness + lineWidth; float innerRad = roundness; glBegin( GL_QUADS ); float prevIX = cos(startAngle) * innerRad; float prevIY = sin(startAngle) * innerRad; float prevOX = cos(startAngle) * outerRad; float prevOY = sin(startAngle) * outerRad; for( float a = startAngle; a < endAngle; a += angleIncrement ) { float cosa = cos(a); float sina = sin(a); float newIX = cosa * innerRad; float newIY = sina * innerRad; float newOX = cosa * outerRad; float newOY = sina * outerRad; glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } glVertex2f( cos(endAngle) * innerRad, sin(endAngle) * innerRad); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( cos(endAngle) * outerRad, sin(endAngle) * outerRad); glEnd(); } void Rect:: ExecDrawOutline() const { bool applyRotation = fabs( rotationAngle ) > OL_NEAR_ZERO; if( roundness <= OL_NEAR_ZERO ) { if( applyRotation ) { glPushMatrix(); RotateMatrix( rotationAngle ); } glBegin( GL_QUADS ); // Top // glVertex2f( pos.x -lineWidth, pos.y -lineWidth ); glVertex2f( pos.x+size.x +lineWidth, pos.y -lineWidth ); glVertex2f( pos.x+size.x +lineWidth, pos.y ); glVertex2f( pos.x -lineWidth, pos.y ); // Bottom // glVertex2f( pos.x -lineWidth, pos.y+size.y ); glVertex2f( pos.x+size.x +lineWidth, pos.y+size.y ); glVertex2f( pos.x+size.x +lineWidth, pos.y+size.y +lineWidth ); glVertex2f( pos.x -lineWidth, pos.y+size.y +lineWidth ); // Left // glVertex2f( pos.x -lineWidth, pos.y ); glVertex2f( pos.x, pos.y ); glVertex2f( pos.x, pos.y+size.y ); glVertex2f( pos.x -lineWidth, pos.y+size.y ); // Right // glVertex2f( pos.x+size.x, pos.y ); glVertex2f( pos.x+size.x +lineWidth, pos.y ); glVertex2f( pos.x+size.x +lineWidth, pos.y+size.y ); glVertex2f( pos.x+size.x, pos.y+size.y ); glEnd(); if( applyRotation ) { glPopMatrix(); } } else { glPushMatrix(); if( applyRotation ) { RotateMatrix( rotationAngle ); } glBegin( GL_QUADS ); // Top // glVertex2f( pos.x +roundness, pos.y -lineWidth ); glVertex2f( pos.x+size.x -roundness, pos.y -lineWidth ); glVertex2f( pos.x+size.x -roundness, pos.y ); glVertex2f( pos.x +roundness, pos.y ); // Bottom // glVertex2f( pos.x +roundness, pos.y+size.y ); glVertex2f( pos.x+size.x -roundness, pos.y+size.y ); glVertex2f( pos.x+size.x -roundness, pos.y+size.y +lineWidth ); glVertex2f( pos.x +roundness, pos.y+size.y +lineWidth ); // Left // glVertex2f( pos.x -lineWidth, pos.y +roundness ); glVertex2f( pos.x, pos.y +roundness ); glVertex2f( pos.x, pos.y+size.y -roundness ); glVertex2f( pos.x -lineWidth, pos.y+size.y -roundness ); // Right // glVertex2f( pos.x+size.x, pos.y +roundness ); glVertex2f( pos.x+size.x +lineWidth, pos.y +roundness ); glVertex2f( pos.x+size.x +lineWidth, pos.y+size.y -roundness ); glVertex2f( pos.x+size.x, pos.y+size.y -roundness ); glEnd(); glTranslatef( pos.x + roundness, pos.y + roundness, GLfloat( 0.0 )); RenderThickCircleOutlineQuarter( AL_PI ); glTranslatef( size.x - 2 * roundness, 0.0, GLfloat( 0.0 )); RenderThickCircleOutlineQuarter( -AL_PI/2 ); glTranslatef( 0.0, size.y - 2 * roundness, GLfloat( 0.0 )); RenderThickCircleOutlineQuarter( 0.0 ); glTranslatef( -size.x + 2 * roundness, 0.0, GLfloat( 0.0 )); RenderThickCircleOutlineQuarter( AL_PI/2 ); glPopMatrix(); } #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void Rect:: Draw( const Rgba *colors ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); glBegin( GL_QUADS ); colors[3].Select(); glVertex2f( pos.x, pos.y+size.y ); colors[2].Select(); glVertex2f( pos.x+size.x, pos.y+size.y ); colors[1].Select(); glVertex2f( pos.x+size.x, pos.y ); colors[0].Select(); glVertex2f( pos.x, pos.y ); glEnd(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } Rect Rect:: ClippedTo( const Rect &other ) const { Rect returnVal; if( other.pos.x < 0 ) { returnVal.pos.x = 0; returnVal.size.x = std::max( std::min( size.x, other.pos.x + other.size.x ), 0.0f ); } else { returnVal.pos.x = pos.x + other.pos.x; returnVal.size.x = std::max( std::min( size.x - other.pos.x, other.size.x ), 0.0f ); } if( other.pos.y < 0 ) { returnVal.pos.y = 0; returnVal.size.y = std::max( std::min( size.y, other.pos.y + other.size.y ), 0.0f ); } else { returnVal.pos.y = pos.y + other.pos.y; returnVal.size.y = std::max( std::min( size.y - other.pos.y, other.size.y ), 0.0f ); } return returnVal; } std::string Rect:: ToString() const { std::ostringstream str; str << "Rect: Pos: " << pos.ToString() << " Size: " << size.ToString() << " Roundness: " << roundness << " Rotation angle: " << rotationAngle; return str.str(); } Collision Rect:: DoCollisionTest( const ol::Poly &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults ) const { return LineStripCollision( GetVertices(), other.GetVertices(), thisPlacement, otherPlacement, getResults, true, true ); } openlayer-2.1.orig/src/TextRenderer.cpp0000644000175000017500000003442210575626474020442 0ustar georgeskgeorgesk//#ifndef OL_NO_TTF #ifndef OL_TEXT_RENDERER_CPP #define OL_TEXT_RENDERER_CPP #include "TextRenderer.hpp" #include "Internal.hpp" #include "Setup.hpp" #include "Settings.hpp" #include "Blenders.hpp" #include "Transforms.hpp" using namespace ol; using namespace std; // GENERAL FUNCTIONS // TextRenderer:: TextRenderer( const char *filename, int width, int height, Rgba col, int italics, bool useHinting ) : rend( 0 ), texture( 0 ), face( 0 ), italics( italics ), useHinting( useHinting ), col( col ), useTags( true ), loader( 0 ) { AddToCollection(); if( !Load( filename, width, height, col, italics, useHinting )) { OlError( string("Cannot construct a TextRenderer - Loading font '") + filename + "' failed!" ); } } TextRenderer:: TextRenderer( const TextRenderer &otherRend, int width, int height, Rgba col, int italics ) : GarbageCollected(), rend( 0 ), texture( 0 ), face( 0 ), italics( italics ), useHinting( otherRend.useHinting ), col( col ), useTags( true ), loader( 0 ) { AddToCollection(); if( !Load( otherRend, width, height, col, italics )) { OlError( "Cannot construct a TextRenderer - The font face from the other TextRenderer is invalid!" ); } } TextRenderer:: TextRenderer( GLYPH_FACE *face, int width, int height, Rgba col, int italics, bool useHinting ) : rend( 0 ), texture( 0 ), face( 0 ), italics( italics ), useHinting( useHinting ), col( col ), useTags( true ), loader( 0 ) { AddToCollection(); if( !Load( face, width, height, col, italics, useHinting )) { OlError( string("Cannot construct a TextRenderer - The passed font face is ") + string((face == 0)? "null" : "invalid" ) + string(" !" )); } } TextRenderer:: TextRenderer() : rend( 0 ), texture( 0 ), face( 0 ), italics( 0 ), useHinting( true ), useTags( true ), loader( 0 ) { AddToCollection(); } bool TextRenderer:: Load( const char *filename, int w, int h, Rgba col, int italics, bool useHinting ) { if( !Setup::IsScreenSetUp() ) { OlLog( string( "Loading queued for font: " ) + filename ); loader = new FileLoader( filename, w, h, italics, col ); return true; } if( filename == 0 ) { OlError( "Attempted to load a true type font with a null filename!" ); return false; } string absoluteFilename = Setup::ToAbsolutePathname( filename ); OlLog( string( "Loading a true type font: " ) + absoluteFilename ); face = gk_load_face_from_file( absoluteFilename.c_str(), 0 ); bool valid = false; if( face ) { valid = Load( face, w, h, col, italics, useHinting ); } if( !valid ) { OlError( "Font loading failed!" ); } return valid; } bool TextRenderer:: Load( const TextRenderer &otherRenderer, int w, int h, Rgba col, int italics ) { if( !Setup::IsScreenSetUp() ) { OlLog( "Font copying queued" ); loader = new RendLoader( otherRenderer, w, h, italics, col ); return true; } OlLog( "Copying font" ); if( col.IsValid() == false ) { col = otherRenderer.GetColor(); } if( italics == UNDEFINED_ITALICS ) { italics = otherRenderer.GetItalics(); } bool valid = Load( otherRenderer.GetFace(), w, h, col, italics ); return valid; } bool TextRenderer:: Load( GLYPH_FACE *face, int w, int h, Rgba col, int italics, bool useHinting ) { if( !face ) return false; this->col = col; this->face = face; this->useHinting = useHinting; rend = gk_create_renderer( face, 0 ); if( !rend ) return false; gk_rend_set_italic( rend, italics ); gk_rend_set_size_pixels( rend, w, h ); if( useHinting ) { gk_rend_set_hinting_default( rend ); } else { gk_rend_set_hinting_off( rend ); } rend_set_render_mode_normal( rend ); SendToGPU(); return true; } void TextRenderer:: SelectColor( const Rgba &col ) const { Rgba channels = Transforms::GetColorChannels(); Rgba affectedCol( col.r * channels.r, col.g * channels.g, col.b * channels.b, col.a * channels.a ); gk_rend_set_text_alpha_color( rend, affectedCol.SpecialPacked() ); } void TextRenderer:: FinishRendering() const { Blenders::SelectBlender(); if( Settings::TextureMappingUsed() ) { glEnable( GL_TEXTURE_2D ); } else { glDisable( GL_TEXTURE_2D ); } } const static char TAG_START = '['; const static string COLOR_START_TAG_BEGIN = "[color "; const static char TAG_END = ']'; const static string COLOR_END_TAG = "[/color]"; void TextRenderer:: Print( const string &text, int x, int y ) const { if( !IsValid()) { return; } StartRendering(); int textHeight = gk_rend_ascender_pixels( rend ); unsigned int start = 0; const Rgba originalColor = GetColor(); int lineX = 0; for( unsigned int i = 0; i < text.length(); ) { unsigned int newStart = start; bool startNewLine = false; bool changeColor = false; Rgba newColor; if( text[i] == '\n' ) { newStart = i+1; startNewLine = true; } else if( text[i] == TAG_START && useTags ) { string::size_type tagStartLength = COLOR_START_TAG_BEGIN.length(); if( text.substr( i, tagStartLength ) == COLOR_START_TAG_BEGIN ) { string::size_type tagEndPos = text.find( TAG_END, i + tagStartLength ); string colorStr = text.substr( i + tagStartLength, tagEndPos - ( i + tagStartLength )); changeColor = true; newColor = Rgba( colorStr ); newStart = tagEndPos+1; } else if( text.substr( i, COLOR_END_TAG.length() ) == COLOR_END_TAG ) { changeColor = true; newColor = originalColor; newStart = i + COLOR_END_TAG.length(); } } if( newStart != start ) { string substr( text, start, i-start ); gk_render_line_gl_utf8( texture, substr.c_str(), x + lineX, y ); i = start = newStart; if( startNewLine ) { y += textHeight; lineX = 0; } else { lineX += Width( substr ); } if( changeColor ) { SelectColor( newColor ); } } else { i++; } } if( start != text.length() ) { string substr( text, start, text.length()-start ); gk_render_line_gl_utf8( texture, substr.c_str(), x + lineX, y ); } } void TextRenderer:: Print( const string &text, int x, int y, int maxLineWidth, TextAlignment alignment ) const { if( !IsValid()) { return; } StartRendering(); int textHeight = gk_rend_ascender_pixels( rend ); unsigned int start = 0; unsigned int lastSpace = 0; bool noLastSpace = true; for( unsigned int i = 0; i < text.length(); i++ ) { switch( text[i] ) { case ' ': case '\n': { string substr( text, start, i-start ); int lineWidth = gk_text_width_utf8( rend, substr.c_str() ); if( lineWidth > maxLineWidth && !noLastSpace ) { string line( text, start, lastSpace - start ); RenderLineAligned( line, x, y, maxLineWidth, alignment ); y += textHeight; start = lastSpace+1; } if( text[i] == ' ' ) { lastSpace = i; noLastSpace = false; break; } string line( text, start, i-start ); lineWidth = gk_text_width_utf8( rend, substr.c_str() ); TextAlignment realAlignment = ( alignment == JUSTIFY )? LEFT : alignment; RenderLineAligned( line, x, y, maxLineWidth, realAlignment ); y += textHeight; start = i+1; lastSpace = 0; noLastSpace = true; break; } } } if( start != text.length() ) { string line( text, start, text.length()-start ); int lineWidth = gk_text_width_utf8( rend, line.c_str() ); if( lineWidth > maxLineWidth && !noLastSpace ) { string linePart( text, start, lastSpace - start ); RenderLineAligned( linePart, x, y, maxLineWidth, alignment ); y += textHeight; start = lastSpace+1; line = string( text, start, text.length()-start ); } TextAlignment realAlignment = ( alignment == JUSTIFY )? LEFT : alignment; RenderLineAligned( line, x, y, maxLineWidth, realAlignment ); } } void TextRenderer:: RenderLineAligned( const string &line, int x, int y, int maxLineWidth, TextAlignment alignment ) const { if( alignment != JUSTIFY ) { int textX = x; switch( alignment ) { case LEFT: break; case RIGHT: textX += maxLineWidth - gk_text_width_utf8( rend, line.c_str() ); break; case CENTER: textX += (maxLineWidth - gk_text_width_utf8( rend, line.c_str() ))/2; break; case JUSTIFY: break; //nothing } gk_render_line_gl_utf8( texture, line.c_str(), textX, y ); } else { int numSpaces = 0; for( unsigned int i = 0; i < line.length(); i++ ) { if( line[i] == ' ' ) numSpaces++; } float pixelsPerSpace = float( maxLineWidth - gk_text_width_utf8( rend, line.c_str() ))/numSpaces; int wordStart = 0; float wordX = x; for( unsigned int i = 0; i < line.length(); i++ ) { if( line[i] == ' ' ) { string word( line, wordStart, i - wordStart ); gk_render_line_gl_utf8( texture, word.c_str(), int( wordX ), y ); wordX += gk_text_width_utf8( rend, ( word + " " ).c_str() ) + pixelsPerSpace; wordStart = i+1; } } if( wordStart != (signed)line.length() ) { string word( line, wordStart, line.length() - wordStart ); gk_render_line_gl_utf8( texture, word.c_str(), int( wordX ), y ); } } } int TextRenderer:: FontHeight() const { return gk_rend_ascender_pixels( rend ); } int TextRenderer:: FontTotalHeight() const { return gk_rend_height_pixels( rend ); } int TextRenderer:: FirstLineWidth( const string &text ) const { int width = 0; for( unsigned int i = 0; i < text.length(); i++ ) { if( text[i] == '\n' ) { string substr( text, 0, i ); width = gk_text_width_utf8( rend, substr.c_str() ); break; } } if( width == 0 ) { width = gk_text_width_utf8( rend, text.c_str() ); } return width; } int TextRenderer:: FirstLineHeight( const std::string &text ) const { return gk_rend_ascender_pixels( rend ); } string TextRenderer:: GetColoredText( const std::string &str, Rgba color ) { return COLOR_START_TAG_BEGIN + color.ToHex() + TAG_END + str + COLOR_END_TAG; } int TextRenderer:: Width( const string &text ) const { int width = 0; int currW = 0; unsigned int start = 0; for( unsigned int i = 0; i < text.length(); i++ ) { if( text[i] == '\n' ) { string substr( text, start, i-start ); currW += gk_text_width_utf8( rend, substr.c_str() ); if( currW > width ) width = currW; start = i+1; currW = 0; } else if( text[i] == TAG_START && useTags ) { string::size_type tagEndPos = text.find( TAG_END, i + 1 ); if( tagEndPos != string::npos ) { string substr( text, i, tagEndPos - i + 1 ); if( substr.substr( 0, COLOR_START_TAG_BEGIN.size() ) == COLOR_START_TAG_BEGIN || substr == COLOR_END_TAG ) { string textThusFar( text, start, i-start ); currW += gk_text_width_utf8( rend, textThusFar.c_str() ); start = tagEndPos+1; i = start-1; } } } } if( start != text.length() || currW != 0 ) { string substr( text, start, text.length()-start ); currW += gk_text_width_utf8( rend, substr.c_str() ); if( currW > width ) width = currW; } return width; } int TextRenderer:: Height( const string &text ) const { int textHeight = gk_rend_ascender_pixels( rend );//text_height_utf8( rend, text.c_str()); int height = 0; unsigned int start = 0; for( unsigned int i = 0; i < text.length(); i++ ) { if( text[i] == '\n' ) { height += textHeight; start = i+1; } } if( start != text.length() ) { height += textHeight; } return height; } void TextRenderer:: SendToGPU() { if( texture ) { UnloadFromGPU(); } texture = gk_create_texture( rend, 32, 96 ); gk_send_texture_to_gpu( texture ); } void TextRenderer:: UnloadFromGPU() { if( texture ) { gk_unload_texture_from_gpu( texture ); gk_destroy_texture( texture ); texture = 0; } } bool TextRenderer:: IsValid() const { return rend != 0 && texture != 0 && face != 0; } void TextRenderer:: SetColor( const Rgba& col ) { this->col = col; } const Rgba& TextRenderer:: GetColor() const { return col; } void TextRenderer:: SetItalics( int italics ) { if( italics != this->italics ) { UnloadFromGPU(); gk_rend_set_italic( rend, italics ); SendToGPU(); } } int TextRenderer:: GetItalics() const { return italics; } GarbageCollection &OlGetCollection(); void TextRenderer:: Destroy( bool eraseFromGarbageCollection ) { UnloadFromGPU(); if( eraseFromGarbageCollection ) { OlGetCollection().Remove( this ); } } // GARBAGE COLLECTION / AUTOLOADER ROUTINES // OlLoadResult TextRenderer::FileLoader:: Load( TextRenderer &subject ) { if( subject.Load( filename, w, h, col, italics ) == true ) { return OL_LR_SUCCESS; } return OL_LR_FAILURE; } OlLoadResult TextRenderer::RendLoader:: Load( TextRenderer &subject ) { if( !rend.IsValid() ) { return OL_LR_PENDING; } if( subject.Load( rend, w, h, col, italics ) == true ) { return OL_LR_SUCCESS; } return OL_LR_FAILURE; } OlLoadResult TextRenderer:: ExecuteQueuedCommands() { OlLoadResult result = OL_LR_SUCCESS; if( loader ) { result = loader->Load( *this ); loader = 0; } return result; } void TextRenderer:: AddToCollection() { OlGetCollection().Add( this ); } bool TextRenderer:: IsLoadingQueued() const { return loader != 0; } #endif /* OL_TEXT_RENDERER_CPP */ //#endif // OL_NO_TTF openlayer-2.1.orig/src/Rgba.cpp0000644000175000017500000000554710575626474016710 0ustar georgeskgeorgesk#include "Rgba.hpp" #include "Internal.hpp" #include using namespace ol; using namespace std; // STATIC CLASS VARIABLES // const Rgba Rgba::BLACK = Rgba( 0.0, 0.0, 0.0, 1.0 ); const Rgba Rgba::WHITE = Rgba( 1.0, 1.0, 1.0, 1.0 ); const Rgba Rgba::RED = Rgba( 1.0, 0.0, 0.0, 1.0 ); const Rgba Rgba::YELLOW = Rgba( 1.0, 1.0, 0.0, 1.0 ); const Rgba Rgba::GREEN = Rgba( 0.0, 1.0, 0.0, 1.0 ); const Rgba Rgba::BLUE = Rgba( 0.0, 0.0, 1.0, 1.0 ); const Rgba Rgba::INVISIBLE = Rgba( 0.0, 0.0, 0.0, 0.0 ); static string HEX_CHARS = "0123456789abcdef"; static string HEX_CHARS_UPPER = "0123456789ABCDEF"; // GENERAL FUNCTIONS // Rgba:: Rgba( const string &hex ) { if( hex.length() != 6 && hex.length() != 8 ) { OlError( "Cannot parse the color " + hex ); return; } r = CompToF( parseHex( hex, 0 )); g = CompToF( parseHex( hex, 2 )); b = CompToF( parseHex( hex, 4 )); if( hex.length() == 8 ) { a = CompToF( parseHex( hex, 6 )); } else { a = 1.0; } } inline static unsigned int GetHexValue( char ch ) { string::size_type pos = HEX_CHARS.find( ch ); if( pos != string::npos ) { return pos; } else return HEX_CHARS_UPPER.find( ch ); } unsigned int Rgba:: parseHex( const string &hex, int pos ) { return ( GetHexValue( hex[pos] ) << 4 ) | GetHexValue( hex[pos+1] ); } // Optimized version by Leniuch // Rgba Rgba:: MixWith( const Rgba &other, float factor ) const { float red = r + (other.r - r) * factor; float green = g + (other.g - g) * factor; float blue = b + (other.b - b) * factor; float alpha = a + (other.a - a) * factor; return Rgba( red, green, blue, alpha ); } int Rgba:: SpecialPacked() const { return (Rgba::CompToI(a) << 24) | (Rgba::CompToI(r) << 16) | (Rgba::CompToI(g) << 8) | Rgba::CompToI(b); } Rgba:: Rgba( int col, bool notUsed ) : r( CompToF(( col >> 16 ) & 0xff)), g( CompToF(( col >> 8 ) & 0xff)), b( CompToF( col & 0xff)), a( CompToF(( col >> 24 ) & 0xff)) { notUsed = true; } Rgba:: Rgba( bool invalidiate ) : r( -1.0 ), g( -1.0 ), b( -1.0 ), a( -1.0 ) { invalidiate = true; } int Rgba:: Packed() const { return makeacol32( Rgba::CompToI(r), Rgba::CompToI(g), Rgba::CompToI(b), Rgba::CompToI(a)); } std::string Rgba::ToString() const { std::stringstream s; s << "Color: ( " << r << ", " << g << ", " << b << ", " << a << " )"; return s.str(); } std::string Rgba::ToHex() const { std::stringstream s; s << std::hex << std::setw( 2 ) << std::setfill('0') << CompToI(r); s << std::hex << std::setw( 2 ) << std::setfill('0') << CompToI(g); s << std::hex << std::setw( 2 ) << std::setfill('0') << CompToI(b); s << std::hex << std::setw( 2 ) << std::setfill('0') << CompToI(a); return s.str(); } openlayer-2.1.orig/src/GarbageCollector.cpp0000644000175000017500000000633210402077072021204 0ustar georgeskgeorgesk#include "GarbageCollector.hpp" #include "Internal.hpp" #include "General.hpp" #include "Framebuffer.hpp" using namespace ol; static GarbageCollection *gbCollection; GarbageCollection &OlGetCollection() { if( !gbCollection ) { gbCollection = new GarbageCollection; } return *gbCollection; } void OlCollectTheGarbage() { OlLog( "Collecting garbage" ); OlGetCollection().DestroyGarbage(); OlLog( "Destroying the framebuffer" ); FrameBuffer::GetInstance().DestroySurfaces(); FrameBuffer::DestroyFramebuffers(); OlLog( "OpenLayer shutdown finished" ); } void GarbageCollection:: ExecuteQueues() { std::list< GarbageCollected *> pendings = collection; OlLog( std::string( "\nAuto Loader: Executing " ) + ToString( pendings.size() ) + " pending loading commands" ); while( !pendings.empty()) { unsigned int numPendings = pendings.size(); for( std::list< GarbageCollected *> ::iterator iter = pendings.begin(); iter != pendings.end(); ) { OlLoadResult result = (*iter)->ExecuteQueuedCommands(); bool removeItem = true; switch( result ) { case OL_LR_FAILURE: OlError( "Auto Loader: Couldn't load a resource!" ); break; case OL_LR_SUCCESS: break; case OL_LR_PENDING: removeItem = false; break; default: OlError( "Auto Loader: Unknown OlLoadResult enumeration!" ); } if( removeItem ) iter = pendings.erase( iter ); else iter++; } if( pendings.size() >= numPendings ) { OlError( "Auto Loader: Circular dependancy detected! Bailing out!" ); break; } } OlLog( "Auto Loader: Completed\n" ); } void GarbageCollection:: DestroyGarbage() { OlLog( std::string( "\nGarbage Collector: Destroying " ) + ToString( collection.size() ) + " items" ); for( std::list< GarbageCollected *> ::iterator iter = collection.begin(); iter != collection.end(); iter++ ) { (*iter)->Destroy(); // If the auto-delete feature is used the object is deleted // if((*iter)->AutoDeleteUsed()) { delete *iter; } } collection.clear(); OlLog( "Garbace Collector: Completed\n" ); } void GarbageCollection:: UnloadAllToMemory() { OlLog( std::string( "\nSuspend: Unloading " ) + ToString( collection.size() ) + " items" ); for( std::list< GarbageCollected *> ::iterator iter = collection.begin(); iter != collection.end(); iter++ ) (*iter)->UnloadToMemory(); } void GarbageCollection:: LoadAllToGPU() { OlLog( std::string( "\nAwake: Loading " ) + ToString( collection.size() ) + " items" ); for( std::list< GarbageCollected *> ::iterator iter = collection.begin(); iter != collection.end(); iter++ ) (*iter)->SendToGPU(); } void GarbageCollection:: Add( GarbageCollected *item ) { collection.push_back( item ); } void GarbageCollection:: Remove( GarbageCollected *item ) { collection.remove( item ); } openlayer-2.1.orig/src/FpsCounter.cpp0000644000175000017500000000450510377212142020075 0ustar georgeskgeorgesk#include "FpsCounter.hpp" #include "Includes.hpp" using namespace ol; // CONSTANTS // static const int MS_PER_TICK = 1; static const int FRAMES_PER_CHECK = 30; // STATIC CLASS VARIABLES // float FpsCounter::defaultFps = 60.0; volatile int FpsCounter::timer = 0; int FpsCounter::frameCount = 0; float FpsCounter::fps = 0.0; float FpsCounter::deltaTime = 0.0; bool FpsCounter::paused = false; int FpsCounter::pausedTimer = 0; int FpsCounter::framesPerCheck = 30; int FpsCounter::normalFPC = 50; int FpsCounter::quickFPC = 10; bool FpsCounter::useAdvanced = true; float FpsCounter::actionLimit = 0.3; // GENERAL FUNCTIONS // void FpsCounter:: SetNumOfAveragedFrames( int averagedFrames ) { if( averagedFrames == AUTO ) { useAdvanced = true; framesPerCheck = 30; } else { useAdvanced = false; framesPerCheck = averagedFrames; } } void FpsCounter:: Start( float defaultFps ) { FpsCounter::defaultFps = defaultFps; timer = 0; frameCount = 0; frameCount = 0; framesPerCheck = normalFPC; paused = false; install_int( FpsCounter::Tick, MS_PER_TICK ); } float FpsCounter:: NewFrameStarted() { if( !paused && ++FpsCounter::frameCount > framesPerCheck && FpsCounter::timer > 0 ) { float lastFps = fps; fps = 1000.0 * float(FpsCounter::frameCount)/float(FpsCounter::timer * MS_PER_TICK); if( useAdvanced ) { float ratio = fps/lastFps; if( 1.0 - ratio > actionLimit || 1.0 - 1.0/ratio > actionLimit ) { framesPerCheck /= 2; if( framesPerCheck < quickFPC ) framesPerCheck = quickFPC; } else { framesPerCheck *= 2; if( framesPerCheck > normalFPC ) framesPerCheck = normalFPC; } } frameCount = 0; timer = 0; deltaTime = defaultFps/fps; } return deltaTime; } void FpsCounter:: Tick() { timer++; } float FpsCounter:: GetDeltaTime() { return deltaTime; } float FpsCounter:: GetFps() { return fps; } void FpsCounter:: Pause() { paused = true; pausedTimer = timer; } void FpsCounter:: Resume() { paused = false; timer = pausedTimer; } openlayer-2.1.orig/src/Effects.cpp0000644000175000017500000000166210377212142017365 0ustar georgeskgeorgesk#include "Effects.hpp" #include "Setup.hpp" using namespace ol; using namespace std; // STATIC CLASS VARIABLES // std::list< Effect *> EffectSystem::enabledEffects; Bitmap *Effect::screenDump; // EFFECTSYSTEM FUNCTIONS // void EffectSystem:: Enable( Effect *effect ) { enabledEffects.push_back( effect ); } void EffectSystem:: Disable(Effect *effect ) { enabledEffects.remove( effect ); } void EffectSystem:: DisableAll() { enabledEffects.clear(); } void EffectSystem:: Apply() { for( list< Effect *> ::iterator iter = enabledEffects.begin(); iter != enabledEffects.end(); iter++ ) { (*iter)->Apply(); } } // EFFECTS // Bitmap &Effect:: GetScreenDump() { if( !screenDump ) { InitScreenDump(); } return *screenDump; } void Effect:: InitScreenDump() { screenDump = new Bitmap( Setup::GetWindowWidth(), Setup::GetWindowHeight() ); } openlayer-2.1.orig/src/TextureInfo.cpp0000644000175000017500000000766310424556726020305 0ustar georgeskgeorgesk#include "TextureInfo.hpp" #include "Internal.hpp" #include using namespace ol; using namespace std; void OlTexCoords:: CalculateTextureCoords() { convx1 = texture.rect.x + x1 / texture.imgWidth * texture.rect.w; convx2 = texture.rect.x + x2 / texture.imgWidth * texture.rect.w; if( flipW ) { float temp = convx1; convx1 = convx2; convx2 = temp; } convy1 = texture.rect.y + texture.rect.h - y1 / texture.imgHeight * texture.rect.h; convy2 = texture.rect.y + texture.rect.h - y2 / texture.imgHeight * texture.rect.h; if( flipH ) { float temp = convy1; convy1 = convy2; convy2 = temp; } } OlTexCoords OlTexCoords:: ClippedTo( const OlRect &rect ) const { OlTexCoords returnVal = *this; if( rect.x < 0.0 ) { returnVal.x1 = x1; returnVal.x2 = min( x2 + rect.x, returnVal.x1 + rect.x + rect.w ); } else { returnVal.x1 = x1 + rect.x; returnVal.x2 = min( returnVal.x1 + x2 - rect.x, returnVal.x1 + rect.w ); } if( rect.y < 0.0 ) { returnVal.y1 = y1; returnVal.y2 = min( y2 + rect.y, returnVal.y1 + rect.y + rect.h ); } else { returnVal.y1 = y1 + rect.y; returnVal.y2 = min( returnVal.y1 + y2 - rect.y, returnVal.y1 + rect.h ); } return returnVal; } OlTextureInfo:: OlTextureInfo( int textureWidth, int textureHeight, int imageWidth, int imageHeight, GLenum format, GLuint index ) : format( format ), index( index ), texWidth( textureWidth ), texHeight( textureHeight ), imgWidth( imageWidth ), imgHeight( imageHeight ), fullImgWidth( imageWidth ), fullImgHeight( imageHeight ), xMul( ConvDimension( imageWidth, textureWidth )), yMul( ConvDimension( imageHeight, textureHeight )) { rect = OlRect( 0.0, 1.0 - yMul, xMul, yMul ); } OlTextureInfo:: OlTextureInfo( const OlTextureInfo &other, OlRect clipRect ) : format( other.format ), index( other.index ), texWidth( other.texWidth ), texHeight( other.texHeight ), fullImgWidth( other.fullImgWidth ), fullImgHeight( other.fullImgHeight ), xMul( other.xMul ), yMul( other.yMul ) { clipRect.y = other.imgHeight - clipRect.y - clipRect.h; /* printf( "Other rect: %f %f %f %f\n", clipRect.x, clipRect.y, clipRect.w, clipRect.h );*/ float xRectMul = other.xMul / other.fullImgWidth; float yRectMul = other.yMul / other.fullImgHeight; //printf( "Mul: %f, %f\n", xRectMul, yRectMul ); OlRect convClipRect( xRectMul * clipRect.x, yRectMul * clipRect.y, xRectMul * clipRect.w, yRectMul * clipRect.h ); /* printf( "Converted rect: %f %f %f %f\n", convClipRect.x, convClipRect.y, convClipRect.w, convClipRect.h ); printf( "Rect: %f %f %f %f\n", other.rect.x, other.rect.y, other.rect.w, other.rect.h );*/ rect = other.rect.ClippedTo( convClipRect ); /* printf( "Clipped rect: %f %f %f %f\n", rect.x, rect.y, rect.w, rect.h ); */ float sizeXMul = rect.w / other.rect.w; float sizeYMul = rect.h / other.rect.h; //printf( "SizeMul: %f, %f\n", sizeXMul, sizeYMul ); imgWidth = int(sizeXMul * other.imgWidth); imgHeight = int(sizeYMul * other.imgHeight); /* texWidth = int(sizeXMul * other.texWidth); texHeight = int(sizeYMul * other.texHeight);*/ } OlTextureInfo:: OlTextureInfo() : format( 0 ), index( 0 ), texWidth( 0 ), texHeight( 0 ), imgWidth( 0 ), imgHeight( 0 ), fullImgWidth( 0 ), fullImgHeight( 0 ) {} int OlTextureInfo:: GetBytesPerPixel() const { switch( format ) { case GL_RGBA: return 4; case GL_RGB: return 3; case GL_ALPHA: return 1; } OlError( "Unknown pixel format" ); return 0; } bool OlTextureInfo:: HasAlphaChannel() const { switch( format ) { case GL_RGBA: return true; case GL_RGB: return false; case GL_ALPHA: return true; } OlError( "Unknown pixel format" ); return false; } openlayer-2.1.orig/src/Transforms.cpp0000644000175000017500000001004510575626474020160 0ustar georgeskgeorgesk#include "Transforms.hpp" #include "Internal.hpp" #include "Settings.hpp" #include "Setup.hpp" #include "Rgba.hpp" using namespace ol; // STATIC CLASS VARIABLES // float Transforms::x = 0.0; float Transforms::y = 0.0; float Transforms::angle = 0.0; float Transforms::pivotX = 0.0; float Transforms::pivotY = 0.0; float Transforms::xStretch = 1.0; float Transforms::yStretch = 1.0; Rgba Transforms::color = Rgba::INVISIBLE; Rgba Transforms::colorChannels = Rgba::WHITE; bool Transforms::transformationStored = false; int Transforms::stackCounter = 0; // GENERAL FUNCTIONS // // * POSITION TRANSFORMATIONS // void Transforms:: PushPlacement() { glPushMatrix(); stackCounter++; } void Transforms:: PopPlacement() { if( stackCounter > 0 ) { glPopMatrix(); stackCounter--; } else { OlError( "Transforms::PopPlacement called before calling Transforms::PushPlacement" ); } } void Transforms:: SetPosition( float x, float y ) { Transforms::x = x; Transforms::y = y; ApplyTransforms(); } void Transforms:: SetPosition( const Vec2D& pos ) { Transforms::x = pos.x; Transforms::y = pos.y; ApplyTransforms(); } void Transforms:: SetRotation( float angle ) { Transforms::angle = angle; ApplyTransforms(); } void Transforms:: SetRotationPivot( float pivotX, float pivotY ) { Transforms::pivotX = pivotX; Transforms::pivotY = pivotY; ApplyTransforms(); } void Transforms:: SetRotationPivot( const Vec2D& pivot ) { Transforms::pivotX = pivot.x; Transforms::pivotY = pivot.y; ApplyTransforms(); } void Transforms:: SetStretch( float xStretch, float yStretch ) { Transforms::xStretch = xStretch; Transforms::yStretch = yStretch; ApplyTransforms(); } void Transforms:: SetStretch( const Vec2D& stretch ) { Transforms::xStretch = stretch.x; Transforms::yStretch = stretch.y; ApplyTransforms(); } void Transforms:: SetPlacement( const Placement& placement, const Vec2D& pivot ) { Transforms::x = placement.GetPosition().x; Transforms::y = placement.GetPosition().y; Transforms::angle = placement.GetRotation(); Transforms::pivotX = pivot.x; Transforms::pivotY = pivot.y; Transforms::xStretch = placement.GetStretch(); Transforms::yStretch = placement.GetStretch(); ApplyTransforms(); } void Transforms:: ResetPlacement() { if( transformationStored ) { while( stackCounter > 0 ) { PopPlacement(); } glPopMatrix(); transformationStored = false; x = 0; y = 0; angle = 0.0; xStretch = 1.0; yStretch = 1.0; } } void Transforms:: ApplyTransforms() { if( transformationStored ) { glPopMatrix(); } glPushMatrix(); transformationStored = true; glTranslatef( x, y, 0.0 ); if( angle != 0.0 ) { glTranslatef( pivotX, pivotY, 0.0 ); RotateMatrix( angle ); glTranslatef( -pivotX, -pivotY, 0.0 ); } if( xStretch != 1.0 || yStretch != 1.0 ) { float xTranslate = -(xStretch - 1.0) * (SCREEN_W/2 - x); float yTranslate = -(yStretch - 1.0) * (SCREEN_H/2 - y); glTranslatef( xTranslate, yTranslate, 0.0 ); glScalef( xStretch, yStretch, 0.0 ); } } // * TINTING // void Transforms:: SetTintColor( const Rgba& color ) { Transforms::color = color; } void Transforms:: ApplyTinting() { if( color.a > 0.0 ) { color.Select(); glDisable( GL_TEXTURE_2D ); glBegin( GL_QUADS ); glVertex2f( 0.0, SCREEN_H ); glVertex2f( SCREEN_W, SCREEN_H ); glVertex2f( SCREEN_W, 0.0 ); glVertex2f( 0.0, 0.0 ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } } // * COLOR CHANNELS // void Transforms:: SetColorChannels( const Rgba& cofficients ) { colorChannels = cofficients; } const Rgba& Transforms:: GetColorChannels() { return colorChannels; } openlayer-2.1.orig/src/Polygon.cpp0000644000175000017500000001344110441730664017441 0ustar georgeskgeorgesk#include "Polygon.hpp" #include "Bitmap.hpp" #include "Line.hpp" #include "VertexListCollision.hpp" #include "LineStrip.hpp" #include "LineStripRender.hpp" using namespace std; using namespace ol; ol::Poly:: Poly( const Vec2D *vertices, int numVertices, Vec2D rotationPivot ) : outlineTexture( 0 ) { placement.SetRotationPivot( rotationPivot ); for( int i = 0; i < numVertices; i++ ) { data.AddToEnd( vertices[i] ); } } ol::Poly:: ~Poly() {} void Poly:: Add( Vec2D vec ) { data.AddToEnd( vec ); } void ol::Poly:: ExecDrawOutline() const { data.LineStripRender( 0, 0, outlineTexture, lineWidth, placement, true ); } void ol::Poly:: SetVertex( int index, const Vec2D &newValue ) { if( index < 0 || index >= (int)data.GetVertices().size()) { OlError( "Invalid vertex index: " + VarToString( index ) + " ( Number of vertices: " + VarToString( (int)data.GetVertices().size()) + " )" ); } data.GetVertices()[index] = newValue; } void ol::Poly:: ExecDraw() const { const vector< Vec2D > &vertices = data.GetVertices(); glPushMatrix(); placement.Apply(); glBegin( GL_POLYGON ); for( std::vector< Vec2D > ::const_iterator iter = vertices.begin(); iter != vertices.end(); iter++ ) { glVertex2f( iter->x, iter->y ); } glEnd(); glPopMatrix(); } /* void ol::Poly:: MoveBy( const Vec2D &amount ) { for( std::vector< Vec2D > ::iterator iter = vertices.begin(); iter != vertices.end(); iter++ ) { *iter += amount; } } */ Collision ol::Poly:: DoCollisionTest( const ol::Poly &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults ) const { return LineStripCollision( data.GetVertices(), other.data.GetVertices(), thisPlacement, otherPlacement, getResults, true, true ); } Collision ol::Poly:: DoCollisionTest( const ol::LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults ) const { return LineStripCollision( data.GetVertices(), other.GetVertices(), thisPlacement, otherPlacement, getResults, true, false ); } Collision ol::Poly:: DoCollisionTest( const ol::Line &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults ) const { std::vector< Vec2D > otherVertices; otherVertices.reserve( 2 ); otherVertices.push_back( other.start ); otherVertices.push_back( other.end ); return LineStripCollision( data.GetVertices(), otherVertices, thisPlacement, otherPlacement, getResults, true, false ); } std::string ol::Poly:: ToString() const { const vector< Vec2D > &vertices = data.GetVertices(); std::ostringstream str; str << "Polygon: Placement: " << placement.ToString() << " Vertices:"; for( vector< Vec2D > ::const_iterator iter = vertices.begin(); iter != vertices.end(); iter++ ) { str << " ( " << iter->x << ", " << iter->y << " )"; } return str.str(); } /* Collision ol::Poly:: DoCollisionTest( const ol::Poly &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults ) const { if( vertices.size() < 2 || other.vertices.size() < 2 ) { OlError( "An empty Poly can't ever collide!" ); return Collision( false ); } Vec2D thisCo = thisPlacement.GetPosition(); Vec2D otherCo = otherPlacement.GetPosition(); Matrix2D thisTransform = thisPlacement.Get2DMatrix(); Matrix2D otherTransform = otherPlacement.Get2DMatrix(); std::vector< Vec2D > ::const_iterator thisIter = vertices.begin(); Vec2D thisPrev = thisTransform.Transform( *thisIter - rotationPivot ) + thisCo + rotationPivot; thisIter++; // Loop through each vertex // while( true ) { bool breakNow = false; // Test if we've reached the last line segment // if( thisIter == vertices.end() ) { breakNow = true; thisIter = vertices.begin(); } Vec2D thisVertex = thisTransform.Transform( *thisIter - rotationPivot ) + thisCo + rotationPivot; thisIter++; std::vector< Vec2D > ::const_iterator otherIter = other.vertices.begin(); Vec2D otherPrev = otherTransform.Transform( *otherIter - other.rotationPivot ) + otherCo + other.rotationPivot; otherIter++; // Loop through each vertex of the other polygon // while( true ) { bool breakNow = false; // Test if we've reached the last line segment of the other polygon // if( otherIter == other.vertices.end() ) { breakNow = true; otherIter = other.vertices.begin(); } Vec2D otherVertex = otherTransform.Transform( *otherIter - other.rotationPivot ) + otherCo + other.rotationPivot; otherIter++; // Test for collision // if( IsCounterClockwise( thisPrev, thisVertex, otherPrev ) != IsCounterClockwise( thisPrev, thisVertex, otherVertex ) && IsCounterClockwise( otherPrev, otherVertex, thisPrev ) != IsCounterClockwise( otherPrev, otherVertex, thisVertex )) { if( !getResults ) { return Collision( true ); } else { Line thisLine( thisVertex, thisPrev ); Line otherLine( otherVertex, otherPrev ); return Collision( thisLine, otherLine ); } } // Is last line segment of the other polygon processed? // if( breakNow ) { break; } // Advance to the next vertex of the other polygon // otherPrev = otherVertex; } // Is last line segment processed? // if( breakNow ) { break; } // Advance to the next vertex // thisPrev = thisVertex; } return Collision( false ); } */ openlayer-2.1.orig/src/Animation.cpp0000644000175000017500000000124710556123320017722 0ustar georgeskgeorgesk#include "Animation.hpp" using namespace std; using namespace ol; bool Animation:: Load( string filenameBegin, string extension, int numNumbers ) { frames = Bitmap::LoadListOfBitmaps( filenameBegin, extension, numNumbers ); if( frames.empty() ) { throw( "No animation frames loaded" ); return false; } return true; } bool Animation:: Update( float deltaTime ) { currentFrame += deltaTime * framesPerTick; if( currentFrame >= frames.size() ) { currentFrame -= frames.size(); return true; } return false; } const Bitmap &Animation:: GetFrame() { return *(frames[int( currentFrame )]); } openlayer-2.1.orig/src/Glyph.cpp0000644000175000017500000003153510575626474017114 0ustar georgeskgeorgesk#ifndef OL_GLYPH_CPP #define OL_GLYPH_CPP #include "Glyph.hpp" #include "GfxRend.hpp" namespace ol { // Static count of instances of fonts to track library static int instances=0; #ifdef USE_NEW_TTF static FT_Library ftLibrary = NULL; #endif // Character ctor character::character() { } character::~character() { //if(line)delete [] line; } // Constructor Glyph::Glyph() { //Load library #ifdef USE_NEW_TTF if(ftLibrary==NULL) { FT_Init_FreeType(&ftLibrary); } #endif instances++; ID = instances; faceLoaded = kerning = false; currentIndex=0; currentFilename=""; faceName=""; currentChar = new character; workBitmap=NULL; color = Rgba::WHITE; #ifdef USE_NEW_TTF hintingFlag = FT_LOAD_FORCE_AUTOHINT; renderFlag = FT_LOAD_TARGET_NORMAL; #endif } // Destructor /*! Nothing yet */ Glyph::~Glyph() { #ifdef USE_NEW_TTF FT_Done_Face(face); #endif if(instances>0)instances--; if(instances==0) { #ifdef USE_NEW_TTF FT_Done_FreeType(ftLibrary); #endif } if(currentChar)delete currentChar; } // Comparison of IDs bool Glyph::operator==(Glyph *f) { if(ID==f->ID)return true; return false; } // Extract glyph character Glyph::extractGlyph(signed long unicode) { #ifdef USE_NEW_TTF int w, h, ew; character tempChar; // Enable below whenever able to get angles to work properly //FT_Matrix a, matrix; FT_Matrix matrix; matrix.xx = 0x10000; matrix.xy = (FT_Fixed)(sin(size.italics)*(GLYPH_SQRT2*0x10000)); matrix.yx = 0; matrix.yy = 0x10000; /*a.xx = (FT_Fixed)( cos(0)*0x10000); a.xy = (FT_Fixed)(-sin(0)*0x10000); a.yx = (FT_Fixed)( sin(0)*0x10000); a.yy = (FT_Fixed)( cos(0)*0x10000); FT_Matrix_Multiply(&a,&matrix);*/ if(size.italics!=0)FT_Set_Transform( face, &matrix, 0 ); FT_Load_Char(face, unicode, renderFlag | FT_LOAD_RENDER | hintingFlag); w = face->glyph->bitmap.width; h = face->glyph->bitmap.rows; ew = 0; if (!w)ew = 1; if (!h)h = 1; tempChar.width = (w + ew); tempChar.height = h; tempChar.rows = face->glyph->bitmap.rows; tempChar.grays = face->glyph->bitmap.num_grays; tempChar.pitch = face->glyph->bitmap.pitch; tempChar.line = new unsigned char[tempChar.rows * tempChar.pitch]; memcpy(tempChar.line,face->glyph->bitmap.buffer,tempChar.rows * tempChar.pitch); tempChar.left = face->glyph->bitmap_left; tempChar.top = face->glyph->bitmap_top; tempChar.right = face->glyph->advance.x >> 6; tempChar.unicode = unicode; tempChar.length = ( (w + ew)+face->glyph->advance.x ) >> 6; return tempChar; #else return character(); #endif } // Create single index void Glyph::createIndex() { #ifdef USE_NEW_TTF std::map >::iterator p; p = fontTable.find(size); if(p==fontTable.end()) { FT_Set_Pixel_Sizes(face, size.width, size.height); FT_UInt g; FT_ULong unicode = FT_Get_First_Char(face, &g); std::maptempMap; while (g) { tempMap.insert(std::make_pair(unicode,extractGlyph(unicode))); unicode = FT_Get_Next_Char(face, unicode, &g); } fontTable.insert(std::make_pair(size,tempMap)); } #endif } // Render a character from the lookup table (utilizing the workBitmap) void Glyph::drawCharacter(signed long unicode, double &x1, double &y1, Bitmap *bitmap, const Rgba & col) { #ifdef USE_NEW_TTF std::map >::const_iterator ft = fontTable.find(size); if(ft!=fontTable.end()) { std::map::const_iterator p = (ft->second).find(unicode); if(p!=(ft->second).end()) { const character *tempChar = &p->second; unsigned char *line = tempChar->line; for (int y = (int)y1; y < (int)(y1)+tempChar->rows; y++) { unsigned char *buffer = line; for (int x = (int)x1; x < (int)(x1)+tempChar->width; x++) { Rgba checkCol = colorConvert(buffer++,tempChar->grays); if(checkCol.r==0 && checkCol.g==0 && checkCol.b==0 && checkCol.a==0) continue; const double intensity = ( checkCol.r * 0.30 + checkCol.g * 0.59 + checkCol.b * 0.11); checkCol.r = col.r * intensity; checkCol.g = col.g * intensity; checkCol.b = col.b * intensity; checkCol.a = col.a * intensity; ol::Point(float(x + tempChar->left),float(y - tempChar->top)).Draw( checkCol ); } line += tempChar->pitch; } x1+=tempChar->right; } } #endif } // Load font from memory bool Glyph::loadFromMemory(const unsigned char *memoryFont, unsigned int length, int index, unsigned int width, unsigned int height) { #ifdef USE_NEW_TTF if(!FT_New_Memory_Face(ftLibrary,memoryFont, length,index,&face)) { currentFilename = "memoryFont"; currentIndex = index; faceLoaded = true; setSize(width, height); if(FT_HAS_GLYPH_NAMES(face)) { char buff[1024]; if(!FT_Get_Glyph_Name(face,currentIndex,buff,sizeof(buff))) { faceName = currentFilename; } else faceName = std::string(buff); } else { faceName = currentFilename; } if(FT_HAS_KERNING(face))kerning=true; else kerning = false; } else { faceLoaded=false; std::cout << "Load system font failed\n"; } return faceLoaded; #else return false; #endif } // Load font from file bool Glyph::load(const std::string & filename, int index, unsigned int width, unsigned int height) { #ifdef USE_NEW_TTF if(!FT_New_Face(ftLibrary,filename.c_str(),index,&face)) { currentFilename = filename; currentIndex = index; faceLoaded = true; setSize(width, height); if(FT_HAS_GLYPH_NAMES(face)) { char buff[1024]; if(!FT_Get_Glyph_Name(face,currentIndex,buff,sizeof(buff))) { faceName = currentFilename; } else faceName = std::string(buff); } else { faceName = currentFilename; } if(FT_HAS_KERNING(face))kerning=true; else kerning = false; } else { faceLoaded=false; } return faceLoaded; #else return false; #endif } void Glyph::render(double x, double y, const Rgba& col, Bitmap *bmp, int alignment, const char* text, ...) { #ifdef USE_NEW_TTF if(faceLoaded) { double rend_x=0; double rend_y=0; std::ostringstream str; // Get extra arguments va_list ap; va_start(ap, text); const size_t text_length = strlen(text); for(size_t i = 0; i> 6; previous = next; } drawCharacter(text[i],rend_x, rend_y, bmp, col); } // Set previous pointsize glPointSize(psGrab); // Restore last mode ol::Settings::RestoreOldProjection(); // Restore transform ol::Transforms::PopPlacement(); } #endif } // Get text length double Glyph::getLength(const char* text) { double length=0; std::map >::iterator ft; ft = fontTable.find(size); if(ft!=fontTable.end()) { const size_t text_length = strlen(text); for(unsigned int i = 0; i::iterator p; p = (ft->second).find(text[i]); if(p!=(ft->second).end()) { if(p!=fontTable[size].end()) { length+=(p->second).length; } } } } return length; } // Set size void Glyph::setSize(int w, int h) { size.width=w; size.height=h; createIndex(); } // Set italics void Glyph::setItalics(int i) { if(i < -45)i=-45; else if(i > 45)i=45; size.italics = (double)(i)*GLYPH_PI/180; createIndex(); } // Set FreeType LoadFlags void Glyph::setHinting(bool on) { #ifdef USE_NEW_TTF if(on) { hintingFlag = FT_LOAD_FORCE_AUTOHINT; } else { hintingFlag = FT_LOAD_NO_HINTING; } #endif fontTable.clear(); setSize(size.width, size.height); } // Set FreeType LoadFlags void Glyph::setAntialias(bool on) { #ifdef USE_NEW_TTF if(on) { renderFlag = FT_LOAD_TARGET_NORMAL; } else { renderFlag = FT_LOAD_TARGET_MONO; } #endif fontTable.clear(); setSize(size.width, size.height); } // Get Width int Glyph::getWidth() { return size.width; } // Get Height int Glyph::getHeight() { return size.height; } // Get total height int Glyph::getTotalHeight() { #ifdef USE_NEW_TTF return size.height * (face->height)/(double)(face->units_per_EM); #else return size.height; #endif } // Get Italics int Glyph::getItalics() { return (int)size.italics; } /* * These items are so that we can maintain compatibility with Glyph Keeper * until TextRender adopts the new system and replaces references to * GlyphKeeper in the future. */ GLYPH_FACE::GLYPH_FACE() { // Nothing to do } GLYPH_FACE::~GLYPH_FACE() { // Nothing to do if(glyphFace)delete glyphFace; } GLYPH_FACE *gk_load_face_from_file(const char *filename, int index) { GLYPH_FACE *temp = new GLYPH_FACE(); temp->glyphFace = new Glyph(); if(!temp->glyphFace->load(filename,index))return 0; return temp; } GLYPH_REND::GLYPH_REND() { // Nothing to do } GLYPH_REND::~GLYPH_REND() { // Nothing to do } GLYPH_REND *gk_create_renderer( GLYPH_FACE* const face, int index ) { GLYPH_REND *temp = new GLYPH_REND(); temp->glyphFace = face->glyphFace; return temp; } void gk_rend_set_italic( GLYPH_REND* const rend, int italics ) { rend->glyphFace->setItalics(italics); } void gk_rend_set_size_pixels( GLYPH_REND* const rend, const unsigned int width, const unsigned int height) { rend->glyphFace->setSize(width, height); } void gk_rend_set_hinting_default( GLYPH_REND* const rend ) { rend->glyphFace->setHinting(true); } void gk_rend_set_hinting_off( GLYPH_REND* const rend ) { rend->glyphFace->setHinting(false); } void rend_set_render_mode_normal( GLYPH_REND* const rend ) { rend->glyphFace->setAntialias(true); } void gk_rend_set_text_alpha_color( GLYPH_REND* const rend, const unsigned alpha_color) { rend->glyphFace->color = colorConvert(alpha_color); } int gk_rend_ascender_pixels( GLYPH_REND* const rend ) { return rend->glyphFace->getHeight(); } int gk_rend_height_pixels( GLYPH_REND* const rend ) { return rend->glyphFace->getTotalHeight(); } int gk_text_width_utf8(GLYPH_REND* const rend,const char* const text) { return (int)rend->glyphFace->getLength(text); } GLYPH_TEXTURE::GLYPH_TEXTURE() { // Nothing to do } GLYPH_TEXTURE::~GLYPH_TEXTURE() { // Nothing to do } GLYPH_TEXTURE *gk_create_texture( GLYPH_REND *rend, int rangeStart, int rangeLength ) { GLYPH_TEXTURE *temp = new GLYPH_TEXTURE(); temp->glyphFace = rend->glyphFace; return temp; } void gk_unload_texture_from_gpu( GLYPH_TEXTURE *texture ) { // Nothing } void gk_destroy_texture( GLYPH_TEXTURE *texture ) { // De-Init the texture ? nothing yet } void gk_render_line_gl_utf8( GLYPH_TEXTURE *texture, const char *text, int x, int y ) { texture->glyphFace->renderFixed(x,y,texture->glyphFace->color,NULL,0,text); } void gk_send_texture_to_gpu( GLYPH_TEXTURE *texture ) { // Nothing to be done } } #endif /* OL_GLYPH_CPP */ openlayer-2.1.orig/src/Setup.cpp0000644000175000017500000000635310531214024017101 0ustar georgeskgeorgesk#include "Setup.hpp" #include "Includes.hpp" #include "Settings.hpp" #include "Blenders.hpp" #include "Transforms.hpp" #include "GarbageCollector.hpp" #include "General.hpp" #include "Internal.hpp" #include "GlDriver.hpp" #include "Rgba.hpp" #include "Canvas.hpp" #ifndef OL_NO_PNG #include #endif // OL_NO_PNG using namespace ol; // STATIC CLASS VARIABLES // bool Setup::programIsSetUp = false; bool Setup::screenIsSetUp = false; std::string Setup::executablePath = ""; int Setup::windowWidth = 0; int Setup::windowHeight = 0; int Setup::colorDepth = 0; // GENERAL FUNCTIONS // void OlCollectTheGarbage(); bool Setup:: SetupProgram( int devices ) { return SetupProgram( devices & KEYBOARD, devices & MOUSE, devices & TIMER ); } bool Setup:: SetupProgram( bool setupKeyboard, bool setupMouse, bool setupTimer ) { GlDriver::Get()->SetupProgram( setupKeyboard, setupMouse, setupTimer ); atexit( OlCollectTheGarbage ); executablePath = GlDriver::Get()->GetExecutablePath(); programIsSetUp = true; #ifndef OL_NO_PNG register_png_file_type(); #endif OlLog( "OpenLayer started up succesfully" ); return true; } GarbageCollection &OlGetCollection(); bool Setup:: SetupScreen( int w, int h, bool fullscreen, int colorDepth, int zDepth, int refreshRate ) { GlDriver::Get()->SetupScreen( w, h, fullscreen, colorDepth, zDepth, refreshRate ); Setup::windowWidth = w; Setup::windowHeight = h; Setup::colorDepth = colorDepth; screenIsSetUp = true; Settings::SetOrthographicProjection(); Blenders::Set( ALPHA_BLENDER ); Transforms::SetRotationPivot( SCREEN_W/2, SCREEN_H/2 ); Transforms::SetColorChannels( Rgba::WHITE ); Settings::SetAntialiasing( true ); Canvas::ReadBufferSizes(); Canvas::SetTo( SCREEN_BACKBUF ); Canvas::Fill( Rgba( 0.0, 0.0, 0.0, 1.0 ), ALPHA_ONLY ); Canvas::Refresh(); Canvas::Fill( Rgba( 0.0, 0.0, 0.0, 1.0 ), ALPHA_ONLY ); OlGetCollection().ExecuteQueues(); OlLog( "Screen set up succesfully\n" ); return true; } bool Setup:: IsScreenSetUp() { return screenIsSetUp; } bool Setup:: IsProgramSetUp() { return programIsSetUp; } std::string Setup:: ToAbsolutePathname( std::string pathname ) { return GlDriver::Get()->ToAbsolutePathname( pathname ); } void Setup:: SuspendProgram() { OlGetCollection().UnloadAllToMemory(); } void Setup:: WakeUpProgram() { OlGetCollection().LoadAllToGPU(); } const char *Setup:: GetGLError() { GLenum error = glGetError(); if( error == GL_NO_ERROR ) return 0; if( error == GL_INVALID_ENUM ) return "GL_INVALID_ENUM"; if( error == GL_INVALID_VALUE ) return "GL_INVALID_VALUE"; if( error == GL_INVALID_OPERATION ) return "GL_INVALID_OPERATION"; if( error == GL_STACK_OVERFLOW ) return "GL_STACK_OVERFLOW"; if( error == GL_STACK_UNDERFLOW ) return "GL_STACK_UNDERFLOW"; if( error == GL_OUT_OF_MEMORY ) return "GL_OUT_OF_MEMORY"; OlLog( "Unknown OpenGL error code" ); OlLog( ToString( error )); return "OTHER"; } openlayer-2.1.orig/src/Internal.cpp0000644000175000017500000000014610531575202017557 0ustar georgeskgeorgesk#include "Internal.hpp" #include "Internal.hpp" namespace ol { bool firstLog = true; } openlayer-2.1.orig/src/Collisions.cpp0000644000175000017500000000654010426666656020146 0ustar georgeskgeorgesk#include "Collisions.hpp" #include "Line.hpp" #include "Internal.hpp" #include using namespace ol; const Line Collision::DEFAULT_SEGMENT( Vec2D( 0, 0 ), Vec2D( 0, 0 )); const Vec2D Collision::DEFAULT_NORMAL( 0, 0 ); Collision:: Collision( const Line &aSegment, const Line &bSegment ) : isCollision( true ) { segmentLists.push_back( new std::pair< Line, Line >( aSegment, bSegment )); normals[(int) OBJ_A] = 0; normals[(int) OBJ_B] = 0; points.push_back( aSegment.GetIntersectionPoint( bSegment )); } Collision:: Collision( const std::vector< std::pair< Line, Line > *> &segmentLists ) : isCollision( true ), segmentLists( segmentLists ) { normals[(int) OBJ_A] = 0; normals[(int) OBJ_B] = 0; for( std::vector< std::pair< Line, Line > *> ::const_iterator iter = segmentLists.begin(); iter != segmentLists.end(); iter++ ) { points.push_back((*iter)->first.GetIntersectionPoint((*iter)->second )); } } Collision:: Collision( const Collision& c ) { operator =( c ); } Line Collision:: CreateVirtualSegment( const Vec2D &normal ) { Vec2D s = Vec2D( -normal.y, normal.x ) * 0.5; return Line( GetPoint() - s, GetPoint() + s ); } const Line Collision:: GetSegment( CollidingObject objectID ) { if( !segmentLists.empty()) { switch( objectID ) { case OBJ_A: return segmentLists[0]->first; break; case OBJ_B: return segmentLists[0]->second; break; default: OlError(std::string( "Unknown objectID in GetSegment: " ) + ToString((int) objectID )); } } else { const Vec2D *normal = normals[(int) objectID]; if( !normal ) { OlError( "Can't create a virtual collision segment without a normal!" ); return DEFAULT_SEGMENT; } Vec2D s = Vec2D( -normal->y, normal->x ) * 0.5; return Line( GetPoint() - s, GetPoint() + s ); } return DEFAULT_SEGMENT; } Vec2D Collision:: GetNormal( CollidingObject objectID ) { Vec2D *normal = normals[(int) objectID]; if( !normal ) { if( !segmentLists.empty()) { const Line &segment = GetSegment( objectID ); normal = new Vec2D( segment.GetNormal() ); normals[(int) objectID] = normal; } else { OlError( "Can't create a collision normal without a segment!" ); return DEFAULT_NORMAL; } } return *normal; } Collision:: ~Collision() { for( int i = 0; i < (int) NUM_OBJS; i++ ) { if( normals[i] ) { delete normals[i]; } } for( std::vector< std::pair< Line, Line > *> ::const_iterator iter = segmentLists.begin(); iter != segmentLists.end(); iter++ ) { delete *iter; } } Collision& Collision:: operator =( const Collision& c ) { isCollision = c.isCollision; for( std::vector< Vec2D > ::const_iterator iter = c.points.begin(); iter != c.points.end(); iter++ ) { points.push_back( *iter ); } for( std::vector< std::pair< Line, Line > *> ::const_iterator iter = c.segmentLists.begin(); iter != c.segmentLists.end(); iter++ ) { segmentLists.push_back( new std::pair< Line, Line > (*(*iter))); } normals[(int)OBJ_A] = ( c.normals[(int)OBJ_A] )? new Vec2D( *c.normals[(int)OBJ_A] ) : 0; normals[(int)OBJ_B] = ( c.normals[(int)OBJ_B] )? new Vec2D( *c.normals[(int)OBJ_B] ) : 0; return *this; } openlayer-2.1.orig/src/General.cpp0000644000175000017500000000031410377212142017354 0ustar georgeskgeorgesk#include "General.hpp" using namespace ol; namespace ol { int ToNextPowOfTwo( int num ) { int pow2 = 1; while( pow2 < num ) pow2 <<= 1; return pow2; } } openlayer-2.1.orig/src/Bitmap.cpp0000644000175000017500000010755710570160412017231 0ustar georgeskgeorgesk#include "Bitmap.hpp" #include "Transforms.hpp" #include "Settings.hpp" #include "Setup.hpp" #include "Internal.hpp" #include "GlDriver.hpp" #include "General.hpp" #include "Canvas.hpp" #include "Rectangle.hpp" #include "Framebuffer.hpp" #include "Polygon.hpp" #include #include #include using namespace ol; using namespace std; static const int OL_BYTES_PER_TEXTURE_PIXEL = 4; static const float MAX_POLY_SKIP_PER_AREA = 0.0015; // HELPER FUNCTIONS // static inline void SelectBlittingColor( float fact ) { #ifdef NO_COLOR_CHANNELS glColor4f( 1.0, 1.0, 1.0, fact ); #else // NO_COLOR_CHANNELS Rgba channels = Transforms::GetColorChannels(); glColor4f( channels.r, channels.g, channels.b, channels.a * fact ); #endif // NO_COLOR_CHANNELS } static inline void SelectBlittingColor( const Rgba &col, float fact ) { #ifdef NO_COLOR_CHANNELS glColor4f( col.r, col.g, col.b, col.a * fact ); #else // NO_COLOR_CHANNELS Rgba channels = Transforms::GetColorChannels(); glColor4f( channels.r * col.r, channels.g * col.g, channels.b * col.b, channels.a * col.a * fact ); #endif // NO_COLOR_CHANNELS } // GENERAL FUNCTIONS // Bitmap:: Bitmap( int w, int h ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( NULL ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { collisionPoly = 0; AddToCollection(); OlLog( string( "Creating an empty Bitmap, width: " ) + ToString( w ) + " height: " + ToString( h ) ); int textureWidth = ToNextPowOfTwo(w); int textureHeight = ToNextPowOfTwo(h); float *data = new float[4 * textureWidth * textureHeight]; Load( w, h, textureWidth, textureHeight, data ); delete[] data; } Bitmap:: Bitmap( int w, int h, Rgba fillColor ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( NULL ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { collisionPoly = 0; AddToCollection(); OlLog( string( "Creating an empty Bitmap, width: " ) + ToString( w ) + " height: " + ToString( h ) + " Color: ( " + ToString( fillColor.r ) + ", " + ToString( fillColor.g ) + ", " + ToString( fillColor.b ) + " )" ); int textureWidth = ToNextPowOfTwo(w); int textureHeight = ToNextPowOfTwo(h); int dataSize = 4 * textureWidth * textureHeight; GLfloat *data = new GLfloat[dataSize]; GLfloat *dataEnd = data + dataSize; for( GLfloat *iter = data; iter != dataEnd; ) { *(iter++) = fillColor.r; *(iter++) = fillColor.g; *(iter++) = fillColor.b; *(iter++) = fillColor.a; } Load( w, h, textureWidth, textureHeight, data ); delete[] data; } Bitmap:: Bitmap( const Bitmap &other, float x, float y, float width, float height ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( false ), pendingLoad( NULL ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( true ) { collisionPoly = 0; AddToCollection(); textureInfo = other.textureInfo; /*printf( "TexInfo1 rect: %f %f %f %f\n", textureInfo.rect.x, textureInfo.rect.y, textureInfo.rect.w, textureInfo.rect.h ); printf( "TexInfo1 dims: %d %d %d %d\n", textureInfo.texWidth, textureInfo.texHeight, textureInfo.imgWidth, textureInfo.imgHeight );*/ textureInfo = OlTextureInfo( other.textureInfo, OlRect( x, y, width, height )); /*printf( "TexInfo2 rect: %f %f %f %f\n", textureInfo.rect.x, textureInfo.rect.y, textureInfo.rect.w, textureInfo.rect.h ); printf( "TexInfo2 dims: %d %d %d %d\n", textureInfo.texWidth, textureInfo.texHeight, textureInfo.imgWidth, textureInfo.imgHeight );*/ } Bitmap:: Bitmap( const Bitmap &other, const Rect &area ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( false ), pendingLoad( NULL ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( true ) { collisionPoly = 0; AddToCollection(); textureInfo = other.textureInfo; textureInfo = OlTextureInfo( other.textureInfo, OlRect( area.pos.x, area.pos.y, area.size.x, area.size.y )); } void Bitmap:: Load( int w, int h, int textureWidth, int textureHeight, GLfloat *data, GLenum format ) { OlAssert( w > 0 && h > 0 && textureWidth > 0 && textureHeight > 0 && data ); OlTextureInfo info( textureWidth, textureHeight, w, h, format ); textureInfo = GlDriver::Get()->UploadTexture( data, info ); Select(); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); if( Settings::useAntiAlias ) { glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); } else { glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); } } void Bitmap:: CopyFromCanvas( int x, int y ) { int w = Width(); int h = Height(); if( x < 0 ) { w += x; x = 0; } if( y < 0 ) { h += y; y = 0; } if( x + w > Canvas::Width() ) { w = Canvas::Width() - x; } if( y + h > Canvas::Height() ) { h = Canvas::Height() - y; } Select(); glFlush(); glFinish(); FrameBuffer::GetInstance().CopyTexSubImage( x, y, w, h, textureInfo.texHeight - Height() ); } enum { TOPLEFT_COL_INDEX = 0, TOPRIGHT_COL_INDEX = 1, BOTTOMRIGHT_COL_INDEX = 2, BOTTOMLEFT_COL_INDEX = 3 }; void Bitmap:: TexturedQuad( float w, float h, float fact, const RenderMode &mode ) const { GetReadyToRender( fact ); OlRect renderArea = mode.GetRenderRect( OlRect( 0.0, 0.0, Width(), Height() )); renderArea.w *= w/Width(); renderArea.h *= h/Height(); OlTexCoords texCoordArea = mode.GetTexCoords( OlTexCoords( textureInfo )); texCoordArea.CalculateTextureCoords(); bool setsTexCoords = mode.SetsTexCoords(); glBegin( GL_QUADS ); if( texCoordArea.ChangesColors()) SelectBlittingColor( texCoordArea.GetColor(BOTTOMLEFT_COL_INDEX), fact ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_BOTTOMLEFT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_BOTTOMLEFT, renderArea, texCoordArea, w, h ); glVertex2f( renderArea.x, renderArea.y + renderArea.h ); if( texCoordArea.ChangesColors()) SelectBlittingColor( texCoordArea.GetColor(BOTTOMRIGHT_COL_INDEX), fact ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_BOTTOMRIGHT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_BOTTOMRIGHT, renderArea, texCoordArea, w, h ); glVertex2f( renderArea.x + renderArea.w, renderArea.y + renderArea.h ); if( texCoordArea.ChangesColors()) SelectBlittingColor( texCoordArea.GetColor(TOPRIGHT_COL_INDEX), fact ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_TOPRIGHT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_TOPRIGHT, renderArea, texCoordArea, w, h ); glVertex2f( renderArea.x + renderArea.w, renderArea.y ); if( texCoordArea.ChangesColors()) SelectBlittingColor( texCoordArea.GetColor(TOPLEFT_COL_INDEX), fact ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_TOPLEFT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_TOPLEFT, renderArea, texCoordArea, w, h ); glVertex2f( renderArea.x, renderArea.y ); glEnd(); } void Bitmap:: TexturedQuad( float w, float h, float fact ) const { GetReadyToRender( fact ); textureInfo.OutputTexturedQuad( w, h ); if( !Settings::TextureMappingUsed() ) glDisable( GL_TEXTURE_2D ); } void Bitmap:: StartFastBlitting( float fact ) { SelectBlittingColor( fact ); glEnable( GL_TEXTURE_2D ); //OlTextureInfo::StartRendering(); } void Bitmap:: FinishFastBlitting() { //OlTextureInfo::FinishRendering(); if( !Settings::TextureMappingUsed() ) glDisable( GL_TEXTURE_2D ); } void Bitmap:: Blit( float x, float y, const RenderMode &mode, float fact ) const { mode.Select(); glPushMatrix(); glTranslatef( x, y, 0.0 ); TexturedQuad( textureInfo.imgWidth, textureInfo.imgHeight, fact, mode ); glPopMatrix(); mode.Unselect(); if( !Settings::TextureMappingUsed() ) glDisable( GL_TEXTURE_2D ); } void Bitmap:: BlitRotated( float x, float y, float angle, const RenderMode &mode, float fact ) const { BlitRotated( x, y, pivot.x, pivot.y, angle, mode, fact ); } void Bitmap:: BlitRotated( float x, float y, float pivotX, float pivotY, float angle, const RenderMode &mode, float fact ) const { mode.Select(); glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); glTranslatef( -pivotX, -pivotY, 0.0 ); TexturedQuad( textureInfo.imgWidth, textureInfo.imgHeight, fact, mode ); glPopMatrix(); mode.Unselect(); if( !Settings::TextureMappingUsed() ) glDisable( GL_TEXTURE_2D ); } void Bitmap:: BlitStretched( float x, float y, float w, float h, const RenderMode &mode, float fact ) const { mode.Select(); glPushMatrix(); glTranslatef( x, y, 0.0 ); TexturedQuad( w, h, fact, mode ); glPopMatrix(); mode.Unselect(); if( !Settings::TextureMappingUsed() ) glDisable( GL_TEXTURE_2D ); } void Bitmap:: BlitTransformed( float x, float y, float w, float h, float angle, const RenderMode &mode, float fact ) const { BlitTransformed( x, y, w, h, pivot.x, pivot.y, angle, mode, fact ); } void Bitmap:: BlitTransformed( float x, float y, float w, float h, float pivotX, float pivotY, float angle, const RenderMode &mode, float fact ) const { mode.Select(); glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); glTranslatef( -pivotX * w / textureInfo.imgWidth, -pivotY * h / textureInfo.imgHeight, 0.0 ); TexturedQuad( w, h, fact, mode ); glPopMatrix(); mode.Unselect(); if( !Settings::TextureMappingUsed() ) glDisable( GL_TEXTURE_2D ); } void Bitmap:: BlitDistorted( float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const RenderMode &mode, float fact ) const { mode.Select(); GetReadyToRender( fact ); OlRect renderArea = mode.GetRenderRect( OlRect( 0.0, 0.0, textureInfo.imgWidth, textureInfo.imgHeight )); OlTexCoords texCoordArea = mode.GetTexCoords( OlTexCoords( textureInfo )); texCoordArea.CalculateTextureCoords(); bool setsTexCoords = mode.SetsTexCoords(); float w = textureInfo.imgWidth; float h = textureInfo.imgHeight; glBegin( GL_QUADS ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_BOTTOMLEFT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_BOTTOMLEFT, renderArea, texCoordArea, w, h ); glVertex2f( x4, y4 ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_BOTTOMRIGHT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_BOTTOMRIGHT, renderArea, texCoordArea, w, h ); glVertex2f( x3, y3 ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_TOPRIGHT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_TOPRIGHT, renderArea, texCoordArea, w, h ); glVertex2f( x2, y2 ); if( setsTexCoords ) mode.SetTexCoord( OL_TC_TOPLEFT, renderArea, texCoordArea, w, h ); else RenderMode::PrimarySetTexCoord( OL_TC_TOPLEFT, renderArea, texCoordArea, w, h ); glVertex2f( x1, y1 ); glEnd(); mode.Unselect(); if( !Settings::TextureMappingUsed() ) glDisable( GL_TEXTURE_2D ); } void Bitmap:: GetReadyToRender( float fact ) const { SelectBlittingColor( fact ); glEnable( GL_TEXTURE_2D ); Select(); } void Bitmap:: Blit( float x, float y, float fact ) const { glPushMatrix(); glTranslatef( x, y, 0.0 ); TexturedQuad( textureInfo.imgWidth, textureInfo.imgHeight, fact ); glPopMatrix(); } void Bitmap:: SetDefaultPivot( Vec2D point ) { pivot = point; useDefaultPivot = false; } void Bitmap:: BlitRotated( float x, float y, float angle, float fact ) const { BlitRotated( x, y, pivot.x, pivot.y, angle, fact ); } void Bitmap:: BlitRotated( float x, float y, float pivotX, float pivotY, float angle, float fact ) const { glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); glTranslatef( -pivotX, -pivotY, 0.0 ); TexturedQuad( textureInfo.imgWidth, textureInfo.imgHeight, fact ); glPopMatrix(); } void Bitmap:: BlitStretched( float x, float y, float w, float h, float fact ) const { glPushMatrix(); glTranslatef( x, y, 0.0 ); TexturedQuad( w, h, fact ); glPopMatrix(); } void Bitmap:: BlitTransformed( float x, float y, float w, float h, float angle, float fact ) const { BlitTransformed( x, y, w, h, pivot.x, pivot.y, angle, fact ); } void Bitmap:: BlitTransformed( float x, float y, float w, float h, float pivotX, float pivotY, float angle, float fact ) const { glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); glTranslatef( -pivotX * w / textureInfo.imgWidth, -pivotY * h / textureInfo.imgHeight, 0.0 ); TexturedQuad( w, h, fact ); glPopMatrix(); } void Bitmap:: BlitDistorted( float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float fact ) const { GetReadyToRender( fact ); textureInfo.OutputTexturedQuad( Vec2D( x1, y1 ), Vec2D( x2, y2 ), Vec2D( x3, y3 ), Vec2D( x4, y4 )); } GarbageCollection &OlGetCollection(); void Bitmap:: Destroy( bool eraseFromCollection ) { UnloadFromGPU(); if( bmp && destroyBmp ) { destroy_bitmap( bmp ); bmp = 0; } if( collisionPoly ) { delete collisionPoly; collisionPoly = 0; } if( pendingLoad ) { delete pendingLoad; pendingLoad = 0; } if( eraseFromCollection ) { OlGetCollection().Remove( this ); } } void Bitmap:: UnloadFromGPU() { if( textureInfo.index != 0 && !isSubBitmap ) { glDeleteTextures( 1, &textureInfo.index ); textureInfo.index = 0; } } bool Bitmap:: IsValid() const { return textureInfo.index != 0; } bool Bitmap:: HasAlphaChannel() const { return textureInfo.HasAlphaChannel(); } void Bitmap:: SelectDefaultPivot( int imageWidth, int imageHeight ) { if( useDefaultPivot ) { pivot.x = imageWidth/2; pivot.y = imageHeight/2; } } bool Bitmap:: Load( OL_MEMORY_IMG *bmp, int conversionMode, int extraFlags ) { collisionPoly = 0; return Load( bmp, conversionMode & HAS_ALPHA_CHANNEL, conversionMode & CONVERT_MAGIC_PINK, extraFlags ); } bool Bitmap:: Load( OL_MEMORY_IMG *toBmp, bool hasAlphaChannel, bool convertMagicPink, int extraFlags ) { collisionPoly = 0; Destroy(); ASSERT( toBmp ); isSolid = !hasAlphaChannel; int width = toBmp->w; int height = toBmp->h; OlLog( string("Loading bitmap from an Allegro OL_MEMORY_IMG (Alpha channel: ") + string( hasAlphaChannel? "Yes" : "No" ) + string(", Convert Magic Pink: ") + string( convertMagicPink? "Yes" : "No" ) + string(")")); if( convertMagicPink ) { isSolid = false; bool shouldBeConverted = bitmap_color_depth( toBmp ) != 32; OL_MEMORY_IMG *dst = shouldBeConverted? create_bitmap_ex( 32, width, height ) : toBmp; int maskColor = bitmap_mask_color( toBmp ); int colorDepth = get_color_depth(); set_color_depth( bitmap_color_depth( dst )); for( int y = 0; y < dst->h; y++ ) { for( int x = 0; x < dst->w; x++ ) { int color = getpixel( toBmp, x, y ); int alpha = hasAlphaChannel? geta32( color ) : 255; bool isTransparent = color == maskColor; if( isTransparent ) { int maxY = min(y+1, dst->h-1); int maxX = min(x+1, dst->w-1); int r = 0; int g = 0; int b = 0; int colorMixes = 0; for( int subY = max(y-1, 0); subY <= maxY; subY++ ) { for( int subX = max(x+1, 0); subX <= maxX; subX++ ) { int subColor = getpixel( toBmp, subX, subY ); if( subColor != maskColor ) { r += getr( subColor ); g += getg( subColor ); b += getb( subColor ); } } } if( colorMixes > 0 ) { r /= colorMixes; g /= colorMixes; b /= colorMixes; } color = makeacol32( r, g, b, 0 ); } else { color = makeacol32( getr( color ), getg( color ), getb( color ), alpha ); } ((unsigned int *) dst->line[y])[x] = color; } } set_color_depth( colorDepth ); if( !shouldBeConverted ) { destroyBmp = false; } bmp = dst; } else { bmp = toBmp; destroyBmp = false; } SelectDefaultPivot( bmp->w, bmp->h ); HandleExtraFlags( extraFlags ); SendToGPU(); return true; } static int olColorConversion = COLORCONV_16_TO_32 | COLORCONV_24_TO_32 | COLORCONV_15_TO_32 | COLORCONV_8_TO_32; bool Bitmap:: Load( const char *rgbFilename, const char *alphaFilename, int extraFlags ) { collisionPoly = 0; Destroy(); if( !Setup::IsScreenSetUp() ) { OlLog( string( "Loading queued for bitmap: " ) + rgbFilename + " with an alpha channel from: " + alphaFilename ); pendingLoad = new PendingFileAlphaLoad( rgbFilename, alphaFilename ); return true; } OlLog( string( "Loading bitmap: " ) + rgbFilename + " with an alpha channel from: " + alphaFilename ); set_color_conversion( olColorConversion ); OL_MEMORY_IMG *colordata = load_bitmap( Setup::ToAbsolutePathname( rgbFilename ).c_str(), 0 ); set_color_conversion( COLORCONV_MOST ); OL_MEMORY_IMG *alpha = load_bitmap( Setup::ToAbsolutePathname( alphaFilename ).c_str(), 0 ); if( !colordata ) { OlError( "No such bitmap!" ); return false; } if( !alpha ) { OlError( "No such alpha channel bitmap!" ); return false; } if( bitmap_color_depth( alpha ) != 8 ) { OlError( string( "Wrong color depth for an alpha bitmap: " ) + ToString( bitmap_color_depth( alpha )) + " (Should be 8)"); return false; } isSolid = false; bool useTemp = bitmap_color_depth( colordata ) != 32; bmp = useTemp? create_bitmap_ex( 32, colordata->w, colordata->h ) : colordata; for( int y = 0; y < bmp->h; y++ ) { for( int x = 0; x < bmp->w; x++ ) { int color = getpixel( colordata, x, y ); int a = alpha->line[y][x]; color = makeacol32( getr( color ), getg( color ), getb( color ), a ); ((unsigned int *) bmp->line[y])[x] = color; } } if( useTemp ) { destroy_bitmap( colordata ); } destroy_bitmap( alpha ); SelectDefaultPivot( bmp->w, bmp->h ); HandleExtraFlags( extraFlags ); SendToGPU(); return true; } bool Bitmap:: Load( const char *filename, int extraFlags ) { collisionPoly = 0; if( !Setup::IsScreenSetUp() ) { allegro_message(( string( "Loading queued for bitmap: " ) + filename + "\n" ).c_str()); pendingLoad = new PendingFileLoad( filename ); return true; } string absoluteFilename = Setup::ToAbsolutePathname( filename ); OlLog( string( "Loading bitmap: " ) + filename ); set_color_conversion( olColorConversion ); bmp = load_bitmap( absoluteFilename.c_str(), 0 ); if( !bmp ) { OlError( "No such bitmap!" ); return false; } int width = bmp->w; int height = bmp->h; isSolid = true; if( bitmap_color_depth( bmp ) == 32 ) { for( int y = 0; y < bmp->h; y++ ) { for( int x = 0; x < bmp->w; x++ ) { int color = ((unsigned int *) bmp->line[y])[x]; if( geta32( color ) != 0 ) { isSolid = false; break; } } if( !isSolid ) { break; } } } if( isSolid ) { bool useTemp = bitmap_color_depth( bmp ) != 32; OL_MEMORY_IMG *dst = useTemp? create_bitmap_ex( 32, width, height ) : bmp; for( int y = 0; y < dst->h; y++ ) { for( int x = 0; x < dst->w; x++ ) { int color = getpixel( bmp, x, y ); color = makeacol32( getr( color ), getg( color ), getb( color ), 255 ); ((unsigned int *) dst->line[y])[x] = color; } } if( useTemp ) { destroy_bitmap( bmp ); bmp = dst; } } SelectDefaultPivot( bmp->w, bmp->h ); HandleExtraFlags( extraFlags ); SendToGPU(); return true; } Poly *Bitmap:: GetCollisionPoly() const { return collisionPoly; } void Bitmap:: HandleExtraFlags( int flags ) { if( flags & CREATE_COLLISION_POLY ) { int numSkips = int((1.0 - Settings::GetCollisionPolyAccuracy()) * bmp->w * bmp->h * MAX_POLY_SKIP_PER_AREA); collisionPoly = Bitmap::GetCollisionPolygon( bmp, Settings::collisionPolyAlphaLimit, numSkips, pivot ); } } void Bitmap:: SendToGPU() { if( !bmp ) { OlError( "Cannot send the Bitmap to the graphics card without any memory bitmap content!" ); return; } UnloadFromGPU(); textureInfo = GlDriver::Get()->UploadTexture( bmp, isSolid ); Select(); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); if( Settings::useAntiAlias ) { glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); } else { glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); } if( destroyBmp && !Settings::MemoryBitmapsStored() ) { destroy_bitmap( bmp ); bmp = 0; } } vector< Bitmap *> Bitmap:: LoadListOfBitmaps( string filenameBegin, string extension, unsigned int numNumbers, int extraFlags ) { vector< Bitmap *> bitmapList; for( int index = 1;; index++ ) { stringstream stream; stream << index; string numbers = stream.str(); while( numbers.size() < numNumbers ) { numbers = string("0") + numbers; } string filename = filenameBegin + numbers + string(".") + extension; bool notFound = !exists( filename.c_str() ); if( notFound && index == 1 ) { if( index == 1 ) { OlError( "LoadListOfBitmaps: No image files found! ( First filename to try was: " + filename + " )" ); } break; } Bitmap *frame = new Bitmap; if( !frame->Load( filename.c_str(), extraFlags )) { delete frame; break; } bitmapList.push_back( frame ); } return bitmapList; } bool Bitmap:: Save( const char *filename ) { OL_MEMORY_IMG *image = GetMemoryBitmap(); bool result = GlDriver::Get()->SaveMemoryBitmap( image, Setup::ToAbsolutePathname( filename ).c_str() ); destroy_bitmap( image ); return result; } OL_MEMORY_IMG *Bitmap:: GetMemoryBitmap() const { return GetMemoryBitmap( 0, 0, Width(), Height() ); } OL_MEMORY_IMG *Bitmap:: GetMemoryBitmap( int x, int y, int width, int height ) const { if( x < 0 ) { width += x; x = 0; } if( y < 0 ) { height += y; y = 0; } if( x + width > Width() ) { width = Width() - x; } if( y + height > Height() ) { height = Height() - y; } unsigned int bpp = textureInfo.GetBytesPerPixel(); unsigned char *pixels = new unsigned char[width * height * bpp]; Canvas::Push(); Canvas::SetTo( *this ); FrameBuffer::GetInstance().ReadPixels( x, y, width, height, textureInfo.format, pixels ); Canvas::Pop(); OL_MEMORY_IMG *img = GlDriver::Get()->GetMemoryBitmap( width, height, bpp, pixels ); delete[] pixels; return img; } void Bitmap:: SaveIfSurface( std::string filename ) const { int width = Canvas::Width(); int height = Canvas::Height(); int bpp = Canvas::GetScreenshotBPP(); int format = Canvas::GetScreenshotFormat(); unsigned char *pixels = new unsigned char[width * height * bpp]; FrameBuffer::GetInstance().ReadPixels( 0, 0, width, height, format, pixels ); OL_MEMORY_IMG *image = GlDriver::Get()->GetMemoryBitmap( width, height, bpp, pixels ); delete[] pixels; GlDriver::Get()->SaveMemoryBitmap( image, Setup::ToAbsolutePathname( filename ).c_str() ); GlDriver::Get()->DestroyMemoryBitmap( image ); } // GARBAGE COLLECTION / AUTOLOADER ROUTINES // void Bitmap:: AddToCollection() { OlGetCollection().Add( this ); } bool Bitmap:: IsLoadingQueued() const { return pendingLoad != 0; } OlLoadResult Bitmap:: ExecuteQueuedCommands() { if( IsLoadingQueued() ) { OlLoadResult result = pendingLoad->ExecuteLoading( *this ); delete pendingLoad; pendingLoad = 0; return result; } return OL_LR_SUCCESS; } static inline int GetAlpha( int x, int y, OL_MEMORY_IMG *bitmap ) { return OlGetAlpha( bitmap, x, y ); } static inline bool TestAlpha( int x, int y, int moreThan, OL_MEMORY_IMG *bitmap ) { return GetAlpha( x, y, bitmap ) > moreThan; } /* static inline bool IsSurrounded( int x, int y, int moreThan, OL_MEMORY_IMG *bitmap ) { return TestAlpha( x-1, y ) && TestAlpha( x+1, y ) && TestAlpha( x, y-1 ) && TestAlpha( x, y+1 ); } static inline bool IsSurroundedInv( int x, int y, int lessThan, OL_MEMORY_IMG *bitmap ) { return !TestAlpha( x-1, y ) && !TestAlpha( x+1, y ) && !TestAlpha( x, y-1 ) && !TestAlpha( x, y+1 ); } */ //extern BITMAP *tempbuf; /* enum { CB_EMPTY = 0, CB_TRACED = 1, CB_FILLED = 2 }; */ // COLLISION ROUTINES // ol::Poly *Bitmap:: GetCollisionPolygon( OL_MEMORY_IMG *bitmap, int alphaLimit, int numSkips, Vec2D rotationPivot ) { OlLog( "Creating collision polygon (Number of skips between vertices: " + ToString( numSkips ) + ")" ); int bmpColorDepth = GlDriver::Get()->GetImageColorDepth( bitmap ); if( bmpColorDepth != 32 ) { OlError( "Illegal Bitmap color depth for GetCollisionPoly: " + ToString( bmpColorDepth ) + " ( Expected 32 )" ); return 0; } Poly *poly = new Poly( rotationPivot ); int lastCol = bitmap->w-1; int lastRow = bitmap->h-1; int x = bitmap->w/2; int y = bitmap->h/2; int xMov = 1; int yMov = 1; int lastXMove = x, lastYMove = y; int startX = 0; int startY = 0; bool found = false; for( int iy = 0; iy < bitmap->h; iy++ ) { for( int ix = 0; ix < bitmap->w; ix++ ) { if( TestAlpha( ix, iy, alphaLimit, bitmap )) { startX = ix; startY = iy; found = true; break; } } if( found ) { break; } } x = startX; y = startY; int skipCounter = 0; int i = 0; int width = bitmap->w; int height = bitmap->h; char *collisionBuffer = new char[width * height]; for( int ii = 0; ii < width * height; ii++ ) { collisionBuffer[ii] = 0; } do { //printf( "x %d y %d xMov %d yMov %d\n", x, y, lastXMove, lastYMove ); //putpixel( tempbuf, x, y, makeacol( 4*i, 4*i, (255 - 4*i), 255 )); bool polyAllowed = true; int storedX = x; int storedY = y; char &collisionBufPoint = collisionBuffer[ y * width + x]; bool movedAlready = false; if( collisionBufPoint != 0 ) { //cout << "Going back" << endl; // We're going back in our tracks // if( lastXMove == 0 ) { if( x > 0 && TestAlpha( x-1, y, alphaLimit, bitmap ) && collisionBuffer[ y * width + (x-1) ] == 0 ) { xMov = -1; x += xMov; yMov = 0; movedAlready = true; } else if( x < lastCol && TestAlpha( x+1, y, alphaLimit, bitmap ) && collisionBuffer[ y * width + (x+1) ] == 0 ) { xMov = 1; x += xMov; yMov = 0; movedAlready = true; } } if( lastYMove == 0 || !movedAlready ) { if( lastYMove <= 0 ) { if( y > 0 && TestAlpha( x, y-1, alphaLimit, bitmap ) && collisionBuffer[ (y-1) * width + x ] == 0 ) { yMov = -1; y += yMov; xMov = 0; movedAlready = true; } } if( lastYMove >= 0 && !movedAlready ) { if( y < lastRow && TestAlpha( x, y+1, alphaLimit, bitmap ) && collisionBuffer[ (y+1) * width + x ] == 0 ) { yMov = 1; y += yMov; xMov = 0; movedAlready = true; } } } if( !movedAlready && lastYMove == 0 ) { if((( lastXMove < 0 && x > 0 ) || ( lastXMove > 0 && x < lastCol )) && TestAlpha( x+lastXMove, y, alphaLimit, bitmap ) && collisionBuffer[ y * width + (x+lastXMove) ] == 0 ) { xMov = lastXMove; x += xMov; yMov = 0; movedAlready = true; } } if( !movedAlready ) { movedAlready = true; xMov = -(( collisionBufPoint >> 4 )-1); yMov = -(( collisionBufPoint & 0xf )-1); //printf( "Moves: %d %d\n", xMov, yMov ); x += xMov; y += yMov; } } if( movedAlready ) { lastYMove = yMov; lastXMove = xMov; //printf( "movedAlready: %d %d\n", (int) lastXMove, (int) lastYMove ); } else { collisionBufPoint = ((lastXMove+1) << 4) | (lastYMove+1); i++; if( y == 0 || y == lastRow ) { if( lastYMove != 0 ) { // Entering the edge // xMov = ( x != 0 && TestAlpha( x-1, y, alphaLimit, bitmap ))? -1 : 1; } else { polyAllowed = false; } if(( x != 0 || xMov > 0 ) && ( x != lastCol || xMov < 0 )) { if( !TestAlpha( x + xMov, y, alphaLimit, bitmap )) { yMov = (y == 0)? 1 : -1; y += yMov; } else { x += xMov; } } } else if( x == 0 || x == lastCol ) { if( lastXMove != 0 ) { // Entering the edge // yMov = ( y != 0 && TestAlpha( x, y-1, alphaLimit, bitmap ))? -1 : 1; } else { polyAllowed = false; } if(( y != 0 || yMov > 0 ) && ( y != lastRow || yMov < 0 )) { if( !TestAlpha( x, y + yMov, alphaLimit, bitmap )) { xMov = (x == 0)? 1 : -1; x += xMov; } else { y += yMov; } } } else { bool left = TestAlpha( x-1, y, alphaLimit, bitmap ); bool right = TestAlpha( x+1, y, alphaLimit, bitmap ); bool top = TestAlpha( x, y-1, alphaLimit, bitmap ); bool bottom = TestAlpha( x, y+1, alphaLimit, bitmap ); //putpixel( bitmap, x, y, 0xffff009f ); //printf( "%d %d %d %d\n", (int) left, (int) right, (int) top, (int) bottom ); if( left ) { if( top ) { if( right ) { if( bottom ) { if( lastXMove == 0 ) { bool lastLeft = TestAlpha( x-1, y - lastYMove, alphaLimit, bitmap ); xMov = lastLeft? 1 : -1; x += xMov; } else { bool lastTop = TestAlpha( x - lastXMove, y-1, alphaLimit, bitmap ); yMov = lastTop? 1 : -1; y += yMov; } } else { x += xMov; polyAllowed = false; } } else { if( bottom ) { y += yMov; polyAllowed = false; } else { if( lastXMove == 0 ) { xMov = -1; x += xMov; } else { yMov = -1; y += yMov; } } } } else { if( right ) { // Bottom doesn't matter // x += xMov; polyAllowed = false; } else if( bottom ) { if( lastXMove == 0 ) { xMov = -1; x += xMov; } else { yMov = 1; y += yMov; } } else { // End of a line, go back left // xMov = -1; x += xMov; } } } else { if( top ) { if( bottom ) { // Right doesn't matter // y += yMov; polyAllowed = false; } else if( right ) { if( lastXMove == 0 ) { xMov = 1; x += xMov; } else { yMov = -1; y += yMov; } } else { // End of a line, go back up // yMov = -1; y += yMov; } } else { if( right ) { if( bottom ) { if( lastXMove == 0 ) { xMov = 1; x += xMov; } else { yMov = 1; y += yMov; } } else { // End of a line, go back right // xMov = 1; x += xMov; } } else if( bottom ) { // End of a line, go back down // yMov = 1; y += yMov; } else { printf( "GetCollisionPoly confused!" ); OlError( "GetCollisionPoly confused!" ); break; } } } } lastXMove = x - storedX; lastYMove = y - storedY; } skipCounter++; if( polyAllowed && skipCounter > numSkips ) { poly->Add( Vec2D( storedX, storedY )); skipCounter = 0; } } while( x != startX || y != startY ); delete[] collisionBuffer; return poly; } void Bitmap:: UnloadToMemory() { bmp = GetMemoryBitmap(); destroyBmp = true; UnloadFromGPU(); } openlayer-2.1.orig/src/GlDriver.cpp0000644000175000017500000002576110531214024017523 0ustar georgeskgeorgesk#include "GlDriver.hpp" #include "General.hpp" #include "GfxRend.hpp" #include "TextureInfo.hpp" using namespace ol; // CONSTANTS // const static int FILENAME_BUF_SIZE = 512; // STATIC CLASS VARIABLES // static AllegroGLDriver defaultDriver; GlDriver *GlDriver::activeDriver = &defaultDriver; const std::string GlDriver::TEXTURE_NOT_POWER_OF_TWO_EXT = "GL_ARB_texture_non_power_of_two"; // GENERAL FUNCTIONS // bool AllegroGLDriver:: SetupProgram( bool setupKeyboard, bool setupMouse, bool setupTimer ) { if( allegro_init() != 0 ) return false; if( install_allegro_gl() != 0 ) return false; if( setupKeyboard ) { if( install_keyboard() != 0 ) return false; } if( setupTimer || setupMouse ) { if( install_timer() != 0 ) return false; } if( setupMouse ) { if( install_mouse() == -1 ) return false; } return true; } bool AllegroGLDriver:: SetupScreen( int w, int h, bool fullscreen, int colorDepth, int zDepth, int refreshRate ) { allegro_gl_clear_settings(); allegro_gl_set( AGL_COLOR_DEPTH, colorDepth ); allegro_gl_set( AGL_DOUBLEBUFFER, 1 ); allegro_gl_set( AGL_Z_DEPTH, zDepth ); allegro_gl_set( AGL_RENDERMETHOD, 1 ); allegro_gl_set( AGL_WINDOWED, fullscreen? FALSE : TRUE ); allegro_gl_set( AGL_SUGGEST, AGL_COLOR_DEPTH | AGL_DOUBLEBUFFER | AGL_RENDERMETHOD | AGL_Z_DEPTH | AGL_WINDOWED ); if( refreshRate > 0 ) { request_refresh_rate( refreshRate ); } if( set_gfx_mode( GFX_OPENGL, w, h, 0, 0) != 0 ) { std::string errorText = std::string( "Couldn't up the screen! (Width: ") + ToString( w ) + ", Height: " + ToString( h ) + ", " + ((fullscreen)? "Fullscreen" : "Windowed") + ", Color depth: " + ToString( colorDepth ) + ", Z Depth: "+ ToString( zDepth ) + ")"; OlError( errorText ); return false; } return true; } static inline void ExtractColor( unsigned char *&pixelPtr, int color, int format ) { *pixelPtr++ = getr( color ); *pixelPtr++ = getg( color ); *pixelPtr++ = getb( color ); if( format == GL_RGBA ) { *pixelPtr++ = geta( color ); } } /* glEnum GlDriver:: GetBytesPerPixel( glEnum textureFormat, int colorDepth ) { int returnVal = 0; switch( colorDepth ) { case 32: switch( textureFormat ) { case GL_RGB: returnVal = 4; break; case GL_RGBA: returnVal = 3; break; default: OlError( "Unknown texture format in GetBytesPerPixel: " + ToString((int) textureFormat )); } break; case 16: switch( textureFormat ) { case GL_RGB: returnVal = 4; break; case GL_RGBA: returnVal = 3; break; default: OlError( "Unknown texture format in GetBytesPerPixel: " + ToString((int) textureFormat )); } break; default: OlError( "Unknown color depth in GetBytesPerPixel: " + ToString( colorDepth )); } } */ Rgba AllegroGLDriver:: GetPixel( OL_MEMORY_IMG *img, int x, int y ) { int pixel = getpixel( img, x, y ); return Rgba( getr( pixel ), getg( pixel ), getb( pixel ), geta( pixel )); } OlTextureInfo AllegroGLDriver:: UploadTexture( OL_MEMORY_IMG *bmp, bool isSolid ) { isSolid = false; bool useTemp = false; int bmpW = bmp->w; int bmpH = bmp->h; int textureW = bmpW; int textureH = bmpH; if( !IsExtensionAlvailable( TEXTURE_NOT_POWER_OF_TWO_EXT )) { int bmpW = bmp->w; int bmpH = bmp->h; textureW = ToNextPowOfTwo( bmpW ); textureH = ToNextPowOfTwo( bmpH ); } bool expandW = textureW != bmpW; bool expandH = textureH != bmpH; bool useExtendedDimensions = expandH || expandW; int format = isSolid? GL_RGB : GL_RGBA; int bpp = isSolid? 3 : 4; int bitmapBpp = bitmap_color_depth( bmp )/8; /* unsigned char *data = new unsigned char[textureW * textureH * bpp]; unsigned char *pixelPtr = data; */ unsigned char *data = new unsigned char[textureW * textureH * bpp]; //float *data = new float[textureW * textureH * bpp]; //char buffer[100]; unsigned char *imageStart = data + bpp * (textureH - bmpH) * textureW; unsigned char *pixelPtr = imageStart; for( int y = bmpH-1; y >= 0; y-- ) { for( int x = 0; x < bmpW; x++ ) { int color = getpixel( bmp, x, y ); ExtractColor( pixelPtr, color, format ); } pixelPtr += bpp * (textureW - bmpW); } if( expandW ) { for( int y = 0; y < bmpH; y++ ) { int color = getpixel( bmp, bmpW-1, y ); pixelPtr = imageStart + bpp * (y * textureW + bmpW); ExtractColor( pixelPtr, color, format ); } } if( expandH ) { int lastLine = bmpH - 1; pixelPtr = imageStart - bpp * textureW; for( int x = 0; x < bmpW+1; x++ ) { int color = getpixel( bmp, x, lastLine ); ExtractColor( pixelPtr, color, format ); } } OlTextureInfo textureInfo( textureW, textureH, bmp->w, bmp->h, format ); GLuint index = 0; glGenTextures( 1, &index ); glBindTexture( GL_TEXTURE_2D, index ); glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, bpp, textureW, textureH, 0, format, GL_UNSIGNED_BYTE, data ); delete[] data; /*glTexImage2D( GL_TEXTURE_2D, 0, 4, textureInfo.texWidth, textureInfo.texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );*/ textureInfo.SetIndex( index ); return textureInfo; } /* OlTextureInfo AllegroGLDriver:: UploadTexture( OL_MEMORY_IMG *bmp, bool isSolid ) { OL_MEMORY_IMG *usedBmp = bmp; bool useTemp = false; int textureH = bmp->h; int textureW = bmp->w; if( !IsExtensionAlvailable( TEXTURE_NOT_POWER_OF_TWO_EXT )) { int bmpW = bmp->w; int bmpH = bmp->h; textureW = ToNextPowOfTwo( bmpW ); textureH = ToNextPowOfTwo( bmpH ); useTemp = textureW != bmpW || textureH != bmpH; if( useTemp ) { int tempW = textureW + 1; int tempH = textureH + 1; OL_MEMORY_IMG *temp = create_bitmap_ex( bitmap_color_depth( bmp ), tempW, tempH ); blit( bmp, temp, 0, 0, 0, 0, bmpW, bmpH ); blit( bmp, temp, bmp->w-1, 0, bmp->w, 0, 1, bmp->h ); blit( bmp, temp, 0, bmp->h-1, 0, bmp->h, bmp->w, 1 ); usedBmp = temp; } } GLint maxTextureSize = 0; glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize ); int format = isSolid? GL_RGB : GL_RGBA; OlTextureInfo textureInfo( textureW, textureH, bmp->w, bmp->h, format ); if( isSolid ) { textureInfo.SetIndex( allegro_gl_make_texture_ex( AGL_TEXTURE_FLIP, usedBmp, format )); // AGL_TEXTURE_FLIP } else { textureInfo.SetIndex( allegro_gl_make_texture_ex( AGL_TEXTURE_FLIP | AGL_TEXTURE_HAS_ALPHA, usedBmp, format )); } if( useTemp ) destroy_bitmap( usedBmp ); return textureInfo; } */ OlTextureInfo AllegroGLDriver:: UploadTexture( GLfloat *data, OlTextureInfo textureInfo ) { glGenTextures( 1, &textureInfo.index ); glBindTexture( GL_TEXTURE_2D, textureInfo.index ); glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, 4, textureInfo.texWidth, textureInfo.texHeight, 0, GL_RGBA, GL_FLOAT, data ); return textureInfo; } std::string AllegroGLDriver:: GetExecutablePath() { char buf[FILENAME_BUF_SIZE]; get_executable_name( buf, FILENAME_BUF_SIZE ); char *namePos = get_filename( buf ); *namePos = '\0'; return buf; } std::string AllegroGLDriver:: ToAbsolutePathname( std::string pathname ) { if( is_relative_filename( pathname.c_str())) { char buf[FILENAME_BUF_SIZE]; make_absolute_filename( buf, GetExecutablePath().c_str(), pathname.c_str(), FILENAME_BUF_SIZE ); return buf; } else { return pathname; } } OL_MEMORY_IMG *AllegroGLDriver:: GetMemoryBitmap( int width, int height, int bpp, unsigned char *pixelData ) { int colorDepth = 8 * bpp; OL_MEMORY_IMG *img = create_bitmap_ex( colorDepth, width, height ); int bytesPerLine = width * bpp; unsigned char *pixelPtr = pixelData; if( bpp != 3 && bpp != 4 ) { OlError( "Unsupported bpp in GetMemoryBitmap: " + bpp ); return img; } // The retrieved texture is naturally upside down // for( int y = img->h-1; y >= 0; y-- ) { for( int x = 0; x < img->w; x++ ) { //unsigned int col = *((unsigned int *) pixelPtr ); int r = *pixelPtr++; int g = *pixelPtr++; int b = *pixelPtr++; unsigned int col; if( bpp == 4 ) { int a = *pixelPtr++; col = makeacol_depth( colorDepth, r, g, b, a ); } else { col = makecol_depth( colorDepth, r, g, b ); } // putpixel is guranteed to work with the bitmap's color depth // putpixel( img, x, y, col ); } } return img; } void GlDriver:: Set( GlDriver *driver ) { if( driver ) activeDriver = driver; else OlError( "Tried to select a null GlDriver!" ); } GlDriver *GlDriver:: Get() { return activeDriver; } bool GlDriver:: IsExtensionAlvailable( std::string extensionName ) { char *extensionsChars = (char *) glGetString( GL_EXTENSIONS ); if( !extensionsChars ) { OlLog( "No OpenGL extensions were found." ); return false; } std::string extensions = extensionsChars; std::string::size_type nameStart = 0; std::string::size_type spaceIndex = 0; while(( spaceIndex = extensions.find( " ", nameStart )) != std::string::npos) { std::string currentExtension = extensions.substr( nameStart, spaceIndex - nameStart ); //TRACE( "%s\n", currentExtension.c_str() ); if( currentExtension == extensionName ) { return true; } nameStart = spaceIndex + 1; } //OlLog( std::string( "OpenGL extension " ) + extensionName + " was not found."); return false; } int AllegroGLDriver:: GetImageColorDepth( OL_MEMORY_IMG *bmp ) { return bitmap_color_depth( bmp ); } bool AllegroGLDriver:: SaveMemoryBitmap( OL_MEMORY_IMG *bmp, std::string filename ) { //save_bitmap returns non-zero on error - translate to a truth value for our //GLDriver function if( save_bitmap( filename.c_str(), bmp, 0 )) return false; return true; } void AllegroGLDriver:: DestroyMemoryBitmap( OL_MEMORY_IMG *bmp ) { if( bmp ) { destroy_bitmap( bmp ); } else { OlError( "Tried to destroy a NULL BITMAP!" ); } } openlayer-2.1.orig/src/loadpng.c0000644000175000017500000002620310552323114017065 0ustar georgeskgeorgesk/* loadpng, Allegro wrapper routines for libpng * by Peter Wang (tjaden@users.sf.net). * * This file is hereby placed in the public domain. */ #include #include #include #include "loadpng.h" /* We need internals _color_load_depth and _fixup_loaded_bitmap. The * first can be replaced by the new get_color_depth() function which * is in Allegro 4.1 branch. But it's not worth it to break 4.0 * compatibility. */ double _png_screen_gamma = -1.0; int _png_compression_level = Z_BEST_COMPRESSION; /* get_gamma: * Get screen gamma value one of three ways. */ static double get_gamma(void) { if (_png_screen_gamma == -1.0) { /* Use the environment variable if available. * 2.2 is a good guess for PC monitors. * 1.1 is good for my laptop. */ AL_CONST char *gamma_str = getenv("SCREEN_GAMMA"); return (gamma_str) ? atof(gamma_str) : 2.2; } return _png_screen_gamma; } /* read_data: * Custom read function to use Allegro packfile routines, * rather than C streams (so we can read from datafiles!) */ static void read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) { PACKFILE *f = (PACKFILE *)png_get_io_ptr(png_ptr); if ((png_uint_32)pack_fread(data, length, f) != length) png_error(png_ptr, "read error (loadpng calling pack_fread)"); } /* check_if_png: * Check if input file is really PNG format. */ #define PNG_BYTES_TO_CHECK 4 static int check_if_png(PACKFILE *fp) { char buf[PNG_BYTES_TO_CHECK]; ASSERT(fp); if (pack_fread(buf, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) return 0; return (png_sig_cmp((png_byte *)buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0); } /* really_load_png: * Worker routine, used by load_png and load_memory_png. */ static BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, RGB *pal) { BITMAP *bmp; PALETTE tmppal; png_uint_32 width, height, rowbytes; int bit_depth, color_type, interlace_type; double image_gamma, screen_gamma; int intent; int bpp, dest_bpp; int tRNS_to_alpha = FALSE; int number_passes, pass; ASSERT(png_ptr && info_ptr && rgb); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) png_set_expand(png_ptr); /* Adds a full alpha channel if there is transparency information * in a tRNS chunk. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); tRNS_to_alpha = TRUE; } /* Convert 16-bits per colour component to 8-bits per colour component. */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* Convert grayscale to RGB triplets */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb(png_ptr); /* Optionally, tell libpng to handle the gamma correction for us. */ if (_png_screen_gamma != 0.0) { screen_gamma = get_gamma(); if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } } /* Turn on interlace handling. */ number_passes = png_set_interlace_handling(png_ptr); /* Call to gamma correct and add the background to the palette * and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* Even if the user doesn't supply space for a palette, we want * one for the load process. */ if (!pal) pal = tmppal; /* Palettes. */ if (color_type & PNG_COLOR_MASK_PALETTE) { int num_palette, i; png_colorp palette; if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { /* We don't actually dither, we just copy the palette. */ for (i = 0; ((i < num_palette) && (i < 256)); i++) { pal[i].r = palette[i].red >> 2; /* 256 -> 64 */ pal[i].g = palette[i].green >> 2; pal[i].b = palette[i].blue >> 2; } for (; i < 256; i++) pal[i].r = pal[i].g = pal[i].b = 0; } } else { generate_332_palette(pal); } rowbytes = png_get_rowbytes(png_ptr, info_ptr); /* Allocate the memory to hold the image using the fields of info_ptr. */ bpp = rowbytes * 8 / width; /* Allegro cannot handle less than 8 bpp. */ if (bpp < 8) bpp = 8; dest_bpp = _color_load_depth(bpp, (bpp == 32)); bmp = create_bitmap_ex(bpp, width, height); /* Maybe flip RGB to BGR. */ if ((bpp == 24) || (bpp == 32)) { int c = makecol_depth(bpp, 0, 0, 255); unsigned char *pc = (unsigned char *)&c; if (pc[0] == 255) png_set_bgr(png_ptr); } /* Read the image, one line at a line (easier to debug!) */ for (pass = 0; pass < number_passes; pass++) { png_uint_32 y; for (y = 0; y < height; y++) png_read_row(png_ptr, bmp->line[y], NULL); } /* Let Allegro convert the image into the desired colour depth. */ if (dest_bpp != bpp) bmp = _fixup_loaded_bitmap(bmp, pal, dest_bpp); /* Read rest of file, and get additional chunks in info_ptr. */ png_read_end(png_ptr, info_ptr); return bmp; } /* load_png: * Load a PNG file from disk, doing colour coversion if required. */ BITMAP *load_png(AL_CONST char *filename, RGB *pal) { PACKFILE *fp; BITMAP *bmp; png_structp png_ptr; png_infop info_ptr; ASSERT(filename); fp = pack_fopen(filename, "r"); if (!fp) return NULL; if (!check_if_png(fp)) { pack_fclose(fp); return NULL; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, NULL, NULL); if (!png_ptr) { pack_fclose(fp); return NULL; } /* Allocate/initialize the memory for image information. */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); pack_fclose(fp); return NULL; } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_ptr->jmpbuf)) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); pack_fclose(fp); /* If we get here, we had a problem reading the file */ return NULL; } /* Use Allegro packfile routines. */ png_set_read_fn(png_ptr, fp, (png_rw_ptr)read_data); /* We have already read some of the signature. */ png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); /* Really load the image now. */ bmp = really_load_png(png_ptr, info_ptr, pal); /* Clean up after the read, and free any memory allocated. */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* Done. */ pack_fclose(fp); return bmp; } /* read_data_memory: * Custom reader function to read a PNG file from a memory buffer. */ typedef struct { AL_CONST char *buffer; png_uint_32 bufsize; png_uint_32 current_pos; } MEMORY_READER_STATE; static void read_data_memory(png_structp png_ptr, png_bytep data, png_uint_32 length) { MEMORY_READER_STATE *f = (MEMORY_READER_STATE *)png_get_io_ptr(png_ptr); if (length > (f->bufsize - f->current_pos)) png_error(png_ptr, "read error in read_data_memory (loadpng)"); memcpy(data, f->buffer + f->current_pos, length); f->current_pos += length; } /* check_if_png_memory: * Check if input buffer is really PNG format. */ static int check_if_png_memory(AL_CONST void *buffer) { return (png_sig_cmp((png_byte *)buffer, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0); } /* load_memory_png: * Load a PNG file from memory, doing colour coversion if required. */ BITMAP *load_memory_png(AL_CONST void *buffer, int bufsize, RGB *pal) { MEMORY_READER_STATE memory_reader_state; BITMAP *bmp; png_structp png_ptr; png_infop info_ptr; if (!buffer || (bufsize <= 0)) return NULL; if (!check_if_png_memory(buffer)) return NULL; /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, NULL, NULL); if (!png_ptr) return NULL; /* Allocate/initialize the memory for image information. */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_ptr->jmpbuf)) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* If we get here, we had a problem reading the file */ return NULL; } /* Set up the reader state. */ memory_reader_state.buffer = (const char *)buffer; memory_reader_state.bufsize = bufsize; memory_reader_state.current_pos = PNG_BYTES_TO_CHECK; /* Tell libpng to use our custom reader. */ png_set_read_fn(png_ptr, &memory_reader_state, (png_rw_ptr)read_data_memory); /* We have already read some of the signature. */ png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); /* Really load the image now. */ bmp = really_load_png(png_ptr, info_ptr, pal); /* Clean up after the read, and free any memory allocated. */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return bmp; } openlayer-2.1.orig/src/Circle.cpp0000644000175000017500000002436310471111302017201 0ustar georgeskgeorgesk#include "Circle.hpp" using namespace ol; static const float OL_NEAR_ZERO = 0.000001; std::string ol::Ellipse:: ToString() const { std::ostringstream str; str << "Circle: Pos: ( " << pos.x << ", " << pos.y << " ) Radius: ( " << xRad << ", " << yRad << " ) Angle: " << angle; return str.str(); } void ol::Ellipse:: RotateBy( float angle ) { this->angle += angle; } std::vector< Vec2D > ol::Ellipse:: ToPolygon( float startAngle, float angleSweep ) const { std::vector< Vec2D > vertices; vertices.reserve( int( 2.0 * AL_PI / angleIncrement )); float endAngle = startAngle - angleSweep; if( endAngle < startAngle ) { float temp = startAngle; startAngle = endAngle; endAngle = temp; } for( float a = endAngle; a >= startAngle; a -= angleIncrement ) { vertices.push_back( pos + Vec2D( cos(a) * xRad, sin(a) * yRad )); } if( angleSweep < 2.0 * AL_PI ) { vertices.push_back( pos + Vec2D( cos(endAngle) * xRad, sin(endAngle) * yRad )); } return vertices; } void ol::Ellipse:: ExecDraw() const { glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); glBegin( GL_TRIANGLE_FAN ); glVertex2f( 0.0, 0.0 ); for( float a = 0.0; a <= 2.0 * AL_PI; a += angleIncrement ) { glVertex2f( cos(a) * xRad, sin(a) * yRad ); } glVertex2f( xRad, 0.0 ); glEnd(); glPopMatrix(); } void ol::Ellipse:: ExecDrawOutline() const { if( lineWidth > 1 + OL_NEAR_ZERO ) { DiskRender( Rgba::WHITE, Rgba::WHITE, xRad - lineWidth, yRad - lineWidth, false ); return; } glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); glLineWidth( lineWidth ); glBegin( GL_LINE_LOOP ); for( float a = 0.0; a < 2 * AL_PI; a += angleIncrement ) { glVertex2f( cos(a) * xRad, sin(a) * yRad ); } glEnd(); glPopMatrix(); } void ol::Ellipse:: Draw( const Rgba &innerCol, const Rgba &outerCol ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); glBegin( GL_TRIANGLE_FAN ); innerCol.Select(); glVertex2f( 0.0, 0.0 ); outerCol.Select(); for( float a = 0.0; a < 2 * AL_PI; a += angleIncrement ) { glVertex2f( cos(a) * xRad, sin(a) * yRad ); } glVertex2f( xRad, 0.0 ); glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void ol::Ellipse:: DrawSlice( const Rgba &color, float startAngle, float angleSweep ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); float endAngle = startAngle - angleSweep; if( endAngle < startAngle ){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_TRIANGLE_FAN ); glVertex2f( 0.0, 0.0 ); for( float a = startAngle; a < endAngle; a += angleIncrement ) { glVertex2f( cos(a) * xRad, sin(a) * yRad ); } glVertex2f( cos( endAngle ) * xRad, sin( endAngle ) * yRad ); glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void ol::Ellipse:: DrawSlice( const Rgba &color1, const Rgba &color2, float startAngle, float angleSweep ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); float endAngle = startAngle - angleSweep; if( endAngle < startAngle ){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_TRIANGLE_FAN ); glVertex2f( 0.0, 0.0 ); float mixAlpha = 0.0; float mixIncr = angleIncrement / (endAngle - startAngle); for( float a = startAngle; a < endAngle; a += angleIncrement ) { color1.MixWith( color2, mixAlpha ).Select(); glVertex2f( cos(a) * xRad, sin(a) * yRad ); mixAlpha += mixIncr; } glVertex2f( cos( endAngle ) * xRad, sin( endAngle ) * yRad ); glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void ol::Ellipse:: DrawArc( const Rgba &color, float startAngle, float angleSweep, float innerXRad, float innerYRad ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); float endAngle = startAngle - angleSweep; if( endAngle < startAngle ) { float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_QUADS ); float prevIX = cos( startAngle ) * innerXRad; float prevIY = sin( startAngle ) * innerYRad; float prevOX = cos( startAngle ) * xRad; float prevOY = sin( startAngle ) * yRad; for( float a = startAngle; a < endAngle; a += angleIncrement ) { float cosa = cos(a); float sina = sin(a); float newIX = cosa * innerXRad; float newIY = sina * innerYRad; float newOX = cosa * xRad; float newOY = sina * yRad; glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } glVertex2f( cos( endAngle ) * innerXRad, sin( endAngle ) * innerYRad ); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( cos( endAngle ) * xRad, sin( endAngle ) * yRad ); glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void ol::Ellipse:: DrawArc( const Rgba &innerColor, const Rgba &outerColor, float startAngle, float angleSweep, float innerXRad, float innerYRad ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); float endAngle = startAngle - angleSweep; if( endAngle < startAngle ) { float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_QUADS ); float prevIX = cos( startAngle ) * innerXRad; float prevIY = sin( startAngle ) * innerYRad; float prevOX = cos( startAngle ) * xRad; float prevOY = sin( startAngle ) * yRad; for( float a = startAngle; a < endAngle; a += angleIncrement ) { float cosa = cos(a); float sina = sin(a); float newIX = cosa * innerXRad; float newIY = sina * innerYRad; float newOX = cosa * xRad; float newOY = sina * yRad; innerColor.Select(); glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); outerColor.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } innerColor.Select(); glVertex2f( cos( endAngle ) * innerXRad, sin( endAngle ) * innerYRad ); glVertex2f( prevIX, prevIY ); outerColor.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( cos( endAngle ) * xRad, sin( endAngle ) * yRad ); glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void ol::Ellipse:: DiskRender( const Rgba &innerCol, const Rgba &outerCol, float innerXRad, float innerYRad, bool setCols ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( pos.x, pos.y, 0.0 ); RotateMatrix( angle ); glBegin( GL_QUADS ); float prevIX = innerXRad; float prevIY = 0.0; float prevOX = xRad; float prevOY = 0.0; for( float a = 0.0; a <= 2 * AL_PI; a += angleIncrement ) { float cosa = cos(a); float sina = sin(a); float newIX = cosa * innerXRad; float newIY = sina * innerYRad; float newOX = cosa * xRad; float newOY = sina * yRad; if( setCols ) innerCol.Select(); glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); if( setCols ) outerCol.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } if( setCols ) innerCol.Select(); glVertex2f( innerXRad, 0.0 ); glVertex2f( prevIX, prevIY ); if( setCols ) outerCol.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( xRad, 0.0 ); glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } openlayer-2.1.orig/src/Framebuffer.cpp0000644000175000017500000001767110402077072020241 0ustar georgeskgeorgesk#include "Framebuffer.hpp" #include "Internal.hpp" #include "GlDriver.hpp" #include "Setup.hpp" #include "Canvas.hpp" #include "Blenders.hpp" using namespace ol; using namespace std; // STATIC CLASS VARIABLES // std::vector< FrameBuffer *> FrameBuffer::possibleFramebufs; FrameBuffer *FrameBuffer::frameBuffer; // GENERAL FUNCTIONS // FrameBuffer:: ~FrameBuffer() {} OlFramebufferObjExt:: ~OlFramebufferObjExt() { OlFramebufferObjExt::DestroySurfaces(); } FrameBuffer &FrameBuffer:: GetInstance() { if( !frameBuffer ) { InitFramebuf(); } return *frameBuffer; } void FrameBuffer:: Register( FrameBuffer *buffer ) { if( !buffer ) { OlError( "Tried to register a null FrameBuffer!" ); return; } possibleFramebufs.push_back( buffer ); } void FrameBuffer:: InitFramebuf() { //Register( new OlFramebufferObjExt ); Register( new BackbufFramebuf ); for( vector< FrameBuffer *> ::iterator iter = possibleFramebufs.begin(); iter != possibleFramebufs.end(); iter++ ) { if((*iter)->Initialize() ) { frameBuffer = *iter; OlLog( string( "Used framebuffer: " ) + frameBuffer->GetName() ); break; } } if( !frameBuffer ) { OlError( "Couldn't retrieve a possible framebuffer!" ); } } void BackbufFramebuf:: ReadPixels( int x, int y, int width, int height, GLenum textureFormat, unsigned char *pixelData ) { glReadPixels( x, Setup::GetWindowHeight() - ( y + Canvas::Height() ), width, height, textureFormat, GL_UNSIGNED_BYTE, pixelData ); } void OlFramebufferObjExt:: ReadPixels( int x, int y, int width, int height, GLenum textureFormat, unsigned char *pixelData ) { glReadPixels( x, height - y, width, height, textureFormat, GL_UNSIGNED_BYTE, pixelData ); } void BackbufFramebuf:: CopyTexSubImage( int x, int y, int width, int height, int yOffset ) { int readY = Setup::GetWindowHeight() - ( y + height ); printf( "%d %d, %d\n", y, height, readY ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, yOffset, x, readY, width, height ); } void OlFramebufferObjExt:: CopyTexSubImage( int x, int y, int width, int height, int yOffset ) { printf( "%d %d, %d\n", y, height, Canvas::Height() - (y + height)); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, yOffset, x, Canvas::Height() - (y + height), width, height ); } const char *BackbufFramebuf:: GetName() { return "Framebuffer emulation"; } bool BackbufFramebuf:: Initialize() { return true; } void BackbufFramebuf:: BindToTexture( const OlTextureInfo &texture ) { boundTexture = &texture; //Canvas::SetPixelWriteMode( COLOR_AND_ALPHA ); glDrawBuffer( GL_BACK ); //glViewport( 0, 0, texture.texWidth, texture.texHeight ); glPushMatrix(); /* glScalef( float(Setup::GetWindowWidth()) / texture.texWidth, float(Setup::GetWindowHeight()) / texture.texHeight, 1.0); */ Blenders::Push(); Blenders::Set( COPY_BLENDER ); //glDrawBuffer( GL_FRONT ); boundTexture->GetReadyToRender(); boundTexture->OutputTexturedQuadXY( 0, 1 );//SpecialWorkaround(); // TODO Blenders::Pop(); //glDrawBuffer( GL_BACK ); //readkey(); /* glFlush(); glFinish(); allegro_gl_flip(); readkey(); allegro_gl_flip(); */ //allegro_gl_flip(); //readkey(); } void BackbufFramebuf:: DestroySurfaces() { boundTexture = 0; } void BackbufFramebuf:: Release() { glViewport( 0, 0, Setup::GetWindowWidth(), Setup::GetWindowHeight() ); glPopMatrix(); boundTexture = 0; Canvas::DisableClipping(); } void BackbufFramebuf:: Destroy( OlTextureInfo &texture ) { if( boundTexture->index == texture.index ) Release(); } void BackbufFramebuf:: RefreshSurface() { if( !boundTexture ) { OlError( "No bound texture for BackbufFramebuf!" ); return; } GLint buffer = 0; glGetIntegerv( GL_READ_BUFFER, &buffer ); glReadBuffer( GL_BACK ); glFlush(); glFinish(); glBindTexture( GL_TEXTURE_2D, boundTexture->index ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, boundTexture->texHeight - boundTexture->imgHeight, 0, Setup::GetWindowHeight() - boundTexture->imgHeight-1, boundTexture->imgWidth, boundTexture->imgHeight ); glReadBuffer( buffer ); } const char *OlFramebufferObjExt:: GetName() { return "GL_EXT_framebuffer_object"; } bool OlFramebufferObjExt:: Initialize() { const char *extName = "GL_EXT_framebuffer_object"; #ifndef GL_EXT_framebuffer_object OlLog( string( "OpenGL extension " ) + extName + " wasn't found in compile time." ); return false; #else // GL_EXT_framebuffer_object if( !GlDriver::IsExtensionAlvailable( extName )) { return false; } #ifdef _WIN32 glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) wglGetProcAddress( "glGenFramebuffersEXT" ); glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) wglGetProcAddress( "glFramebufferTexture2DEXT" ); glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) wglGetProcAddress( "glBindFramebufferEXT" ); glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) wglGetProcAddress( "glDeleteRenderbuffersEXT" ); if( !glGenFramebuffersEXT || !glFramebufferTexture2DEXT || !glBindFramebufferEXT || !glDeleteRenderbuffersEXT ) { OlError( "GL_EXT_framebuffer_object functions couldn't be loaded!" ); } return true; #endif // _WIN32 #endif // GL_EXT_framebuffer_object //Default return false; } void OlFramebufferObjExt:: BindToTexture( const OlTextureInfo &texture ) { #ifdef GL_EXT_framebuffer_object std::map< GLuint, GLuint > ::iterator iter = bufferMap.find( texture.index ); GLuint framebufferID = 0; if( iter != bufferMap.end() ) { framebufferID = iter->second; glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, framebufferID ); } else { glGenFramebuffersEXT( 1, &framebufferID ); glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, framebufferID ); glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture.index, 0 ); bufferMap[texture.index] = framebufferID; } #endif glViewport( 0, 0, texture.texWidth, texture.texHeight ); glPushMatrix(); glScalef( float(Setup::GetWindowWidth()) / texture.texWidth, float(Setup::GetWindowHeight()) / texture.texHeight, 1.0); boundTexture = &texture; } void OlFramebufferObjExt:: Release() { glViewport( 0, 0, Setup::GetWindowWidth(), Setup::GetWindowHeight() ); glPopMatrix(); #ifdef GL_EXT_framebuffer_object glFlush(); glFinish(); glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); #endif boundTexture = 0; } void OlFramebufferObjExt:: Destroy( OlTextureInfo &texture ) { #ifdef GL_EXT_framebuffer_object std::map< GLuint, GLuint > ::iterator iter = bufferMap.find( texture.index ); if( iter != bufferMap.end() ) { GLuint framebufferID = iter->second; glDeleteRenderbuffersEXT( 1, &framebufferID ); OlLog( "Framebuffer destroyed: " + ToString( framebufferID )); } else { OlError( "No framebuffer exists for the specified texture ID!" ); } #endif } void OlFramebufferObjExt:: DestroySurfaces() { #ifdef GL_EXT_framebuffer_object for( std::map< GLuint, GLuint > ::iterator iter = bufferMap.begin(); iter != bufferMap.end(); iter++ ) { GLuint framebufferID = iter->second; glDeleteRenderbuffersEXT( 1, &framebufferID ); } #endif } void OlFramebufferObjExt:: RefreshSurface() { glFlush(); glFinish(); } void FrameBuffer:: DestroyFramebuffers() { for( std::vector< FrameBuffer *> ::iterator iter = possibleFramebufs.begin(); iter != possibleFramebufs.end(); iter++ ) { delete *iter; } possibleFramebufs.clear(); frameBuffer = 0; } openlayer-2.1.orig/src/GfxRend.cpp0000644000175000017500000007310310377212142017342 0ustar georgeskgeorgesk#include "GfxRend.hpp" #include "Transforms.hpp" #include "Blenders.hpp" #include "Internal.hpp" #include "Canvas.hpp" #include #include using namespace ol; using namespace std; // CONSTANTS // static const double MAX_CIRCLE_ANGLE_INCREMENT = 0.35 * AL_PI; static const float OL_NEAR_ZERO = 0.000001; // GENERAL FUNCTIONS // // * GENERAL ROUTINES // void GfxRend:: RefreshScreen() { Canvas::SetTo( SCREEN_BACKBUF ); Canvas::Refresh(); } void GfxRend:: FillScreen( Rgba col ) { Canvas::SetTo( SCREEN_BACKBUF ); Canvas::Fill( col ); } float GfxRend:: GetAngleIncrement( float rad, float accuracy ) { return min(( 2.0 * asin( 1.0/rad )/accuracy ), MAX_CIRCLE_ANGLE_INCREMENT ); } // * CIRCLE ROUTINES // void GfxRend:: Circle( float x, float y, float rad, Rgba col, float accuracy ) { col.Select(); glDisable( GL_TEXTURE_2D ); float da = GetAngleIncrement( rad, accuracy ); glBegin( GL_TRIANGLE_FAN ); glVertex2f( x, y ); for( float a = 0.0; a <= 2 * AL_PI; a += da ) { glVertex2f( x + cos(a) * rad, y + sin(a) * rad ); } glVertex2f( x + rad, y ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: CircleOutline( float x, float y, float rad, Rgba col, float lineWidth, float accuracy ) { col.Select(); glDisable( GL_TEXTURE_2D ); if( lineWidth > 1 + OL_NEAR_ZERO ) { Disk( x, y, rad - lineWidth, rad + lineWidth, col, accuracy ); return; } glLineWidth( lineWidth ); float da = GetAngleIncrement( rad, accuracy ); glBegin( GL_LINE_LOOP ); for( float a = 0.0; a < 2 * AL_PI; a += da ) { glVertex2f( x + cos(a) * rad, y + sin(a) * rad ); } glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: CircleGradient( float x, float y, float rad, Rgba innerCol, Rgba outerCol, float accuracy ) { glDisable( GL_TEXTURE_2D ); float da = GetAngleIncrement( rad, accuracy ); glBegin( GL_TRIANGLE_FAN ); innerCol.Select(); glVertex2f( x, y ); outerCol.Select(); for( float a = 0.0; a < 2 * AL_PI; a += da ) { glVertex2f( x + cos(a) * rad, y + sin(a) * rad ); } glVertex2f( x + rad, y ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: DiskRender( float x, float y, float innerRad, float outerRad, Rgba innerCol, Rgba outerCol, float accuracy, bool setCols ) { float da = GetAngleIncrement( outerRad, accuracy ); glBegin( GL_QUADS ); float prevIX = x + innerRad; float prevIY = y; float prevOX = x + outerRad; float prevOY = y; for( float a = 0.0; a <= 2 * AL_PI; a += da ) { float cosa = cos(a); float sina = sin(a); float newIX = x + cosa * innerRad; float newIY = y + sina * innerRad; float newOX = x + cosa * outerRad; float newOY = y + sina * outerRad; if( setCols ) innerCol.Select(); glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); if( setCols ) outerCol.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } if( setCols ) innerCol.Select(); glVertex2f( x + innerRad, y ); glVertex2f( prevIX, prevIY ); if( setCols ) outerCol.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( x + outerRad, y ); glEnd(); } void GfxRend:: Disk( float x, float y, float innerRad, float outerRad, Rgba col, float accuracy ) { col.Select(); glDisable( GL_TEXTURE_2D ); DiskRender( x, y, innerRad, outerRad, col, col, accuracy, false ); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: DiskGradient( float x, float y, float innerRad, float outerRad, Rgba innerCol, Rgba outerCol, float accuracy ) { glDisable( GL_TEXTURE_2D ); DiskRender( x, y, innerRad, outerRad, innerCol, outerCol, accuracy, true ); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * ELLIPSE ROUTINES // void GfxRend:: Ellipse( float x, float y, float xRad, float yRad, Rgba col, float angle, float accuracy ) { EllipseSlice( x, y, xRad, yRad, col, 0.0, -2.0 * AL_PI, angle, accuracy ); } void GfxRend:: EllipseSlice( float x, float y, float xRad, float yRad, Rgba col, float startAngle, float sweepAngle, float angle, float accuracy ) { col.Select(); glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); float da = 1.0; if( xRad < yRad ) da = GetAngleIncrement( xRad, accuracy ); else da = GetAngleIncrement( yRad, accuracy ); float endAngle = startAngle - sweepAngle; if( endAngle < startAngle ){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_TRIANGLE_FAN ); glVertex2f( 0.0, 0.0 ); for( float a = startAngle; a < endAngle; a += da ) { glVertex2f( cos(a) * xRad, sin(a) * yRad ); } glVertex2f( cos( endAngle ) * xRad, sin( endAngle ) * yRad ); glEnd(); glPopMatrix(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: EllipseOutline( float x, float y, float xRad, float yRad, Rgba col, float angle, float lineWidth, float accuracy ) { col.Select(); glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); float da = 1.0; if( xRad < yRad ) da = GetAngleIncrement( xRad, accuracy ); else da = GetAngleIncrement( yRad, accuracy ); float innerXRad = xRad - lineWidth; float outerXRad = xRad + lineWidth; glBegin( GL_QUADS ); float prevIX = innerXRad; float prevIY = 0.0; float prevOX = outerXRad; float prevOY = 0.0; for( float a = 0.0; a <= 2 * AL_PI; a += da ) { float cosa = cos(a); float sina = sin(a); float newIX = cosa * innerXRad; float newIY = sina * (yRad - lineWidth); float newOX = cosa * outerXRad; float newOY = sina * (yRad + lineWidth); glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } glVertex2f( innerXRad, 0.0 ); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( outerXRad, 0.0 ); glEnd(); glPopMatrix(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: EllipseGradient( float x, float y, float xRad, float yRad, Rgba innerCol, Rgba outerCol, float angle, float accuracy ) { EllipseSliceGradient( x, y, xRad, yRad, innerCol, outerCol, 0.0, -2.0 * AL_PI, angle, accuracy ); } void GfxRend:: EllipseSliceGradient( float x, float y, float xRad, float yRad, Rgba innerCol, Rgba outerCol, float startAngle, float sweepAngle, float angle, float accuracy ) { glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); float da = 1.0; if( xRad < yRad ) da = GetAngleIncrement( xRad, accuracy ); else da = GetAngleIncrement( yRad, accuracy ); float endAngle = startAngle - sweepAngle; if( endAngle < startAngle ){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } if( endAngle - startAngle >= da ) { glBegin( GL_TRIANGLE_FAN ); innerCol.Select(); glVertex2f( 0.0, 0.0 ); outerCol.Select(); for( float a = startAngle; a < endAngle; a += da ) { glVertex2f( cos(a) * xRad, sin(a) * yRad ); } glVertex2f( cos( endAngle ) * xRad, sin( endAngle ) * yRad ); glEnd(); } glPopMatrix(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: EllipseSliceGradient( float x, float y, float xRad, float yRad, Rgba innerCol1, Rgba outerCol1, Rgba innerCol2, Rgba outerCol2, float startAngle, float sweepAngle, float angle, float accuracy ) { glDisable( GL_TEXTURE_2D ); glPushMatrix(); glTranslatef( x, y, 0.0 ); RotateMatrix( angle ); float da = 1.0; if( xRad < yRad ) da = GetAngleIncrement( xRad, accuracy ); else da = GetAngleIncrement( yRad, accuracy ); float endAngle = startAngle - sweepAngle; if( endAngle < startAngle ){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } if( endAngle - startAngle >= da ) { glBegin( GL_QUAD_STRIP ); for( float a = startAngle; a < endAngle; a += da ) { float colFact = (a-startAngle)/(endAngle-startAngle); innerCol1.InterpolateWith( innerCol2, colFact ).Select(); glVertex2f( 0.0, 0.0 ); outerCol1.InterpolateWith( outerCol2, colFact ).Select(); glVertex2f( cos(a) * xRad, sin(a) * yRad ); } glVertex2f( cos( endAngle ) * xRad, sin( endAngle ) * yRad ); glEnd(); } glPopMatrix(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * SLICE ROUTINES // void GfxRend:: Slice( float x, float y, float rad, float startAngle, float sweepAngle, Rgba col, float accuracy ) { col.Select(); glDisable( GL_TEXTURE_2D ); float da = GetAngleIncrement( rad, accuracy ); float endAngle = startAngle - sweepAngle; if( endAngle < startAngle ) { float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_TRIANGLE_FAN ); glVertex2f( x, y ); for( float a = startAngle; a < endAngle; a += da ) { glVertex2f( x + cos(a) * rad, y + sin(a) * rad ); } glVertex2f( x + cos( endAngle ) * rad, y + sin( endAngle ) * rad ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: SliceGradient( float x, float y, float rad, float startAngle, float sweepAngle, Rgba innerCol, Rgba outerCol, float accuracy ) { glDisable( GL_TEXTURE_2D ); float da = GetAngleIncrement( rad, accuracy ); float endAngle = startAngle - sweepAngle; if(endAngle < startAngle){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_TRIANGLE_FAN ); innerCol.Select(); glVertex2f( x, y ); outerCol.Select(); for( float a = startAngle; a < endAngle; a += da ) { glVertex2f( x + cos(a) * rad, y + sin(a) * rad ); } glVertex2f( x + cos( endAngle ) * rad, y + sin( endAngle ) * rad ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * ARC ROUTINES // void GfxRend:: Arc( float x, float y, float innerRad, float outerRad, float startAngle, float sweepAngle, Rgba col, float accuracy ) { glDisable( GL_TEXTURE_2D ); col.Select(); float da = GetAngleIncrement( outerRad, accuracy ); float endAngle = startAngle - sweepAngle; if(endAngle < startAngle){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_QUADS ); float prevIX = x + cos(startAngle) * innerRad; float prevIY = y + sin(startAngle) * innerRad; float prevOX = x + cos(startAngle) * outerRad; float prevOY = y + sin(startAngle) * outerRad; for( float a = startAngle; a < endAngle; a += da ) { float cosa = cos(a); float sina = sin(a); float newIX = x + cosa * innerRad; float newIY = y + sina * innerRad; float newOX = x + cosa * outerRad; float newOY = y + sina * outerRad; glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } glVertex2f( x + cos(endAngle) * innerRad, y + sin(endAngle) * innerRad); glVertex2f( prevIX, prevIY ); glVertex2f( prevOX, prevOY ); glVertex2f( x + cos(endAngle) * outerRad, y + sin(endAngle) * outerRad); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: ArcGradient( float x, float y, float innerRad, float outerRad, float startAngle, float sweepAngle, Rgba innerCol, Rgba outerCol, float accuracy ) { glDisable( GL_TEXTURE_2D ); float da = GetAngleIncrement( outerRad, accuracy ); float endAngle = startAngle - sweepAngle; if(endAngle < startAngle){ float temp = startAngle; startAngle = endAngle; endAngle = temp; } glBegin( GL_QUADS ); float prevIX = x + cos(startAngle) * innerRad; float prevIY = y + sin(startAngle) * innerRad; float prevOX = x + cos(startAngle) * outerRad; float prevOY = y + sin(startAngle) * outerRad; for( float a = startAngle; a < endAngle; a += da ) { float cosa = cos(a); float sina = sin(a); float newIX = x + cosa * innerRad; float newIY = y + sina * innerRad; float newOX = x + cosa * outerRad; float newOY = y + sina * outerRad; innerCol.Select(); glVertex2f( newIX, newIY ); glVertex2f( prevIX, prevIY ); outerCol.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( newOX, newOY ); prevIX = newIX; prevIY = newIY; prevOX = newOX; prevOY = newOY; } innerCol.Select(); glVertex2f( x + cos(endAngle) * innerRad, y + sin(endAngle) * innerRad); glVertex2f( prevIX, prevIY ); outerCol.Select(); glVertex2f( prevOX, prevOY ); glVertex2f( x + cos(endAngle) * outerRad, y + sin(endAngle) * outerRad); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * POLYGON ROUTINES // void GfxRend:: Polygon( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba col ) { col.Select(); glDisable( GL_TEXTURE_2D ); glBegin( GL_POLYGON ); for( int i = 0; i < numCoordinates; i++ ) { glVertex2f(xCoordinates[i], yCoordinates[i]); } glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: PolygonOutline( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba col, float lineWidth ) { col.Select(); glDisable( GL_TEXTURE_2D ); glLineWidth( lineWidth ); glBegin( GL_LINE_LOOP ); for( int i = 0; i < numCoordinates; i++ ) { glVertex2f(xCoordinates[i], yCoordinates[i]); } glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: PolygonGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba *colors ) { glDisable( GL_TEXTURE_2D ); glBegin( GL_POLYGON ); for( int i = 0; i < numCoordinates; i++ ) { colors[i].Select(); glVertex2f(xCoordinates[i], yCoordinates[i]); } glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * RECTANGLE ROUTINES // void GfxRend:: Rect( float x, float y, float w, float h, Rgba col ) { col.Select(); glDisable( GL_TEXTURE_2D ); glBegin( GL_QUADS ); glVertex2f( x, y+h ); glVertex2f( x+w, y+h ); glVertex2f( x+w, y ); glVertex2f( x, y ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: RectOutline( float x, float y, float w, float h, Rgba col, float lineWidth ) { col.Select(); glDisable( GL_TEXTURE_2D ); glLineWidth( lineWidth ); glBegin( GL_QUADS ); // Top // glVertex2f( x -lineWidth, y -lineWidth ); glVertex2f( x+w +lineWidth, y -lineWidth ); glVertex2f( x+w +lineWidth, y ); glVertex2f( x -lineWidth, y ); // Bottom // glVertex2f( x -lineWidth, y+h ); glVertex2f( x+w +lineWidth, y+h ); glVertex2f( x+w +lineWidth, y+h +lineWidth ); glVertex2f( x -lineWidth, y+h +lineWidth ); // Left // glVertex2f( x -lineWidth, y ); glVertex2f( x, y ); glVertex2f( x, y+h ); glVertex2f( x -lineWidth, y+h ); // Right // glVertex2f( x+w, y ); glVertex2f( x+w +lineWidth, y ); glVertex2f( x+w +lineWidth, y+h ); glVertex2f( x+w, y+h ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: RectGradient( float x, float y, float w, float h, Rgba *colors ) { glDisable( GL_TEXTURE_2D ); glBegin( GL_QUADS ); colors[3].Select(); glVertex2f( x, y+h ); colors[2].Select(); glVertex2f( x+w, y+h ); colors[1].Select(); glVertex2f( x+w, y ); colors[0].Select(); glVertex2f( x, y ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * LINE ROUTINES // void GfxRend:: Line( float x1, float y1, float x2, float y2, Rgba col, float lineWidth ) { col.Select(); glDisable( GL_TEXTURE_2D ); glLineWidth( lineWidth ); glBegin( GL_LINES ); glVertex2f( x1, y1 ); glVertex2f( x2, y2 ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: LineGradient( float x1, float y1, float x2, float y2, Rgba col1, Rgba col2, float lineWidth ) { glDisable( GL_TEXTURE_2D ); glLineWidth( lineWidth ); glBegin( GL_LINES ); col1.Select(); glVertex2f( x1, y1 ); col2.Select(); glVertex2f( x2, y2 ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: LineStrip( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba col, float lineWidth ) { if( numCoordinates <= 0 ) { return; } LineStripRender( xCoordinates, yCoordinates, numCoordinates, &col, lineWidth, true ); } void GfxRend:: LineStripGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba *colors, float lineWidth ) { if( numCoordinates <= 0 ) { return; } LineStripRender( xCoordinates, yCoordinates, numCoordinates, colors, lineWidth, false ); } Rgba *GfxRend:: GenerateColors( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba col1, Rgba col2 ) { if( numCoordinates <= 0 ) { return 0; } std::vector< float > lengths; float totalLength = 0.0; for( int i = 1; i < numCoordinates; i++ ) { float dx = xCoordinates[i] - xCoordinates[i-1]; float dy = yCoordinates[i] - yCoordinates[i-1]; float length = sqrt( dx * dx + dy * dy ); totalLength += length; lengths.push_back( length ); } Rgba *colors = new Rgba[numCoordinates]; int index = 0; float lengthsSum = 0.0; for( std::vector< float > ::iterator iter = lengths.begin();; iter++ ) { float factor = lengthsSum / totalLength; colors[index++] = col1.InterpolateWith( col2, factor ); if( iter == lengths.end()) break; else lengthsSum += *iter; } return colors; } void GfxRend:: LineStripGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba col1, Rgba col2, float lineWidth ) { if( numCoordinates <= 0 ) { return; } Rgba *colors = GenerateColors( xCoordinates, yCoordinates, numCoordinates, col1, col2 ); LineStripRender( xCoordinates, yCoordinates, numCoordinates, colors, lineWidth, false ); delete[] colors; } void GfxRend:: LineStripGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba col1, Rgba col2, Rgba leftCol, Rgba rightCol, float lineWidth ) { if( numCoordinates <= 0 ) { return; } Rgba *colors = GenerateColors( xCoordinates, yCoordinates, numCoordinates, col1, col2 ); LineStripRender( xCoordinates, yCoordinates, numCoordinates, colors, lineWidth, false, true, leftCol, rightCol ); delete[] colors; } void GfxRend:: LineStripRender( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba *cols, float lineWidth, bool singleColor, bool useSideColors, Rgba leftCol, Rgba rightCol ) { if( singleColor ) cols->Select(); else cols[0].Select(); glDisable( GL_TEXTURE_2D ); // Find the normal of the beginning of the strip // float lastX = xCoordinates[0]; float lastY = yCoordinates[0]; float lastSx = xCoordinates[1] - lastX; float lastSy = yCoordinates[1] - lastY; float lastSLength = sqrt( lastSx * lastSx + lastSy * lastSy ); lastSx /= lastSLength; lastSy /= lastSLength; float lastUpperX = lastX + lastSy * lineWidth; float lastUpperY = lastY - lastSx * lineWidth; float lastLowerX = lastX - lastSy * lineWidth; float lastLowerY = lastY + lastSx * lineWidth; // Render the begin of the strip // if( !useSideColors ) { glBegin( GL_QUAD_STRIP ); glVertex2f( lastUpperX, lastUpperY ); glVertex2f( lastLowerX, lastLowerY ); } for( int i = 1; i < numCoordinates-1; i++ ) { float x = xCoordinates[i]; float y = yCoordinates[i]; if( x == lastX && y == lastY ) { continue; } // Find the direction vector from the next point to the current one // float bx = x - xCoordinates[i+1]; float by = y - yCoordinates[i+1]; float bLength = sqrt( bx * bx + by * by ); if( bLength > -OL_NEAR_ZERO && bLength < OL_NEAR_ZERO ) { continue; } bx /= bLength; by /= bLength; // Find the direction vector of the displacement // float cx = lastSx + bx; float cy = lastSy + by; float cLength = sqrt( cx * cx + cy * cy ); float nx, ny; if( cLength > -OL_NEAR_ZERO && cLength < OL_NEAR_ZERO ) { nx = -by; ny = bx; float nRatio = lineWidth/sqrt( nx * nx + ny * ny ); nx *= nRatio; ny *= nRatio; } else { cx /= cLength; cy /= cLength; // Make sure that the displacement happens always in the same side // float diff1 = lastSx - bx; float diff2 = lastSy - by; float diff3 = cx - bx; float diff4 = cy - by; if(( diff1 * diff4 ) - ( diff2 * diff3 ) > 0) { cx = -cx; cy = -cy; } // Find the displacement multiplicator // float s = lastSy * cx + (-lastSx) * cy; nx = cx * lineWidth / s; ny = cy * lineWidth / s; } // Find the displaced coordinates // float upperX = x + nx; float upperY = y + ny; float lowerX = x - nx; float lowerY = y - ny; if( !useSideColors ) { if( !singleColor ) cols[i].Select(); glVertex2f( upperX, upperY ); glVertex2f( lowerX, lowerY ); } else { glBegin( GL_QUAD_STRIP ); // Upper side // leftCol.Select(); glVertex2f( lastUpperX, lastUpperY ); glVertex2f( upperX, upperY ); // Middle // if( !singleColor ) cols[i-1].Select(); else cols->Select(); glVertex2f( lastX, lastY ); if( !singleColor ) cols[i].Select(); glVertex2f( x, y ); // Lower side // rightCol.Select(); glVertex2f( lastLowerX, lastLowerY ); glVertex2f( lowerX, lowerY ); glEnd(); } // Store the information which can be used when calculating the next point // lastX = x; lastY = y; lastSx = -bx; lastSy = -by; lastUpperX = upperX; lastUpperY = upperY; lastLowerX = lowerX; lastLowerY = lowerY; } // Render the end of the strip // int lastIndex = numCoordinates-1; float x = xCoordinates[lastIndex]; float y = yCoordinates[lastIndex]; float upperX = x + lastSy * lineWidth; float upperY = y - lastSx * lineWidth; float lowerX = x - lastSy * lineWidth; float lowerY = y + lastSx * lineWidth; if( !useSideColors ) { if( !singleColor ) cols[lastIndex].Select(); glVertex2f( upperX, upperY ); glVertex2f( lowerX, lowerY ); glEnd(); } else { glBegin( GL_QUAD_STRIP ); // Upper side // leftCol.Select(); glVertex2f( lastUpperX, lastUpperY ); glVertex2f( upperX, upperY ); // Middle // if( !singleColor ) cols[lastIndex-1].Select(); else cols->Select(); glVertex2f( lastX, lastY ); if( !singleColor ) cols[lastIndex].Select(); glVertex2f( x, y ); // Lower side // rightCol.Select(); glVertex2f( lastLowerX, lastLowerY ); glVertex2f( lowerX, lowerY ); glEnd(); } if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * TRIANGLE ROUTINES // void GfxRend:: Triangle( float x1, float y1, float x2, float y2, float x3, float y3, Rgba col ) { col.Select(); glDisable( GL_TEXTURE_2D ); glBegin( GL_TRIANGLES ); glVertex2f( x1, y1 ); glVertex2f( x2, y2 ); glVertex2f( x3, y3 ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: TriangleOutline( float x1, float y1, float x2, float y2, float x3, float y3, Rgba col, float lineWidth ) { col.Select(); glDisable( GL_TEXTURE_2D ); glLineWidth( lineWidth ); glBegin( GL_LINE_LOOP ); glVertex2f( x1, y1 ); glVertex2f( x2, y2 ); glVertex2f( x3, y3 ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } void GfxRend:: TriangleGradient( float x1, float y1, float x2, float y2, float x3, float y3, Rgba *cols ) { glDisable( GL_TEXTURE_2D ); glBegin( GL_TRIANGLES ); cols[0].Select(); glVertex2f( x1, y1 ); cols[1].Select(); glVertex2f( x2, y2 ); cols[2].Select(); glVertex2f( x3, y3 ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * POINT ROUTINES // void GfxRend:: Point( float x, float y, Rgba col ) { col.Select(); glDisable( GL_TEXTURE_2D ); glBegin( GL_POINTS ); glVertex2f( x + 0.5, y + 0.5 ); glEnd(); if( Settings::TextureMappingUsed() ) glEnable( GL_TEXTURE_2D ); } // * ERROR HANDLING ROUTINES // const char *GfxRend:: ErrorString() { OlLog( "Retrieving error" ); GLenum error = glGetError(); OlLog( "Done... Got: " + ToString( error )); if( error == GL_NO_ERROR ) return 0; if( error == GL_INVALID_ENUM ) return "GL_INVALID_ENUM"; if( error == GL_INVALID_VALUE ) return "GL_INVALID_VALUE"; if( error == GL_INVALID_OPERATION ) return "GL_INVALID_OPERATION"; if( error == GL_STACK_OVERFLOW ) return "GL_STACK_OVERFLOW"; if( error == GL_STACK_UNDERFLOW ) return "GL_STACK_UNDERFLOW"; if( error == GL_OUT_OF_MEMORY ) return "GL_OUT_OF_MEMORY"; OlLog( "Unknown OpenGL error code" ); OlLog( ToString( error )); return "OTHER"; } openlayer-2.1.orig/src/Shape.cpp0000644000175000017500000000025210413425714017042 0ustar georgeskgeorgesk#include "Shape.hpp" ol::Shape:: ~Shape() {} void ol::Shape:: RotateBy( float angle ) {} void ol::Shape:: TransformBy( const Placement &placement ) {} openlayer-2.1.orig/src/Point.cpp0000644000175000017500000000035710517576304017110 0ustar georgeskgeorgesk#include "Point.hpp" #include std::string ol::Point:: ToString() const { return "Point: " + pos.ToString(); } void ol::Point:: TransformBy( const Placement &placement ) { pos += placement.GetPosition(); } openlayer-2.1.orig/src/TexturedPoly.cpp0000644000175000017500000004066510471113532020462 0ustar georgeskgeorgesk#include "TexturedPoly.hpp" #include "Bitmap.hpp" #include "Circle.hpp" #include "Rectangle.hpp" #ifdef OL_DEBUG_TEXTURED_POLY #include #endif // OL_DEBUG_TEXTURED_POLY using namespace ol; using namespace std; static const float OL_NEAR_ZERO = 0.001; void TexturedPoly:: Draw( float opacity ) { if( dirty ) { Construct(); } glPushMatrix(); placement.Apply(); texture->GetReadyToRender( opacity ); for( std::vector< HSlice *> ::iterator iter = slices.begin(); iter != slices.end(); iter++ ) { (*iter)->Render(); } glBindTexture( GL_TEXTURE_2D, 0 ); glPopMatrix(); } void TexturedPoly::HSlice:: Render() { bool skipping = true; std::vector< SlicePart *> ::iterator newStartPoint = parts.end(); //glBegin( GL_QUAD_STRIP ); use skipping for( std::vector< SlicePart *> ::iterator iter = parts.begin(); iter != parts.end(); iter++ ) { bool zeroHeight = (*iter)->IsHeightZero(); if( zeroHeight ) { if( skipping ) { newStartPoint = iter; continue; } } else if( skipping ) { skipping = false; glBegin( GL_QUAD_STRIP ); if( newStartPoint != parts.end() ) { (*newStartPoint)->RenderStripPart(); newStartPoint = parts.end(); } } (*iter)->RenderStripPart(); if( zeroHeight ) { skipping = true; glEnd(); } } if( !skipping ) { glEnd(); } #ifdef OL_DEBUG_TEXTURED_POLY glDisable( GL_TEXTURE_2D ); glLineWidth( 2.0 ); glBegin( GL_LINE_STRIP ); for( std::vector< SlicePart *> ::iterator iter = parts.begin(); iter != parts.end(); iter++ ) { glTexCoord2f((*iter)->textureTop, (*iter)->textureX ); glVertex2f((*iter)->x, (*iter)->top ); glTexCoord2f((*iter)->textureBottom, (*iter)->textureX ); glVertex2f((*iter)->x, (*iter)->bottom ); } glEnd(); glEnable( GL_TEXTURE_2D ); #endif // OL_DEBUG_TEXTURED_POLY } bool TexturedPoly:: LineCollides( const Line &line, std::vector< Vec2D > ::const_iterator start, std::vector< Vec2D > ::const_iterator end ) { const std::vector< Vec2D > &vertices = GetVertices(); std::vector< Vec2D > ::const_iterator iter = start; std::vector< Vec2D > ::const_iterator iterPrev = iter; iter++; if( iter == vertices.end() ) { iter = vertices.begin(); } while( true ) { if( line.Collides( Line( *iterPrev, *iter ))) { return true; } if( iter == end ) { break; } iterPrev = iter; iter++; if( iter == vertices.end() ) { iter = vertices.begin(); } } return false; } void TexturedPoly:: Construct() { const std::vector< Vec2D > &vertices = GetVertices(); // Remove the old slices for( std::vector< HSlice *> ::iterator iter = slices.begin(); iter != slices.end(); iter++ ) { delete *iter; } slices.clear(); if( vertices.size() < 3 ) { return; } if( !texture->IsValid() ) { OlError( "Polygon texture isn't loaded correctly!" ); return; } // Find the area of the polygon const Vec2D &firstVertex = vertices.front(); float minX = firstVertex.x, minY = firstVertex.y; float maxX = firstVertex.x, maxY = firstVertex.y; std::vector< Vec2D > ::const_iterator iter = vertices.begin(); iter++; std::vector< Vec2D > ::const_iterator leftmost = vertices.begin(), rightmost = vertices.begin(); for(; iter != vertices.end(); iter++ ) { if( iter->x > maxX ) { maxX = iter->x; rightmost = iter; } else if( iter->x < minX ) { minX = iter->x; leftmost = iter; } if( iter->y > maxY ) { maxY = iter->y; } if( iter->y < minY ) { minY = iter->y; } } #ifdef OL_DEBUG_TEXTURED_POLY Circle( *leftmost, 20 ).Draw( Rgba::YELLOW ); Circle( *rightmost, 20 ).Draw( Rgba( 0.0, 1.0, 1.0 )); #endif // OL_DEBUG_TEXTURED_POLY // Cut the polygon to vertical slices, starting from minX and ending at maxX float bmpW = texture->Width(); float bmpH = texture->Height(); minX -= 1.0; minY -= 1.0; for( float y = minY; y <= maxY; y += bmpH ) { for( float x = minX; x <= maxX; x += bmpW ) { #ifdef OL_DEBUG_TEXTURED_POLY cout << endl << "NEW LOOP: " << x << ", " << y << endl << endl; #endif // OL_DEBUG_TEXTURED_POLY std::vector< Vec2D > ::const_iterator topStart = rightmost; std::vector< Vec2D > ::const_iterator topEnd = leftmost; SideProcessed topSide = ProcessSide( topStart, topEnd, x, y, true, false ); std::vector< Vec2D > ::const_iterator bottomStart = leftmost; std::vector< Vec2D > ::const_iterator bottomEnd = rightmost; SideProcessed bottomSide = ProcessSide( bottomStart, bottomEnd, x, y, false, true ); if( topSide.isEmpty && bottomSide.isEmpty ) { // Let's check if the slice is really inside the polygon Line topVLine( Vec2D( x, minY ), Vec2D( x, y )); Line bottomVLine( Vec2D( x, y+bmpH ), Vec2D( x, maxY )); #ifdef OL_DEBUG_TEXTURED_POLY topVLine.Draw( Rgba( 1.0, 0.0, 1.0 )); bottomVLine.Draw( Rgba( 0.0, 1.0, 1.0 )); #endif // OL_DEBUG_TEXTURED_POLY if( !( LineCollides( topVLine, topStart, topEnd ) && LineCollides( bottomVLine, bottomStart, bottomEnd ))) { // The slice is outside the polygon (test works only with convex polygons) continue; } } // Remember that the top side is right to left std::vector< Vec2D > ::reverse_iterator topIter = topSide.vertices.rbegin(); std::vector< Vec2D > ::reverse_iterator topPrev = topIter; topIter++; std::vector< Vec2D > ::const_iterator bottomIter = bottomSide.vertices.begin(); std::vector< Vec2D > ::const_iterator bottomPrev = bottomIter; bottomIter++; HSlice *hslice = new HSlice(); float startTop = topPrev->y; float startBottom = bottomPrev->y; if( startTop > startBottom ) { float temp = startTop; startTop = startBottom; startBottom = temp; } hslice->AddPart( new SlicePart( startTop, startBottom, x, x, y, texture )); while( topIter != topSide.vertices.rend() && bottomIter != bottomSide.vertices.end() ) { float top, bottom, sliceX; // Unoptimized, uses Line::GetIntersectionPoint if( topIter->x < bottomIter->x ) { // Top cuts from bottom sliceX = topIter->x; top = topIter->y; Line vLine( *topIter, Vec2D( topIter->x, y + bmpH + 1.0 )); Line bottomLine( *bottomPrev, *bottomIter ); bottom = vLine.GetIntersectionPoint( bottomLine ).y; topPrev = topIter; topIter++; } else { // Bottom cuts from top sliceX = bottomIter->x; bottom = bottomIter->y; Line vLine( *bottomIter, Vec2D( bottomIter->x, y - 1.0 )); Line topLine( *topPrev, *topIter ); top = vLine.GetIntersectionPoint( topLine ).y; bottomPrev = bottomIter; bottomIter++; } if( top > bottom ) { float temp = bottom; bottom = top; top = temp; } #ifdef OL_DEBUG_TEXTURED_POLY cout << "Adding at x = " << sliceX << ": Top: " << top << " Bottom " << bottom << endl; #endif // OL_DEBUG_TEXTURED_POLY // Construct the SlicePart hslice->AddPart( new SlicePart( top, bottom, sliceX, x, y, texture )); } slices.push_back( hslice ); } } dirty = false; } TexturedPoly::SideProcessed TexturedPoly:: ProcessSide( std::vector< Vec2D > ::const_iterator start, std::vector< Vec2D > ::const_iterator end, float x, float y, bool isUpper, bool leftToRight ) { TexturedPoly::SideProcessed ret; float bmpW = texture->Width(); float bmpH = texture->Height(); const std::vector< Vec2D > &vertices = GetVertices(); if( end == vertices.end() ) { end = vertices.begin(); } #ifdef OL_DEBUG_TEXTURED_POLY Rect( x, y, bmpW, bmpH ).DrawOutline( Rgba::BLUE ); #endif // OL_DEBUG_TEXTURED_POLY Vec2D topLeft = Vec2D( x, y ); Vec2D topRight = Vec2D( x + bmpW, y ); Vec2D bottomRight = Vec2D( x + bmpW, y + bmpH ); Vec2D bottomLeft = Vec2D( x, y + bmpH ); Line *textureEdges[4]; textureEdges[0] = new Line( topLeft, topRight ); textureEdges[1] = new Line( topRight, bottomRight ); textureEdges[2] = new Line( bottomRight, bottomLeft ); textureEdges[3] = new Line( bottomLeft, topLeft ); std::vector< Vec2D > ::const_iterator beforeIter = start; std::vector< Vec2D > ::const_iterator iter = start; iter++; if( iter == vertices.end() ) { iter = vertices.begin(); } bool inside = start->y > y && start->y < y + bmpH && (( leftToRight && start->x >= x ) || ( !leftToRight && start->x <= x + bmpW )); if( inside ) { ret.vertices.push_back( *start ); } else { // Find the first vertex which is inside the polygon area while( iter != end ) { if(( leftToRight && iter->x >= x ) || ( !leftToRight && iter->x <= x + bmpW )) { AddEdgePoints( ret.vertices, Line( *beforeIter, *iter ), textureEdges, leftToRight ); //cout << "first last: \n" << ret.vertices.back().ToString() << endl; break; } beforeIter = iter; iter++; if( iter == vertices.end() ) { iter = vertices.begin(); } } } bool shouldEnd = false; std::vector< Vec2D > ::const_iterator beforeBeforeIter = vertices.end(); // Process all vertices inside the polygon area while( !shouldEnd ) { if( iter == end ) { shouldEnd = true; } if (( !leftToRight && iter->x < x ) || ( leftToRight && iter->x > x + bmpW )) { // Add the point where the side leaves the texture area if( inside ) { AddEdgePoints( ret.vertices, Line( *beforeIter, *iter ), textureEdges, leftToRight ); } break; } if( iter->y >= y - OL_NEAR_ZERO && iter->y <= y + bmpH + OL_NEAR_ZERO ) { if( !inside ) { inside = true; AddEdgePoints( ret.vertices, Line( *beforeIter, *iter ), textureEdges, leftToRight ); } ret.vertices.push_back( *iter ); } else if( inside ) { inside = false; AddEdgePoints( ret.vertices, Line( *beforeIter, *iter ), textureEdges, leftToRight ); } beforeBeforeIter = beforeIter; beforeIter = iter; iter++; if( iter == vertices.end() ) { iter = vertices.begin(); } } // Add vertex in the case if the only crossing line crosses both the lower and upper sides of the region if( ret.vertices.empty() && beforeBeforeIter != vertices.end() ) { #ifdef OL_DEBUG_TEXTURED_POLY cout << "A1: " << Line( *beforeBeforeIter, *beforeIter ).ToString() << endl; #endif AddEdgePoints( ret.vertices, Line( *beforeBeforeIter, *beforeIter ), textureEdges, leftToRight ); } for( int i = 0; i < 4; i++ ) { delete textureEdges[i]; } // Add a suitable first vertex if it's needed if( !ret.vertices.empty() && (( leftToRight && ret.vertices.front().x > x + OL_NEAR_ZERO ) || ( !leftToRight && ret.vertices.front().x < x + bmpW - OL_NEAR_ZERO ))) { vector< Vec2D > newRet; if( leftToRight ) { newRet.push_back( Vec2D( x, ret.vertices.front().y )); } else { newRet.push_back( Vec2D( x + bmpW, ret.vertices.front().y )); } for( vector< Vec2D > ::iterator iter = ret.vertices.begin(); iter != ret.vertices.end(); iter++ ) { newRet.push_back( *iter ); } ret.vertices = newRet; } bool wasNoFirst = false; // If no vertices exist, we need to find suitable start and end vertices if( ret.vertices.empty() ) { wasNoFirst = true; ret.vertices.push_back( Vec2D( leftToRight? x : x+bmpW, isUpper? y : y+bmpH )); } // Add the last vertex if the side has not collided with the left or the right side if((( leftToRight && ret.vertices.back().x < x + bmpW - OL_NEAR_ZERO ) || ( !leftToRight && ret.vertices.back().x > x + OL_NEAR_ZERO ))) { ret.vertices.push_back( Vec2D( leftToRight? x+bmpW : x, ret.vertices.back().y )); if( wasNoFirst ) { ret.isEmpty = true; } } #ifdef OL_DEBUG_TEXTURED_POLY glLineWidth( 2.0 ); glBegin( GL_LINE_STRIP ); if( isUpper ) Rgba( 0.0, 1.0, 0.5, 0.5 ).Select(); else Rgba( 1.0, 0.7, 0.0, 0.5 ).Select(); for( vector< Vec2D > ::iterator iter = ret.vertices.begin(); iter != ret.vertices.end(); iter++ ) { glVertex2f( iter->x, iter->y ); } glEnd(); glLineWidth( 1.0 ); for( vector< Vec2D > ::iterator iter = ret.vertices.begin(); iter != ret.vertices.end(); iter++ ) { Circle( *iter, isUpper? 5.0 : 7.0 ).Draw( isUpper? Rgba::GREEN.WithAlpha( 0.7 ) : Rgba::RED.WithAlpha( 0.7 )); } #endif // OL_DEBUG_TEXTURED_POLY return ret; } void TexturedPoly:: AddEdgePoints( vector< Vec2D > &vecs, const Line &segment, Line **textureEdges, bool leftToRight ) { vector< Vec2D > addList; for( int i = 0; i < 4; i++ ) { if( textureEdges[i]->Collides( segment )) { Vec2D collisionPoint = textureEdges[i]->GetIntersectionPoint( segment ); if( vecs.empty() || collisionPoint != vecs.back() ) { vector< Vec2D > ::iterator insertPoint = addList.begin(); for( vector< Vec2D > ::iterator iter = addList.begin(); iter != addList.end(); iter++ ) { if(( iter->x < collisionPoint.x ) != leftToRight ) { break; } insertPoint++; } addList.insert( insertPoint, collisionPoint ); } } } for( vector< Vec2D > ::iterator iter = addList.begin(); iter != addList.end(); iter++ ) { vecs.push_back( *iter ); } } TexturedPoly::SlicePart:: SlicePart( float top, float bottom, float x, float textureStartX, float textureStartY, const Bitmap *bmp ) : top( top ), bottom( bottom ), x( x ) { const OlRect &textureRect = bmp->textureInfo.rect; float mul = 1.0 / bmp->Height(); textureTop = textureRect.y + textureRect.h - mul * (top - textureStartY) * textureRect.h; textureBottom = textureRect.y + textureRect.h - mul * (bottom - textureStartY) * textureRect.h; textureX = textureRect.x + (x - textureStartX) / bmp->Width() * textureRect.w; } TexturedPoly::HSlice:: ~HSlice() { for( std::vector< SlicePart *> ::iterator iter = parts.begin(); iter != parts.end(); iter++ ) { delete *iter; } } void TexturedPoly:: Add( Vec2D vec ) { Poly::Add( vec ); dirty = true; } void TexturedPoly:: SetTexture( const Bitmap &texture ) { this->texture = &texture; dirty = true; } void TexturedPoly:: SetVertex( int index, const Vec2D &newValue ) { Poly::SetVertex( index, newValue ); dirty = true; } openlayer-2.1.orig/src/savepng.c0000644000175000017500000001570010552323114017104 0ustar georgeskgeorgesk/* loadpng, Allegro wrapper routines for libpng * by Peter Wang (tjaden@users.sf.net). * * This file is hereby placed in the public domain. */ #include #include #include "loadpng.h" /* write_data: * Custom write function to use Allegro packfile routines, * rather than C streams. */ static void write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) { PACKFILE *f = (PACKFILE *)png_get_io_ptr(png_ptr); if ((png_uint_32)pack_fwrite(data, length, f) != length) png_error(png_ptr, "write error (loadpng calling pack_fwrite)"); } /* Don't think Allegro has any problem with buffering * (rather, Allegro provides no way to flush packfiles). */ static void flush_data(png_structp png_ptr) { (void)png_ptr; } /* save_indexed: * Core save routine for 8 bpp images. * */ static int save_indexed(png_structp png_ptr, BITMAP *bmp) { ASSERT(bitmap_color_depth(bmp) == 8); if (is_memory_bitmap(bmp)) { /* fast path */ int y; for (y=0; yh; y++) { png_write_row(png_ptr, bmp->line[y]); } return 1; } else { /* generic case */ unsigned char *rowdata; int x, y; rowdata = (unsigned char *)malloc(bmp->w * 3); if (!rowdata) return 0; for (y=0; yh; y++) { unsigned char *p = rowdata; for (x=0; xw; x++) { *p++ = getpixel(bmp, x, y); } png_write_row(png_ptr, rowdata); } free(rowdata); return 1; } } /* save_rgb: * Core save routine for 15/16/24 bpp images (original by Martijn Versteegh). */ static int save_rgb(png_structp png_ptr, BITMAP *bmp) { AL_CONST int depth = bitmap_color_depth(bmp); unsigned char *rowdata; int y, x; ASSERT(depth == 15 || depth == 16 || depth == 24); rowdata = (unsigned char *)malloc(bmp->w * 3); if (!rowdata) return 0; for (y=0; yh; y++) { unsigned char *p = rowdata; if (depth == 15) { for (x = 0; x < bmp->w; x++) { int c = getpixel(bmp, x, y); *p++ = getr15(c); *p++ = getg15(c); *p++ = getb15(c); } } else if (depth == 16) { for (x = 0; x < bmp->w; x++) { int c = getpixel(bmp, x, y); *p++ = getr16(c); *p++ = getg16(c); *p++ = getb16(c); } } else { /* depth == 24 */ for (x = 0; x < bmp->w; x++) { int c = getpixel(bmp, x, y); *p++ = getr24(c); *p++ = getg24(c); *p++ = getb24(c); } } png_write_row(png_ptr, rowdata); } free(rowdata); return 1; } /* save_rgba: * Core save routine for 32 bpp images. */ static int save_rgba(png_structp png_ptr, BITMAP *bmp) { unsigned char *rowdata; int x, y; ASSERT(bitmap_color_depth(bmp) == 32); rowdata = (unsigned char *)malloc(bmp->w * 4); if (!rowdata) return 0; for (y=0; yh; y++) { unsigned char *p = rowdata; for (x=0; xw; x++) { int c = getpixel(bmp, x, y); *p++ = getr32(c); *p++ = getg32(c); *p++ = getb32(c); *p++ = geta32(c); } png_write_row(png_ptr, rowdata); } free(rowdata); return 1; } /* save_png: * Writes a non-interlaced, no-frills PNG, taking the usual save_xyz * parameters. Returns non-zero on error. */ static int really_save_png(PACKFILE *fp, BITMAP *bmp, AL_CONST RGB *pal) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; int depth; int colour_type; depth = bitmap_color_depth(bmp); if (depth == 8 && !pal) return -1; /* Create and initialize the png_struct with the * desired error handler functions. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, NULL, NULL); if (!png_ptr) goto Error; /* Allocate/initialize the image information data. */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) goto Error; /* Set error handling. */ if (setjmp(png_ptr->jmpbuf)) { /* If we get here, we had a problem reading the file. */ goto Error; } /* Use packfile routines. */ png_set_write_fn(png_ptr, fp, (png_rw_ptr)write_data, flush_data); /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. */ if (depth == 8) colour_type = PNG_COLOR_TYPE_PALETTE; else if (depth == 32) colour_type = PNG_COLOR_TYPE_RGB_ALPHA; else colour_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, bmp->w, bmp->h, 8, colour_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Set the palette if there is one. Required for indexed-color images. */ if (colour_type == PNG_COLOR_TYPE_PALETTE) { png_color palette[256]; int i; for (i = 0; i < 256; i++) { palette[i].red = _rgb_scale_6[pal[i].r]; /* 64 -> 256 */ palette[i].green = _rgb_scale_6[pal[i].g]; palette[i].blue = _rgb_scale_6[pal[i].b]; } /* Set palette colors. */ png_set_PLTE(png_ptr, info_ptr, palette, 256); } /* Optionally write comments into the image ... Nah. */ /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* Once we write out the header, the compression type on the text * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again * at the end. */ /* Set compression level. */ png_set_compression_level(png_ptr, _png_compression_level); /* Save the data. */ switch (depth) { case 8: if (!save_indexed(png_ptr, bmp)) goto Error; break; case 15: case 16: case 24: if (!save_rgb(png_ptr, bmp)) goto Error; break; case 32: if (!save_rgba(png_ptr, bmp)) goto Error; break; default: ASSERT(FALSE); goto Error; } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; Error: if (png_ptr) { if (info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); else png_destroy_write_struct(&png_ptr, NULL); } return -1; } int save_png(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal) { PACKFILE *fp; int result; ASSERT(filename); ASSERT(bmp); fp = pack_fopen(filename, "w"); if (!fp) return -1; acquire_bitmap(bmp); result = really_save_png(fp, bmp, pal); release_bitmap(bmp); pack_fclose(fp); return result; } openlayer-2.1.orig/src/Matrix.cpp0000644000175000017500000000102710377212142017245 0ustar georgeskgeorgesk#include "Matrix.hpp" using namespace ol; Matrix2D operator *( const Matrix2D &first, const Matrix2D &second ) { Matrix2D returnVal; for( int n = 0; n < Matrix2D::SIDE_LENGTH; n++ ) { for( int p = 0; p < Matrix2D::SIDE_LENGTH; p++ ) { float val = 0.0; for( int m = 0; m < Matrix2D::SIDE_LENGTH; m++ ) { val += first.Get( n, m ) + second.Get( m, p ); } returnVal.Set( n, p, val ); } } return returnVal; } openlayer-2.1.orig/src/LineStrip.cpp0000644000175000017500000000445510441730664017730 0ustar georgeskgeorgesk#define DEBUGMODE #include "LineStrip.hpp" #include "Bitmap.hpp" #include "VertexListCollision.hpp" #include "LineStripRender.hpp" #include using namespace std; using namespace ol; Collision LineStrip:: DoCollisionTest( const ol::LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults ) const { return LineStripCollision( GetVertices(), other.GetVertices(), thisPlacement, otherPlacement, getResults, false, false ); } Collision LineStrip:: DoCollisionTest( const ol::Line &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults ) const { std::vector< Vec2D > otherVertices; otherVertices.reserve( 2 ); otherVertices.push_back( other.start ); otherVertices.push_back( other.end ); return LineStripCollision( GetVertices(), otherVertices, thisPlacement, otherPlacement, getResults, true, false ); } void LineStrip:: ExecDraw() const { Render( 0, 0 ); } void LineStrip:: Draw( const Rgba &startColor, const Rgba &endColor ) const { Render( &startColor, &endColor ); } void LineStrip:: Render( const Rgba *color1, const Rgba *color2 ) const { data.LineStripRender( color1, color2, texture, lineWidth, placement, false ); } Vec2D LineStrip:: GetVertex( unsigned int index ) const { const list< Vec2D > &vertices = GetVertices(); if( index >= vertices.size()) { OlError( "Tried to retrieve vertex #" + VarToString( index ) + " from a LineStrip with only " + VarToString( vertices.size() ) + " vertices!" ); return Vec2D( 0.0, 0.0 ); } list< Vec2D > ::const_iterator iter = vertices.begin(); for( unsigned int i = 0; i < index && iter != vertices.end(); i++ ) { iter++; } return *iter; } std::string LineStrip:: ToString() const { std::ostringstream str; str << "LineStrip: Placement: " << placement.ToString() << " Vertices:"; const list< Vec2D > &vertices = GetVertices(); for( list< Vec2D > ::const_iterator iter = vertices.begin(); iter != vertices.end(); iter++ ) { str << " ( " << iter->x << ", " << iter->y << " )"; } return str.str(); } openlayer-2.1.orig/src/PendingLoad.cpp0000644000175000017500000000126510377212142020171 0ustar georgeskgeorgesk#include "PendingLoad.hpp" #include "Bitmap.hpp" using namespace ol; OlLoadResult PendingFileLoad:: ExecuteLoading( Bitmap &bmp ) { return bmp.Load( filename )? OL_LR_SUCCESS : OL_LR_FAILURE; } OlLoadResult PendingFileAlphaLoad:: ExecuteLoading( Bitmap &bmp ) { return bmp.Load( filename, alphaFilename )? OL_LR_SUCCESS : OL_LR_FAILURE; } OlLoadResult PendingDataLoad:: ExecuteLoading( Bitmap &bmp ) { return OL_LR_FAILURE; //bmp.Load( data, textureInfo ); } template< class Type > OlLoadResult PendingFunctorLoad :: ExecuteLoading( Bitmap &bmp ) { return bmp.Load( width, height, functor )? OL_LR_SUCCESS : OL_LR_FAILURE; } openlayer-2.1.orig/src/Placement.cpp0000644000175000017500000000237610416457264017733 0ustar georgeskgeorgesk#include "Placement.hpp" #include "Internal.hpp" #include "Setup.hpp" #include "math.h" using namespace ol; Matrix2D Placement:: Get2DMatrix() const { Matrix2D returnVal; float sinA = sin( rotation ); float cosA = cos( rotation ); returnVal.Set( 0, 0, stretch * cosA ); returnVal.Set( 1, 0, stretch * sinA ); returnVal.Set( 0, 1, stretch * -sinA ); returnVal.Set( 1, 1, stretch * cosA ); return returnVal; } void Placement:: Apply( const Vec2D &pivot ) const { glTranslatef( position.x, position.y, 0.0 ); if( rotation != 0.0 ) { glTranslatef( pivot.x, pivot.y, 0.0 ); RotateMatrix( -rotation ); glTranslatef( -pivot.x, -pivot.y, 0.0 ); } if( stretch != 1.0 ) { float xTranslate = -(stretch - 1.0) * Setup::GetWindowWidth()/2; float yTranslate = -(stretch - 1.0) * Setup::GetWindowHeight()/2; glTranslatef( xTranslate, yTranslate, 0.0 ); glScalef( stretch, stretch, 0.0 ); } } std::string Placement:: ToString() const { std::ostringstream str; str << "Position: ( " << position.x << ", " << position.y << " ) Angle: " << rotation << " Stretch: " << stretch; return str.str(); } openlayer-2.1.orig/demos/0000700000175000017500000000000012262355751015614 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/linestripdemo/0000700000175000017500000000000012262355751020472 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/linestripdemo/Makefile0000644000175000017500000000066710377212142022144 0ustar georgeskgeorgesk#demos/linestripdemo/Makefile EXE_SOURCES=Main.cpp EXE=linestripdemo ifeq "$(ENVIRONMENT)" "WINDOWS" EXE :=$(EXE).exe endif ifeq "$(ENVIRONMENT)" "MSYS" EXE :=$(EXE).exe endif all: $(EXE) .PHONY: all clean clean: @echo "Making clean..." $(RM) *.o $(RM) $(EXE) @echo "Demo is cleaned" $(EXE): $(EXE_SOURCES) $(CC) $(CFLAGS) $(LDFLAGS) $(EXE_SOURCES) ../../lib/$(LIB) $(LIBFLAGS) -o $@ openlayer-2.1.orig/demos/linestripdemo/Main.cpp0000644000175000017500000001530710377212142022071 0ustar georgeskgeorgesk/*** OpenLayer LineStrip Demo --- Purpose: This demo demonstrates usage of the ol::LineStrip class, as well as common usage of ol::FpsCounter Author: Esa Tanskanen Modified by: Brady Eidson "Use it wherever you want, as long as you don't claim the code to be your own!" ***/ #include #include #include using namespace ol; using namespace std; // A helper function to return a random number between min and max // float FRand( float min, float max ) { return min + float( rand() )/float( RAND_MAX ) * ( max - min ); } // Enumeration to keep track of the color scheme // enum ColorMode { WHITE_TO_BLACK = 0, RED_TO_BLUE, BLUE_TO_GREEN, GREEN_TO_RED, CYCLING }; int main() { // SETUP // // Set up the program with all possible drivers // Setup::SetupProgram(); // Set up the screen in windowed mode with the window size of 800 x 600 // Setup::SetupScreen( 800, 600, WINDOWED ); // Load the font with the size 30 x 24 and a white color // TextRenderer neuropol( "Fonts/Neuropol.ttf", 25, 20, Rgba::WHITE ); // Test if the font was really loaded (maybe it didn't exist) // if( !neuropol ) { allegro_message( "Couldn't load Fonts/Neuropol.ttf!" ); exit( -1 ); } // Set up the delta time routines with fps of 100.0 // FpsCounter::Start( 100.0 ); // The initial coordinates of the particle // float x = 200.0, y = 100.0; // The speed of the particle should be totally random in the beginning // float speedX = FRand( 4.0, 6.0 ), speedY = FRand( 4.0, 6.0 ); // We'll hold a list of the last 100 positions of the particle // const int NUM_STORED_COORDS = 100; // We have to know when it's the time to add a new position to the list // float recordTimer = 0.0; // The LineStrip Object we will be using // LineStrip strip; // Keeps track of the color scheme // int colorMode = WHITE_TO_BLACK; // For the CYCLING color mode, we will start with a base gray color // Rgba cycleColor( 0.5, 0.5, 0.5 ); // Setup the "speed" at which the cycling color will shift // float deltaR = 0.005; float deltaG = 0.01; float deltaB = 0.02; // Keep track of whether or not we're reversing the color gradient when we // // render the LineStrip object // bool reverseMode = false; // Run the game loop until esc is pressed // while( !key[KEY_ESC] ) { // LOGIC // // Inform the fps counter that a new frame has started // FpsCounter::NewFrameStarted(); // Get the delta time // float deltaTime = FpsCounter::GetDeltaTime(); // Keep track of time passed so we can record a point each time at // // least 1 frame has passed // recordTimer += deltaTime; if( recordTimer > 1.0 ) { recordTimer = 0.0; // If we already have our maximum number of vertices, dump one // if( strip.GetNumOfVertices() == NUM_STORED_COORDS ) strip.DeleteLast(); // Add the current position to the start of the line strip strip.AddToBegin( Vec2D( x, y )); } // If we are in the CYCLING color mode, we shift our cycling color here // // based on the deltaTime // if( colorMode == CYCLING ) { if( (cycleColor.r += deltaR * deltaTime) > 1.0 ) { cycleColor.r = 1.0; deltaR *= -1; }else if( cycleColor.r < 0.0 ) { cycleColor.r = 0.0; deltaR *= -1; } if( (cycleColor.g += deltaG * deltaTime) > 1.0 ) { cycleColor.g = 1.0; deltaG *= -1; }else if( cycleColor.g < 0.0 ) { cycleColor.g = 0.0; deltaG *= -1; } if( (cycleColor.b += deltaB * deltaTime) > 1.0 ) { cycleColor.b = 1.0; deltaB *= -1; }else if( cycleColor.b < 0.0 ) { cycleColor.b = 0.0; deltaB *= -1; } } // Move the particle // x += deltaTime * speedX; y += deltaTime * speedY; // Make sure that the particle stays in the screen // if( x < 0.0 ) { x = 0.0; speedX = -speedX; } if( x > SCREEN_W ) { x = SCREEN_W; speedX = -speedX; } if( y < 0.0 ) { y = 0.0; speedY = -speedY; } if( y > SCREEN_H ) { y = SCREEN_H; speedY = -speedY; } const float SPEED_MAX_CHANGE = 10.0; const float MAX_SPEED = 15.0; // Change the speed of the particle randomly // speedX += deltaTime * FRand( -SPEED_MAX_CHANGE, SPEED_MAX_CHANGE ); // Make sure that the maxium speed isn't exceeded // if( speedX > MAX_SPEED ) speedX = MAX_SPEED; if( speedX < -MAX_SPEED ) speedX = -MAX_SPEED; speedY += deltaTime * FRand( -SPEED_MAX_CHANGE, SPEED_MAX_CHANGE ); // Make sure that the maxium speed isn't exceeded // if( speedY > MAX_SPEED ) speedY = MAX_SPEED; if( speedY < -MAX_SPEED ) speedY = -MAX_SPEED; // RENDERING // // Clear the background of the screen to black Canvas::Fill( Rgba::BLACK ); // Based on the selected color mode, decide which two colors will be // // our color gradient's start and finish color // Rgba start, finish; switch( colorMode ) { case WHITE_TO_BLACK: start = Rgba::WHITE; finish = Rgba::BLACK; break; case RED_TO_BLUE: start = Rgba::RED; finish = Rgba::BLUE; break; case BLUE_TO_GREEN: start = Rgba::BLUE; finish = Rgba::GREEN; break; case GREEN_TO_RED: start = Rgba::GREEN; finish = Rgba::RED; break; case CYCLING: start = cycleColor; finish = Rgba::BLACK; }; // If we're in reversing mode, swap the start and the finish color // if( reverseMode ) { Rgba tempColor = finish; finish = start; start = tempColor; } // Tell the LineStrip object to render the lines on our specified // // color gradient // strip.Draw( start, finish ); // Display the instructions // neuropol.Print( "Hit ESC to exit.\nHit 'C' to change the color scheme\nHit 'R' to reverse the color gradient", 5, 25 ); // Refresh the screen contents to show this frame // Canvas::Refresh(); // Check for keyboard input from user // while( keypressed()) { int key = readkey(); if( key >> 8 == KEY_ESC ) return 0; if( key >> 8 == KEY_R ) { reverseMode = !reverseMode; continue; } if( key >> 8 == KEY_C ) if( colorMode == CYCLING ) colorMode = WHITE_TO_BLACK; else colorMode = colorMode + 1; } // Yielding the CPU is good etiquette // rest(0); } return 0; } END_OF_MAIN() openlayer-2.1.orig/demos/linestripdemo/Gfx/0000700000175000017500000000000012262355751021216 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/linestripdemo/Gfx/Bitmap.png0000644000175000017500000006753010377212142023154 0ustar georgeskgeorgesk‰PNG  IHDR(S£÷ ø pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFduIDATxÚìýÇ“d×¹'~G]á2<ÜCkZk Š$’à#¨ÉWU¯«…õLmºg1‹ù f5‹1ëYÔØŒÕTWñ5‹âQCk ‘:#eh•¡<ÜÃÃõUGôâDÜt$$ØEB°°HëWœs~çÓ¿Àgû@aŒ€RJ)BƒRŠ1–RRJBJ)„|yümJ©”Ò0 PJaŒ•Rá_ ÃPJ5~„>ùò¸¿°?³`S;¥TŽ1FiŒ)¥!ús)¥þ«l8¾œò¿âAÑ[ža®ëÆãñ 0ÆzÌëõºR*RJ}ß×çø¾1B|9zŸàQJ9çz¿ ·R)e(Öô¡!þ$„è™B(¥„~_"ð/ÚòÂá2MÓ0 BH©T"„˜¦&!DJÉó›þçç~/ûì<ŠaBÓ4Cõ2n!J©Öp½ñ÷–”RÛ¶1ÆŒ1}/µÐ³¸B¦irÎc‘HDò}¢Ñh(»ôìhFáœ;ŽnŽRJ˲8çÿ5²No¬zBZ¿µ, !Ä{`Þ¿Þ-êô~É9×"„„’MOj¨ö4*œú¯á áïZ/Ò?À/àŸP4 Ã0M3DišZŸçœkOïkA(¥8çÑh´R©hH„âÈqÀÿJ[#‰è»k“^ßsn¦_ïÿøø€ÞÕôXëM´Ñ„Ó3­G?ÄU(CÙ¨%aˆ:­j†¹a–e1ÆB³ðËCŽáX,fš¦+BcÌq­·kƒM+#zék˜qÎ#‘H¹\ŽÇãŽãX–eÛ¶çyœóÆ]ò/]!øµf«!§oýØ>ïB}Ѝ A¥çXcIÏn¨%† 5F­ü4ºOÂ3õd4z8Ch[Kª¹¹ cH·$Ó©¤JJ RJËm­®çsÙ­ÜæÖßüLÓ •Cºz½Fƒ „(%:;[ãѨP¢¹)ÑÒ’²M“Kêü¡g !²¹Yº|õÖÆFá/B…^ ÚMF¥”Z¬iÝGJ©¬¾K¨æh„ ¼5¾Ú$h”u?ZÊi…0ük-ýÅð—PÉBèÑ×zQ8…!z[[›ÛZR­™ææLbgw'¤ú"zRòp:ײ›k+¹ÉéÅ/¶ ³, <Ï#„ض-¥ô}_)eY¥”1ÔÛÝÙÚÞ”ij"Œø¾OSJ(…Aã RrƘVAƒ Ðj ÷y ‚?¼ð^¹\ý‹PÇ-ËÒpõú»ZúÐ3¤±Š„ðQ „|F$FÐÙïloO§RÑd`i¹ÍUB‹+…Å{›<ÛÁ½Ý‰„5:ØšŒ›J©­Íë7ï”* $pœìü"$|NÕ-U¤”¦i 0‚"$7†lomîééH§S€˜ Áw'׋U¸€÷®.º.ÿ¨ë?ûÄè}K3—oM×”üÀ „€€og ¶A×××Õ’Nõö¶75Å@r™ÛÚÚڬܜ¯×ÝP… ÆlŸ÷ˆÑ' )Á˜2™²m RjCN_ª¿¿·££-ëÍðÚÍ™™¹Õ|¾¼{¬'·î$D)„pƒ‹’@)¤R‚H +k…×§víêïïíÈå6_{í].¾€4…„Ïø¶‹`…x 5%" }!mË%M£££V$‚)VBåóååÕÜõs®Ï‰Èž]Ý&3F‡;c¡/Cu¶uÎ¥ç …!4ÄÆFþâå;¥R0‚ (ƒB@)4ÅÐÈî½--m±XŒ1æ8ÞµñÙ­RõÖ%ýÀ­™Ä¡Cmp黫ë5ƒ€^ R’P÷Á÷A*ðøœŠ=ô‰‰»Fç‡Îó •I °ÐyÕ"¥išÊ$Àض0ÔþO„Ðè®á––Û4Bù|ùÎÔâÄÄR"Ù»»ïБP'AZÒ‚€À 66 ¾ïB9žä"†G‰ˆµBçÏߨ=6N7]¼|sii•s”ꡬü¬b# Œ¡³5*AD‚ 0MÓŽÚ™æf½œ¯ß˜žÏæóÅ¡Žt:yôð°RÛÛ!Hréú~½îbŒ•PU×-•\)©DlnnZ–µ±±Q«Õ‚ PJ`ŒF€°ÞR·Ÿ$fÁž½»ÚÛ;“É8!djfõÆ­ÙÅ{¹ÓÇÇlÛØ5Ú­”B­¬m^¿5ßÝÙ|poÿôôô; „€ $øH¹½fý@¯ ½3þÝOï‹B˲B×h­iju£»%T8Ãè€dDÙ&"HÈí˜R&#¦‰ú{;»{;ãÑ8Bbi¹póöòäl¶¯'½o÷Ø@`ð‡z[‘X•JEÇqÇ÷]‚P÷×”†œ}ýýÝÃÃÉD̶ÍùÅ·ß¾OF÷ŒööõµH,D ”Þ…•”òÝ w=µ?—;wþª€RX¨û¡Âfáó¨rþM€§³O<ÏÓÉ¡jÞè;–RjR»ÅÂй†AÈ4ß4±bÇ'©, ZÒéþÁÁH,¦Êç«ç/LÜ[Ùlk‰Ÿ==ÚÕ‘Âgs•K׿î­l?<ØšIôvgt´ïæíÅñÛËûöôíÙÕëyÞìô¬žB¡ˆÏAJåA2ZXZ‹G£©tÓëo^®Õí âœkï¶Î‡ ç[©ÏŠÐCB@w*n™¶©UƒZ­ÖÖÒ¶wÿˆmÛ áöäÂåËé–äþþt©–ëõº_,¹TJ(Ïsc¢PÝu1¸¾Ôjd{{»ïû¹\NaÛvµZæ~ƒ¯}Q!ê(‚!‹îÛ·«µµ5‰är[oŸ¿¡”8}|_gg†û¾BÈ­»ÅbµR«W«ÏóÚZÒ=}] «ét*‰üîo–Ëõ0+mÛ¡ýA÷y”xô¯nÄcŒuàEÏ·6Ïs,µ½§]Ɔa踜Ýh*áÙ&6„®À`Q0 µþþá–Ž6¥ë.LÜšX¶ úØÙ}vu#¤ê¾xã­ñ{+›gNŒ}ý+G¥”œËááþÁáþß½p!‹õô´DbM…BÕXBrß÷EÎ-Œ@k&½–ͧR “ ÕRE?¿Öo1Æ–q!)?3sŽÐ¶M¥!g›ÈaT©mÛ‘‘‘‘‘¥D6W|÷ÝqŸósè”’s.+•ºRÏÇJ„ªÕªØxòdYªV«éu?77;éDW#$ 8;Þ-è(BðààÀÐP_4E¿pãÚøôWž<12Ô)%8ŽW*U …¢ã¸˜RÙŽ1)Uê=Ô`3 È `Œ0ÖFˆR~’þÊÀÓÖ—Öã!ötÈH's…ѼÐÛaÔ4#ƒž Œ‘e“)FP{gOWOiÚRµ›sç/LÀð`û¹G÷[U ¦ç³/¼rmïîžÿ៾†´õïóÀó\ß/Ýææf+AH}ýk§ßyo¼­--±UácÓ4™I%!·î ­‡)Å¥THÝw'ì8Ö !­&tK‚ïK.%`Y–ïKŒÉÈÈPGGc|m|æâå;»võž=}!Å9ßÜ,—JÇó,ÃØØØ Ô*pj!¤^w]Ž9)eµZÿPèL2"’+©¶õ=-è(A¦iî?¸§½µÕ²Œ•µü+¯]îèhùïþ雌‘ 6ÖóÙ\AžÇó«5LI’ Û¶„@®+i ]ZZ –í¤%}¢©ô¯(ëBŸÇ–ТÕNBˆ–r–e¹®‹1¦”‚”˜“!†$Ac$%ËÄQ›P ã»Ò--J©¥åüû'7òeÓdOœÝ7Ü߀áý‹“—¯Ï=ó•û†Û%(©d¥Xò}ßó”ëƒP$‹läË-é8B*‹H 5ÊÕ*#¤^¯3Æc‚HOW›eùüV,#U«u¢_M«ÁZ;WJrŽ”"‰O{ÿ%(üA£Á4("ÄqË2FG‡ººZð˯^œ[X}ꉣý½¡ÍÍr¡XᜋE·^BpÉ…(+!„A€ê>ј¥ÚÞÛ7 $Á,:J€RÒÒ’Ù»w,bLß~÷Ö‰¹¯<~bl¬Û­×ó…ÒÒÂj¥RÑu$zðpE sxxPò‚cœË•óu…_˜LÛ¿ðtP[g04ÚryÉŒ±`g–´èó§PüëÏu]˲töIˆ«xZ¦i)§ëëBsŠRiH)#eŒs‰1¦S ¶‰ºzúÚ;»Rùò‹¯^/—ëpúøØ‘C ¹Dýêï»>ÿö·N'bVà››¹jµÊ}p9Ô]Ž1ŠFMÛ6s›[ñd\)¢ ƒB8Ž ãñh¦9‘hJ´µ5K ·nÏtt¦äw„H µ#ðTæÀ( àÓ™|½ÜÑC¢¦J¥’ƒƒ½¡7ß¾º²–{þ¹ÇZ[Sž'¦§—Šår¡7M³\,Šíc[c p¡´ú()zàC ÅÔ0F‡ûz(¥S3+o½s=Jþ›ŸNb@¯¿y¹V©ám¿¥õO úû”xÚù¡ÿB­òq§?Ô…­zzC¾É}ÛÆK‚Š0"¹Ä„ Ûdñ(ëínÎ4¨«×çÎ_šË O?u¤§+­@!…Ãkoßt]þío7sœÚʽEÏ ê.÷#D QÊA¾Ïmfnä‹Éd!D).Šßxöܶ£RÊõ‚÷/ÞìjK·¤š¶¶Jù¼A±Ï裡pŒnï²J)ŸBøS³ë>(vô‡ƒd2ÅL3‰´ud¤”7nÍNL-=õÔÑL&U«yKKk•J%·±Aµ\æ\j¼i•YÊu—®À®C䣔‡íI§ÓŒ±wÞ»ywr1•J>ÿü9%DµZŸŸßÚ*ù¾/D‚‹û6¡ïrf'Ž9HD ÅR-[¥Jµ^×¹´œË‡:à?;ÎäOxÚ¹§Í¶ÐqÒ¯kÌôiLÑ%„‚3#€¥O –K) JB†AÓ©èÀЈº>ñÕëËËyhÍ$žyòp‡rU*D…P”RfKKY.WTG‹ãTZZâ’ÔÒ’ÒvRjvzis³’Û,9³¿%—RÞ¾yÛd ” â;ʤÁ¤¡p > Û?yq‡>¤h! †a)„,ËjiI%ãñj½>>>}èÀðÐ@/÷ù©YÏ rÙ5ß÷…øä´á‘@Èv â«gu¦i8°«¹¹^yíÚüâJWWË׿vß*–'''ëõºÏ}:.Õvˆ#lG’ÇNŠDì­­rµZïëëôýàÂ…›AÜG|¡P÷x”RÏótÑÔD ¸Utð Ì‚e#Ò0AB"¤ñŠ1ƘZmoÏ B²›•—^¹¦ÕËîÎÌ·¿~\b$çÌ$åª{m|ö‡ÏŸ‰´Z¯ÎÌL¹.¯Ô8UHD,d`Žhëˆ5%"ùüf2nt½Ú&R-©¸ÁˆÈm–~öËwõ£îÙÕÝÓÓòØÙ=P­VnݺƒT%G~ ¤RZæ </@\âÐþùTRu1ŒT´0LP<žTJaLS©$ÆøÚµ Ã2N? ¤ZZÊV‹Õb¹èx^¨X> ðÐ`´6êÈ,%`0`ŒÚvtïÞ±ææ&ÀèÅ/¯®ç››Ï={†s?¿Yœ™šª×ëAàù¾ Á€1`@éÖŽƒ÷†±¶–¼  +‚×ß¼â8Žïûâ#ŒçÏ;êþbà5&X6fuýÙCq€2™ (0ÆŠƒ €¶Ý¡Ì¶YWOWoo/Æ03·þâ«×õ·öŽõ<~n¿<mÛJ¡Wß¼ñíožŒ%"µZmjrÂq„˱ωçIŒçT!j26Ô4êútjnkßž¡|Ñ5ãÝU—Ô< UiXÉüñ3!¤"ª®Z_/Œßœ %eT—¨èp?|0#> 0|Zzæ‡íŠ€bÊL“ ”LÆmÓ¨»õ‰©¥g¾v ´‘Ý\]ߨÖëõjý¡ ¨ @ü¥¨3ˆÙ»w,•J*D^zñ’FÝ·¾~V‘Ï'ïÞu]×÷]/¸j½k`Œ2™ŽãÇÀâÒªi²þÁ.Ïó_óR­V‚à Œº¿xÁuZ ©à0HƒIƒ*F$‰1H „ ̳,«»»»§¯ ®ŒÏ¾qJ_äÈ¡ÁSÇÆ ^¯W*5ÓdŒ‘{÷6{ºÒ™æ„ï¹ÓÓÓõº,×…R¨îrFH “ŽŽ–HÄÊæŠŒ rii}×h_µR3(E U+õX Ty«¶²–Í®mV]×÷9D J!!uR£k[¿Ú§#î ôq§”V«ÕöÎΦ¦Æxbb±³3ÓÙÙR«Ô&&–——…â#êštªQG郆¨Û³gW*•À˜þñå‹«ëyÛ4¿ÿ+$Š…­™© Ç©<ðù6¤‘N"ˆ'⇊Ǔpkb¶«­%•NÔëÎÛo_©Vj:3ö¡ËK~!P÷—OçÈi^7]Ùõ§—v¢è@¹”’e`aR0¨$L'è!ˆB³,«¿°½=o¼sSÇ ´óðÁA(Šår¤lJ4!„fçW?·WZXXÚÜr\Wz8Ï9c¦ÁhSSld¤_‚œ˜X8y|Ÿª\®*¥|ŸG£‘Í­òâbVJBHÉu¦ëº^°ÍSæIOJ €Ãˆ0C@»Â?­9Cè!‹m—ùÒ––6É·=ùâ`7R(›-x^€1õ<ñ'Š-> uèè3XÄ´‡Gš›‘?¾xqu=ßþIŒe¡Xº{ûv½VãA Äö(„!Õœ:yò$Æt³T^[ÉØ7‚ ÅÊ›o^r]W!¥zˆ@V ¿@t9ðtF¬®(y(ä«¿‹Y9ç„(†„AÁd€é6Y# G£Ñ¾¾ÖÖf¥Ô›ïÞzu¡\6W*•”v4jÚ,›+µ¶&BóóóëëùºËL¤¤AQ ˈ` –a ö!ÆoÎôö¶†Û·æöíDIäÒòºã¸úI|îsÁyàs.Ú˰òò3GÔ‰®\h}$D<Ñ^ÜjµÞßß¡Z]ÏB8Ž÷'ÖîïG0­a~ŠÌ`+ÒÛßÛÖÖbÖ ¯\Ѩû‡o<OšÕryêÎDµZõ|îóõAkk|l÷þd2…™˜Z4 ºw÷°Rê­w¯g³9íMyè8aÝ_¼Ðe§“žõ* Ëç€\èoËꤔ¶I *âŒJà B(îsÆÆ`0F©58ØßÔ”Býæ…KË;•§OŽÚ7€1^]^-–‹ÜõBÉTJ)´¼š;qdÈ÷åV©Vs”ãH NÄŠ¸¾KJ „GGû¢ñh.[àÜïêÈTju×­Gmkum£½µ¥T) e„)wÐæº¾Ï%4Ð*…Ã$Ÿ•C=$~¥©O"¶m !‚ °Mà”V.×VW7*•êÇ—;ñ$Äè†aÒˆiëhëín'”^¼:=¿¸Ÿ;ÔÓ“ö<÷îÝ»¥JÉãÜ 0Œ¡5onnÛÙܬ.¯çû{Û±h­æ\½~w}#Ç— uù–l(qP >ÿ\~9ðôú3 C§)êD“20Wj(ëB'»AbNˆ´(` œKB°¶ë¨iÚm]©T~ýû‹Ë«ùЮ;v`H¬Ü[Éå²Û7ÝÉÁE „@KK˹\Å劖ï»`2›ëkjŠ •[wæÎž=¢”ššZسg8Ì8ššZàü>iÒ6_„vÏѱ“€n …t:MÑ â¤ïº¶mW*—ïä¦4î®ЦE,ËnÊ4÷övBffÖ®\» {võŸ<¾g3—›˜˜ÚÌå<Ÿkõ’hMÇRéôèè(Æ”™ö•kS‘ˆu`ψbemãúõ‰j½ÞÀ> Ôû|QÙéŸuH X#7^EhL (¡’FˆbDDa¬UPİX,ÖÚÞÙÙÙo½w;DÝž]ÝgNì–J­¬¬lä6ÏÛæ#ÃØ÷]Œ™L.×y­ÆS†aq)1¦Édtd¨7™Œº.¿}wöäñ}H©É饎ŽÛ¶Ö76;Z[ªÕj6» $äô‚Pt*¥#ãŸFéÑhRgrK.Aºø·X,~Lq‡²íîu–‰ Ê%ƒƒ½¦iмþö5H¥âO=vhkss}cc}uՏ޾´·Äš››GÆÆ!”Òñ› RÂþý£çÕ]çÒ¥›ù|A!…ØNN“ vÒS>Š9âïxºlÇó¼ÄzV„ÔΡæÒ1!ŠÁ ѦŸÊ4©R$‰´´µut´a ï_œ¼3±]ùßÓ•~òÜA¥Tv-»±¾žR c&9Ä"”jœK$ˆB„bIP‘H¤««­¿¿K(µ™/Þ¼=wäȘm³õõÍõõ]£Ç=/ !¤nݺ+ï>mçXîl%;Á’Ï.eªúíP!Ä¥¬9Nʲj5/Ä"… „ã×q’ŠI˜LfÆb±þÞîˆeq.ÿ˯^ÑýηcŒä7*³““BÁ@oKsssWO`ʹy{!²k´Ré»7nÜÍmnÕjŽV£táyèÝ‘_PÝòã¯1&&a6švu ZÔ®ý Å`2EŒD° TCÒ&6 ˲¬ææLGG!øÚøÌÕsú"­™Ä³_=Ê¥âúê²ä>H`”%LËØ©¾Ïp¢)a!•LÆÛÛÛR©d$bI)§§—æç×?wضY¡P¾}wöôé€a-›ïïí¨Ôj›[%LC\ä÷—Xñ8øü1O+¥|߯×ëRÆ„’VÄ ÑÝÝ>Ð×¥-±?‹:¢5̆p%ÀPô£ÑÖÖÖT*i›æߺì8}r¹Í©©¹CF±ÈÊJ¾5“Ä®]¹ŽAJÉ@,ÁB~ ³D"qüèî––TµZÏå¶.^¾ó™êz£ÔƒE@;Ê™Tš¯Ë …bwgËP_×ÌÌÒÁƒ£»Fûþð´QG?¤db Ô ¶m'b‰®Ž–XĘœ^[X€ÁþöãGG+•šS«>zX“LÂ67+“³³¦ÉíÀû¾\]]Ÿ]ÞÜ* !ta£RRKo)?ÇŒ‰}à騱¦$‚•Pè5&m<€CŠ1Âa2 À ÷ !ƒ¶iwvvš&[Ën½þöðŽÏ|íh*wÝúò BžBm€ˆXÒ6m¡$5ç.Æ02Ôùû?¾wæÔÞžŽäxÁÍÛ‹Ó³+pêØXWG­­¬,ß»×’Švwg\ŸcŒÒéx6»©·mÓõM¡`I”‚&ý³£-}êÔýHѨÚñxô¥WÞÿLO¡c aØCJɹŸÍº¥žŽLkêîô|­RomM?qîØ;ï]øGšvxøƒñFÀ2PÌ6SM‘áÁöhÔÜÚª¼ôÚe°,ãÙ§ŽÕj5Œ!•NSŠ}WÎÜÛ˜_Ìövgž8»Ïó!‚Õåü½•Üúú–Bé­AJØ[|Ám¹¿xºæ@ëíѼ†ô²ZhL1¢ Іƒ@"¤‚@`Œ"1J +ÝÑF \­º/¾zÕÛ±=NíhKÕëîÂÌT­²‰±—0€ e™ˆFÌ”ãxžÓÕ–:{rÏ»ïßþu®¤¿~æÔ®GNîêéJ€çxkk+[›¹–t|×¾}HÁäüÚÞÝ}•šs÷î$`L‘ˆ3¤ε÷U§Dƒƒ½}pwréÝó7±Èãîéjh*˺,=L,¾ŸÑ¯ àŸ(ÕŸ”FØRáÿ!uoe-–°Ïœ:ôâËçÏ>r°³»íé§ÏÞ¹33¿°ö0íJ>ð &Û‚¦%¬ŽöÖh<ÊzãÛ;ñžÝMM¡ÔúFñÞ½ÜÕ³G u¶%÷Ž´BÔëõõÕåB¡¼º^pŹЛ‚p‚ÌÆþ;9ЇLômgIØp>ÈEºÚ‰ìÃ#ŠbnPe2ňB ! „fš±D¢¹¹µ»»!õÒk׿Öõ·†Û¿òøaŒarrzcuK?„1!D)„±4BHD!¦Ù»·Ç4RxûaDÀ1ÆŽãæ Õ™™eJ1BèÔ‰=vÔžœœè2MóÂ…ñÀ«P¬AžçyŽòSÂ,ËÝ5œN§àÒ•‰ñ›³‰Xä™gN&b‘­­Ò{ï]ü¨^_JaׇJ-ø„ÕQM²>£@)eŒé¦:ÓmÿÞ¡ÖLºæø¯¿~á‘G77'=Ïñ}?—+ ÅB¡œÏ¾í´d;>¥ §ÓJ§ScjéTK$Œc“Ó¹_½ ¶mž;³·îz—®LŸ9±;“‰µ·&D $ÈZ­V.äK•­B¡èºàÊ÷Á÷E Àó€ÿýi•Kâi}ÍYßXíßX|ý€ ;ƒ)‚$!Š0…±”€@(B°Rˆ†aXñh²½½@Î,dCÔ%b‘³§÷ÀÊÊÚÆú†PAè&Ýi^#H"…0¦ <5µÞÙÙ‰X–Eõr/W¥åÍÍ’®³¤”ž>¾—™ìÞ½µöÖf‚ðÊÊJ±°N±pw^ŒÖ±¯d*9:<‰E|—¿òÆ•åÕ¼aЧž8’ŒÚ›ùü•+ã)ô!»J!äºAÝ•®ÿ),&¥€‹mý!ý¿@X)JFݽ;k ÍÍMÏ|í‘^9ßÙžÙ=Öß”HÄ"‘Þî]ŽQH)BưÃ"C0!Dç@X–E™œ^Ó¨€Ñán!àȱý»û¥äBˆR©V©T²Ùl¥T✠¡jò]åxàsàœ|¸ãÏ—À{Ð-fÆ)ÃzÔv¶waš˜A5ÀÀˆ‚ dÛ)Š1¦Ô Œ%ššÚ;[)žÏßzçfx¯=yØ0h¥TZ^^âÒ‡†þÚJ¡@ , ¤ÂB2$(ÆC¡PÏåjAàAà8ŽfRbŠññ£»›šâ…͈Çc…BáöÍ[–!”€¶ý±+ÀÈ2Xgw×À@ŸÈåʯ¼qEW!}ãéS--ÉJ©róæm„cZæë½F@ ”ïKŸcŸëÁùtÖ€$P@#enlÒÀ`‚šššîojnþÎ7OÏ.®¿þöå­­ÊÙÓû8çí­‰ÎöBÊd¥„À „P†e”*î‰5 €Ï-e§g³=]ép“íîÎ<û”®ŸÚBJ¸õÚf.[*•|Ÿ»¾ åxÊçÒó æ© xÿËã>ð¥ÙŸ P· Ñ;¥@`1¢…HÐDlÛŽÆb Û¶àý«“:ýNM·$ݺ{gj­»÷KÔ¹¤”bŠ…"¾#$p„¦¾’3FÏ£W*Bˆë»J).¶—OÜ×Üœ¬–k››¥Ñ]}Žãܸq“%¥ÜÖÌB„ L#»öìI¥SB¡»“K¹Í’aPøú3'[Z’•J寭 Ÿsšk# ‰@¹\ AênðQ•šŸ¤è 8|Ž<Em©gÙ¦ŠD¨e½87;šZ2‡vÅí;Ì¥ºqkÝ´ñ»î,-z;®Ô¡} )¥øwŸ‹F÷Õ]ôÿ¾‘ˆñÝçŽpî Ål6»¹Urvd_{{sss«‡Œ ¤ÆÇoy^ Á Æu4ÆÔ°:ºÚF†F ·Yº3±xøÀÈ˯_ÎçËçÎì씜OÞ-W«Jµmó(ˆ”çK¥ç¸êª‡Ò}ºÑóÆæ÷CŒB„PkÙÒêz1³¢Q“’HXñ¨HAC ¬Lß÷9fÚ&ØâKW¦VÖrðè™}¥Jefn©\,k _(t»BRçàñ>Ÿ cCš1!èìÙñXZZR--)øøØ Ë5?ðø])aµël,üÑ`¬Q)É•~¥Æ!ƈ‰%MMRÊÜf)LÈ)…”Ò T½.C"ÍD"ÖÚÚÔßÛ©·Æ\nk||ú£ú9·¤SŽ|Ô™‰Dlx°»¥%ÕÜœÐ'\¾|§ø±[«>`2hìÉÔ,]¸Œw„cJÇ^€fËÞÉ QFh4n`, 1þãO_Û4Ÿÿƹrµ¸±±±¶²âûNHfWêÞ=îØ’Nµu¤Û[›õ»A°‘/Þ¸>¥5:(ʹÜÖÕëŠ.¢žž=,zxǶVsšo„Xͤc©Tº³³UsÒ‹ÅééùR©Æ¡†ÑÙÙL)¾2> ëôqÜÚÚüÔSgJ¥ÒwÂn< ±4Ì%LÇr§9Loó<ïOÅñ4kèÆl¤aÿ0ä1­šL1"è¾{†bšv<ÏdZ;:º˜©|ŸÿóÏ_×n•³§÷îÚÕSÈÇÇoר$h[übÈ÷Q "(ÌÆnìà ;ýÝÛÒÒä9þ­;3'ŽíVݺq·Ïb¼ÔEîííícc#°¼š¿·’?¼X!¤QwèÀà‰c»Ü  Zwßyçbà€Q P¥!étr÷H_K[)%á>Rè•7.nn–ÂÆÑãžž¶®®¶öLÓg¾þö•­­ ¥ôèÁ±îÞv©RjûÕ‚ xùÕKZ›ÓM`>~¨PßWoä‡þÜ0À$Ê0”N—kŒâ2ÓŒGã­­™D"bÛö/~õÖZv¾ùÌéîîL>_¸zõºãÔ\ï!ÙÌ¢¡Û+ÆØdìС]z+iÜþ aRÊjµ‰X.½õ›ï^Ó8)å®ÑÞîîöXÄ µ}m(¼õÖåÍ­J#ùH:|ì‘à ©F©Ím½ýöµFŽœŽ¶äþ½ƒmmé0ËJÊíðÉõëw}Ÿ›¶ÙßÛ‘HÄ^}ýêüâÚØHÏ#§„W(Ëï¿I304æ*E\Ž¥Ä Ÿ(]ÿª&€nYVØcrÁÂúWØIà J±IcŠÒÅf<žljjjmïhkipçç×^}ó:tu¤Ÿ}ú„RêâÅ«[[[VˆuwrÎ —8œÚP×M’FOÛ“L%jµúäôâ‰#»•RwïNnnf)ðm}€ŠiWWÛÐÈÆpõêŒBèøÑ!Ï ~þ/²¹Ò=½_yr?Þ¡ª½tevi9·°”7MöÝçŽ õ¥K¥µù›>×.)c¤g`W¢)£×Ñ[ËÙ\Q÷U<{z׉cÃËKs¹ì=F˜”FÓm]©TŠbYª9믿;ÞuâÄhµ˜¯×«é¶.F˜BèÚøü;‹Ùl þáÙc##]+‹÷ÆoOr.]×w1¸þÎذÐÕGô^½ßôv‡Žc̲¨d Â2ªav4ÚšimëHY–uáÒÄÕëSðÔGì*WËçß½T,Oq€Âæ$ÀÈ6 À¶ “²GÆ:Ú:˜iK)«urzmñ^~v>«sÍþí?>ÞÑ–œ_û?}:ÛßîH*Y™~7^$ÖkÄFTJ˜¿·95µ2~û<ùèî“ÇG*¥ÒÌÔøŽtÀ‘DSÿ¨BèÒ•é·Þ›€TÒþÁwN'ãÑ»7/:NMó×u÷4gZ‰R˜Âøí{ÙléÊø<þèîÓLJŠù5Ï«ÙÑx$’$ÌÜ*9?ûåù­’ɤmYÆShmN¬olLܹuŸ¼K÷Þð9öâs(B(ݪà£B)´Ñ‡B>ØiI¥? [Ø…· {Mb¬$HR˜Éa” L¡Ô°Í(!( ·YÖ7Ú·oP)´²²Z*U"AàëK…J3ÆX)PÛ^SÆ ý®Œ±T2~äØÛ¶¶J嵕Üñ£{@©;·&J•͈Awbn$™´÷ìÛµm…Ô+¯ÝéìÍ8Ž÷óß\ÈæJý½™¯=yPçX_¾<ýæù‰“G‡ÏœùW?8])9?ûÍ¥®®GÒ-ÅÕZ¡L-³µ¹-ÓÞI©Å9¿xuþòÕÏ ŽúwÿýÓ¦i¾÷þ]Ši"‘¨–ã”â–¶®––!„ç/¿7¹°œ?¸»ÿÿú?}üó/ß=|%Ó]MÄ9Ÿ]̾üúõÑáÎ'ÏlKÇ%àŸþâ­®®l%Êåz¥®lƒø@ìàM€”ÛŽŒÞºQ‰;­ÎA4{/ˆ’°3ÂLÓŒE"m)Ã0nß]Ò¨;t`xïî~ÇsîÜ™(—‹^ ”J€ÑR]±*ˆÅp__×Áƒ{a©Å{›®ÌÌ/æL“=½çÇß}Ô°hvmóÖÄ’ï·jÔ¥SÑŸ|ïd"ayµ¢ æö#ñT«RhuµðÚ{·Ë]£ßxúÙùÅ­Ÿþâý“'wÇ“iðÀ4ͦæÖæL'"jüæ¢F]S"òÃïžN%íR©èû¾iÛétkº¥‹ÆpáÒôùK3žœ<:ò?ÿŸ¾aXôwnûÊ ”Ši˜àpgbõë_;ÚÖ’ ­­•~ýÇ÷~÷•ï?ÿx*ÕˆY­ƒxA !͹BˆH)Á„¥Ø ¶N˲4v´Yô ð ÃÀkž]€G)¥”ŠŽºŸV¡p×AvιÂŒ‚‘P‚ `R@J l0ÛŒ–!%WJ­®æ ÓœèêÈ8Ž3ywžû<ÉLMq‹)©B’K!„s° þ W?p_OÇ޽ÔâÕõÜæféÀ¾!PèÖ­»N½HP@)¥„ ––äðè.ÆØÚFqzvõèáád2Z­{¿øõ…l®ÔÛùî?œ¥îN¯½õÞÝÑáöÿùß=µÅ Š'£P¯úŒ²«‹utõÅ“)„Èì|îÕׯ—*Now景N$"PÚª%S…T½Z5m³¥¥+™L¸qgyüæÒÞ½ýO=q $G­çJ‹÷rµšƒ1(…^yãBè_ÿðqÆp}^¯{žl•*‰D$™J"â#„ ò…ªÎ-Ö(úK ?!B hö!ðî›è”€i(ðbM‰îÞvÃ07Þzç:Þ?òÔ“'J¥­¹™¥¥¥eŸ P:=m§BB À˜º»;û{uåZvëõwï,.æà±Göœ<:dšÌ0(ÙÞÞôæù‰7ÿãØ&û×?<‹Y•­r.·ÒÒwÂ4£€‹—gîLÝ{üÌîÁÞ&íÀ¸vsÉ4™ØÆ–iÊdRéüÂ¥¹kã ÐÔùñwO¥â‘Jykqv2‰´v$Í`ñ^î…WÆ‹åzoæé¯iJDBÅb9•Œ0¢0ö[[[)¥žç__<´¯—™¦”P®Ö_|õ¢çž,/o w67E666R1 û>  Œìs$ò<¡Fè.aŒ…Ì)ÛÀkìÝ£›Š0ÆBª¢PiÌ÷ ÉŽ(¥)(A®§À2¥ŒRð,ÆL!ê/”`l¬!T(ën] 4¡ÞÑSý `Œ!×—†¡Ép±R‚1ÝGÖ€¾¾®}ûF0À[Ó†aØ7ß¹uË­‘⌌‘e¨¶¶Ö¾¡ŒñääJv³øè©½R‚ëú¿üÍûÙ\©­-ù­¯õ]ÿ¥×Æÿ{ª9Áâ” ue|±X¬§SQ×ç†aõô ˜¦­zéµñ›·à±³{N RB©T¿»ôÄÙ] >:ºKJìyÞ¯ÿx½·»å¿0FHPe³…þÅ{Éd4™´³¹ÒÛïÞ:y|Woc껾B„sþ‡—.xNК‰`™&qj3™.Ð& e; àcÚ}ÛÍFèà lšv&Ó<4ÐgÛV¹ì¾ðÊE8rhôì#jµÚÄÄÌÂÂ’à`zŸcS³YƒFq2•>tèePŒá/_½~k Ú[›¾úÄÎÎ&Û¶ R&#u7Èæ¶nÝYÓdÿôã3‰˜U«T …|Wß! P®8¿øõû‡÷÷ÿ7?zƒDÆ~ÿ≩ÕS'FB^­bšfG÷€eH©_»‰ËuÛd?ùÞé–T´RÙZ[™K&“m]ý¦/¾zãÚÍE­Xž<>¦—t©T»~céñGw!¤šDH6Wš_Ì<>"”/øÃ —JŽhó<¯TÚÎËçR …AX(P #âŠKÌ%"‡b¨dZ–¥ Ê·±£UGÝK¤Ñi¢ñ¾p¤T[üú¢:%R€¥TŒ XHAÀ#Š1Õ ‘’•Š£/2Ð×­š]bÛS¼Á¤)¹Rp„°¢hÃ!‰EöŽ d2i%Ä»o tuud”R·nÜpëe SŒAZ–Ì´¶÷ Ž „.\šÆ9¹û¾ûËßרûÁ·N..å/^=÷è4¥ƒPH(d …Þ¹8óÊ·è߯÷ŽÄV׋¿ýãåb¹Þ”ˆ|ç›ÇÛ;›•ˆñ›s[[µ'Û‹”ÚÌÎôc€ÛSk×n/=vvOk¦¤ÄXPŠ×׋?ýÅyÏ Îœ™›[½zcñûÏŸ±mS÷öÚXÛüÍKWJ¥Ú¹3» Šëõ*Æ`2TGbs‹cô1§øÇsÜkÔ±‡¡Î`È0¬¶¶–={vY–U*9?ý/¯Àé“{îö¼àîÝÉ¥¥e¤\¤‰1ºð B4ÕÒöÈ#'MƲÙܯ~ÿ~±X€±‘Žoó$c ¤´  —«u)ùoÝÕWøÁ·Ž¶f5§VÈçÛ:†1ÆSËׯç¾óÍ㉄EPJ)?ýùùùÅÍŽ¶ä™Sc©zµ800ÂL³Tª½{aº¹9ñê›·l“ý›=Ò–ŽÖë•ÂÆZ,‘jëè#„­o”ù› zʾýÍ£í-?Æo,ËÕ'Ý@"Jé™ÕR©vòøˆä $AJýËoÎgs%èéJkf׉;·‚ÀÃ(D©PJ!Šƒ@(„•Bž'ÅvC·¯êîHx!ºB×§vrj˜iø)¥t“-­sjU“1&¥DÛ®!,Ú^=ŠDm]B)9 EB áþþvf²Í|¡T©¦!A¤Ú¶!1®`D8B¾ç…Ò•1Æ9èëÛÝo2V­×oÞœ9p`$‹¸¾;yw2ðjƒŠi›$Oö Œ(…^}}|x¸£¯§M)ä9Î/ÿ~6[J&íoýè[ïO"¥þÛõ!Šb à d)ÀXÁÏ~{ñöݵ®ŽäWß#¥´ ‹06;Ÿûç_ž€Ž¶ä÷¾uº¹9"ñÞ•ÙùÅÓÇGêÇåÂR×À(Hùâë· Ãøþ?œPŠHÎC„ÀúzáýùÏ ÚÛ›`#_þ·ÿxŽ1ç|zvå׿¿¬Å#'Ç$àå…%JHÄ „ªÔ*š±Kwð|ÄÇà&Ñý™?JÖ†58Ø?0ÐgYÆÜÂê /]€¯=yb÷îþz½:3·poñȺ”€É¾N0DMšL·Å“©Ýc#&cKË«ÿùgoëtïñ£CS‚f*Êõ=)å{gîN¯Àw¿q¤»»¹îº¹l®»Œ ôê›7•R?úÎiÎ9Æ”*U¼ŸÿæÚúF±£-õã>j›¬^.¶vvBÖÖ¶®ßZÊ4'^~ó–m³úñ£Ýí p·œoní²"1BØüböýÙyhoozþÙ#©TtþÂäÂBö̉‘£»´™Œ0úýËã»F;wB”ªŸÿê=º‘¡Ž¯>q!´°´°™Ë557Çã©b¹¸±‘%tš®á8R(¦µ72ÁN¹î”|_Œ¡L¨UrÎc: ¡‡º—]hÝi ©.ŒBHŒ!$$`0¥ „0„ˆÜ)Q€T2)¹ÌJç‚1ÜŠØÜw’m•*¡Bº7ƒöÈ öîß?*”ZZ\]YË9s)T©Ô'''ƒ †S‚0&ÁH‘x< —®Í94’LÆ ðÜ_l£.úø™±·Þ¹{pÿ@_ #JJW$†ÊgKÿù—— ÅúÐ@˾}\·4b¦1߀ºúá¹Kãó¥Rme­pøàà?~ÿ BHrWa•Lw÷î…ÙáÁööÖ&…(ß4Bh-[þO?¿àyAS"Òœˆ¤“Ñýû0ÖÓ£¤Ï_{ãÖû—§5ê~ò½G"ÙåÕ¶Ž®ž—rL©óç/‹%Ãbã¼ÇùC"f‰74ÖÚ ³F@ B,ËÞ³gO[[:_¿1ýæÛ×RÉøóÿð¸m3Ïs¦§ï--ÝÊá¾ï;Õ&A`ÇÓ==]]mŒ¡‰©¥ùÝy}·¿~|l¤Ë´M¤<¤Pà#ë\Ê·ß¼pež8;::Ú.¹,Ëm}H¡w.Lô÷fû3!‰ÁüÂÖ/wÅñ‚þÞÖï|ë¸m2¯V‰Æ“H‰‰É•;S+ûvuýo¿¾ ?ùÞñ¾Ž„RÂó ±¦vjE‘R3 Û¨ëhKþã÷N_½±T,Ï­­•ŽêûW?: ‚ÀCHQj½siæ‘“#ñxTJÍÈ­~û‡ËKËyØ;Ö÷ø¹ýJ¡•{««ËëGNœŠÅb A!táü¥r¹ˆ0â{ dz¾h4ÍÂÆX:æü4Õ~B-Á´'“RªÏƒæ$´þÑPÞvo"¤@P F.”Ò˜Ažç9ޱP4ªÝP êÕºZ­J!$(Bm7ìPº$œRÚÓÓ64ÐF…Rç/ÜèlÏœ:uON/f³kŒp‚€b®aX®/-‹Uën«"G*…R®ëýò7ç³¹R2iÜÛ;1³öÜ³Ç ƒb)¯b2…RêÖÔÚþù%Ø¿»ó‡Ï—sî#f—¶j¿øýv9ÌZ¶ôÛ—¯¶g’'D£{0€ïs§²Oe¤D³‹Ùb±~êØ0RÄçœû®+)××Kÿéïéª_;jž956Ð׆”@ ¥êu÷ûÕ{ó‹9èkùÉ÷N Š…¼‰¦[¥ÚÂÂÚáÃÃÝÝíŒ(DHkkûÑ£iËŠéê¨Î\3™™/lMM-dZ[+•ÚÂÂ2HîûeL ] :ÀíéíîïïN§ÓJ©_¾81µ°kWÿc«TjwïÎlnnˆ p ¨´X«E‰6µ·wwtµP 7nÍýñå«ú„}瑾P¢&…0í¸Ë=BÈ¿üáÊÄÔ*ΥŠ„Ð<(:`뺎P(LÃü€W³±‹iš®ë†þL}¶&ÕlL~ -–e¹¾kPŒu’ÇEÄf€KÉ%—¾ï[ŧSIÀÚ.c¡aL‚4 @s!¥Pƒ¸˜ P©T¢»³s`¨›²ºž›œ\Üp¤µ9ÁôìR.»Ž!ÀX( D Œ9¥Ô00ÆPÈMMEžïþê·ç³¹2”JN$b<ÿcˆéW¥ô#ØJJ€WÞ¼ûæ»SðãçOŒõ8žàR˜nÍÿ—®9N?|þLo&´BªUßwëÔ€D¢•s¸xyNå’òyÃ0’É8Aj}³ôÓÔut¤~øü©Ls c‰„$­Ôêÿñ§o­eKpúøðgws. ù‚OBÍÌ­OLÜû‡çNxdÌ–JB3M„ĶOTssÓÉ“•RácGÆ$÷kµÚÖV©X(OLNú(‚¡­£­£­e` Ï4Í\®ôÂ+0ÀsÏ>2:ÚW(ËåòôôB¹\R¢l3ü`P˜‰{û‡Z3­­íÍ–A/^žxí­í:¯ÿö_=ÑÕ‘Bp¿ÌˆAÍ(çRâŸýþÂRïï=wjØçàyn,Ö„úåï.Ú××ÕWAÀ˜"®Œ/ýþå[ðÄÙ}œQR*% ƒ*¤~þÛ+­É½cu?øöÑîîÖjU8^YðúZqüæRS":·€}çto+`¬û»®Ç}0¶¢­Pï_žQ :6ìs̹¡º|yR{Îöíé}ê±CJ‰üF^)58<¬š_[^Î;wÊÅbˆ@0!°RÛSÀ˜¡±ƒ1®9žBD þ€—å¾ÄÓ±ß÷5ul^T«Ú:ÔçhÈéX‚ïû¥çJq `¾Ï3]×F•ïûA êu‰°Þþöj¹Ž”Š%bA 0ÆÞá !P#©3͸éííèë֛ǻço$‘'?Wkõ[·f|·J©À0%(…¦ºy€A!ÑX"Aò|ï¿~_£.™´¿õµãíM [)1äSЉ /½qçíóS©dôß>™NÇëu_(¤„ÚÈoÞ¸³¸x/ßþTww3çœó æN­bX4†á8ÞKoÜíïm9´¯€äs›†Á’É$!juu+”uƒý­?úÎ#Q›a*¾Àø…KÓkÛó#ûvµ+É%÷ZÚ’Aà½ýî„m³ÿñ_ ‚z5?uæX?`<·´±ž¯__.ëV,èI%m„Ps“µoW‡À*ûZê8v¨¹V©9ž‡ˆLuÂ!¯¾~íöÝùs:vd·çyÅbyuuceeµZ­ˆ ÆÅ}Ôa  À6)3£ƒÃƒmQÛVJüê·ï…¦ËO~p¶½µIr^.å,Ëðá®®&g³É¸ {FÛŸ}j¿Ï±„Eë®ûÊk7OimŽù®‹SblºçŸ;±{¤KJ 0Â+ÙÒ^ºö•s{#úïÿÃ[ðÜÓ‡ÆF:\WÖªåH¬I)41³šË•ž<·ûÿñÿzA£®¯§…K)¯â9„ˆSjÔjÞ‹¯ßèím9¼@\‰)ÙÈn¾}þ޶ëž<·_r¾µµeÚfs4.%œ¿4ašìÜ£ûAÊ»wïnn•¤4~vO:wG8e;ç¿wqnG_mBbа‚+7&¦Vþñ‡ Õÿÿ?¿ßøê¡Ãûûü@ú¾4í”ðòë7ú2=²ûú%úÓÓÕT-×…ð8w#‘X4EÍ-å._>vdl '-„ª”ª‘X„K~ñê4ôtµ<ýÔ¥P©TŽÇ“ˆš¼üêÕÃû‡;;›B·oß][[ç’„"JÉÆ9ιëKX6”Ñ<$©H{µ¥±\¨’êO!:x½íüØîhG8ç”ebÎ%Æ:PD£v$3M3‘ˆE"¥Tk&–LÆnÞž ‚àØ‘1Œac}czv~kk‹ ¢J¥’­™Öx2ÞÖ֢ﻰ°6~{~°¿óÀ¾!Li½ê®¬¬on•â>cŠ!¡í\ו€…b¦ÚѾ˲¸ïÿú÷ÛŽ©áÁÎo<} ‚À«lå‚  Dm;‘È`Ãøõo/:^ðƒoŸö9x^ y^^óF29vdøòõÙr¹þä¹ýP-W…B†A-Ë`L•JÎ;ïOb€g¿zÌŽÚRòr±ˆ‹X¥Äúzñg¿9¯QwúøØWŸ8 ½ÄÕrÙ眙6ŸX®þóÏÏÿøûgRɸPËõ+ãs¾ë?ñØ‚T¥V»·¸ÂL666²²’s}1Ü߈ëg!R(5=Çf²|±z÷îÊF¾¤Í*-o{z2M‰H¹ì"„öŽu%Sq“1×õ§æûþüü9œŒÛ‘wÞŸ*Uê_y|¿”¸X¬ƒôm›ÙÑ(”Ëõ·Þ»­úê‡" ‚ R©QÊD,Çñþýÿï…–tòûÏ?Š ¼€™L(43·61±tòø®L¦©^¯ß¹3U,„PŽ#…"RN)ÀJyž§ÑJÂÆLÎmUS»RôIZ éú™¹ aúTB‰©”BoWa+À ƒä®¢XJ.9'„”JNSSôЗ^¹táÒ­3§ö¶·gÚ:Z0Æ4Ëøýò¿ñ›sSKƒýíÏ={†1†Ê®mær›A˜„ø„HxN¡¡„ @™m›ãžž.˲\ßÿíïßËåJ:ôyæÄn<'›]Ói4l eJLA‚ëú_ú˜ëKŸ ²º–½zcþèþÁ¾¾6MÛ5:Ø…1•RÆ1@HU*µ›·ïMÏ®?ynÿP­ZÞÌ®qÀ™ÖNÎy.W Q÷ÄÙ}§OyžW©”6sY’™¶Ée,KÆmÓdѨ‰1¾ywei)»¾Q÷ì±WÞÿO?}åðÁ¡áÁŽxÜÖµ‘///ç6òååÕüÑÃCÿæGOB@ÊBqkem³P(ú¾«D@GP€1¡|¾%¦“xÌ¢˜ÛQÛñ¼ßýî|n³gNì:t`ˆ U-o ¾ï+!3%Å$Gˆ–±µUÉd¥­ò•ñ9„Ô7¿v8bY€AJÑÞçý;ñ¤™JÚ©K׿s¹òÜRþ‘ãÃÿî¿ÿ*çÒój›¹l¥²ÉK$2Œ¡¥åÜoþpE£î+çvØ×S­º¹ÜZi3§B 51†”BBaƒ=ýÔ¡ÿåÿý2Œwôµ>qvŸ”œsw}u¹R)QÀ”_/sßíéHýî…KÝËYÃ2í Q¬Ë)‰Ï¹1RcbPPÊóÒ´RŠ 25·6Üßö­gö¶6'– ÙÍÒ»çgÞ|û¼ðÊ5ÛdgO÷`ËÀ÷wDK“ „ˆzݽzcF)T(×nÞ^9~¸?þè;'‘"ˆ ,}ò<§Úݽ~ã^Äß Þ»85~{ißž¾Ÿ|ﬞç„"–Á}.DpùêÌøÍ¥'Îîìo–RTËùå¥Eà&„„R‚sÿ‰³»~ú‹w´r¾k´ë™‘.)e±\ùÙÏÏËõÓLJODJ$.^]ØÚª=þè°ÉÌÀ 0ŶÉ‚Îö¦7Þ¹ÿZ45 +ã³¹\ù޽ܑCCÿæ'Q Ü/ •Jɲ"&³ JɈ…M“H„ÐäìÚÜÜZ©R;qlwOG@Þ[^[œ_ô]@*)$€Ä€FB©ˆï+.Aø´z¨ó:ºpŸ3¥Q|5rBkY§q ÃFj£Æ8;çÜ4M)¹eP ~4JcÆIܶ C±H„&”H&SMMÍ¡¥ÕB6WzïýÉPëmmM ´·¥ã]i]“S)m•¶6K¥Mßç^ ¤¶‘¥ô9;]È !ˆ ƒ©Tj`h :A¢îñG÷Ü߃”ªUJùüºç9"€Ò¨i›v4™L&šH¡õâ¿üáZ©âôt¥OèëIïdý jP|óöâKol“I;4ÐÚÚ4Ð׆Ó¥"¹ìšïûˆÛŒFb±L¦Y(ås\ µt>5³¾¸¸¢=U‘H¤©©©³³3‘HØf DÀ%çœ#%K%D¥RZ»7OPÀLe*°£,‘°ZÛ{M; ×o­xNpwvc-[yhàζٹS!õ䣔bɹÔÕ¼B|Ÿ¦¯¿=§³/½1ýÐë˜&{äh/"cyæXÆ8"Dr¨×«€HlÛq_r¸peþíóSpöôžCú1† J ¦2—«üê÷=/8~täøÁABˆ|ãÖÄÆúzssÄ2Œ¦¦æh4ÚœiÆXbÀR`ª!T,Vþ/o–Jµý{ž~â@ ‚kãó['¶µ%¤ïºžW3™I©ØPˆ\¿³üêë7v¦l0“IŽ´a¡Ji3»¶Ä¹³£±h<§2`bnãåW¯@wgfh¨cl¤W‹œÕÕõlvsîyžJ×H \!˜ËAˆm9dš¦nßFÝvº²’B(,ÄÒk¤…«B«Q§n…æŸösZ–Ë…´œcÓ4c±XŒRjš¦†n2i·¤£¥ÛÅ—TCŸþz©ä,-oT*N:´ˆÁ'DÄ)¾ï Òf†aDãñ‘‘¡x<êy®¯€çž=ÕÙ™Á¯®nlll(¡ên•bª;7D";§†i2ªÖHI Q« ŸcƘ”<ÓL¥”’o˜Rzß"õº¿²¶¹µUÑê·~’D"ÑÔ”HÆÆ@BOÌL-ç6·jµB(‰¤R©T*‰D0ÆH‰HL“(¥*5/—ÛZ]Í×jNh]†Çu>CWW*І´í\© ÛÅi:KQBaŒ©A…@œc¡¥ÆR c¦Sl×(DÑËÅq=¼¶iûÜWBaŠ9çØç2›ÝªÕ<Îe,“RÚ¶­TÐÑUB–A)EˆxžW*ÕÊU!F)M%cJ?5(Æxmmszv¥VÙbLÙ6³ –injiIël fŠ1€”€)ÆœË_þîÝâ}ýÉx4›ÛJ$"CÝ--q¤ã8Åb±\,ÛѨ°(Ēɨ”ù¼ÓÒªe÷ÞZ.—Ûª×ë:=#‹%‰xÿÍ ôNzôðHSSìàþaɹÊqœÍ­­µµ¬ ÝÊ›™&b&çD)ÔܜЄqP­Öײ[Åb=^-ô¨F"‘D"aB*g†… Ró …òÆF!ÜX}ߥ–^a;nÝ_$Líz d÷Qµ°a’fŒi‹®1¶ª§a'“0#&LB ».5’iÈé5¤YwÂô´0´¦J=ð!AÆÜ  íÔe‡Å¸–eYVdll(žŒû>Q÷Ü7Îôtµ(!ïe7·rn½îû~è‰eŒĨa#UŠaJ)¥¾ï;Žã8ŽTêÔ]5ź5ç\CÎu]=ú„=…úÐ3亮ã8õz]325º‚MÓÔ×§0h8Âd½H$B)µ,˶mýÎÑO¨ŸM說ý Ÿ§qMèwÑ©T*íííÔ—Ëåz½®• Ji2™¬T*z xžç8ŽÖkô\ …T*U­V5öLÓ YÆõ ëÝÄ0 í$·m[R¸¹ „Q‰ 7𠪵µ5žŒƒ„¨‰'£QÛ& iUèW¿~+_(ïëyäô¤¦!´µUqg}}£^w”’ˆ`¢Ƙ˜6¦ηž~#ιVzÖ• ç+F"‘X,¶ã“ ‚ Ð3«__Ÿ¯]„öq¢U¶±è.$ú(àÑÓÔ†ôí^†š!0êõzcWÇÆ(áC™ÈBg©ÎmtІ¼ zûןèÁ2¨ÄXTa°#-B˜RŠ©iÚccC‰DÌsýß½´½/~ëë§;;Ò¾Ïççóù¼ëºœû¡½*„À@=€O8—hGs‚ QÚhGK§PëÖ{^Cú+úiõ ê…¥”Ò˜Ñ{d£ išÂùkùõ?Ã%Ö,ë[„¬•@Mêܘ^«ÓúÂ-Yk a%˜^"zËÓ+Òq=þŒ±L&³¾¾®ß®µµµ\.{ž·¾¾ÞÓÓ³ºº*¥ŒÅbµZMCQOúúúº½FC‚=2:>‹é§ÅbzÕrÎ}ߥ+Q)jÁL–HDLÓD8é¥RÉööV=û«ë¹|¾ôþÅ mn{t?€òÝ ´YÚ*Uªõ*÷}…”Rž”À}IA$"y€P]W†Ù’zTÇá;‡¾…~Z½³8Ž£w}‚Lß÷u…jØ­6D”¶ÜÂ…¥ý¡®§o¡Û ,ê‡FÌèe.—F¶•´Õ?Ëü¡¥œF]ÈüÑÜÐÛˆ:¥#‚RɈÔv](ë¶ ìèÐÐ@ssÂó‚u_ædwg†s>7³´¹µé9ç¾BJ ¥T!¾\¼aLõ³ítØá!´<ÑG<}N¿0Тªß«ñüðäpÚ‰BU¼‘’(¼fCSBÑÚ>Sgð…£qŸ†`gÇ ÓõŽFڕЉ­ÁÞQ+ü^G?Xx„ï«ÇGÏf˜VêAz¿Öbƒ$p8„pŠ%$ Œq<ïlJ$R åµ›sÚpu]ÿÚÍÙ–tò{ß~D)T®Ö³kÙz½êy^ és¥T ”HPˆø>æ‡Ï"Äó¼prÞm“rçhLhÖ¯¼ãDùX„¼ál6js Ÿia£hUÍÐÞ#„¸®kš¦~ÛmÜ0¤ÉØô×3#‘HoKK !ôËß¼¢®«#b~þÞæfN÷ˆj´k ^AjŽÀzM<°ôÃÅÚÈÔ>y¡öjŠþ‡ù6Bì5&4<пúO ]èv~  }x…FÀ4>Ü•·‘°£/…zGã£>p…ÜæÃ!UæÝ'P ;Ît‰¥G©’ ’M1“™c»w777a ¥’3·°ö À[³ï_œÈdšž{ö„aÕjýÞÊŠã8~Ý ÏçRåû;RˆÕ:ßéO5êÂçùð”…¾E¸}ƒÅÜ0n Ô‹cF†ú4‘Ûï_¼¨%¾ñÕÝ™ ssK…|Þq<(ÿ€5,Q±ì:žÀbé?ð´áƒ=HŸ$×j8t^¨´?ðë졳ð—^磶FïPø ‚T8ÑH J€2D£ñT*uèÈŒ¡X¬Ï/®†±{¬)…º}{á­÷n%‘ï>÷¨1ªåúÂÂR½^DàûÜóDðPöJ >Ç媉D4[¸ÉþÙ){à-ÓJ>þ*Ÿyh÷7†"”RŒ(F„iì…j•a–ìÍ´6ƒ„ß¿|u]]->çu®ë |`¸1pŽŠe×ç8>C½]¿‡®ÓƒmÇ~)ÅU„©D,’hjÚ»{,‰H€ë7fm“ííѦ `|gbñíwo&‘¯íd"©Tj s u·Î}¿êrà÷KÝRœ+/@^€Beäs4JôS»1¥a¬#4Ð5ê C°Cø‹6í¨Ö0[[›%ÀwPwî̾îîŒïó K…¦xJq x»­BÈw¡Tqêž&ÅûòøÛm¦Û HºY´¦â'Tš¶A1ŽÄb‡Ä”Þ[Éæ ¥C†whcAheyãíwof2‰§ž8’LD+gzr¾V«¸>—R .9Ƙ Ž1V¸ÄBø^®ÏÍöô©@NÓži?AHDA±4¨4 Åú{†…¨Óæòê4éúìüâææ¦çxRrÝö-T$Uj¾/©R_6gû$PþS) E,l¤lÎdNœ8ß\PÜ? €76ŠœÆxy5ÿû/fšÏ={*‹•Ëõ»w§«õj½îû~ ûÃ¥"r<å¨V«aŒ?Ãõ)H<=‚aýÑ6º€T2¦(¾ŸÅ²W4mÛèÛ–u/Þ—uuSs…bÁó>€:ãúÒqd݇?ÁéûåñWQ/}  —`8•ÔmOh<=~ü°ä|üöìÀ@gS,â»þêz¡¯¯ææV^}óÚ`û“Å 噹·^w=M–¯»”J„—\ ås¤ëqþMú—Àƒ0j»;Dƒ§Q)eP`Dš&è„°ðO”RJ Û¶‡û[Ò)øãެkh02»¹¹éyžRB‚THI.9çT¾ßÿ;moÿ‰¢ì›D P,9÷‹$£ñ#Çö !nÜž;¸X)UªÔêu¿··])¥ÛÍÜ?tüè.„P~£0=»àÖ@Hßç:ÁµÁõJœ@`)ùÇŒi} ¼mBhÔýiKƒ*]ó:{4D5êúZÒ)…Ð^¸¢îÐ!¤Ôôì=:¡#àB„]‘¥€@ç_¢îo®a>Š ˜€‚KÙÙ݉š˜ZÜ5Ú'¥œ›[noomkK)¥nÜš½teò©ÇŽ ´À½{Ù••õz½^w}8GyA°íc”ØåHJ„1|NÝ' ¼0×a‡ø};ˆe2 TÒ0Ïm·&·,+”u ¦f²kkõºëŽëoði}‰ºOòx`Œ)F€À¡––”çÍÍMÚ¾î€r¹þÎû7}×ÿþwOÄbœ‹¥¥µµl®V«¡¨àNº,‘\ E\ÁRòFfØ/÷§4̰hÚž$ ª 0¤¶ÿCaŒ1#‘ÈØØP2o”u»võÜ?(¥œš˜Y__wœšãI °pç¸î.ð%êþöâ.”xmS jÆNJÁ`„R#“I"$6ò[’ ”I¨••üZ6ýÆÜñ£c÷@½^[\\+–‹¾ë‚ô— ˜ipΑRŸÓ@lçÐ…y_J¼?ïÆÔJ¦w:jLj2 ň$H!@R Œ0 …1ÂL›Åb±d*îyÁ+¯]Ó¨Û=Òóȉݜó¥¥åÕÕU×­»¾z@¬‰ÏpcÄ/ ¬S@v`Fð}¯¦ÁÀ2€`0M¤„‡A¶gâ¿ùò˯ëj·æ®®–ÿñß>ƒ1– ¶¶¶–––Üz]y>ÅÂB1¥œ»>aø\RŠõÞzã>ïØûÛеÿײ¬Æœ‰ÆB˜1÷{áÃ0t‰ÍÈP‡eáò'¦fVçæ–uþøÇÌ£ûòødÅàýª]Á°gWo:GD0ÅRJÔjÁ½{¹|!LRש'Y¬¡º&úbŒù›N€.Ê é$àƒÕîái˜Üq«PÓ4…$ŒRÀÛžêzÝ_\ÌÎ~‰ºÏ<ðÂ,s ¿JÕ£Œ`‚ ƒ‚„ºçå Õìzyfn¹T®è+¾ÝÕYêòë°v[oÓ:ó ƒº¿­ªê–º@;ÜÃSKÂÚx=ôzÿÛ*mw<¯T*år¹R©|‰ºÏ#WV¶*Âu€®Ž ëntdH‚v˜]]×ý‚ ý[ ´VÂB²F˜Aü©ôᇺ®¾^¯€®Ýö<¯^¯ë¢Ò/Q÷™7ü¶9È5åqXö¥KäJí´Ô²®±Ì´ÑÑ¿!“èßbÜu-s#ODˆ·°ôKk~8 \û‘à ÓñŽ/Q÷¹À^XÛÛ=1·sÿµ4k¤^møI¤±¨ïó¯û„œ+z¼B"Àí¢ïzö°:îOWjh>,‡{hQé—Çgß¿¢-½ªv kšµj õ_z«mìáñ%ðþ¤ô¤T›ga¦e#Ø>&f>\ ÷QE¥_Ÿ}ÓîêÁ ˆõöªA¨ë¾õ6ý÷0Ñýp‚æðù´*G¿<>_RQ3MiøéFá_€ݧ0”Ð'øòøòø8 æïóøßÀ9JNÖUÇIEND®B`‚openlayer-2.1.orig/demos/renderbitmap/0000700000175000017500000000000012262355751020270 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/renderbitmap/Makefile0000644000175000017500000000066510377212142021740 0ustar georgeskgeorgesk#demos/renderbitmap/Makefile EXE_SOURCES=Main.cpp EXE=renderbitmap ifeq "$(ENVIRONMENT)" "WINDOWS" EXE :=$(EXE).exe endif ifeq "$(ENVIRONMENT)" "MSYS" EXE :=$(EXE).exe endif all: $(EXE) .PHONY: all clean clean: @echo "Making clean..." $(RM) *.o $(RM) $(EXE) @echo "Demo is cleaned" $(EXE): $(EXE_SOURCES) $(CC) $(CFLAGS) $(LDFLAGS) $(EXE_SOURCES) ../../lib/$(LIB) $(LIBFLAGS) -o $@ openlayer-2.1.orig/demos/renderbitmap/Main.cpp0000644000175000017500000000157710401557550021676 0ustar georgeskgeorgesk// BITMAP RENDERING DEMO // #include using namespace ol; int main() { // SETUP // // Set up the program with all possible drivers // Setup::SetupProgram(); // Set up the screen in windowed mode with the window size of 800 x 600 // Setup::SetupScreen( 800, 600, WINDOWED ); // Load a bitmap // Bitmap bmp( "Gfx/Bitmap.png" ); // Test if the bitmap was really loaded (maybe it didn't exist) // if( !bmp ) { allegro_message( "Couldn't load the bitmap!" ); exit( -1 ); } // RENDERING // // Empty the screen to black // Canvas::Fill( Rgba::BLACK ); // Draw the bitmap to the screen with the top-left coordinates of x = 200.0, y = 100.0 // bmp.Blit( 200.0, 100.0 ); // Refresh the screen contents to show the rendered image // Canvas::Refresh(); // Wait for a keypress // readkey(); return 0; } END_OF_MAIN() openlayer-2.1.orig/demos/renderbitmap/Gfx/0000700000175000017500000000000012262355751021014 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/renderbitmap/Gfx/Bitmap.png0000644000175000017500000006753010377212142022752 0ustar georgeskgeorgesk‰PNG  IHDR(S£÷ ø pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFduIDATxÚìýÇ“d×¹'~G]á2<ÜCkZk Š$’à#¨ÉWU¯«…õLmºg1‹ù f5‹1ëYÔØŒÕTWñ5‹âQCk ‘:#eh•¡<ÜÃÃõUGôâDÜt$$ØEB°°HëWœs~çÓ¿Àgû@aŒ€RJ)BƒRŠ1–RRJBJ)„|yümJ©”Ò0 PJaŒ•Rá_ ÃPJ5~„>ùò¸¿°?³`S;¥TŽ1FiŒ)¥!ús)¥þ«l8¾œò¿âAÑ[ža®ëÆãñ 0ÆzÌëõºR*RJ}ß×çø¾1B|9zŸàQJ9çz¿ ·R)e(Öô¡!þ$„è™B(¥„~_"ð/ÚòÂá2MÓ0 BH©T"„˜¦&!DJÉó›þçç~/ûì<ŠaBÓ4Cõ2n!J©Öp½ñ÷–”RÛ¶1ÆŒ1}/µÐ³¸B¦irÎc‘HDò}¢Ñh(»ôìhFáœ;ŽnŽRJ˲8çÿ5²No¬zBZ¿µ, !Ä{`Þ¿Þ-êô~É9×"„„’MOj¨ö4*œú¯á áïZ/Ò?À/àŸP4 Ã0M3DišZŸçœkOïkA(¥8çÑh´R©hH„âÈqÀÿJ[#‰è»k“^ßsn¦_ïÿøø€ÞÕôXëM´Ñ„Ó3­G?ÄU(CÙ¨%aˆ:­j†¹a–e1ÆB³ðËCŽáX,fš¦+BcÌq­·kƒM+#zék˜qÎ#‘H¹\ŽÇãŽãX–eÛ¶çyœóÆ]ò/]!øµf«!§oýØ>ïB}Ѝ A¥çXcIÏn¨%† 5F­ü4ºOÂ3õd4z8Ch[Kª¹¹ cH·$Ó©¤JJ RJËm­®çsÙ­ÜæÖßüLÓ •Cºz½Fƒ „(%:;[ãѨP¢¹)ÑÒ’²M“Kêü¡g !²¹Yº|õÖÆFá/B…^ ÚMF¥”Z¬iÝGJ©¬¾K¨æh„ ¼5¾Ú$h”u?ZÊi…0ük-ýÅð—PÉBèÑ×zQ8…!z[[›ÛZR­™ææLbgw'¤ú"zRòp:ײ›k+¹ÉéÅ/¶ ³, <Ï#„ض-¥ô}_)eY¥”1ÔÛÝÙÚÞ”ij"Œø¾OSJ(…Aã RrƘVAƒ Ðj ÷y ‚?¼ð^¹\ý‹PÇ-ËÒpõú»ZúÐ3¤±Š„ðQ „|F$FÐÙïloO§RÑd`i¹ÍUB‹+…Å{›<ÛÁ½Ý‰„5:ØšŒ›J©­Íë7ï”* $pœìü"$|NÕ-U¤”¦i 0‚"$7†lomîééH§S€˜ Áw'׋U¸€÷®.º.ÿ¨ë?ûÄè}K3—oM×”üÀ „€€og ¶A×××Õ’Nõö¶75Å@r™ÛÚÚڬܜ¯×ÝP… ÆlŸ÷ˆÑ' )Á˜2™²m RjCN_ª¿¿·££-ëÍðÚÍ™™¹Õ|¾¼{¬'·î$D)„pƒ‹’@)¤R‚H +k…×§víêïïíÈå6_{í].¾€4…„Ïø¶‹`…x 5%" }!mË%M£££V$‚)VBåóååÕÜõs®Ï‰Èž]Ý&3F‡;c¡/Cu¶uÎ¥ç …!4ÄÆFþâå;¥R0‚ (ƒB@)4ÅÐÈî½--m±XŒ1æ8ÞµñÙ­RõÖ%ýÀ­™Ä¡Cmp黫ë5ƒ€^ R’P÷Á÷A*ðøœŠ=ô‰‰»Fç‡Îó •I °ÐyÕ"¥išÊ$Àض0ÔþO„Ðè®á––Û4Bù|ùÎÔâÄÄR"Ù»»ïБP'AZÒ‚€À 66 ¾ïB9žä"†G‰ˆµBçÏߨ=6N7]¼|sii•s”ꡬü¬b# Œ¡³5*AD‚ 0MÓŽÚ™æf½œ¯ß˜žÏæóÅ¡Žt:yôð°RÛÛ!Hréú~½îbŒ•PU×-•\)©DlnnZ–µ±±Q«Õ‚ PJ`ŒF€°ÞR·Ÿ$fÁž½»ÚÛ;“É8!djfõÆ­ÙÅ{¹ÓÇÇlÛØ5Ú­”B­¬m^¿5ßÝÙ|poÿôôô; „€ $øH¹½fý@¯ ½3þÝOï‹B˲B×h­iju£»%T8Ãè€dDÙ&"HÈí˜R&#¦‰ú{;»{;ãÑ8Bbi¹póöòäl¶¯'½o÷Ø@`ð‡z[‘X•JEÇqÇ÷]‚P÷×”†œ}ýýÝÃÃÉD̶ÍùÅ·ß¾OF÷ŒööõµH,D ”Þ…•”òÝ w=µ?—;wþª€RX¨û¡Âfáó¨rþM€§³O<ÏÓÉ¡jÞè;–RjR»ÅÂй†AÈ4ß4±bÇ'©, ZÒéþÁÁH,¦Êç«ç/LÜ[Ùlk‰Ÿ==ÚÕ‘Âgs•K׿î­l?<ØšIôvgt´ïæíÅñÛËûöôíÙÕëyÞìô¬žB¡ˆÏAJåA2ZXZ‹G£©tÓëo^®Õí âœkï¶Î‡ ç[©ÏŠÐCB@w*n™¶©UƒZ­ÖÖÒ¶wÿˆmÛ áöäÂåËé–äþþt©–ëõº_,¹TJ(Ïsc¢PÝu1¸¾Ôjd{{»ïû¹\NaÛvµZæ~ƒ¯}Q!ê(‚!‹îÛ·«µµ5‰är[oŸ¿¡”8}|_gg†û¾BÈ­»ÅbµR«W«ÏóÚZÒ=}] «ét*‰üîo–Ëõ0+mÛ¡ýA÷y”xô¯nÄcŒuàEÏ·6Ïs,µ½§]Ɔa踜Ýh*áÙ&6„®À`Q0 µþþá–Ž6¥ë.LÜšX¶ úØÙ}vu#¤ê¾xã­ñ{+›gNŒ}ý+G¥”œËááþÁáþß½p!‹õô´DbM…BÕXBrß÷EÎ-Œ@k&½–ͧR “ ÕRE?¿Öo1Æ–q!)?3sŽÐ¶M¥!g›ÈaT©mÛ‘‘‘‘‘¥D6W|÷ÝqŸósè”’s.+•ºRÏÇJ„ªÕªØxòdYªV«éu?77;éDW#$ 8;Þ-è(BðààÀÐP_4E¿pãÚøôWž<12Ô)%8ŽW*U …¢ã¸˜RÙŽ1)Uê=Ô`3 È `Œ0ÖFˆR~’þÊÀÓÖ—Öã!ötÈH's…ѼÐÛaÔ4#ƒž Œ‘e“)FP{gOWOiÚRµ›sç/LÀð`û¹G÷[U ¦ç³/¼rmïîžÿ៾†´õïóÀó\ß/Ýææf+AH}ýk§ßyo¼­--±UácÓ4™I%!·î ­‡)Å¥THÝw'ì8Ö !­&tK‚ïK.%`Y–ïKŒÉÈÈPGGc|m|æâå;»võž=}!Å9ßÜ,—JÇó,ÃØØØ Ô*pj!¤^w]Ž9)eµZÿPèL2"’+©¶õ=-è(A¦iî?¸§½µÕ²Œ•µü+¯]îèhùïþ雌‘ 6ÖóÙ\AžÇó«5LI’ Û¶„@®+i ]ZZ –í¤%}¢©ô¯(ëBŸÇ–ТÕNBˆ–r–e¹®‹1¦”‚”˜“!†$Ac$%ËÄQ›P ã»Ò--J©¥åüû'7òeÓdOœÝ7Ü߀áý‹“—¯Ï=ó•û†Û%(©d¥Xò}ßó”ëƒP$‹läË-é8B*‹H 5ÊÕ*#¤^¯3Æc‚HOW›eùüV,#U«u¢_M«ÁZ;WJrŽ”"‰O{ÿ%(üA£Á4("ÄqË2FG‡ººZð˯^œ[X}ꉣý½¡ÍÍr¡XᜋE·^BpÉ…(+!„A€ê>ј¥ÚÞÛ7 $Á,:J€RÒÒ’Ù»w,bLß~÷Ö‰¹¯<~bl¬Û­×ó…ÒÒÂj¥RÑu$zðpE sxxPò‚cœË•óu…_˜LÛ¿ðtP[g04ÚryÉŒ±`g–´èó§PüëÏu]˲töIˆ«xZ¦i)§ëëBsŠRiH)#eŒs‰1¦S ¶‰ºzúÚ;»Rùò‹¯^/—ëpúøØ‘C ¹Dýêï»>ÿö·N'bVà››¹jµÊ}p9Ô]Ž1ŠFMÛ6s›[ñd\)¢ ƒB8Ž ãñh¦9‘hJ´µ5K ·nÏtt¦äw„H µ#ðTæÀ( àÓ™|½ÜÑC¢¦J¥’ƒƒ½¡7ß¾º²–{þ¹ÇZ[Sž'¦§—Šår¡7M³\,Šíc[c p¡´ú()zàC ÅÔ0F‡ûz(¥S3+o½s=Jþ›ŸNb@¯¿y¹V©ám¿¥õO úû”xÚù¡ÿB­òq§?Ô…­zzC¾É}ÛÆK‚Š0"¹Ä„ Ûdñ(ëínÎ4¨«×çÎ_šË O?u¤§+­@!…Ãkoßt]þío7sœÚʽEÏ ê.÷#D QÊA¾Ïmfnä‹Éd!D).Šßxöܶ£RÊõ‚÷/ÞìjK·¤š¶¶Jù¼A±Ï裡pŒnï²J)ŸBøS³ë>(vô‡ƒd2ÅL3‰´ud¤”7nÍNL-=õÔÑL&U«yKKk•J%·±Aµ\æ\j¼i•YÊu—®À®C䣔‡íI§ÓŒ±wÞ»ywr1•J>ÿü9%DµZŸŸßÚ*ù¾/D‚‹û6¡ïrf'Ž9HD ÅR-[¥Jµ^×¹´œË‡:à?;ÎäOxÚ¹§Í¶ÐqÒ¯kÌôiLÑ%„‚3#€¥O –K) JB†AÓ©èÀЈº>ñÕëËËyhÍ$žyòp‡rU*D…P”RfKKY.WTG‹ãTZZâ’ÔÒ’ÒvRjvzis³’Û,9³¿%—RÞ¾yÛd ” â;ʤÁ¤¡p > Û?yq‡>¤h! †a)„,ËjiI%ãñj½>>>}èÀðÐ@/÷ù©YÏ rÙ5ß÷…øä´á‘@Èv â«gu¦i8°«¹¹^yíÚüâJWWË׿vß*–'''ëõºÏ}:.Õvˆ#lG’ÇNŠDì­­rµZïëëôýàÂ…›AÜG|¡P÷x”RÏótÑÔD ¸Utð Ì‚e#Ò0AB"¤ñŠ1ƘZmoÏ B²›•—^¹¦ÕËîÎÌ·¿~\b$çÌ$åª{m|ö‡ÏŸ‰´Z¯ÎÌL¹.¯Ô8UHD,d`Žhëˆ5%"ùüf2nt½Ú&R-©¸ÁˆÈm–~öËwõ£îÙÕÝÓÓòØÙ=P­VnݺƒT%G~ ¤RZæ </@\âÐþùTRu1ŒT´0LP<žTJaLS©$ÆøÚµ Ã2N? ¤ZZÊV‹Õb¹èx^¨X> ðÐ`´6êÈ,%`0`ŒÚvtïÞ±ææ&ÀèÅ/¯®ç››Ï={†s?¿Yœ™šª×ëAàù¾ Á€1`@éÖŽƒ÷†±¶–¼  +‚×ß¼â8Žïûâ#ŒçÏ;êþbà5&X6fuýÙCq€2™ (0ÆŠƒ €¶Ý¡Ì¶YWOWoo/Æ03·þâ«×õ·öŽõ<~n¿<mÛJ¡Wß¼ñíožŒ%"µZmjrÂq„˱ωçIŒçT!j26Ô4êútjnkßž¡|Ñ5ãÝU—Ô< UiXÉüñ3!¤"ª®Z_/Œßœ %eT—¨èp?|0#> 0|Zzæ‡íŠ€bÊL“ ”LÆmÓ¨»õ‰©¥g¾v ´‘Ý\]ߨÖëõjý¡ ¨ @ü¥¨3ˆÙ»w,•J*D^zñ’FÝ·¾~V‘Ï'ïÞu]×÷]/¸j½k`Œ2™ŽãÇÀâÒªi²þÁ.Ïó_óR­V‚à Œº¿xÁuZ ©à0HƒIƒ*F$‰1H „ ̳,«»»»§¯ ®ŒÏ¾qJ_äÈ¡ÁSÇÆ ^¯W*5ÓdŒ‘{÷6{ºÒ™æ„ï¹ÓÓÓõº,×…R¨îrFH “ŽŽ–HÄÊæŠŒ rii}×h_µR3(E U+õX Ty«¶²–Í®mV]×÷9D J!!uR£k[¿Ú§#î ôq§”V«ÕöÎΦ¦Æxbb±³3ÓÙÙR«Ô&&–——…â#êštªQG郆¨Û³gW*•À˜þñå‹«ëyÛ4¿ÿ+$Š…­™© Ç©<ðù6¤‘N"ˆ'⇊Ǔpkb¶«­%•NÔëÎÛo_©Vj:3ö¡ËK~!P÷—OçÈi^7]Ùõ§—v¢è@¹”’e`aR0¨$L'è!ˆB³,«¿°½=o¼sSÇ ´óðÁA(Šår¤lJ4!„fçW?·WZXXÚÜr\Wz8Ï9c¦ÁhSSld¤_‚œ˜X8y|Ÿª\®*¥|ŸG£‘Í­òâbVJBHÉu¦ëº^°ÍSæIOJ €Ãˆ0C@»Â?­9Cè!‹m—ùÒ––6É·=ùâ`7R(›-x^€1õ<ñ'Š-> uèè3XÄ´‡Gš›‘?¾xqu=ßþIŒe¡Xº{ûv½VãA Äö(„!Õœ:yò$Æt³T^[ÉØ7‚ ÅÊ›o^r]W!¥zˆ@V ¿@t9ðtF¬®(y(ä«¿‹Y9ç„(†„AÁd€é6Y# G£Ñ¾¾ÖÖf¥Ô›ïÞzu¡\6W*•”v4jÚ,›+µ¶&BóóóëëùºËL¤¤AQ ˈ` –a ö!ÆoÎôö¶†Û·æöíDIäÒòºã¸úI|îsÁyàs.Ú˰òò3GÔ‰®\h}$D<Ñ^ÜjµÞßß¡Z]ÏB8Ž÷'ÖîïG0­a~ŠÌ`+ÒÛßÛÖÖbÖ ¯\Ѩû‡o<OšÕryêÎDµZõ|îóõAkk|l÷þd2…™˜Z4 ºw÷°Rê­w¯g³9íMyè8aÝ_¼Ðe§“žõ* Ëç€\èoËꤔ¶I *âŒJà B(îsÆÆ`0F©58ØßÔ”Býæ…KË;•§OŽÚ7€1^]^-–‹ÜõBÉTJ)´¼š;qdÈ÷åV©Vs”ãH NÄŠ¸¾KJ „GGû¢ñh.[àÜïêÈTju×­Gmkum£½µ¥T) e„)wÐæº¾Ï%4Ð*…Ã$Ÿ•C=$~¥©O"¶m !‚ °Mà”V.×VW7*•êÇ—;ñ$Äè†aÒˆiëhëín'”^¼:=¿¸Ÿ;ÔÓ“ö<÷îÝ»¥JÉãÜ 0Œ¡5onnÛÙܬ.¯çû{Û±h­æ\½~w}#Ç— uù–l(qP >ÿ\~9ðôú3 C§)êD“20Wj(ëB'»AbNˆ´(` œKB°¶ë¨iÚm]©T~ýû‹Ë«ùЮ;v`H¬Ü[Éå²Û7ÝÉÁE „@KK˹\Å劖ï»`2›ëkjŠ •[wæÎž=¢”ššZسg8Ì8ššZàü>iÒ6_„vÏѱ“€n …t:MÑ â¤ïº¶mW*—ïä¦4î®ЦE,ËnÊ4÷övBffÖ®\» {võŸ<¾g3—›˜˜ÚÌå<Ÿkõ’hMÇRéôèè(Æ”™ö•kS‘ˆu`ψbemãúõ‰j½ÞÀ> Ôû|QÙéŸuH X#7^EhL (¡’FˆbDDa¬UPİX,ÖÚÞÙÙÙo½w;DÝž]ÝgNì–J­¬¬lä6ÏÛæ#ÃØ÷]Œ™L.×y­ÆS†aq)1¦Édtd¨7™Œº.¿}wöäñ}H©É饎ŽÛ¶Ö76;Z[ªÕj6» $äô‚Pt*¥#ãŸFéÑhRgrK.Aºø·X,~Lq‡²íîu–‰ Ê%ƒƒ½¦iмþö5H¥âO=vhkss}cc}uՏ޾´·Äš››GÆÆ!”Òñ› RÂþý£çÕ]çÒ¥›ù|A!…ØNN“ vÒS>Š9âïxºlÇó¼ÄzV„ÔΡæÒ1!ŠÁ ѦŸÊ4©R$‰´´µut´a ï_œ¼3±]ùßÓ•~òÜA¥Tv-»±¾žR c&9Ä"”jœK$ˆB„bIP‘H¤««­¿¿K(µ™/Þ¼=wäȘm³õõÍõõ]£Ç=/ !¤nݺ+ï>mçXîl%;Á’Ï.eªúíP!Ä¥¬9Nʲj5/Ä"… „ã×q’ŠI˜LfÆb±þÞîˆeq.ÿ˯^ÑýηcŒä7*³““BÁ@oKsssWO`ʹy{!²k´Ré»7nÜÍmnÕjŽV£táyèÝ‘_PÝòã¯1&&a6švu ZÔ®ý Å`2EŒD° TCÒ&6 ˲¬ææLGG!øÚøÌÕsú"­™Ä³_=Ê¥âúê²ä>H`”%LËØ©¾Ïp¢)a!•LÆÛÛÛR©d$bI)§§—æç×?wضY¡P¾}wöôé€a-›ïïí¨Ôj›[%LC\ä÷—Xñ8øü1O+¥|߯×ëRÆ„’VÄ ÑÝÝ>Ð×¥-±?‹:¢5̆p%ÀPô£ÑÖÖÖT*i›æߺì8}r¹Í©©¹CF±ÈÊJ¾5“Ä®]¹ŽAJÉ@,ÁB~ ³D"qüèî––TµZÏå¶.^¾ó™êz£ÔƒE@;Ê™Tš¯Ë …bwgËP_×ÌÌÒÁƒ£»Fûþð´QG?¤db Ô ¶m'b‰®Ž–XĘœ^[X€ÁþöãGG+•šS«>zX“LÂ67+“³³¦ÉíÀû¾\]]Ÿ]ÞÜ* !ta£RRKo)?ÇŒ‰}à騱¦$‚•Pè5&m<€CŠ1Âa2 À ÷ !ƒ¶iwvvš&[Ën½þöðŽÏ|íh*wÝúò BžBm€ˆXÒ6m¡$5ç.Æ02Ôùû?¾wæÔÞžŽäxÁÍÛ‹Ó³+pêØXWG­­¬,ß»×’Švwg\ŸcŒÒéx6»©·mÓõM¡`I”‚&ý³£-}êÔýHѨÚñxô¥WÞÿLO¡c aØCJɹŸÍº¥žŽLkêîô|­RomM?qîØ;ï]øGšvxøƒñFÀ2PÌ6SM‘áÁöhÔÜÚª¼ôÚe°,ãÙ§ŽÕj5Œ!•NSŠ}WÎÜÛ˜_Ìövgž8»Ïó!‚Õåü½•Üúú–Bé­AJØ[|Ám¹¿xºæ@ëíѼ†ô²ZhL1¢ Іƒ@"¤‚@`Œ"1J +ÝÑF \­º/¾zÕÛ±=NíhKÕëîÂÌT­²‰±—0€ e™ˆFÌ”ãxžÓÕ–:{rÏ»ïßþu®¤¿~æÔ®GNîêéJ€çxkk+[›¹–t|×¾}HÁäüÚÞÝ}•šs÷î$`L‘ˆ3¤ε÷U§Dƒƒ½}pwréÝó7±Èãîéjh*˺,=L,¾ŸÑ¯ àŸ(ÕŸ”FØRáÿ!uoe-–°Ïœ:ôâËçÏ>r°³»íé§ÏÞ¹33¿°ö0íJ>ð &Û‚¦%¬ŽöÖh<ÊzãÛ;ñžÝMM¡ÔúFñÞ½ÜÕ³G u¶%÷Ž´BÔëõõÕåB¡¼º^pŹЛ‚p‚ÌÆþ;9ЇLômgIØp>ÈEºÚ‰ìÃ#ŠbnPe2ňB ! „fš±D¢¹¹µ»»!õÒk׿Öõ·†Û¿òøaŒarrzcuK?„1!D)„±4BHD!¦Ù»·Ç4RxûaDÀ1ÆŽãæ Õ™™eJ1BèÔ‰=vÔžœœè2MóÂ…ñÀ«P¬AžçyŽòSÂ,ËÝ5œN§àÒ•‰ñ›³‰Xä™gN&b‘­­Ò{ï]ü¨^_JaׇJ-ø„ÕQM²>£@)eŒé¦:ÓmÿÞ¡ÖLºæø¯¿~á‘G77'=Ïñ}?—+ ÅB¡œÏ¾í´d;>¥ §ÓJ§ScjéTK$Œc“Ó¹_½ ¶mž;³·îz—®LŸ9±;“‰µ·&D $ÈZ­V.äK•­B¡èºàÊ÷Á÷E Àó€ÿýi•Kâi}ÍYßXíßX|ý€ ;ƒ)‚$!Š0…±”€@(B°Rˆ†aXñh²½½@Î,dCÔ%b‘³§÷ÀÊÊÚÆú†PAè&Ýi^#H"…0¦ <5µÞÙÙ‰X–Eõr/W¥åÍÍ’®³¤”ž>¾—™ìÞ½µöÖf‚ðÊÊJ±°N±pw^ŒÖ±¯d*9:<‰E|—¿òÆ•åÕ¼aЧž8’ŒÚ›ùü•+ã)ô!»J!äºAÝ•®ÿ),&¥€‹mý!ý¿@X)JFݽ;k ÍÍMÏ|í‘^9ßÙžÙ=Öß”HÄ"‘Þî]ŽQH)BưÃ"C0!Dç@X–E™œ^Ó¨€Ñán!àȱý»û¥äBˆR©V©T²Ùl¥T✠¡jò]åxàsàœ|¸ãÏ—À{Ð-fÆ)ÃzÔv¶waš˜A5ÀÀˆ‚ dÛ)Š1¦Ô Œ%ššÚ;[)žÏßzçfx¯=yØ0h¥TZ^^âÒ‡†þÚJ¡@ , ¤ÂB2$(ÆC¡PÏåjAàAà8ŽfRbŠññ£»›šâ…͈Çc…BáöÍ[–!”€¶ý±+ÀÈ2Xgw×À@ŸÈåʯ¼qEW!}ãéS--ÉJ©róæm„cZæë½F@ ”ïKŸcŸëÁùtÖ€$P@#enlÒÀ`‚šššîojnþÎ7OÏ.®¿þöå­­ÊÙÓû8çí­‰ÎöBÊd¥„À „P†e”*î‰5 €Ï-e§g³=]ép“íîÎ<û”®ŸÚBJ¸õÚf.[*•|Ÿ»¾ åxÊçÒó æ© xÿËã>ð¥ÙŸ P· Ñ;¥@`1¢…HÐDlÛŽÆb Û¶àý«“:ýNM·$ݺ{gj­»÷KÔ¹¤”bŠ…"¾#$p„¦¾’3FÏ£W*Bˆë»J).¶—OÜ×Üœ¬–k››¥Ñ]}Žãܸq“%¥ÜÖÌB„ L#»öìI¥SB¡»“K¹Í’aPøú3'[Z’•J寭 Ÿsšk# ‰@¹\ AênðQ•šŸ¤è 8|Ž<Em©gÙ¦ŠD¨e½87;šZ2‡vÅí;Ì¥ºqkÝ´ñ»î,-z;®Ô¡} )¥øwŸ‹F÷Õ]ôÿ¾‘ˆñÝçŽpî Ål6»¹Urvd_{{sss«‡Œ ¤ÆÇoy^ Á Æu4ÆÔ°:ºÚF†F ·Yº3±xøÀÈ˯_ÎçËçÎì씜OÞ-W«Jµmó(ˆ”çK¥ç¸êª‡Ò}ºÑóÆæ÷CŒB„PkÙÒêz1³¢Q“’HXñ¨HAC ¬Lß÷9fÚ&ØâKW¦VÖrðè™}¥Jefn©\,k _(t»BRçàñ>Ÿ cCš1!èìÙñXZZR--)øøØ Ë5?ðø])aµël,üÑ`¬Q)É•~¥Æ!ƈ‰%MMRÊÜf)LÈ)…”Ò T½.C"ÍD"ÖÚÚÔßÛ©·Æ\nk||ú£ú9·¤SŽ|Ô™‰Dlx°»¥%ÕÜœÐ'\¾|§ø±[«>`2hìÉÔ,]¸Œw„cJÇ^€fËÞÉ QFh4n`, 1þãO_Û4Ÿÿƹrµ¸±±±¶²âûNHfWêÞ=îØ’Nµu¤Û[›õ»A°‘/Þ¸>¥5:(ʹÜÖÕëŠ.¢žž=,zxǶVsšo„Xͤc©Tº³³UsÒ‹ÅééùR©Æ¡†ÑÙÙL)¾2> ëôqÜÚÚüÔSgJ¥ÒwÂn< ±4Ì%LÇr§9Loó<ïOÅñ4kèÆl¤aÿ0ä1­šL1"è¾{†bšv<ÏdZ;:º˜©|ŸÿóÏ_×n•³§÷îÚÕSÈÇÇoר$h[übÈ÷Q "(ÌÆnìà ;ýÝÛÒÒä9þ­;3'ŽíVݺq·Ïb¼ÔEîííícc#°¼š¿·’?¼X!¤QwèÀà‰c»Ü  Zwßyçbà€Q P¥!étr÷H_K[)%á>Rè•7.nn–ÂÆÑãžž¶®®¶öLÓg¾þö•­­ ¥ôèÁ±îÞv©RjûÕ‚ xùÕKZ›ÓM`>~¨PßWoä‡þÜ0À$Ê0”N—kŒâ2ÓŒGã­­™D"bÛö/~õÖZv¾ùÌéîîL>_¸zõºãÔ\ï!ÙÌ¢¡Û+ÆØdìС]z+iÜþ aRÊjµ‰X.½õ›ï^Ó8)å®ÑÞîîöXÄ µ}m(¼õÖåÍ­J#ùH:|ì‘à ©F©Ím½ýöµFŽœŽ¶äþ½ƒmmé0ËJÊíðÉõëw}Ÿ›¶ÙßÛ‘HÄ^}ýêüâÚØHÏ#§„W(Ëï¿I304æ*E\Ž¥Ä Ÿ(]ÿª&€nYVØcrÁÂúWØIà J±IcŠÒÅf<žljjjmïhkipçç×^}ó:tu¤Ÿ}ú„RêâÅ«[[[VˆuwrÎ —8œÚP×M’FOÛ“L%jµúäôâ‰#»•RwïNnnf)ðm}€ŠiWWÛÐÈÆpõêŒBèøÑ!Ï ~þ/²¹Ò=½_yr?Þ¡ª½tevi9·°”7MöÝçŽ õ¥K¥µù›>×.)c¤g`W¢)£×Ñ[ËÙ\Q÷U<{z׉cÃËKs¹ì=F˜”FÓm]©TŠbYª9믿;ÞuâÄhµ˜¯×«é¶.F˜BèÚøü;‹Ùl þáÙc##]+‹÷ÆoOr.]×w1¸þÎذÐÕGô^½ßôv‡Žc̲¨d Â2ªav4ÚšimëHY–uáÒÄÕëSðÔGì*WËçß½T,Oq€Âæ$ÀÈ6 À¶ “²GÆ:Ú:˜iK)«urzmñ^~v>«sÍþí?>ÞÑ–œ_û?}:ÛßîH*Y™~7^$ÖkÄFTJ˜¿·95µ2~û<ùèî“ÇG*¥ÒÌÔøŽtÀ‘DSÿ¨BèÒ•é·Þ›€TÒþÁwN'ãÑ»7/:NMó×u÷4gZ‰R˜Âøí{ÙléÊø<þèîÓLJŠù5Ï«ÙÑx$’$ÌÜ*9?ûåù­’ɤmYÆShmN¬olLܹuŸ¼K÷Þð9öâs(B(ݪà£B)´Ñ‡B>ØiI¥? [Ø…· {Mb¬$HR˜Éa” L¡Ô°Í(!( ·YÖ7Ú·oP)´²²Z*U"AàëK…J3ÆX)PÛ^SÆ ý®Œ±T2~äØÛ¶¶J嵕Üñ£{@©;·&J•͈Awbn$™´÷ìÛµm…Ô+¯ÝéìÍ8Ž÷óß\ÈæJý½™¯=yPçX_¾<ýæù‰“G‡ÏœùW?8])9?ûÍ¥®®GÒ-ÅÕZ¡L-³µ¹-ÓÞI©Å9¿xuþòÕÏ ŽúwÿýÓ¦i¾÷þ]Ši"‘¨–ã”â–¶®––!„ç/¿7¹°œ?¸»ÿÿú?}üó/ß=|%Ó]MÄ9Ÿ]̾üúõÑáÎ'ÏlKÇ%àŸþâ­®®l%Êåz¥®lƒø@ìàM€”ÛŽŒÞºQ‰;­ÎA4{/ˆ’°3ÂLÓŒE"m)Ã0nß]Ò¨;t`xïî~ÇsîÜ™(—‹^ ”J€ÑR]±*ˆÅp__×Áƒ{a©Å{›®ÌÌ/æL“=½çÇß}Ô°hvmóÖÄ’ï·jÔ¥SÑŸ|ïd"ayµ¢ æö#ñT«RhuµðÚ{·Ë]£ßxúÙùÅ­Ÿþâý“'wÇ“iðÀ4ͦæÖæL'"jüæ¢F]S"òÃïžN%íR©èû¾iÛétkº¥‹ÆpáÒôùK3žœ<:ò?ÿŸ¾aXôwnûÊ ”Ši˜àpgbõë_;ÚÖ’ ­­•~ýÇ÷~÷•ï?ÿx*ÕˆY­ƒxA !͹BˆH)Á„¥Ø ¶N˲4v´Yô ð ÃÀkž]€G)¥”ŠŽºŸV¡p×AvιÂŒ‚‘P‚ `R@J l0ÛŒ–!%WJ­®æ ÓœèêÈ8Ž3ywžû<ÉLMq‹)©B’K!„s° þ W?p_OÇ޽ÔâÕõÜæféÀ¾!PèÖ­»N½HP@)¥„ ––äðè.ÆØÚFqzvõèáád2Z­{¿øõ…l®ÔÛùî?œ¥îN¯½õÞÝÑáöÿùß=µÅ Š'£P¯úŒ²«‹utõÅ“)„Èì|îÕׯ—*Now景N$"PÚª%S…T½Z5m³¥¥+™L¸qgyüæÒÞ½ýO=q $G­çJ‹÷rµšƒ1(…^yãBè_ÿðqÆp}^¯{žl•*‰D$™J"â#„ ò…ªÎ-Ö(úK ?!B hö!ðî›è”€i(ðbM‰îÞvÃ07Þzç:Þ?òÔ“'J¥­¹™¥¥¥eŸ P:=m§BB À˜º»;û{uåZvëõwï,.æà±Göœ<:dšÌ0(ÙÞÞôæù‰7ÿãØ&û×?<‹Y•­r.·ÒÒwÂ4£€‹—gîLÝ{üÌîÁÞ&íÀ¸vsÉ4™ØÆ–iÊdRéüÂ¥¹kã ÐÔùñwO¥â‘Jykqv2‰´v$Í`ñ^î…WÆ‹åzoæé¯iJDBÅb9•Œ0¢0ö[[[)¥žç__<´¯—™¦”P®Ö_|õ¢çž,/o w67E666R1 û>  Œìs$ò<¡Fè.aŒ…Ì)ÛÀkìÝ£›Š0ÆBª¢PiÌ÷ ÉŽ(¥)(A®§À2¥ŒRð,ÆL!ê/”`l¬!T(ën] 4¡ÞÑSý `Œ!×—†¡Ép±R‚1ÝGÖ€¾¾®}ûF0À[Ó†aØ7ß¹uË­‘⌌‘e¨¶¶Ö¾¡ŒñääJv³øè©½R‚ëú¿üÍûÙ\©­-ù­¯õ]ÿ¥×Æÿ{ª9Áâ” ue|±X¬§SQ×ç†aõô ˜¦­zéµñ›·à±³{N RB©T¿»ôÄÙ] >:ºKJìyÞ¯ÿx½·»å¿0FHPe³…þÅ{Éd4™´³¹ÒÛïÞ:y|Woc껾B„sþ‡—.xNК‰`™&qj3™.Ð& e; àcÚ}ÛÍFèà lšv&Ó<4ÐgÛV¹ì¾ðÊE8rhôì#jµÚÄÄÌÂÂ’à`zŸcS³YƒFq2•>tèePŒá/_½~k Ú[›¾úÄÎÎ&Û¶ R&#u7Èæ¶nÝYÓdÿôã3‰˜U«T …|Wß! P®8¿øõû‡÷÷ÿ7?zƒDÆ~ÿ≩ÕS'FB^­bšfG÷€eH©_»‰ËuÛd?ùÞé–T´RÙZ[™K&“m]ý¦/¾zãÚÍE­Xž<>¦—t©T»~céñGw!¤šDH6Wš_Ì<>"”/øÃ —JŽhó<¯TÚÎËçR …AX(P #âŠKÌ%"‡b¨dZ–¥ Ê·±£UGÝK¤Ñi¢ñ¾p¤T[üú¢:%R€¥TŒ XHAÀ#Š1Õ ‘’•Š£/2Ð×­š]bÛS¼Á¤)¹Rp„°¢hÃ!‰EöŽ d2i%Ä»o tuud”R·nÜpëe SŒAZ–Ì´¶÷ Ž „.\šÆ9¹û¾ûËßרûÁ·N..å/^=÷è4¥ƒPH(d …Þ¹8óÊ·è߯÷ŽÄV׋¿ýãåb¹Þ”ˆ|ç›ÇÛ;›•ˆñ›s[[µ'Û‹”ÚÌÎôc€ÛSk×n/=vvOk¦¤ÄXPŠ×׋?ýÅyÏ Îœ™›[½zcñûÏŸ±mS÷öÚXÛüÍKWJ¥Ú¹3» Šëõ*Æ`2TGbs‹cô1§øÇsÜkÔ±‡¡Î`È0¬¶¶–={vY–U*9?ý/¯Àé“{îö¼àîÝÉ¥¥e¤\¤‰1ºð B4ÕÒöÈ#'MƲÙܯ~ÿ~±X€±‘Žoó$c ¤´  —«u)ùoÝÕWøÁ·Ž¶f5§VÈçÛ:†1ÆSËׯç¾óÍ㉄EPJ)?ýùùùÅÍŽ¶ä™Sc©zµ800ÂL³Tª½{aº¹9ñê›·l“ý›=Ò–ŽÖë•ÂÆZ,‘jëè#„­o”ù› zʾýÍ£í-?Æo,ËÕ'Ý@"Jé™ÕR©vòøˆä $AJýËoÎgs%èéJkf׉;·‚ÀÃ(D©PJ!Šƒ@(„•Bž'ÅvC·¯êîHx!ºB×§vrj˜iø)¥t“-­sjU“1&¥DÛ®!,Ú^=ŠDm]B)9 EB áþþvf²Í|¡T©¦!A¤Ú¶!1®`D8B¾ç…Ò•1Æ9èëÛÝo2V­×oÞœ9p`$‹¸¾;yw2ðjƒŠi›$Oö Œ(…^}}|x¸£¯§M)ä9Î/ÿ~6[J&íoýè[ïO"¥þÛõ!Šb à d)ÀXÁÏ~{ñöݵ®ŽäWß#¥´ ‹06;Ÿûç_ž€Ž¶ä÷¾uº¹9"ñÞ•ÙùÅÓÇGêÇåÂR×À(Hùâë· Ãøþ?œPŠHÎC„ÀúzáýùÏ ÚÛ›`#_þ·ÿxŽ1ç|zvå׿¿¬Å#'Ç$àå…%JHÄ „ªÔ*š±Kwð|ÄÇà&Ñý™?JÖ†58Ø?0ÐgYÆÜÂê /]€¯=yb÷îþz½:3·poñȺ”€É¾N0DMšL·Å“©Ýc#&cKË«ÿùgoëtïñ£CS‚f*Êõ=)å{gîN¯Àw¿q¤»»¹îº¹l®»Œ ôê›7•R?úÎiÎ9Æ”*U¼ŸÿæÚúF±£-õã>j›¬^.¶vvBÖÖ¶®ßZÊ4'^~ó–m³úñ£Ýí p·œoní²"1BØüböýÙyhoozþÙ#©TtþÂäÂBö̉‘£»´™Œ0úýËã»F;wB”ªŸÿê=º‘¡Ž¯>q!´°´°™Ë557Çã©b¹¸±‘%tš®á8R(¦µ72ÁN¹î”|_Œ¡L¨UrÎc: ¡‡º—]hÝi ©.ŒBHŒ!$$`0¥ „0„ˆÜ)Q€T2)¹ÌJç‚1ÜŠØÜw’m•*¡Bº7ƒöÈ öîß?*”ZZ\]YË9s)T©Ô'''ƒ †S‚0&ÁH‘x< —®Í94’LÆ ðÜ_l£.úø™±·Þ¹{pÿ@_ #JJW$†ÊgKÿù—— ÅúÐ@˾}\·4b¦1߀ºúá¹Kãó¥Rme­pøàà?~ÿ BHrWa•Lw÷î…ÙáÁööÖ&…(ß4Bh-[þO?¿àyAS"Òœˆ¤“Ñýû0ÖÓ£¤Ï_{ãÖû—§5ê~ò½G"ÙåÕ¶Ž®ž—rL©óç/‹%Ãbã¼ÇùC"f‰74ÖÚ ³F@ B,ËÞ³gO[[:_¿1ýæÛ×RÉøóÿð¸m3Ïs¦§ï--ÝÊá¾ï;Õ&A`ÇÓ==]]mŒ¡‰©¥ùÝy}·¿~|l¤Ë´M¤<¤Pà#ë\Ê·ß¼pež8;::Ú.¹,Ëm}H¡w.Lô÷fû3!‰ÁüÂÖ/wÅñ‚þÞÖï|ë¸m2¯V‰Æ“H‰‰É•;S+ûvuýo¿¾ ?ùÞñ¾Ž„RÂó ±¦vjE‘R3 Û¨ëhKþã÷N_½±T,Ï­­•ŽêûW?: ‚ÀCHQj½siæ‘“#ñxTJÍÈ­~û‡ËKËyØ;Ö÷ø¹ýJ¡•{««ËëGNœŠÅb A!táü¥r¹ˆ0â{ dz¾h4ÍÂÆX:æü4Õ~B-Á´'“RªÏƒæ$´þÑPÞvo"¤@P F.”Ò˜Ažç9ޱP4ªÝP êÕºZ­J!$(Bm7ìPº$œRÚÓÓ64ÐF…Rç/ÜèlÏœ:uON/f³kŒp‚€b®aX®/-‹Uën«"G*…R®ëýò7ç³¹R2iÜÛ;1³öÜ³Ç ƒb)¯b2…RêÖÔÚþù%Ø¿»ó‡Ï—sî#f—¶j¿øýv9ÌZ¶ôÛ—¯¶g’'D£{0€ïs§²Oe¤D³‹Ùb±~êØ0RÄçœû®+)××Kÿéïéª_;jž956Ð׆”@ ¥êu÷ûÕ{ó‹9èkùÉ÷N Š…¼‰¦[¥ÚÂÂÚáÃÃÝÝíŒ(DHkkûÑ£iËŠéê¨Î\3™™/lMM-dZ[+•ÚÂÂ2HîûeL ] :ÀíéíîïïN§ÓJ©_¾81µ°kWÿc«TjwïÎlnnˆ p ¨´X«E‰6µ·wwtµP 7nÍýñå«ú„}瑾P¢&…0í¸Ë=BÈ¿üáÊÄÔ*ΥŠ„Ð<(:`뺎P(LÃü€W³±‹iš®ë†þL}¶&ÕlL~ -–e¹¾kPŒu’ÇEÄf€KÉ%—¾ï[ŧSIÀÚ.c¡aL‚4 @s!¥Pƒ¸˜ P©T¢»³s`¨›²ºž›œ\Üp¤µ9ÁôìR.»Ž!ÀX( D Œ9¥Ô00ÆPÈMMEžïþê·ç³¹2”JN$b<ÿcˆéW¥ô#ØJJ€WÞ¼ûæ»SðãçOŒõ8žàR˜nÍÿ—®9N?|þLo&´BªUßwëÔ€D¢•s¸xyNå’òyÃ0’É8Aj}³ôÓÔut¤~øü©Ls c‰„$­Ôêÿñ§o­eKpúøðgws. ù‚OBÍÌ­OLÜû‡çNxdÌ–JB3M„ĶOTssÓÉ“•RácGÆ$÷kµÚÖV©X(OLNú(‚¡­£­£­e` Ï4Í\®ôÂ+0ÀsÏ>2:ÚW(ËåòôôB¹\R¢l3ü`P˜‰{û‡Z3­­íÍ–A/^žxí­í:¯ÿö_=ÑÕ‘Bp¿ÌˆAÍ(çRâŸýþÂRïï=wjØçàyn,Ö„úåï.Ú××ÕWAÀ˜"®Œ/ýþå[ðÄÙ}œQR*% ƒ*¤~þÛ+­É½cu?øöÑîîÖjU8^YðúZqüæRS":·€}çto+`¬û»®Ç}0¶¢­Pï_žQ :6ìs̹¡º|yR{Îöíé}ê±CJ‰üF^)58<¬š_[^Î;wÊÅbˆ@0!°RÛSÀ˜¡±ƒ1®9žBD þ€—å¾ÄÓ±ß÷5ul^T«Ú:ÔçhÈéX‚ïû¥çJq `¾Ï3]×F•ïûA êu‰°Þþöj¹Ž”Š%bA 0ÆÞá !P#©3͸éííèë֛ǻço$‘'?Wkõ[·f|·J©À0%(…¦ºy€A!ÑX"Aò|ï¿~_£.™´¿õµãíM [)1äSЉ /½qçíóS©dôß>™NÇëu_(¤„ÚÈoÞ¸³¸x/ßþTww3çœó æN­bX4†á8ÞKoÜíïm9´¯€äs›†Á’É$!juu+”uƒý­?úÎ#Q›a*¾Àø…KÓkÛó#ûvµ+É%÷ZÚ’Aà½ýî„m³ÿñ_ ‚z5?uæX?`<·´±ž¯__.ëV,èI%m„Ps“µoW‡À*ûZê8v¨¹V©9ž‡ˆLuÂ!¯¾~íöÝùs:vd·çyÅbyuuceeµZ­ˆ ÆÅ}Ôa  À6)3£ƒÃƒmQÛVJüê·ï…¦ËO~p¶½µIr^.å,Ëðá®®&g³É¸ {FÛŸ}j¿Ï±„Eë®ûÊk7OimŽù®‹SblºçŸ;±{¤KJ 0Â+ÙÒ^ºö•s{#úïÿÃ[ðÜÓ‡ÆF:\WÖªåH¬I)41³šË•ž<·ûÿñÿzA£®¯§…K)¯â9„ˆSjÔjÞ‹¯ßèím9¼@\‰)ÙÈn¾}þ޶ëž<·_r¾µµeÚfs4.%œ¿4ašìÜ£ûAÊ»wïnn•¤4~vO:wG8e;ç¿wqnG_mBbа‚+7&¦Vþñ‡ Õÿÿ?¿ßøê¡Ãûûü@ú¾4í”ðòë7ú2=²ûú%úÓÓÕT-×…ð8w#‘X4EÍ-å._>vdl '-„ª”ª‘X„K~ñê4ôtµ<ýÔ¥P©TŽÇ“ˆš¼üêÕÃû‡;;›B·oß][[ç’„"JÉÆ9ιëKX6”Ñ<$©H{µ¥±\¨’êO!:x½íüØîhG8ç”ebÎ%Æ:PD£v$3M3‘ˆE"¥Tk&–LÆnÞž ‚àØ‘1Œac}czv~kk‹ ¢J¥’­™Öx2ÞÖ֢ﻰ°6~{~°¿óÀ¾!Li½ê®¬¬on•â>cŠ!¡í\ו€…b¦ÚѾ˲¸ïÿú÷ÛŽ©áÁÎo<} ‚À«lå‚  Dm;‘È`Ãøõo/:^ðƒoŸö9x^ y^^óF29vdøòõÙr¹þä¹ýP-W…B†A-Ë`L•JÎ;ïOb€g¿zÌŽÚRòr±ˆ‹X¥Äúzñg¿9¯QwúøØWŸ8 ½ÄÕrÙ眙6ŸX®þóÏÏÿøûgRɸPËõ+ãs¾ë?ñØ‚T¥V»·¸ÂL666²²’s}1Ü߈ëg!R(5=Çf²|±z÷îÊF¾¤Í*-o{z2M‰H¹ì"„öŽu%Sq“1×õ§æûþüü9œŒÛ‘wÞŸ*Uê_y|¿”¸X¬ƒôm›ÙÑ(”Ëõ·Þ»­úê‡" ‚ R©QÊD,Çñþýÿï…–tòûÏ?Š ¼€™L(43·61±tòø®L¦©^¯ß¹3U,„PŽ#…"RN)ÀJyž§ÑJÂÆLÎmUS»RôIZ éú™¹ aúTB‰©”BoWa+À ƒä®¢XJ.9'„”JNSSôЗ^¹táÒ­3§ö¶·gÚ:Z0Æ4Ëøýò¿ñ›sSKƒýíÏ={†1†Ê®mær›A˜„ø„HxN¡¡„ @™m›ãžž.˲\ßÿíïßËåJ:ôyæÄn<'›]Ói4l eJLA‚ëú_ú˜ëKŸ ²º–½zcþèþÁ¾¾6MÛ5:Ø…1•RÆ1@HU*µ›·ïMÏ®?ynÿP­ZÞÌ®qÀ™ÖNÎy.W Q÷ÄÙ}§OyžW©”6sY’™¶Ée,KÆmÓdѨ‰1¾ywei)»¾Q÷ì±WÞÿO?}åðÁ¡áÁŽxÜÖµ‘///ç6òååÕüÑÃCÿæGOB@ÊBqkem³P(ú¾«D@GP€1¡|¾%¦“xÌ¢˜ÛQÛñ¼ßýî|n³gNì:t`ˆ U-o ¾ï+!3%Å$Gˆ–±µUÉd¥­ò•ñ9„Ô7¿v8bY€AJÑÞçý;ñ¤™JÚ©K׿s¹òÜRþ‘ãÃÿî¿ÿ*çÒój›¹l¥²ÉK$2Œ¡¥åÜoþpE£î+çvØ×S­º¹ÜZi3§B 51†”BBaƒ=ýÔ¡ÿåÿý2Œwôµ>qvŸ”œsw}u¹R)QÀ”_/sßíéHýî…KÝËYÃ2í Q¬Ë)‰Ï¹1RcbPPÊóÒ´RŠ 25·6Üßö­gö¶6'– ÙÍÒ»çgÞ|û¼ðÊ5ÛdgO÷`ËÀ÷wDK“ „ˆzݽzcF)T(×nÞ^9~¸?þè;'‘"ˆ ,}ò<§Úݽ~ã^Äß Þ»85~{ißž¾Ÿ|ﬞç„"–Á}.DpùêÌøÍ¥'Îîìo–RTËùå¥Eà&„„R‚sÿ‰³»~ú‹w´r¾k´ë™‘.)e±\ùÙÏÏËõÓLJODJ$.^]ØÚª=þè°ÉÌÀ 0ŶÉ‚Îö¦7Þ¹ÿZ45 +ã³¹\ù޽ܑCCÿæ'Q Ü/ •Jɲ"&³ JɈ…M“H„ÐäìÚÜÜZ©R;qlwOG@Þ[^[œ_ô]@*)$€Ä€FB©ˆï+.Aø´z¨ó:ºpŸ3¥Q|5rBkY§q ÃFj£Æ8;çÜ4M)¹eP ~4JcÆIܶ C±H„&”H&SMMÍ¡¥ÕB6WzïýÉPëmmM ´·¥ã]i]“S)m•¶6K¥Mßç^ ¤¶‘¥ô9;]È !ˆ ƒ©Tj`h :A¢îñG÷Ü߃”ªUJùüºç9"€Ò¨i›v4™L&šH¡õâ¿üáZ©âôt¥OèëIïdý jP|óöâKol“I;4ÐÚÚ4Ð׆Ó¥"¹ìšïûˆÛŒFb±L¦Y(ås\ µt>5³¾¸¸¢=U‘H¤©©©³³3‘HØf DÀ%çœ#%K%D¥RZ»7OPÀLe*°£,‘°ZÛ{M; ×o­xNpwvc-[yhàζٹS!õ䣔bɹÔÕ¼B|Ÿ¦¯¿=§³/½1ýÐë˜&{äh/"cyæXÆ8"Dr¨×«€HlÛq_r¸peþíóSpöôžCú1† J ¦2—«üê÷=/8~täøÁABˆ|ãÖÄÆúzssÄ2Œ¦¦æh4ÚœiÆXbÀR`ª!T,Vþ/o–Jµý{ž~â@ ‚kãó['¶µ%¤ïºžW3™I©ØPˆ\¿³üêë7v¦l0“IŽ´a¡Ji3»¶Ä¹³£±h<§2`bnãåW¯@wgfh¨cl¤W‹œÕÕõlvsîyžJ×H \!˜ËAˆm9dš¦nßFÝvº²’B(,ÄÒk¤…«B«Q§n…æŸösZ–Ë…´œcÓ4c±XŒRjš¦†n2i·¤£¥ÛÅ—TCŸþz©ä,-oT*N:´ˆÁ'DÄ)¾ï Òf†aDãñ‘‘¡x<êy®¯€çž=ÕÙ™Á¯®nlll(¡ên•bª;7D";§†i2ªÖHI Q« ŸcƘ”<ÓL¥”’o˜Rzß"õº¿²¶¹µUÑê·~’D"ÑÔ”HÆÆ@BOÌL-ç6·jµB(‰¤R©T*‰D0ÆH‰HL“(¥*5/—ÛZ]Í×jNh]†Çu>CWW*І´í\© ÛÅi:KQBaŒ©A…@œc¡¥ÆR c¦Sl×(DÑËÅq=¼¶iûÜWBaŠ9çØç2›ÝªÕ<Îe,“RÚ¶­TÐÑUB–A)EˆxžW*ÕÊU!F)M%cJ?5(Æxmmszv¥VÙbLÙ6³ –injiIël fŠ1€”€)ÆœË_þîÝâ}ýÉx4›ÛJ$"CÝ--q¤ã8Åb±\,ÛѨ°(Ēɨ”ù¼ÓÒªe÷ÞZ.—Ûª×ë:=#‹%‰xÿÍ ôNzôðHSSìàþaɹÊqœÍ­­µµ¬ ÝÊ›™&b&çD)ÔܜЄqP­Öײ[Åb=^-ô¨F"‘D"aB*g†… Ró …òÆF!ÜX}ߥ–^a;nÝ_$Líz d÷Qµ°a’fŒi‹®1¶ª§a'“0#&LB ».5’iÈé5¤YwÂô´0´¦J=ð!AÆÜ  íÔe‡Å¸–eYVdll(žŒû>Q÷Ü7Îôtµ(!ïe7·rn½îû~è‰eŒĨa#UŠaJ)¥¾ï;Žã8ŽTêÔ]5ź5ç\CÎu]=ú„=…úÐ3亮ã8õz]325º‚MÓÔ×§0h8Âd½H$B)µ,˶mýÎÑO¨ŸM說ý Ÿ§qMèwÑ©T*íííÔ—Ëåz½®• Ji2™¬T*z xžç8ŽÖkô\ …T*U­V5öLÓ YÆõ ëÝÄ0 í$·m[R¸¹ „Q‰ 7𠪵µ5žŒƒ„¨‰'£QÛ& iUèW¿~+_(ïëyäô¤¦!´µUqg}}£^w”’ˆ`¢Ƙ˜6¦ηž~#ιVzÖ• ç+F"‘X,¶ã“ ‚ Ð3«__Ÿ¯]„öq¢U¶±è.$ú(àÑÓÔ†ôí^†š!0êõzcWÇÆ(áC™ÈBg©ÎmtІ¼ zûןèÁ2¨ÄXTa°#-B˜RŠ©iÚccC‰DÌsýß½´½/~ëë§;;Ò¾Ïççóù¼ëºœû¡½*„À@=€O8—hGs‚ QÚhGK§PëÖ{^Cú+úiõ ê…¥”Ò˜Ñ{d£ išÂùkùõ?Ã%Ö,ë[„¬•@Mêܘ^«ÓúÂ-Yk a%˜^"zËÓ+Òq=þŒ±L&³¾¾®ß®µµµ\.{ž·¾¾ÞÓÓ³ºº*¥ŒÅbµZMCQOúúúº½FC‚=2:>‹é§ÅbzÕrÎ}ߥ+Q)jÁL–HDLÓD8é¥RÉööV=û«ë¹|¾ôþÅ mn{t?€òÝ ´YÚ*Uªõ*÷}…”Rž”À}IA$"y€P]W†Ù’zTÇá;‡¾…~Z½³8Ž£w}‚Lß÷u…jØ­6D”¶ÜÂ…¥ý¡®§o¡Û ,ê‡FÌèe.—F¶•´Õ?Ëü¡¥œF]ÈüÑÜÐÛˆ:¥#‚RɈÔv](ë¶ ìèÐÐ@ssÂó‚u_ædwg†s>7³´¹µé9ç¾BJ ¥T!¾\¼aLõ³ítØá!´<ÑG<}N¿0Тªß«ñüðäpÚ‰BU¼‘’(¼fCSBÑÚ>Sgð…£qŸ†`gÇ ÓõŽFڕЉ­ÁÞQ+ü^G?Xx„ï«ÇGÏf˜VêAz¿Öbƒ$p8„pŠ%$ Œq<ïlJ$R åµ›sÚpu]ÿÚÍÙ–tò{ß~D)T®Ö³kÙz½êy^ és¥T ”HPˆø>æ‡Ï"Äó¼prÞm“rçhLhÖ¯¼ãDùX„¼ál6js Ÿia£hUÍÐÞ#„¸®kš¦~ÛmÜ0¤ÉØô×3#‘HoKK !ôËß¼¢®«#b~þÞæfN÷ˆj´k ^AjŽÀzM<°ôÃÅÚÈÔ>y¡öjŠþ‡ù6Bì5&4<пúO ]èv~  }x…FÀ4>Ü•·‘°£/…zGã£>p…ÜæÃ!UæÝ'P ;Ît‰¥G©’ ’M1“™c»w777a ¥’3·°ö À[³ï_œÈdšž{ö„aÕjýÞÊŠã8~Ý ÏçRåû;RˆÕ:ßéO5êÂçùð”…¾E¸}ƒÅÜ0n Ô‹cF†ú4‘Ûï_¼¨%¾ñÕÝ™ ssK…|Þq<(ÿ€5,Q±ì:žÀbé?ð´áƒ=HŸ$×j8t^¨´?ðë졳ð—^磶FïPø ‚T8ÑH J€2D£ñT*uèÈŒ¡X¬Ï/®†±{¬)…º}{á­÷n%‘ï>÷¨1ªåúÂÂR½^DàûÜóDðPöJ >Ç媉D4[¸ÉþÙ){à-ÓJ>þ*Ÿyh÷7†"”RŒ(F„iì…j•a–ìÍ´6ƒ„ß¿|u]]->çu®ë |`¸1pŽŠe×ç8>C½]¿‡®ÓƒmÇ~)ÅU„©D,’hjÚ»{,‰H€ë7fm“ííѦ `|gbñíwo&‘¯íd"©Tj s u·Î}¿êrà÷KÝRœ+/@^€Beäs4JôS»1¥a¬#4Ð5ê C°Cø‹6í¨Ö0[[›%ÀwPwî̾îîŒïó K…¦xJq x»­BÈw¡Tqêž&ÅûòøÛm¦Û HºY´¦â'Tš¶A1ŽÄb‡Ä”Þ[Éæ ¥C†whcAheyãíwof2‰§ž8’LD+gzr¾V«¸>—R .9Ƙ Ž1V¸ÄBø^®ÏÍöô©@NÓži?AHDA±4¨4 Åú{†…¨Óæòê4éúìüâææ¦çxRrÝö-T$Uj¾/©R_6gû$PþS) E,l¤lÎdNœ8ß\PÜ? €76ŠœÆxy5ÿû/fšÏ={*‹•Ëõ»w§«õj½îû~ ûÃ¥"r<å¨V«aŒ?Ãõ)H<=‚aýÑ6º€T2¦(¾ŸÅ²W4mÛèÛ–u/Þ—uuSs…bÁó>€:ãúÒqd݇?ÁéûåñWQ/}  —`8•ÔmOh<=~ü°ä|üöìÀ@gS,â»þêz¡¯¯ææV^}óÚ`û“Å 噹·^w=M–¯»”J„—\ ås¤ëqþMú—Àƒ0j»;Dƒ§Q)eP`Dš&è„°ðO”RJ Û¶‡û[Ò)øãެkh02»¹¹éyžRB‚THI.9çT¾ßÿ;moÿ‰¢ì›D P,9÷‹$£ñ#Çö !nÜž;¸X)UªÔêu¿··])¥ÛÍÜ?tüè.„P~£0=»àÖ@Hßç:ÁµÁõJœ@`)ùÇŒi} ¼mBhÔýiKƒ*]ó:{4D5êúZÒ)…Ð^¸¢îÐ!¤Ôôì=:¡#àB„]‘¥€@ç_¢îo®a>Š ˜€‚KÙÙ݉š˜ZÜ5Ú'¥œ›[noomkK)¥nÜš½teò©ÇŽ ´À½{Ù••õz½^w}8GyA°íc”ØåHJ„1|NÝ' ¼0×a‡ø};ˆe2 TÒ0Ïm·&·,+”u ¦f²kkõºëŽëoði}‰ºOòx`Œ)F€À¡––”çÍÍMÚ¾î€r¹þÎû7}×ÿþwOÄbœ‹¥¥µµl®V«¡¨àNº,‘\ E\ÁRòFfØ/÷§4̰hÚž$ ª 0¤¶ÿCaŒ1#‘ÈØØP2o”u»võÜ?(¥œš˜Y__wœšãI °pç¸î.ð%êþöâ.”xmS jÆNJÁ`„R#“I"$6ò[’ ”I¨••üZ6ýÆÜñ£c÷@½^[\\+–‹¾ë‚ô— ˜ipΑRŸÓ@lçÐ…y_J¼?ïÆÔJ¦w:jLj2 ň$H!@R Œ0 …1ÂL›Åb±d*îyÁ+¯]Ó¨Û=Òóȉݜó¥¥åÕÕU×­»¾z@¬‰ÏpcÄ/ ¬S@v`Fð}¯¦ÁÀ2€`0M¤„‡A¶gâ¿ùò˯ëj·æ®®–ÿñß>ƒ1– ¶¶¶–––Üz]y>ÅÂB1¥œ»>aø\RŠõÞzã>ïØûÛеÿײ¬Æœ‰ÆB˜1÷{áÃ0t‰ÍÈP‡eáò'¦fVçæ–uþøÇÌ£ûòødÅàýª]Á°gWo:GD0ÅRJÔjÁ½{¹|!LRש'Y¬¡º&úbŒù›N€.Ê é$àƒÕîái˜Üq«PÓ4…$ŒRÀÛžêzÝ_\ÌÎ~‰ºÏ<ðÂ,s ¿JÕ£Œ`‚ ƒ‚„ºçå Õìzyfn¹T®è+¾ÝÕYêòë°v[oÓ:ó ƒº¿­ªê–º@;ÜÃSKÂÚx=ôzÿÛ*mw<¯T*år¹R©|‰ºÏ#WV¶*Âu€®Ž ëntdH‚v˜]]×ý‚ ý[ ´VÂB²F˜Aü©ôᇺ®¾^¯€®Ýö<¯^¯ë¢Ò/Q÷™7ü¶9È5åqXö¥KäJí´Ô²®±Ì´ÑÑ¿!“èßbÜu-s#ODˆ·°ôKk~8 \û‘à ÓñŽ/Q÷¹À^XÛÛ=1·sÿµ4k¤^møI¤±¨ïó¯û„œ+z¼B"Àí¢ïzö°:îOWjh>,‡{hQé—Çgß¿¢-½ªv kšµj õ_z«mìáñ%ðþ¤ô¤T›ga¦e#Ø>&f>\ ÷QE¥_Ÿ}ÓîêÁ ˆõöªA¨ë¾õ6ý÷0Ñýp‚æðù´*G¿<>_RQ3MiøéFá_€ݧ0”Ð'øòøòø8 æïóøßÀ9JNÖUÇIEND®B`‚openlayer-2.1.orig/demos/gamedemo/0000700000175000017500000000000012262355751017372 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/gamedemo/Makefile0000644000175000017500000000065510377212142021041 0ustar georgeskgeorgesk#demos/gamedemo/Makefile EXE_SOURCES=Demo.cpp EXE=gamedemo ifeq "$(ENVIRONMENT)" "WINDOWS" EXE :=$(EXE).exe endif ifeq "$(ENVIRONMENT)" "MSYS" EXE :=$(EXE).exe endif all: $(EXE) .PHONY: all clean clean: @echo "Making clean..." $(RM) *.o $(RM) $(EXE) @echo "Demo is cleaned" $(EXE): $(EXE_SOURCES) $(CC) $(CFLAGS) $(LDFLAGS) $(EXE_SOURCES) ../../lib/$(LIB) $(LIBFLAGS) -o $@ openlayer-2.1.orig/demos/gamedemo/Demo.cpp0000644000175000017500000005246510560043510020772 0ustar georgeskgeorgesk#include #include #include #include #include using namespace std; using namespace ol; // The gravity costant // const float gravity = 0.03; // The gravity costant // const float particleGravity = 0.07; class Block { public: int imageIndex; float opacity; bool destroyed; bool fading; }; float FRand( float min, float max ) { return min + float(rand())/float(RAND_MAX) * (max-min); } const float particleFadeSpeed = 0.01; const float particleMaxAngleDiff = AL_PI/4.0; const float particleSpeedMin = 0.1; const float particleSpeedMax = 5.0; enum ColorScheme { RED_VIOLET, GRAY_BLUE }; class Particle { public: Particle( float x, float y, float speedX, float speedY, Rgba color ) : x( x ), y( y ), speedX( speedX ), speedY( speedY ), color( color ) {} // Construct an usual yellow-orange explosion particle // Particle( float x, float y, ColorScheme scheme ) : x( x ), y( y ) { // Get a random angle for that starting speed of the particle // float angle = FRand( AL_PI/2.0 - particleMaxAngleDiff, AL_PI/2.0 + particleMaxAngleDiff ); // Get a random starting speed for the particle // float speed = FRand( particleSpeedMin, particleSpeedMax ); speedX = cos( angle ) * speed; speedY = -sin( angle ) * speed; switch( scheme ) { case RED_VIOLET: // Get a random color between violet and red // color = Rgba( 1.0, 0.3, 0.7 ).InterpolateWith( Rgba( 1.0, 0.0, 0.0 ), FRand( 0.0, 1.0 )); break; case GRAY_BLUE: // Get a random color between gray and blue // color = Rgba( 0.7, 0.7, 0.7 ).InterpolateWith( Rgba( 0.3, 0.3, 1.0 ), FRand( 0.0, 1.0 )); break; } // Get a random opacity for the particle // color.a = FRand( 0.5, 1.0 ); // Get a random radius for the particle radius = FRand( 1.0, 3.0 ); } // Returns true if the particle should be destroyed // bool Update( float deltaTime ) { // Apply the gravity to the speed // speedY += deltaTime * particleGravity; // Move the particle // x += deltaTime * speedX; y += deltaTime * speedY; color.a -= deltaTime * particleFadeSpeed; // If the opacity is zero or less the particle is gone // return color.a <= 0.0; } void Render() { // Render the particle dot in the screen with the additive blender // Blenders::Set( ADDITIVE_BLENDER ); Circle( x, y, radius ).Draw( color ); // Revert back to the alpha blender // Blenders::Set( ALPHA_BLENDER ); } Rgba color; float x, y; float speedX, speedY; float radius; }; void ShowMessage( TextRenderer &textRenderer, string message ); int main() { // Choose a random seed from the computer clock srand( time( 0 )); // Initialize the program // // Initialize both mouse and keyboard // if( Setup::SetupProgram( true, true ) == false ) { allegro_message( "Error during the program startup!" ); exit( -1 ); } // Open the game in a 800 x 600 window // if( Setup::SetupScreen( 800, 600, WINDOWED ) == false ) { allegro_message( "Error while trying to set graphics mode!" ); //exit( -1 ); } // Load the graphics // Bitmap background( "Gfx/Background.png" ); if( !background ) { allegro_message( "Couldn't load the background bitmap!" ); exit( -1 ); } Bitmap paddle( "Gfx/Paddle.png" ); if( !paddle ) { allegro_message( "Couldn't load the paddle bitmap!" ); exit( -1 ); } Bitmap ball( "Gfx/Ball.png" ); if( !ball ) { allegro_message( "Couldn't load the ball bitmap!" ); exit( -1 ); } // Load tile graphics, stored as Gfx/Blocks/Block01.png, Gfx/Blocks/Block02.png, etc... vector< Bitmap *> blockImages = Bitmap::LoadListOfBitmaps("Gfx/Blocks/Block", "png", 2 ); if( blockImages.empty() ) { allegro_message( "Couldn't load the block bitmaps!" ); exit( -1 ); } // Block width and height // const int BLOCK_W = 40; const int BLOCK_H = 20; // Load the font with size 17 x 14 and a white color // TextRenderer normalTextRenderer( "Fonts/Neuropol.ttf", 17, 12, Rgba::WHITE ); // Create a bigger sized (40 x 30) copy of the font // TextRenderer biggerTextRenderer( normalTextRenderer, 35, 25 ); // Top-left coordinates of the paddle // int paddleXPos = SCREEN_W/2 - paddle.Width()/2; int paddleYCentre = SCREEN_H - paddle.Height() -10; int paddleYPos = paddleYCentre; // The paddle fades away if the ball is destroyed, // // thus paddleOpacity is decreased gradually // float paddleOpacity = 1.0; bool ballDestroyed = false; // Maxium paddle movement in y-direction around paddleYCentre // const int maxPaddleYChange = 20; // Centre coordinates of the ball // float ballXPos = paddleXPos, ballYPos = paddleYPos-1; // Ball speed // float ballXSpeed = 2.0, ballYSpeed = -7.0; // The number of extra lifes // int extraLifes = 5; float maxBallXSpeed = 5.0; // Construct a random map // const int MAP_W = 20; const int MAP_H = 15; Block map[MAP_H][MAP_W]; const int NO_IMAGE = -1; // While creating the map we find out the total number of blocks // int numTotalBlocks = 0; // The number of blocks the player has destroyed yet // int numDestroyedBlocks = 0; for( int y = 0; y < MAP_H; y++ ) { for( int x = 0; x < MAP_W; x++ ) { // Should we place a tile here? // if( rand()%3 == 0 ) { // The tile does exist // map[y][x].destroyed = false; // Get a random image for the tile // map[y][x].imageIndex = rand() % blockImages.size(); // Which one? // // One additional block created // numTotalBlocks++; } else { // Otherwise the tile does not exist // map[y][x].destroyed = true; map[y][x].imageIndex = NO_IMAGE; } // The tile should be fully opaque // map[y][x].opacity = 1.0; // The tile shouldn't be fading // map[y][x].fading = false; } } // The list of active particles // vector< Particle *> particles; // Original mode has no gravity and a paddle moving in the y-direction // bool originalMode = false; // Is the player drunk? // bool drunkenMode = false; float drunkenAngle = 0.0; float maxDrunkenAngle = AL_PI/4.0; float drunkenAngleSpeed = 0.0; float maxDrunkenAngleSpeedChange = 0.003; // Let the user choose one of different color schemes // // The selection is made by changing the coffecients of the color channels // const int numSchemes = 4; Rgba colorSchemes[numSchemes] = { Rgba::WHITE, Rgba( 0.0, 1.0, 1.0 ), Rgba::YELLOW, Rgba( 1.0, 0.0, 0.5 ) }; int selectedScheme = 0; // Is the game still running? // bool gameRunning = true; // The fps we're targetting to run the game at // // (The actual fps will be as high as possible with this // // hardware, but the game will run just like if the fps was 100) // const float defaultFps = 100.0; // FpsCounter to calculates fps and delta time // // We should start the counter right before the game loop starts // FpsCounter::Start( defaultFps ); while( gameRunning ) { // Tell the fps counter that a new frame has started // FpsCounter::NewFrameStarted(); // PROCESSING PHASE // // Check keypresses // if( keypressed() ) { switch( readkey() >> 8 ) { case KEY_ESC: // Quit game // gameRunning = false; break; case KEY_D: // Toggle the drunken mode // drunkenMode = !drunkenMode; drunkenAngle = 0.0; drunkenAngleSpeed = 0.0; if( !drunkenMode ) { // Get rid of the screen rotation and stretching // Transforms::SetRotation( 0.0 ); Transforms::SetStretch( 1.0, 1.0 ); } break; case KEY_S: // Switch to the next color scheme // selectedScheme++; // Wrap around back to zero if needed // if( selectedScheme >= numSchemes ) { selectedScheme = 0; } break; } } // These values will change in this frame if the level is finished // or the ball gets destroyed // bool levelFinished = false; bool gameOver = false; int mouseXMovement, mouseYMovement; // Retrieve the mouse movement since the last frame // get_mouse_mickeys( &mouseXMovement, &mouseYMovement ); // Move the paddle // paddleXPos += mouseXMovement; if( !originalMode ) paddleYPos += mouseYMovement; // Make sure that the paddle doesn't go out of the screen // if( paddleXPos < 0 ) { paddleXPos = 0; } else if( paddleXPos + paddle.Width() >= SCREEN_W ) { paddleXPos = SCREEN_W - paddle.Width() -1; } // Make sure the the y-coordinates of the paddle stay in a certain range // if( paddleYPos < paddleYCentre - maxPaddleYChange ) { paddleYPos = paddleYCentre - maxPaddleYChange; } else if( paddleYPos > paddleYCentre + maxPaddleYChange ) { paddleYPos = paddleYCentre + maxPaddleYChange; } // Since the last frame, how much time has elapsed (in frames)? // float deltaTime = FpsCounter::GetDeltaTime(); // Store the old ball coordinates // float oldBallXPos = ballXPos; float oldBallYPos = ballYPos; // Apply gravity if we're not in the "original arcanoid mode" // if( !originalMode ) ballYSpeed += deltaTime * gravity; // Move the ball ballXPos += deltaTime * ballXSpeed; ballYPos += deltaTime * ballYSpeed; // Make sure that the ball doesn't go out of the screen // if( ballXPos < 0.0 ) { ballXPos = 0.0; ballXSpeed = -ballXSpeed; } else if( ballXPos >= SCREEN_W ) { ballXPos = SCREEN_W-1; ballXSpeed = -ballXSpeed; } if( ballYPos < 0.0 ) { ballYPos = 0.0; ballYSpeed = -ballYSpeed; } // Does the ball hit the paddle? // if( ballYPos >= paddleYPos && ballYPos < paddleYPos + paddle.Height() && ballXPos >= paddleXPos && ballXPos <= paddleXPos + paddle.Width() ) { ballYPos = paddleYPos - 1; // In original mode you don't hit the ball with a paddle // if( originalMode ) { ballYSpeed = -fabs( ballYSpeed ); } else { // ballYSpeed += ((float(mouseYMovement) = SCREEN_H ) { ballDestroyed = true; } // Does the ball hit a block? // if( ballYPos > 0.0 && ballYPos < MAP_H * BLOCK_H ) { int ballTileX = int( ballXPos )/BLOCK_W; int ballTileY = int( ballYPos )/BLOCK_H; if( !map[ballTileY][ballTileX].destroyed ) { // Destroy the block // map[ballTileY][ballTileX].destroyed = true; // Fade the block in the screen // map[ballTileY][ballTileX].fading = true; // One more destroyed block... // numDestroyedBlocks++; // Have all the blocks been destroyed? // if( numDestroyedBlocks >= numTotalBlocks ) { levelFinished = true; } // On which tile the ball was in the previous frame? // int oldBallTileX = int( oldBallXPos )/BLOCK_W; int oldBallTileY = int( oldBallYPos )/BLOCK_H; // Do we have a collision in the x-direction? // // (We do, if the ball would not hit the block if it's not moved in x-direction) // if( ballTileX != oldBallTileX ) { ballXSpeed = -ballXSpeed; } // The same in the y-direction // if( ballTileY != oldBallTileY ) { ballYSpeed = -ballYSpeed; } } } // Move all particles and destroy those which are faded out // for( vector< Particle *> ::iterator iter = particles.begin(); iter != particles.end(); ) { bool shouldBeDestroyed = (*iter)->Update( deltaTime ); if( shouldBeDestroyed ) { // Delete the particle and erase it from the list // delete *iter; iter = particles.erase( iter ); } else { iter++; } } // Fade the blocks that need to be faded // for( int y = 0; y < MAP_H; y++ ) { for( int x = 0; x < MAP_W; x++ ) { if( map[y][x].fading ) { map[y][x].opacity -= deltaTime * 0.03; // Spawn some random explosion particles from the fading block // if( map[y][x].opacity > 0.5 && rand()%3 == 0 ) { float particleX = x * BLOCK_W + FRand( 0.0, BLOCK_W ); float particleY = y * BLOCK_H + FRand( 0.0, BLOCK_H ); particles.push_back( new Particle( particleX, particleY, RED_VIOLET )); } // Has the tile been completely faded? // if( map[y][x].opacity <= 0.0 ) { map[y][x].fading = false; } } } } if( ballDestroyed ) { // Fade the paddle gradualy // paddleOpacity -= deltaTime * 0.01; // Spit out some explosion particles from the paddle // float particleX = FRand( paddleXPos, paddleXPos + paddle.Width() ); float particleY = FRand( paddleYPos, paddleYPos + paddle.Height() ); particles.push_back( new Particle( particleX, particleY, GRAY_BLUE )); // Shake the screen! // Transforms::SetPosition( 0.0, FRand( -2.0, 2.0 )); // Has the paddle been completely faded? // if( paddleOpacity < 0.0 ) { //Restore the old screen position // Transforms::SetPosition( 0.0, 0.0 ); // Decrease the number of lifes left // extraLifes--; // Out of extra lifes? // if( extraLifes < 0 ) { // Then it's game over! // gameOver = true; } // Otherwise, the ball should re-appear on top of the paddle // else { // New ball should appear! // ballDestroyed = false; // Select the starting position of the new ball // ballYPos = paddleYPos-1; ballXPos = paddleXPos + paddle.Width()/2; // Select the starting speed of the ball // ballXSpeed = -2.0; ballYSpeed = -6.0; // The paddle should be completely visible again // paddleOpacity = 1.0; } } } if( drunkenMode ) { // Rotate the screen randomly // drunkenAngleSpeed += deltaTime * FRand( -maxDrunkenAngleSpeedChange, maxDrunkenAngleSpeedChange ); drunkenAngle += drunkenAngleSpeed; // Make sure that the angle stays in the range // if( drunkenAngle > maxDrunkenAngle ) { drunkenAngle = maxDrunkenAngle; drunkenAngleSpeed = 0.0; } else if( drunkenAngle < -maxDrunkenAngle ) { drunkenAngle = -maxDrunkenAngle; drunkenAngleSpeed = 0.0; } // Rotate and stretch the screen // Transforms::SetRotation( drunkenAngle ); float drunkenMaxStretch = 0.20; float drunkenStretch = drunkenAngle/maxDrunkenAngle * drunkenMaxStretch; Transforms::SetStretch(( 1.0 - drunkenMaxStretch) + drunkenStretch, ( 1.0 - drunkenMaxStretch) - drunkenStretch ); } // RENDERING PHASE // // Select the color scheme by changing the color channels // Transforms::SetColorChannels( colorSchemes[selectedScheme] ); //Transforms::SetPosition( 0.5, 0.5 ); if( drunkenMode ) { // We need to fill the screen with back as we can see the things outside the background // Canvas::Fill( Rgba::BLACK ); } // Draw the background // background.Blit( 0, 0 ); // Draw the map // for( int y = 0; y < MAP_H; y++ ) { for( int x = 0; x < MAP_W; x++ ) { // Is the block not destroyed or destroyed but fading? // if( !map[y][x].destroyed || map[y][x].fading ) { // Get the bitmap index of this block from the map // int imageIndex = map[y][x].imageIndex; // How opaque should the block be? // float blockOpacity = map[y][x].opacity; // Render the block image that corresponds to that index to the screen // blockImages[imageIndex]->Blit( x * BLOCK_W, y * BLOCK_H, blockOpacity ); } } } // Construct the tinting color of the paddle // Rgba paddleNormalColor( 0.0, 0.3, 0.6, 0.3 ); Rgba paddleTintColor = paddleNormalColor; if( ballDestroyed) { // Get the tint factor from the opacity // double tintFactor = ((1.0 - paddleOpacity) * 2.0 ); // We don't want it to exceed 0.5 // if( tintFactor > 0.5 ) tintFactor = 0.5; // Construct the final tint color which is mix of paddleNormalColor and white // paddleTintColor = paddleNormalColor.InterpolateWith( Rgba::WHITE, tintFactor ); } // Draw the paddle // paddle.Blit( paddleXPos, paddleYPos, TintMode( paddleTintColor ), paddleOpacity ); // Draw the ball // ball.Blit( ballXPos - ball.Width()/2, ballYPos - ball.Height()/2, TintMode( Rgba( 1.0, 1.0, 1.0, 0.3 ))); // Render the particles // for( vector< Particle *> ::iterator iter = particles.begin(); iter != particles.end(); iter++ ) { (*iter)->Render(); } string text = "Blocks Destroyed: " + ToString( numDestroyedBlocks ) + " / " + ToString( numTotalBlocks ) + "\nExtra balls: " + ToString( max( extraLifes, 0 )) + "\nFPS: " + ToString( int( FpsCounter::GetFps() )) + "\n" + (drunkenMode? "Press D to restore normal mode" : "Press D for Drunken Mode!" ) + "\nPress S to change the color scheme"; // Make sure that the screen isn't rotated, stretched or moved when the texts are rendered // Transforms::ResetTransforms(); // We don't want the color channel modifications to affect text rendering // // So we revert all channels back to 1.0 // Transforms::SetColorChannels( Rgba::WHITE ); // Print the shadow of the text to the screen at x = 4, baselineY = 16 Rgba col = normalTextRenderer.GetColor(); normalTextRenderer.SetColor( Rgba::BLACK ); normalTextRenderer.Print( text, 5-1, 15+1 ); normalTextRenderer.SetColor( col ); // Print the text to the screen at x = 5, baselineY = 15 normalTextRenderer.Print( text, 5, 15 ); // Do we need to display a message in the screen? // if( levelFinished ) { // Show a message in the screen (the function to do this is there below the main()-function) ShowMessage( biggerTextRenderer, "Level Finished!" ); // Sorry, but only one level in this demo :P // gameRunning = false; } if( gameOver ) { // Show a message in the screen (the function to do this is there below the main()-function) ShowMessage( biggerTextRenderer, "Game Over!" ); // Sorry, but you need to restart the game in to play again :P // gameRunning = false; } // Show the current frame in the screen // Canvas::Refresh(); } // Destroy the block images // for( vector< Bitmap *> ::iterator iter = blockImages.begin(); iter != blockImages.end(); iter++ ) { delete *iter; } return 0; } END_OF_MAIN() void ShowMessage( TextRenderer &textRenderer, string message ) { // Retrieve the width and the height of the text // int textWidth = textRenderer.Width( message ); int textHeight = textRenderer.Height( message ); // The amount of empty space around the text in the box // const int paddingSpace = 20; int msgBoxX = SCREEN_W/2 - textWidth/2 - paddingSpace; int msgBoxY = SCREEN_H/2 - textHeight/2 - paddingSpace; // Tint the screen slightly to black to darken it // Transforms::SetTintColor( Rgba( 0.0, 0.0, 0.0, 0.30 )); // Draw the box below the text // Rect boxRect( msgBoxX, msgBoxY, textWidth + 2 * paddingSpace, textHeight + 2 * paddingSpace ); boxRect.Draw( Rgba( 0.4, 0.4, 0.4, 0.5 )); boxRect.DrawOutline( Rgba( 0.1, 0.1, 0.1, 0.8 )); // Draw the text // textRenderer.Print( message, msgBoxX + paddingSpace, msgBoxY + paddingSpace + 25 ); // Show the current frame in the screen // Canvas::Refresh(); // Wait for a keypress // clear_keybuf(); readkey(); } openlayer-2.1.orig/demos/gamedemo/Fonts/0000700000175000017500000000000012262355751020463 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/gamedemo/Fonts/Neuropol.ttf0000644000175000017500000014503010377212142023011 0ustar georgeskgeorgesk LTSH›Zœ $ OS/2g³¨VVDMXhEoØÄ8àcmap6ð;hüºcvt # hfpgm2Jsc¸bgasp Ä(glyfå¤Âs €xhdmxùQ{G4ÈheadáëQ,6hheaÑ ¢d$hmtx9¬<]$kernß ç-° loca¼µX­ømaxpˆ nameNMuº postžž_pÀ ˆprep~5»ò J33 ­¶_<õ»n´™»n¹§ÿpþF Xþw ¨ÿpÿy   ]X bcšqþ‹šq$f €§ LARA@ öÂãþ‹ãS €FF¸*½,ž(ª)>3?/>CH!ƒ:·Dt0kkR~Pn,¬JüF€'©-j-‡L‡Mv14$/£:#g/2ì†Qô0†L³+­+1+‹N{N0¢+×+žN‡RZL@+mE`?¶(nQñ $(ò¦#:<k16 *ß ü³G¯:ª'àO‚*Æ@·EÀ_Ž>´ÒGrP¤G¯I¦E´C»GÇ,+9ÖMOÞ$~ÆP‡(v.}Pƒ4;Lˆ3 9rBiZ5IØa)ÿ¤x7ù ù ù ù ù ù Õ,Ç5Ç5Ç5Ç5Šÿë„Iÿ¿ïÿèrRECECECECECrRjAjAjAjA–sî>î>î>î>î>î>HWú0•&•&•&•&yÿÆy ÿ·²ÿÆ™I77A7-JÂ9Â9Â9Â9²@yjðM~L ¤ëƒ©rÉt/Wsy¦M¤êÛÿÿ÷ ¬5Ç<jšXSMA;±e€-Ò¢ž4 xAvZrÉè%7$-ƒ:Ã:§>“@`ÏÿÜÏ·@àO@*´C<j a‘ /‘ ¨-™9Ä5Gì‚*³+¯I‡R¶(+¦#‡(×ÿprÿ{ª'ô0¶(+ô0ª'¦#‡(n¦#‡(¶(+`?Ç,ìG×+rÿñ³+‚*†LàO¯I‡RÏÿÜZL¦EÖMQn9ÿÉ`?Ç ÖMQ×+9UP                                                                                                                                                                                                                                                                                                                                                                                                                                 "               "     #              #   %                 %   &                &  p& ÇÆ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_noqsz„‡†ˆŠ‰‹Ž‘“’”•–˜—™›šžŸ °ea´¶­g…d³Áfcp€b»¾Œœi`º¹²jm~£¤¼½«¬©ª¡¥µÂñÄÅltkurwxyv|}{‚ƒ¢¦¨À·¿§h¸®¯J\@"~«°¶¸¾ÏÐÖÜÞïðöüÿ1:>DHUY[eq~ÇÉÝ~¼    " & : ¬!"öÂÿÿ # ­²¸»¿ÐÑØÝßðñøý 19=AGPXZ^nxÆÉØ~¼    & 9 ¬!"öÁÿÿÿáÿ°ÿªÿ©ÿ¨ÿ¦ÿ¥ÿ¤ÿqÿ¹ÿ©ÿý÷üžüÿà©àŒà‰à#ߟ +\^tz€„€€|€Š”–˜ž ¦´ºÆÆÊÎÒÇÆ`a´µbȶc³¾ºdÀeÓÔf»g¹ÐÑÒÉÊÍÌËΡðñÖÕåæâáö÷úØ×ôõßàÚÙùøûü£¤îïìíãäÿéþý¥ÝÞêëç覯·¿§®¨¸©ªÄ«¬Å°±­J\@"~«°¶¸¾ÏÐÖÜÞïðöüÿ1:>DHUY[eq~ÇÉÝ~¼    " & : ¬!"öÂÿÿ # ­²¸»¿ÐÑØÝßðñøý 19=AGPXZ^nxÆÉØ~¼    & 9 ¬!"öÁÿÿÿáÿ°ÿªÿ©ÿ¨ÿ¦ÿ¥ÿ¤ÿqÿ¹ÿ©ÿý÷üžüÿà©àŒà‰à#ߟ +\^tz€„€€|€Š”–˜ž ¦´ºÆÆÊÎÒÇÆ`a´µbȶc³¾ºdÀeÓÔf»g¹ÐÑÒÉÊÍÌËΡðñÖÕåæâáö÷úØ×ôõßàÚÙùøûü£¤îïìíãäÿéþý¥ÝÞêëç覯·¿§®¨¸©ªÄ«¬Å°±­¸,K¸PX±ŽY¸ÿ…¸D¹_^-¸, EiD°`-¸,¸*!-¸, F°%FRX#Y Š ŠIdŠ F had°%F hadRX#eŠY/ °SXi °TX!°@Yi °TX!°@eYY:-¸, F°%FRX#ŠY F jad°%F jadRX#ŠY/ý-¸,K °&PXQX°€D°@DY!! E°ÀPX°ÀD!YY-¸, EiD°` E}iD°`-¸,¸*-¸,K °&SX°€°@YŠŠ °&SX#!°ÀŠŠŠ#Y °&SX#!¸ŠŠŠ#Y °&SX#!¸@ŠŠŠ#Y ¸&SX°%E¸€PX#!¸€#!°%E#!#!Y!YD-¸ ,KSXED!!Y-¸+º+º+¾3*%+¾>3%+º+¸ E}iD*·Þ þﻺ€€X\¸/¸ /¸¸Ð¸/¸ ¸ܸ¹ü¸¹ü¸EX¸/¹>Y»+¸¸¹ü013!%!!€ý€þXù¨€X*›LP¸/¸/¸/¸/¸7/¸9/¸B/¸E/» +¸»K+¸K¸ ¸и ¸#и¸*и¸,иK¸3иK¸>и¸Mи¸OÐ01#!32+#"54?##"54?#"5476;7#"54763!67632367>3232#3&ÿ1ÄR%ÿf+BQR¯e+BR QÃU&þ1ÄR&e*AR Q­f+(#QRÄRýÁ±0¯ (!$†H'"&þì' ?"Þþì' ?ÞD(%&†H*%' ?Þ( ? "Þ¶†,ÿŽ’#4?»;+¸;» +¸»$+¸¸¸и/¸ ¸и ¸и¸ и¸)и ¸5и/¸/¸/¸/¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y»!)+¸!¸¹ü¸и)¸и¸*и+и,и0и0/¸1и1/¸2и2/¸3и3/¸!¸5и5/01!#"'&5"&'&543! '&5!47632 54'&#;2; "’ýÃ#N4 þ}0?HRùþF ?( ZO=Ü'«  ýÁOj'$þ×N ;GURß4GMýðþÙpiV þ®NYZT (ÿÜw½,>IÞ»F$+¸F»?+¸»9+¸9».+¸¸F¸и/¸¸KܸEX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»=+¸=»(D+¸(» 7+¸ »H!+¸H¸7¸0и0/¸7¸2и2/¸7¸4и4/01%# =47632#"547632! =4763254+"'.#"324'.#"32w¼1–gþY¨NËÌT°å$û® ŒR#W‹Vý'þ$þK¨f³³m°µƒ ·?3NÚüCOJ3¸µæ°Ž/ ÎŒ//Œ5$"ûßC$!%þ†ØÒŠ00Šý^aNõV`x)ÿøºDQ\8»V+¸V»$F+¸$»4-+¸4¸8и8/º89¸$¸'и'/¸4¸:и:/¸4¸<иY¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº 9º, 9º- 9º5 9º? 9º@ 9¸¹Hü¸ ¹Rü¸Zи[Ð01%+"'&'#!"'&=4767&'&5467676!32747632>7'54+"%63!2[/ q‡ôþW½‡Áe7˜£ e&ë¢q‘ £îN¬¸/¸/¸/¸/01#"546767632N1-QP/ -RPg þÞ2 E !2 ?ÿøóºU»+¸¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y01#"'&547632ó7h7ž7ZHûþXNw-%F3Pýüee"-G hïø`>ÿøñºQ» +¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01#"54?654'&5432ñJElHX7f7£2LYýXnb\+ F,%H4MZs#,Ba÷Htüò<Y¸/¸/¸//¸2/º29º 29º29º29º!29º+29º62901#"/5#"'&547#"'&54?'&547632&547>327632üHtpG02ÔQSBÑ 21GllH01"ÔD3.QÙ /011#./`‹F 0wb/0!22!21aj%. Cga33!=öj!o»+¸¸и¸ и /¸¸ и /¸¸и/¸¸и/¸/¸/¸/» +¸ ¸¸и ¸Ð01+#"'&=476=#"54;543232öR°ON#¬SS©Om °RXYsO A  YYlM!‡:ÿdI$¸/¸ /¸/¸/01%#"546767>32I0/ ,!O./ ,#Pß þÞ1 E #/D¡rJ » +¸ 01#!"'&543!2rOýp: O8 ïN:N 0ÿùDѸ /¸EX¸/¹>Y01%#"'&547632D-'68&,,)45)-f354ÿøVº %¸EX¸ /¹ >Y¸EX¸/¹>Y01#"547632V"û¶bY#IgXy$!ûÛB"#%Rÿøº …¸!/¸"/¸Ü¸!¸ и /¸и/¸ ¸и/¸ ¸ и /¸¹ü¸ ¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y¸ ¹ü¸¹ü01) &54765) 4)")276ýÍþ¦ýÞ3Z3Þþ¯þŸC€Saž3€?þ¹(.lI’‘JJþ·ýÕ%š#fýÚ•!Pÿø.º Q»+¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01%#"5432./LOOL/G;O%N:,ÿøBº,¶¸-/¸./¸Ü¸-¸и/¹ü¸¸ и /¸¹ü¸EX¸&/¹& >Y¸EX¸)/¹) >Y¸EX¸ /¹ >Y»+¸¸ ¹ü¸)¹üA‰™]A 8HXhx]¸ Ð01) !2#!"54%>3!276=4'&#"'&5432B*gþ„þþÌçQQú‹N7{FìSg}ßQÒ1 N©È*ƒWk¦F¬sÖ[\O<ÍE FhT 5NBQJÿøb½6½» +¸ ¸и¸/к3 9¸EX¸"/¹" >Y¸EX¸$/¹$ >Y¸EX¸&/¹& >Y¸EX¸(/¹( >Y¸EX¸+/¹+ >Y¸EX¸/¹>Y»+¸¸¹ ü¸+¹ü¸к3901#!"543! =4)"543! =4'.+"54;27>32b³Åü;NNÅ'þâü2NNÏxX@ÉQQ)"1Ï· KK 9µQ;OhsfiNmsH[Z,D´‚'S48OFÿö¶¼£¸/¸/¸Ü¹ü¸¸ и /¹ü¸¸иEX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸01%#"'&=!"547632!47632¶eP2úúp2Pe|2PeGQ<ç¾<Qý•k<Q'ÿøYº#w¸$/¸%/¸Ü¸$¸и/¸и¹ ü¸¹ü¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¹ü¸¹ü01)"543! =4'&#!"543!2#!!2YýÜü@NN°ViVWüNN×N 1ý¶^Á…³*þÎOh|²M$N¶NN5èCV¦-ÿø|¼#3ª¸4/¸5/¸Ü¸4¸ и /¹+ü¸и¹$ü¸EX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y»)+¸¸¹ü¸и¹/ü01#! '&5!;2+ !254'&#!3!276|°„½ý³þÀs^_/ -37 .úþÊTÝ~ÂÜ|Vjü§{NnI[Nl*¦Pº/¸EX¸/¹ >Y¸EX¸/¹>Y¸¹ ü01#"547!"543!2>*ü²aQûlNN8‹_-1üJ‹OfLÿø<º*>ø?/¸@/¸Ü¹,üº,9¸¸и/¸?¸и/¸и/¸¹5üº59¸,¸и/¸5¸#и#/¸EX¸/¹ >Y¸EX¸ /¹ >Y»'0+¸'º0'9º0'9¸¹ ü¸ ¹:ü01#!"'&54767&'&5) 54) )27654'&#!"3!276<Y ¹~Ïþ%¶–º VW)£$Üþ¸þ]þµ6ÍbS~…]]þKtFLËÛeQt(uOD@’©S=>R¨„,P4+L-{7þÊYY‚XkþFh;>j `#Mÿø:º"2µ¸3/¸4/¸Ü¹ü¸3¸и/¸¸#и¹.ü¸EX¸/¹ >Y¸EX¸/¹>Y»#+¸#¸¹ üA 7 G W g w ]A† – ]¸ и /¸ииии¹(ü01!"'&5432; =! 54763!24'&#!"3:þí—þÛ1 N %  ]ý ýã±{ÄðÅ‘·Ü{Viþk?l|^b1ÕD 6O–R7À¡Q=>TµþÖ*P' G¹M"1Dª T»+AŠš]A 9IYiy]¸и¸и /¸EX¸/¹>Y01#"'&547632#"'&547632D‰8&,-&64)-,&77&-,)48&,?m54ýú4644ÿdi§%¸ /¸/¸/01#"'&547632#"546767>32i+&75),,%88%,&0/ +#O./ ,"P<655þn þÞ1 E #//ÏöÛ¸/¸/¸/¸/º901#"'&547>?6$7632 öD,üÓ)"¾‚”*& ýFº :S P6m< ( þãþã :0i »+¸» +¸ 01#!"'&543!2#!"'&543!2iOýo9 O‘8 Oýo9O‘8 §O и>/¸EX¸-/¹- >Y¸EX¸//¹/ >Y¸EX¸8/¹8>Y»+¸¸и/¸¸и/¸¸!и!/¸-¹)üA‰)™)]A 8)H)X)h)x)]01+"#"5467>54!2;276=4!"547632#"'&5476327¸“¦ë6(>S` $ \Ptþ³O) LÄ©ý ,&77&-,&78&,ê•L8A<rÆ<ˆ“b8@R®üò4642gäóFR³»+<+¸+» +¸»"+¸¸ ¸Gл07+¸0»B'+¸B»G+¸G»+¸» H+¸ ¸¸и/¸¸и/¸G¸ и /¸0¸-и0¸2и2/01#!"'&=476;&#"#"#"54323254'&#!"!;2?2+"'&54763!25#"3äÄþZx[ysU½ ‡ :J¥M{5?LE+þ/Þ +<<“‚rŒˆc“ÔŒ[yþNÁ&>CF15·.9f.o7+JI:0Œþú55ö+\ý6[CC,;xË~:*.<{ýÜÆ&-(ÿßÒÈ*¸/¸ /¸EX¸/¹ >Y»+¸01%#"'!#"'&547632 Ò>.@(ÅüXÅ %%"&¾+iNèýåþ¯þ­K.><þâ/# 1B, ûãñþQÿø5º(2ݸ3/¸4/¸ܸи3¸и/¸¸и/¸¸и/¸¹"üAŠ"š"]A 9"I"Y"i"y"]¸ и /¸¹&ü¸"¸)и&¸,и,/¸"¸0и0/¸EX¸ /¹ >Y¸EX¸/¹>Y»'++¸'¸ ¹$ü¸¹-ü01#!"543!24'&)! 4)! 7>5¦€ÂüRNN¡}goMU%%Ù þêüþ þíüì <¯TAO%NHQkh. * @:( E­!EþªþË~þ·s,0ÿø“º m»+¸¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸¹ü¸¹ü¸ Ð01#! )2#!"'&'&'&54767>3!2“Nüéþà?óQQý ™CIOZ$+iX~ \?NTOsý¥ˆ[\ (/3:]^sQCLÿø:º e¸/¸/¸Ü¸¸и/¸¹ü¸¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y¸ ¹ü¸¹ü01#!"543! 4'&#!!276:­†ÁüTNN±ïÜlM`üågKkA¬YDO%NþÊý¾AG#üª&+ÿø‰º'y»%+¸%¸и/¸EX¸/¹ >Y¸EX¸ /¹ >Y»&+¸&¸ ¹ü¸¹ü¸и/¸и/¸и/¸"Ð01#!)2#!"'&5476!32+"'.# !2‰SûÓNNü殑²;€IÙMM  $ þ“0RYaÈOh>Q¡\WG˜fO„Õ+ÿøƒº†» +¸¸иEX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹üA‰™]A 8HXhx]01#!#"'&5476;2# !2ƒSûÙNS 0¼¬¦OOþ@'ST\þOO9W’NY¸EX¸/¹>Y¸¹ü¸и/¸и/¸и/¸и¹ ü01#!"'&5476;2+"'.# )276547632¥€¸þƇº¾–µÈQQ $ þš,õHQf0DN.¦Q?9N«b¤O;Z[|ýŸ|":;7NNÿø<º!ɸ"/¸#/¸Ü¹ü¸"¸и/¹ ü¸и¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y»+¸01%#"'&5!#"&'&547>32!47632Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01%#"&'&547>32,N"00/ 0&NGO;%;N0ÿøÖºl» +¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¹üA 7GWgw]A†–]01!"5432765432ÖÏ„þüOO¨ANL1UÛO3hO#qN ;+ÿøxº»» +¸¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º9º901%#"'#"'&547632632 xZcüYOP --KO„_Y5ü¢|5AI íþXO9%:NþgßH.þ=þ)+ÿø‘ºJ»+¸¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¹ü01%#!"'&54323!2‘Ný8ô‰ÓNK0š1³¼NGO,IÌ3N:üÍ_ NÿóO·˜¸ /¸!/¸Ü¹ü¸ ¸и/¹ü¸/¸/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Yº 9º 901%#"5#"'#"'&5432 632O0LNýq4YZ4ýeNM0|Q1 ú0NG:OüØ@@,üèO:þq:üeœ:{Rÿð6Ã~¸/¸/¸Ü¸¸ и /¹ü¸¹ü¸/¸/¸ /¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Yº9º901%#"'#"543247>326z8Gûó00"NrHLÿ00"O{‹;qü«;Oø„@ü™P:NLÿøºe¸/¸/¸Ü¸¸и/¸¹ü¸¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y¸ ¹ü¸¹ü01)"'&5) 4) ) ýËþ¦å„Ê3ZlÂßþ¯þ þ¬TaP?þ¹:Rº2J.KÑýÔ'ššýÙ•+ÿøº~¸/¸/¸Ü¸¸ и /¹ü¸¹ü¸¸иEX¸/¹ >Y¸EX¸/¹>Y¸EX¸ /¹ >Y»+¸¸¹ü01#!#"543!254)! ¶Çüý0 SNN¼ƒÁÜþÞüñ!î·Q;þœ9O%N4H“¶¦jþ\Eÿa)º+‚¸,/¸-/¸Ü¹üº9¸,¸и/¹%ü¸ /¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¹)üº)9¸¹ü01#"/! 4763!24)"3! )È#&2&#- ùþUý½Ê÷dþzÆßþ™þ¥:Ž…0€U=ÄJ# ,‰B>ÐF)&DÔý»G‡ _ý»] ?ÿ÷ º$´¸%/¸&/¸Ü¸%¸и/º9¹ü¸¹ü¸¸!иEX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»#+¸#º 9¸¹ ü01#!#"'#"'&543!254)!  ®Š´þ’æ;ƒ4ü NS 0N~І¿ÞþÈýó¥L8þÅ3K±þ—O9%N6M±•šzþz(ÿøŽº1µ¸2/¸3/¸Ü¸2¸и/¸и/¸¹ü¸¹'ü¸и/¸EX¸/¹ >Y¸EX¸/¹>Y»,+¸,¸¹ ü¸¸и/¸¹$üA‰$™$]A 8$H$X$h$x$]01)"54763! =4-.'&'&=476!2# 3!2ŽSþ]üÿM 07þÓþ_ExV^ìq-N/Xþ”ˆcH)Õ{Â&b7•O6sip AHu\ÕDf;€UO7P¦ÿø_ºV» +¸¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸¹ü¸ и Ð01#!#"'&5!"54763!2_NþMN/þO 3³NTOüBO;¾O6Qÿô/º%¬¸&/¸'/¸Ü¸&¸ и /¹ü¸¹ü¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸!/¹! >Y¸EX¸#/¹# >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¹ü¸Ð01!"&'.# '&54323!276547632/ýg=((<þ,_!NK1*sN2¯Y¸EX¸/¹ >Y¸EX¸/¹>Yº 901#"'&5432 632æý05PR3ý.mS”‘Tn|#üJI#A$üR®$ÿø Æ%v¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸"/¹" >Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º9º901#"' #"'&547632 632 632  þ,^\'þ€þs$^e$þ! )#+Hš†*\ )(Œ”Q)!(qüZT5üÉINü(2ü™EZü³f2ÿóº#i¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y01%#"' #"547 &547632 632 00"6ýÖýÐBv(;ýØ':T^Z'ýÛ8*?&Ôþ,F$"áÍ!%6 þ;ÄC%!þ3þ$ÿøäºU» +¸¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01#"5&5432 632ä$ý©- ROý§"YeeZy#"ýÁþR; N¯?!#Bþÿ#ÿø„©¸ /¸EX¸/¹>Y¹ü01%#!"'&547632!2„Qû§H1>#k18%-üÄQT\!A*Á+ !/%ü´<ÿøÿºG» +¸¸EX¸/¹ >Y¸EX¸ /¹ >Y¸¹ü¸ ¹ü01+32#!"543!2ÿN—’OOþÞNN'NTOüªOhO%NÿøVº %¸EX¸ /¹ >Y¸EX¸/¹>Y01%#"'&5432VXcû·#YfJ":B%#"AûÛ!6ÿøúº?»+¸EX¸/¹ >Y¸EX¸/¹>Y¹ü¸¹ ü01%#!"54;#"54763!2úNþÙOO—’O 2"NGOOhVO7N*3㸸/¸/¸/01#"'.'.'#"547632ãE#" L?Fp*I %% m: H:Hh#: þõ þ¾Öÿ‘ » +¸ 01#!"'&543!2ÖNúÏ: N18ôN* MO+ ³ÒHQ¸/¸/¸/¸/01#"'&'.'&54632HC?D /  8?G " þìGÿø½·4ª¸5/¸6/¸Ü¸5¸и/¸¹ ü¸ и /¸ ¸#и#/¸ ¸&и&/¸¹,ü¸EX¸/¹>Y»+¸» &+¸ ¸¸и/¸¸и/¸¸и/¸¹0ü01)"'&=4763!&!"+"54324&'.5!"3!276½þPýü¦y£›s­êþó  NNý†æÏýBF[^Y¸EX¸ /¹ >Y¸EX¸/¹>Y»+¸¸¹ü01)"'&547632! 4)3!2676uþ þ¼±”¿* NNuóÒþãý‡ˆ1`1-EYj&þÒ?Q™I:O»þ×þ§U|þ$A! 'ÿø„·:»+¸¸EX¸/¹>Y» +¸ ¸¹ü01%#!"'&5)2#!")2„büóácªÂDRRüËþ!OGO+D³z#YYkþ‰zOÿø‘¹!’¸"/¸#/¸"¸ и /¸и/¸ ¸ и /¸#¸ܹü¸и ¹ü¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¹ü01#! &547)5432! 3! ‘¿‡¾þ¾þávN8"+Óý…þåk.‡0FšP=0Nc*»O8ü¹Û}þ¬] *ÿøX¸'¡¸(/¸)/¸Ü¸(¸и/¹'ü¸и/¸¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y»"+¸»+¸¸ ¹ üA 7 G W g w ]A† – ]01#!32#"&'&'&54763!254!"X;ûç #…gNNj‡#®Ru´{ËЦm—ÎþSý^…ÇWˆ' bO@[{a¦P:7F‡vlIn@ÿø£»£» +¸¸и/¸EX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹üA‰™]A 8HXhx]¸и/01#!#"'&5!2#"!2£Nþ¾NN *ÙQ%NŽ+†?NabýHO9Y GNBEþïrº"0Ó¸1/¸2/¸Ü¹#ü¸и/¸#¸и/¸1¸и/¸#¸ и /¸¹.ü¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸¹ ü¸¹#ü¸¹(ü¸)Ð01%+"54;2767!"'&5!2;24'&#!"!rΉÒXOO™(nrý½Í„ÀT. '½™ÇÕu_Rþ³v3i:¥M7cN!"3I¬d.8N§þ&ÑG$ Pþ›{_ÿøŒº Ÿ¸!/¸"/¸Ü¹ü¸!¸и/¹ ü¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y» +¸01%#"54'&#!#"'&547632!2Œ* NNjFký”NN **KN:ýf½G9O5YýHO9%:N½(DÄ>ÿøP¦;»+¸¸ܸ /¸EX¸/¹>Y¸EX¸/¹>Y01#"'&547632#"'&5432P,&77&,,&77&,OM )OL *:444ûÙO9%N8ÿ/¤ª!I»+¸¸#ܸ /¸EX¸/¹>Y¸EX¸/¹>Y»+¸01#"'&547632!"543 5432¤,&85),,)58&,¿TþìNNTOM *>555ûßÊ>cO`,N8Gÿø¨º™» +¸¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º9º901%#"'#"54323632 ¨YTý/* LNNI)ÇEY6ýz•6BJ iþÝ8O%N:ý×dI0þ¾þµPÿø#º Q»+¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01%#"'&5432#NM +NI*GO8%N:Gÿø]·<»(.+¸(»+¸»+¸¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸*/¹*>Y¸EX¸,/¹,>Y»: +¸:¸ ¸ и ¸ и /¸ ¸и/¸ ¸и/¸ ¸"и"/¸ ¸%и:¸1и:¸4и4/¸:¸8и8/01%#"'&54!+"#"54'&+"'.# #"5!26763 ]NN +þó *^+ NO=*_  þð* NNÌ[sweZ„F¥»GO9Or ^ýÌ9O6Utý³9O79<8 þÇIÿøe·y¸ /¸!/¸Ü¹ü¸ ¸и/¹ü¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y» +¸01%#"'&54'.#!"#"'&5) eON +lO<þ”7KfNN *äYßGO9bAAýŸO9_þñEÿøa·#X¸$/¸%/¸Ü¸$¸ и /¸¹ü¸ ¹ü¸EX¸/¹>Y»+¸¸¹ü01#!"'&54763! 4)"3!276a¢s¿þ¡®®­¼`ÔÖþüþ©`LlnIbWSJf"¤L:;N¡a¡S@þÎþqr#GþŸD !Cþïp·~¸/¸ /¸Ü¸¸ и /¹ü¸¹ü¸¸иEX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹ü01)#"54763! 4'&#! !2pþ8ýn+ MN¦`ÜPûÕu/€þ·þè’ó)þ×Ã8N]¯C+þæþ‰tL qþGþït·~¸/¸/¸Ü¹ü¸¸ и /¸¸и ¹ü¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹ü01#"=! ) 4) 3t, NNýqþ7úSàÕþêþ·þÚòÃ8NÃ)sþäþæplþŒv,ÿø›·M»+¸¸EX¸ /¹ >Y¸EX¸ /¹ >Y»+¸¸¸и/01#"&#"#"547632›^ 1 ó,JKÁvéOSOyý¹:PF¼C*+ÿøê·%z¸&/¸'/¸Ü¸&¸и/¸и/¸¹ ü¸¹ ü¸EX¸/¹>Y»+¸»# +¸#¸¹ü¸¸и/01)"543!2=4#! 547>32+") êþ^ý6NNËÆ´þ©þ'î0¹ŒOO˜wi^‡ þîOba$W4¯1 dN32Vþýÿø#ºƒ» +¸¸ ¸и¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¸ и¸Ð01#!#"'&5"&'&547>35432!2#Oþ²NM +*5 22 5*NM +NOMNýHO8¸BB½N8½Mÿõ‰·!š¸"/¸#/¸Ü¸"¸ и /¹ü¸¹ü¸/¸/¸/¸/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸ /¹ >Y¹ü¸Ð01!"&'&+ 432) 547632‰ýœ6$ -ýþNN */;)+ OOþßRO9ý®mjU9Oÿâ5»)¸/¸EX¸ /¹ >Y¸EX¸/¹>Y01#"'&5432 6325ý`#--!ý\sE=:Erv#üÔ)'.#E!ýFº!$»»K¸/¸ /¸EX¸/¹>Y¸EX¸/¹>Yº 9º 9º 901#"' #"'&5432 632 632»þy"^Z#þÉþÄ$]a"þcVD<%UR&<CWdwý CAGý·BEø' D/ýŽGFEý¸r/ÿøb·#V¸/¸/¸/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º!901%#"' #"547 &547632 632 b7Zþ(þ$ZZ-Öþ/+9 WÕË[Z+þ:Ð,>6 Xþ¨F) PQ*7 þ¨WE*þ±þ­ Pþïv·)¢¸*/¸+/¸Ü¹ü¸*¸и/¹ü¸¸"и/¸/¸%/¸'/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸¹ ü¸ и /¸ и /¸и/¸и¹!ü01%!"'&54;23 5! 47632)432vìWþÔ1 O  ýŠþ$* NN vON *Ã<7O^J9Oý¶n¸O9(ÿø`—¸ /¸EX¸/¹>Y¹ü01%#!"'&5476322`Rû«5,08;)%*5üqqRQY"33$¼7*&ý®.ÿZHZ!9» +¸ ¸и¸л +¸ » +¸ 01+32#"'&54'&5476547632HYj11jHH˜7ƒ8778‚6šYRþ@-+Bþ QM `&%"#cPþî.#7»+¸ /¸ /¸EX¸/¹>Y¸EX¸/¹>Y01#"&'&547632.N"000MNÃO;˜:N4ÿZNZ!A»+¸¸¸и/¸¸л  +¸ »+¸01#"54;47&5#"5432N87‚?‘IIj22jYYš6‚78X% ýûbMQõA,-@îRScýþ"#Lï07W¸8/¸9/¸8¸и/¹ü¸и/¸9¸7ܹ1ü¸,и,/»(+¸(»  +¸ 01#"'&54'&#"#"'&=4763 327654.5432ïŠKØ´[€;­D"6ON *ŠKØD8 /¬G 5ON *²:%.A UV_9u±;%¤~AU`93þ’F[ !»+¸¸ܸ /¸/¸/01#"'&5432#"5432F-)46&-‰8&,/LOOL/î33mû¾;O9N:ÿÿ9ˆ–J'D0MlBÿøº<µ»8+¸8¸и/¸¸ и¸и8¸.и./¸EX¸#/¹# >Y¸EX¸)/¹) >Y¸EX¸/¹>Y¸EX¸/¹>Y»9+¸9»+¸¸¸ и9¸и¸/и¸6Ð01%+#"=#".54;5#"'&54;5&5432 63232+32M:y/KO› ;››) ;›ý§"YeeZ$ý©w( :xx) ¼7>:N? 8Y )7'?!#BþÿA#"ýÁ' *8Y ZiŒ"!» +¸ ¸¸и ¸Ð01#"'&547632#"'&547632Œ') ""*'þ¤!** ""*'Ã! ** !(** !´Î:/?#º(8+¸(º+¸º+¸º0 +¸0¸¸к 809¸¸и/A  qA9 I Y i y ‰ ™ © ¹ É Ù é ù ]A6(F(V(f(v(†(–(¦(¶(Æ(Ö(æ(ö( ]A((q¸0¸AÜ»,4+¸,»<$+¸<º+¸º +¸º 9014+!253##"'#"543!24'&#"32767#"'&547632Qlü _YÁ]þƒ1-4ÒÆ‡†¾À………ˆ½½‡‡^¢¤ãã¡   ä㣣£<Â8‹¶Ó11“«Ä’‹ËÌ‹ŽŽŽÉ𬧧¬ð¬¦I°jï¸ /¸!/¸Ü¸ÜA qA9IYiy‰™©¹ÉÙéù ]¸и/¸ ¸и/¸ÜA6FVfv†–¦¶ÆÖæö ]Aq¸и/¸¸ и /¸¸и/º+¸º +¸ 01#"'&5476324'&#"3276°YXƒƒXXXY‚‚YYU@@__@@@@__@@6‚YXXXƒƒXYYY_@@@@__@@@@ØÒmQ¸ /¸/¸/01#"547632m’BHC /’BG8 ")ÿøŒ¹²»+» +¸ »+¸A 6FVfv]A…•]¸¸ и¸ܸEX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y» +¸¸¹ü¸ ¸Ð013!!""5!#"5# )2Ù£ZýšX[þû\Z‡þ•aÆ<¬ŠûÐLMý³IIM <ûÇLÿ¤þ¡eº+¸¸¹ü01+"54;27>7632e¿´NNd/ Ufkô\Y1,0N7þš?T3C͸D/¸E/¸D¸Ð¸/¸E¸ܹ üAŠ š ]A 9 I Y i y ]¸и/¸¸и/¸¸и/¸¹&ü¸¸:и:/¸¸>и>/¸8/»)/+¸)»+¸¸¸и¸и/¸¸"и"/017476;254.547632!+"'.#"!2#"'&547632#"'&7¸Š¯ë6(>Sþ  $ [QtMO) LÄ©õ,&75),,&77&-j”L9A<rÆ<ˆ“b8@R®454ÿÿ ÿßÂr&"ðA|!ÿÿ ÿßÂt&"ðfÉ#ÿÿ ÿßÂt&"ð¦%ÿÿ ÿßÂ"&"ð¨íDÿÿ ÿßÂr&"ðcñTÿÿ ÿßÂ{&"ð§ûÿìÉ36Õ»14+¸1¸и/¸4¸и/º419¸ /¸/¸EX¸/¹ >Y¸EX¸!/¹! >Y¸EX¸ /¹ >Y¸EX¸/¹>Y»4+¸4¸и/¸ ¹ü¸!¹&üº!&9¸(и(/¸)и)/¸+и+/¸.и¹2ü01#!!32+"'&5!#"'&5476326!32+"'.# !2SþÌNNÖÏy©þ*Å %%"&¾+kr…»MM  þ“ìRüåþ­YaÈOh=Q³þâ/# 1Cj[fO„Õ¾ñþÿÿ,þɺ&$ühE(ÿÿ5ÿø“m&& A&ÿÿ5ÿø“y&& fÊ(ÿÿ5ÿø“x&& ¦?)ÿÿ5ÿø“|&& c^ÿÿÿëÿø€n&*Aÿ8ÿÿÿøœz&*fÿ/)ÿÿÿ¿ÿøx~&*Q¦þÔ/ÿÿÿèÿø}&*3cþŽ_ÿÿRÿð61&/¨+SÿÿCÿør&0÷AJ!ÿÿCÿø}&0÷fx,ÿÿCÿøt&0÷¦ç%ÿÿCÿø0&0÷¨ÍRÿÿCÿø&0÷c¸aRÄ ƒ¸!/¸"/¸!¸и/¹ü¸Ð¸/¸"¸ܺ 9¹ü¸EX¸/¹ >Y¸EX¸/¹>Y¸¹ü¸ии¹ ü¸ иÐ01 &#!  3! 54) ) 8)-þ þ¬æüâE(aPßýËþ¦ýÍ3Z {±$èšýÙ ‚üý•'0+ýÏþ¹F2J3KÿÿAÿôy&6ðA•(ÿÿAÿôt&6ðfš#ÿÿAÿôs&6ð¦æ$ÿÿAÿôy&6ðcÀ[sÿíV½:¯¸;/¸Y¸EX¸/¹>Y»+¸¸¹ ü¸.¹üº7901#!"543! =4)"543! =4'.#!"#"54763!2V³Åþ“NNm'þâþŠNNwxVBý§D.=, ONd[“ŠÏ· KM 9µQ;OhsfiNmsH<ü«9PTQL,D´‚'S48O'ÿÿ>ÿø´g&B÷Ajÿÿ>ÿø´i&B÷fïÿÿ>ÿø´f&B÷¦ÿÿ>ÿø´ &B÷¨•,ÿÿ>ÿø´P&B÷c=2ÿÿ>ÿø´V&B÷§,ÿëWÿøê¸7>S»K+¸K»>?+¸>»8+¸¸>¸и/¸?¸BиB/¸?¸EиE/¸,/¸0/¸3/¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»8+¸8»E+¸¸ ¹ üA 7 G W g w ]A† – ]¸,¹;ü¸ и /¸;¸#и#/¸;¸%и%/¸;¸'и'/¸ ¸OиPÐ01#!32# '+"'&=4763!&!"+"543 67>3254! 4&'.5!";276ê;ü럆mN9^þµpjðÄ’£›s­ªþó  Nepƒaž(‡dŸt—ÎþéþŽÕþSBF[^LŒz–K:ecObF6FއvltnÝ**2y5!ÿÿ0þ«·&D hj ÿÿ&ÿøTb&FüA ÿÿ&ÿøTb&Füfƒÿÿ&ÿøTa&Fü¦„ÿÿ&ÿøTV&Füch8ÿÿÿÆÿø[k&¢úAÿÿÿ ÿø¡R&¢þfÿ4ÿÿÿ·ÿøp[&¢:¦þÌ ÿÿÿÆÿøø[&¢cþl=ÿÿIÿøe&O¨*ÿÿ7ÿøSb&PòAäÿÿ7ÿøSX&PòfNÿÿAÿø]_&Pü¦¡ÿÿ7ÿøS &Pò¨{,ÿÿ-ÿøIU&Pècj7Jÿøf· 't¸(/¸)/¸(¸и/¸)¸ܺ9¹üº 9¸¹ü¸и/¸EX¸/¹>Y»$ +¸$¸¹ü01%3!27654/!"#!"'&54763!2Ã4?WRKfÛþ•`LlH¢s¿þ¡ýn~­¼`àa“² Bq ;#GþŸ oþ¤L:;C¬a¡S@&Aÿÿ9ÿõub&VìA:ÿÿ9ÿõug&Vìf[ÿÿ9ÿõue&V즓ÿÿ9ÿõuU&Vìct7ÿÿ@þïfV&Zðc…8jÿø<j 7»+¸ /¸ /¸EX¸/¹>Y¸EX¸/¹>Y01%#"'&5432/¸0ܸи/¸=¸и/¸0¹4ü¸¹9ü¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸"/¹" >Y¸EX¸/¹>Y¸EX¸/¹>Y»1+¸1¸¹ü¸и/¸ и и"¹(üA‰(™(]A 8(H(X(h(x(]¸-и-/¸6и ¸;Ð01#!!;2732+"'!"'&5! 67>32#"'7&# !24! ! ¯Sþq0< NN|ü‹‹þ²å„ÊCYz^–&ƒ^0 Mþ“’Rý7þ™þ¬kPYaÈ‚Ohgg:Rº2JcF4O„Õþ•'ššýÙ•Lÿø/¸$.<Ç»7+¸7».0+¸.»%+¸¸.¸и/¸/¸ /¸EX¸ /¹ >Y¸EX¸/¹>Y»%+¸%¸ ¹ üA 7 G W g w ]A† – ]¸ ¸и/¸ ¹2ü¸(и(/¸ ¸9Ð01#!32+ '!"'&5476; 6!254!"4!"!276/;ýEŸ‡jNN_þµq}þå®®­¼*t‹&Ÿt—Îþó0U*sÖþÛ`Ll:SJfÇW‹'bO__;N¡a¡S@]^6Fއvl Bnþûqr#GþŸy!ÿÿ ÿøßs&:ûc—UëʤO¸/¸/¸/01#"'.'.'#"547632¤E#" L?Fp*I %% : H:Hh#: þõ© (k ¸ /¸/01#"'&5476324'&#"3276(97PN7:96PN8:F$&00&$$&00&$»O1113MN2003M1 12 ÉI÷Þ» +¸ 01#!"'&543!2÷/ýp: O7 0  7D /‚?@¸/¸/¸ /¸/01#"'&'.5432?PR./PP/1ÇE 4! E 1þÞ ÿÿˆ(FÿÚš†GD)#¸/¸/¸/¸/¸ /¸/¸"/¸$/01#"&'&'.5432#"&'&'.5432-P#, //PQ-1P#, //PQ-1ËE 1! E 2þÞ E 1! E 2þÞ ‚F@'#¸/¸/¸/¸/¸/¸/¸$/¸&/01#"546767632#"546767632F1-QP/ -RPþæ1-QP/ -RPû þÞ2 E !2 E þÞ2 E !2 ©‹ ¸/¸/01#!"'&54763! ‹fJSþ©bInlL`W"@! DaG#rMþ¡º+¸¸¹ ü01432;2+"5MfU /dNN´¿>N0,1Y\ôêÉ£N¸/¸/¸/01432>7632#"'&êE#" L?Fp*Iþö%%þõ: H:Hh#:þõ ÿÿÿ÷¨Áe» +¸¸Ð¸/¸ ¸и/¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¸и¸ Ð01#"5#"54;543232#¾PRžII’zx˜DDý0JJÐFDÂddÂEE ÿĶÁ'†»!+¸¸!¸и/¸!¸и/¸¸ и /¸/¸EX¸ /¹ >Y»+¸»+¸¸¸Ð¸¸и¸и¸"Ð017'#"54;543232+32+#"=#"543ù¢HH’{w˜EE¦¢II’{w˜DDtÑÌFDÂddÂEEÌÑFEÁddÁFEܵ»+¸»+¸» +¸AŠš]A 9IYiy]AŠ š ]A 9 I Y i y ]A 6FVfv]A…•]¸ܸEX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸¹üA 7GWgw]A†–]¸иÐ01%#"5432#"5432#"54327uttu¥uttuúªuttu]\\XX\\XX\\X´Î:%5ïº.+¸º +¸º&+¸&A qA9IYiy‰™©¹ÉÙéù ]A6FVfv†–¦¶ÆÖæö ]Aq¸7Ü»"*+¸"»2+¸2» +¸»+¸01";2+"=4;2#4'&#"32767#"'&547632]bcÜ((æ®°å((5‡‡½½ˆ……ˆ½½‡‡^¢¤ãã¡   ä䣢§QÐR-0­Öª-0°Ã’ŽŽ‹ÊÌ‹ŽŽŽÉ𬧧¬ð¬ªÿÿª¹Y» +¸¸иEX¸ /¹ >Y¸EX¸/¹>Y»+¸¸¹ü¸ ¹ü01!2#%"5!32+ !2#FEEûˆ]Ù¢GG‘þÌžEEþFKR8/ELœîEJjÿ¹1Ÿ»+¸¸Ð¸¸и¸ и¸+иEX¸#/¹# >Y¸EX¸/¹>Y»+¸»,+¸,¸¹ ü¸¸и¸и¸и,¸и#¹(ü01!2#!)2#! 5#"54;5#"54;5)2#! !2#ŽW>>ý©KãCCýþ1@@11@@1ÛÐAAý6þÒEE¨¬D@E¢HI/ICA¬F?oHIŒoDAX/¸ 3Ѹ4/¸5/¸4¸и/¹ü¸5¸ ܹüº 9¸ ¸и¸и/¸¸к"9¸¸$и¸.иEX¸&/¹& >Y¸EX¸/¹>Y»+¸»0+¸0º9¸¹üº"09¸&¹+ü01"3!2=4#)"543!254+ =47&54!32+"3 ¯¦Ã—ªYxxþýÕIIH—¥òþ{wws)LLQ¦½ûnçWA`X=c o4;kþDFtdëDh69nâHDVbïMJ΀H¸/¸/¸EX¸ /¹ >Y¹üA‰™]A 8HXhx]01&5476323267>32#"&] |_3e=  V’LI•©SU  hle;Øž ¸/¸/¸ /¸/01#"547632#"547632ž7ÿ998,97þï97e°I{7'¸/¸//¸/¸/º 9º&901%#".547-.54>32#".547-.54>32Ä $þè   c"$üÀ #þæ   d#$Â&ÓÐ $ þë((þî&ÓÐ $ þë'(-®z7'¸/¸/¸/¸//º 9º&901632 #"&'&547632 #"&'&547´ #þæ   þœ#$A $þç   þ##g$ÓÎ$ %)%ÓÎ$ %)¢þùjªV¸/¸/¸¸Ð¸/¹ü¸¸ܹü¸¸и/¸ /¸/¸EX¸/¹>Y¹ü01432!25432)#"5¢TS‰ðTTþIý–TSbHHý(WHHý©þõ¸OOž¶K8 »+¸01"543!2#âDD+>>¶?C@B ¶a8 »+¸01"543!2#ãCC@>>¶?C@BA=¯¹ j¸/¸/¸ܹü¸¸и/¹ü¸¸и/¸EX¸/¹ >Y» +¸»+¸¸¹ü01!"3!25) =4)6+"54; þmqrm’þîþÂþâÀo‚<Y¸EX¸3/¹3 >Yº +9º +9¸+¹ü¸$и%Ð01+"=#"/#"&'&5##"&'.5#"547632 >32 3D´44¹D0® #“D +70 %Wå2D¼Ý%%âÁD1Eþ»#!EC$þÅ<U$®+z¸/¸/º 901632 #"&'&547ª $þç   þ##g%ÓÎ$ %)-®4z¸/¸/º 9017#".547-.54>32® $þç   c##Á$ÓÎ$ þì%)ÿÿ:ÿdI$ :ÿdu$+#¸/¸ /¸/¸/¸/¸/¸'/¸*/01%#"546767>32#"546767>32u0/ ,!O./ ,#PþÔ0/ ,!O./ ,#Pß þÞ1 E #/E þÞ1 E #/>îh¬'#¸/¸/¸/¸/¸/¸/¸$/¸&/01#"546767632#"546767632h1-QP/ -RPþæ1-QP/ -RPg þÞ2 E !2 E þÞ2 E !2 @ÿùS @»+¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y01#"5432#"5476329/LOOL/,&8‰,)44)-::N9O;ûó5m4`þF³Žº+¸и¸и/¸/01#3#3³SSSS¨æø¸æÿÜÿøŠº+“¸,/¸-/¸,¸Ð¸/¸-¸ܸ¸и¹'ü¸и¹ ü¸EX¸/¹ >Y¸EX¸ /¹ >Y»+¸¸¸и ¹ü¸¹%ü¸¸'Ð0143! #!"5#"'&543+!27654'&#!32œN±ï­†ÁüTNˆ, 8 8meMkmM_üåm, °¼NþÊý½¬YDOÁ 8N[Mþ§&RAH"þ«ÿÿÿøÕ{&:ñf†*ÿÿ@þïf]&Zðf Oÿø‘½#‹¸$/¸%/¸$¸ и /¸и/¸ ¸ и /¸%¸ܹü¸и ¹ü¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¹ü¸¹!ü01#! &547)5#"543!2! 3! ‘¿‡¾þ¾þáv´OO„Óý…þåk.‡0FšP=0Nc*e[NSü¹Û}þ¬] *ÿøº Џ!/¸"/¸Ü¸!¸ и /¹ü¸и/¸¹ü¸¸иEX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y»+¸»+¸01#!#"'47>32!254)! ¶Çüýql/ 0&N¼ƒÁÜþÞüñ!:·Q;°OO%;Nf4H“¶¦jþ\Cþïpº#¼¸$/¸%/¸Ü¸$¸ и /¹!ü¸и/¸!¸к 9¸¹ü¸EX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸º9¸¹!ü01)#"543263! 4'&#! !2pþ8ýn+ MNNI*]±PûÕu/€þ·þù‘ó)þ×Ã8N/N:Ñþæþ‰tL dþjÿ¹1Ÿ»+¸¸Ð¸¸и¸ и¸+иEX¸#/¹# >Y¸EX¸/¹>Y»+¸»,+¸,¸¹ ü¸¸и¸и¸и,¸и#¹(ü01!2#!)2#! 5#"54;5#"54;5)2#! !2#ŽW>>ý©KãCCýþ1@@11@@1ÛÐAAý6þÒEE¨¬D@E¢HI/ICA¬F?oHIŒoDA‘ÿç ÌÎ -»+»'!+¸'»+¸¸¸и/¸¸(и¸/ܸ/¸ /¸/¸EX¸/¹ >Y¸EX¸/¹ >Y»(+¸(01#"5432#"547632#"=!"&5432!432BYXYXO %WÌYXý0*VW›XY„MMìMMûR!BP!ûýMM•,3øMMþU«MM‘ÿç¼Î 7§»+»&+¸»,+¸¸!и¸9ܸ/¸ /¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸#/¹#>Y»*+¸*»5/+¸5¸#¹ü01#"5432#"547632)"!2#!"=4)2=4+"54; BYXYXuN 'XÖþ¹þç®ÆHHüÍCv‡|ÔMMÄ>„MMìMMûR!BP!þìGLLDâáDWCMJë-ÿç Î #Pû)3+¸)»+¸»+¸¸¸и)¸$к&3)9¸3¸Eи¸Rܸ /¸/¸/¸EX¸/¹ >Y¸EX¸M/¹M >Y»+¸»1++¸1»?9+¸?º&9?9¸M¹Hü01#"547632#"=!"&5432!432%)"543!2=4'&#!"543!267#6=4+"54; N 'XÉYXý0+WVœXY÷òiiþ”ýñPP%¥&D7ýÕPP+82¢¡PP€tR!BP"üOO•+3øMMþU«MM€k78t0ðJMSRMO Q>LLÝ9=÷¹j¸ /¸!/¸Ü¸ ¸и/¹ü¸¸ и¹ü¸EX¸/¹ >Y» +¸»+¸¸¹ü01)"!2#!"=4)2=4+"54; ÷þ¹þè¯ÇGGüÍDw…|ÔMMÄ>—îEMJBãàDXCLLë5=¹,p»+¸¸Ðº9¸¸!и¸.ܸEX¸)/¹) >Y» +¸ »+¸º9¸)¹$ü01)"543!2=4'&#!"543!267#6=4+"54; vvþ”ýñPP$¦&D9ý×PP) 72£ QQ~v«l67u0ðJMSRMO Q>LLÝÿÿGþ¡½·&B®Ôÿÿþ¡ÒÈ&"®Hÿÿ*þ¡X¸&F®¹ÿÿ+þ¡‰º&&®¬ÿÿIÿøeQ&Of5ÿÿRÿð6P&/f¡ÿÿÿ(ÿøŽP&4f›ÿÿÿ+ÿøê/&Tf_Þÿÿ#ÿø„P&;f0ÿÿÿ(ÿø`Q&[f!ÿÿÿpÿø‘º&-GÿgQÖÙÿÿÿ{ÿøùº&MGÿrC\_ÿÿ'ÿø„N&D¯Žÿÿ0ÿø“M&$¯³ÿÿÿ(ÿøŽM&4¯”ÿÿÿ+ÿøêN&T¯Cÿÿ0ÿø“P&$fWÿÿÿ'ÿø„Q&Df2ÿÿ#ÿø„M&;¯|ÿÿÿ(ÿø`N&[¯Gÿÿÿø_M&5¯pÿÿÿ#ÿø„&;¿ÿÿÿ(ÿø`&[¿þÿÿ(þ¡Žº&4hVÿÿ+þ¡ê·&Thÿÿ?ÿ÷ P&3fÿÿÿ,ÿø›Q&SfÃÿÿÿßÒ&"·èÿÿÿGÿø½€&B·tÿÿ+ÿø‘P&-fIÿÿÿÿñÿø†Q&Mfÿÿÿ+ÿø‰M&&¯“ÿÿÿ*ÿøXN&F¯zÿÿLÿø:M&%¯üÿÿÿOÿø‘N&E¯©ÿÿIÿøeN&O¯‘ÿÿRÿð6M&/¯ýÿÿÜÿøŠº+“¸,/¸-/¸,¸Ð¸/¸-¸ܸ¸и¹'ü¸и¹ ü¸EX¸/¹ >Y¸EX¸ /¹ >Y»+¸¸¸и ¹ü¸¹%ü¸¸'Ð0143! #!"5#"'&543+!27654'&#!32œN±ï­†ÁüTNˆ, 8 8meMkmM_üåm, °¼NþÊý½¬YDOÁ 8N[Mþ§&RAH"þ«ÿÿLÿø&0¸£ÿÿÿEÿøaž&P¸IÿÿMÿõ‰ž&V¸aÿÿQÿô/&6¸¶ÿÿÿþ¡_º&5hÀÿÿÿÉþ¡#º&Uh%ÿÿ?ÿ÷ M&3¯éÿÿÿ ÿøÂN&S¯ÿÿÿMÿõ‰k&V§‚ÿÿQÿô/j&6§×ÿÿÿ+ÿø‘ &- Hçÿÿÿø#Œ&U ³hÿÿPÿøl;&M #BBBBòÒ¬ÎüLœ „´Öþ,¦è†.¨  º ò ² V ° ô 4 p ° šb®nØ8¬”,pÈX  Œð^äzlüBÀ4ŠÀ.l¢Äð’LÎZÔ„R¬ , n!D!²""Š"ö#>#²$$$¤$Þ%>%¨&6&j&º&ð'D'¾'ü( (¸(þ)ê*”*¼+B+l,0,<,H,T,`,l,x-0-<-H-T-`-l-x-„--œ-¨-´-À-Ì-Ø-ä.b.n.z.†.’/7Pÿ7SÿK7Vÿƒ7Zÿ{8 ÿo8ÿÇ8"þx80ÿÒ8Bþâ8FÿŒ8J8Pÿn8Sÿ•8Vÿ´8Wÿ®8Zÿ¬: ÿ):ÿ^:ÿ):ÿ‡:ÿ…:"ýç:0ÿª:BýÈ:Dÿ:Fþê:HþË:PþÊ:Qþí:RþØ:VÿP:WÿJ:[ý©:†þŽ:‡þœ:ˆþc:‰þq:ŠþU:‹þq:Œþ:ÿ9:Žÿc:ÿc:ÿG:‘ÿG:’€:“ÿò:”U:•€?üä?üÃ?;ü¡?Bü×?Eüs?Füó?HüØ?NüÖ?OüÔ?PüØ?QüÚ?RüÖ?Tüó?VüÐ?ZüÍ@ùß@ùþ@ùà@ùä@ú@ùý@ùý@ùÞ@ùÝ@"ú@#ùÙ@$úd@%ùÞ@&ún@'út@(ùÿ@)ùÜ@,ú@-úf@.ùÜ@/ùØ@0ùé@1ùÿ@2û§@3ùë@4úi@5ú˜@6ùÙ@7ú@8ú@9ú@:ú@;ús@Bú:@Cú‚@Dús@Eúf@FúŸ@Iú–@Lûk@Nùã@Oú’@Pú–@Rûù@Tû @UüÔ@Vún@Wú@Xú@Yú•@[ú—BWÿÆBXÿÞBZÿºC ÿÙCÿÙCWÿÎCZÿÃD FWÿ³FXÿÊFYÿÊFZÿÝG ÿ×Gÿ×GFÿÜGPÿ¾IZÿÇLFÿÚLPÿÃNZÿËOWÿÒOZÿÏP ÿÇPÿÇPWÿÈPXÿßPYÿàPZÿ¼Q ÿÉQÿÉQZÿ²S ÿZSÿ²SÿZSüÚSHSHSDÿêSEÿ¯SFÿÝSG9SHÿ½SI!SNÿÉSOÿÏSPÿ¿SRÿÄSSÿçSUSVÿãSWÿÜSXSY7SZÿÛS[þfU[þ{W ÿWÿWü1WFÿÛWPÿ¼W[ýûX ÿ‘Xÿ‘XüìXFÿÑXPÿÖYFÿºZ ÿqZÿqZFZPÿÅcüœcüzc"ü·c;üXcBüªcDüÊcEü+cFüÇcHü¬cNüªcOü¨cPü¬cQü®cRüªcSüÅcTüÆcVü¤cWüØcXüÍcYüÔcZü¡c[üÉeüºeü˜e;üÖeBüÜe[üµfüªfü…f"üðf;ü”fEüj“”+”CG”G€”I9”L+”MG”•«¦ûܦû¸¦;ûÓ¦Bûø¦[ü§ü•§üp§"ü̧+üà§;üq§Büß§Eü9§Hüá§Nüß§OüݧPüá§Qüã§Rüß§VüÙ§ZüÖ¨üä¨;ûð¨Bü¨Dü0¨EûƨFü-¨Hü¨Nü¨Oü¨Pü¨Qü¨Rü¨Süê¨Tü,¨Vü ¨Wü>¨Xü3¨Yü:¨Zü¨[ü/©"þB©$ÿ€©(ÿq©0ÿQ©2ÿw©4ÿ–©5S©Bþt©Dþ”©Eý½©Fþ‘©GÿŸ©Hþv©Kþ‰©Nþt©Oþr©Pþv©Qþx©Rþt©TþªTþ•ªUÿ}«"ýi«$ÿ‡«(ÿx«0ÿW«2ÿ}«4ÿ«5[«Býc«Dýƒ«Eüä«Fý€«Gÿ¦«Hýe«Kþ¿«Nýc«Oýa«Pýe«Qýg«Rýc«Tý¬;üô¬EüÒ­[üïÆüÝz»ËÓÚôü A V a l … ¨¯ v· - = 4K  " ± ‚Á C Y 2o 6¡ × ç õNeuropolFreeware version. Copyright (c) Ray Larabie, 1997. All rights reserved. Freeware. Revised 2003 www.larabiefonts.com Check www.typodermic.com for new variations and extended font families.NeuropolRegularRayLarabie: Neuropol: 2003NeuropolVersion 2.02 2003NeuropolNeuropol is a trademark of the Typodermic foundry and Ray LarabieRay LarabieRay Larabiehttp://www.typodermic.comhttp://www.larabiefonts.comNeuropolRegularNeuropolFreeware version. Copyright (c) Ray Larabie, 1997. All rights reserved. Freeware. Revised 2003 www.larabiefonts.com Check www.typodermic.com for new variations and extended font families.NeuropolRegularRayLarabie: Neuropol: 2003NeuropolVersion 2.02 2003NeuropolNeuropol is a trademark of the Typodermic foundry and Ray LarabieRay LarabieRay Larabiehttp://www.typodermic.comhttp://www.larabiefonts.comNeuropolRegularNeuropolÿ…   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„–ŽŠƒˆÞ¢­ÉÇ®bcdËeÈÊÏÌÍÎfÓÐѯg‘ÖÔÕh‰jikmln oqprsutvwxzy{}|¡~€º×°±»ØÝÙ¶·´µ‡àá‚«‹…½†Ûߪ©—²³ÜŒ¾¿ÄÅèéëìêíîõôöòó     âãÿäåýþæçûü !"#$%&'()*+,.nullmacronEuroaogonekAogonekeogonekEogoneknacuteNacuteSacutesacuteZacutezacuteTcaron Zdotaccent zdotaccentRacuteracuteAbreveabreveLacutelacuteEcaronecaronDcarondcaronncaronNcaronuni0110 Ohungarumlaut ohungarumlaut uhungarumlaut Uhungarumlautuni0162uni0163RcaronrcaronuringUringLcaronuni0111tcaronlcaronÿÿ øÿÿþ ÿþ ÿþ ÿþ ÿý ÿý ÿý ÿýÿýÿüÿüÿüÿüÿûÿûÿûÿûÿûÿúÿúÿúÿúÿúÿù ÿù!ÿù"ÿù#ÿø$ÿø%ÿø& ÿø' ÿø(!ÿ÷)!ÿ÷*"ÿ÷+#ÿ÷,$ÿö-%ÿö.&ÿö/&ÿö0'ÿö1(ÿõ2)ÿõ3*ÿõ4+ÿõ5+ÿõ6,ÿô7-ÿô8.ÿô9/ÿô:/ÿó;0ÿó<1ÿó=2ÿó>3ÿó?4ÿò@4ÿòA5ÿòB6ÿòC7ÿòD7ÿñE8ÿñF9ÿñG:ÿñH;ÿðI<ÿðJ=ÿðK=ÿðL>ÿðM>ÿïN@ÿïOAÿïPAÿïQBÿïRCÿîSCÿîTDÿîUFÿîVFÿíWGÿíXHÿíYHÿíZJÿí[Jÿì\Kÿì]Lÿì^Lÿì_Mÿë`OÿëaOÿëbPÿëcQÿëdQÿêeRÿêfSÿêgTÿêhTÿêiVÿéjVÿékWÿélXÿémYÿènZÿèoZÿèp[ÿèq\ÿèr]ÿçs]ÿçt^ÿçu_ÿçv`ÿçwaÿæxbÿæycÿæzcÿæ{dÿå|dÿå}fÿå~gÿågÿå€hÿäiÿä‚iÿäƒkÿä„lÿä…lÿã†mÿã‡nÿãˆnÿã‰pÿâŠpÿâ‹qÿâŒrÿâsÿâŽsÿáuÿáuÿá‘vÿá’wÿà“xÿà”yÿà•yÿà–zÿà—zÿߘ|ÿß™}ÿßš~ÿß›~ÿßœÿÞÿÞž€ÿÞŸ‚ÿÞ ‚ÿÝ¡ƒÿÝ¢„ÿÝ£…ÿݤ…ÿÝ¥†ÿܦ‡ÿܧˆÿܨ‰ÿÜ©‰ÿܪŠÿÛ«‹ÿÛ¬ŒÿÛ­ÿÛ®ŽÿÚ¯ŽÿÚ°ÿÚ±ÿÚ²‘ÿÚ³’ÿÙ´’ÿÙµ“ÿÙ¶”ÿÙ·•ÿظ–ÿع—ÿغ—ÿØ»˜ÿؼ™ÿ×½šÿ×¾›ÿ׿›ÿ×Àœÿ×ÁÿÖžÿÖßÿÖÄ ÿÖÅ ÿÕÆ¡ÿÕÇ¢ÿÕÈ£ÿÕɤÿÕʤÿÔË¥ÿÔ̦ÿÔͦÿÔΨÿÔϨÿÓЩÿÓѪÿÓÒ«ÿÓÓ«ÿÒÔ­ÿÒÕ­ÿÒÖ®ÿÒׯÿÒØ°ÿÑÙ°ÿÑÚ±ÿÑÛ²ÿÑܳÿÑÝ´ÿÐÞµÿÐßµÿÐà¶ÿÐá·ÿÏâ¸ÿÏã¹ÿÏä¹ÿÏåºÿÏæ»ÿÎç¼ÿÎè½ÿÎé½ÿÎê¾ÿÍë¿ÿÍìÀÿÍíÁÿÍîÁÿÍïÂÿÌðÃÿÌñÅÿÌòÅÿÌóÆÿÌôÆÿËõÇÿËöÈÿË÷ÉÿËøÊÿÊùÊÿÊúËÿÊûÌÿÊüÍÿÊýÎÿÉþÏÿÉÿÏÿÉopenlayer-2.1.orig/demos/gamedemo/Gfx/0000700000175000017500000000000012262355751020116 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/gamedemo/Gfx/Ball.png0000644000175000017500000000576210377212142021511 0ustar georgeskgeorgesk‰PNG  IHDR 2Ͻ pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚ,бu[1 @ÑG$<‡·P•“ôjÔy˜4ŒÐÚÂ{X$@ Mî·üþó—~å8~}µ1®­÷‹ÖF‘òȨ̂»?|­Tm­´>Î6Æyô1ÐÖ("·Œ¸¹Ûç¹kUýj­­ú1ã@û@ªØšg&ß*R¯µVT•ª í~T©ìp2A}_U J¡”‚ˆ UÑZÑÖaACD. d’™d¹7Û7™‹ØNDHD¼öÞ¸î†ÙbÍ7óýÃZ“µnöÒmö4³›.cÉwGDˆ¶sΧºÛ£®ù9‹œìØü$#ñmwŸë¡n+K)wà;3®ê~‘Z)E^™ùŒí_–ÿ€«ƒep_IEND®B`‚openlayer-2.1.orig/demos/gamedemo/Gfx/Paddle.png0000644000175000017500000001066610377212142022027 0ustar georgeskgeorgesk‰PNG  IHDRd{À˜• pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÓIDATxÚŒYK’Ý6 ì–t‰ñ]²Í&÷¿À¤Ês‡ˆdgA y쩲ß_ Ñh@üëïbþ)½8ó3Eh}ͱa¾4_I²5`¿ )JövŽ'­ßçdù(@$lɽßÞ ¾çxpžnÍa˜£}AÆñk|”ùóúaÝWIBvNŠåö³ûñi›p¸ìp×…?>›·gqÚdžõ.²E’'ö%.W®KÃÂÚeÿIé¦ôq#ü\÷¢}£´—¡Áî8×ßvÉkÈmÌÈ|OG ãéÞt|"ßL6~~ýÄuž'ŽóÂÇÇG…±/Í´É·yozxD0¨à/ÆÔ«YŸ»Ç9qf9)íÿü•žwyÜ•¡{¡8•åŒòÎ÷úÞZaÈ××ÎóÂuœ'Nû'§«Ãq¹ÃvõøBxR+$6¦+3¬÷4üg3¾Ÿ~ãBeȵ+£ åЕ^ ¶âØâûôàáç 2tÑ7›$«|.-\Æ”Ó:µ?U¨Çyâ8\<ð<Áã4£ŽS©yGYÐËA¢ œ¡áDKhjå ú/‹@÷ùêE Â#ï`Sø/T¾ÄáßËÂõˆôÆ£Ã,‰Bý@`T7Æ‚«$‚ÄáH4“‰²tQ(àÆò(ßøˆÙ ‡Þ‰gQ•sŸýIJ1´‰ 48†$yd9ð—q<ð8pi t Œ>–w1Rú0漨–h縿Œ‘¸BDn€(ØDc<&˜×ûð¹®Ï €ð[À¨Êì…Çß4´áÙ”Çæ.4í ütMÁ1r±#G À£w\}t¨ô>@jÉepä›y ¢.¦(ó½9ªÙÄsŒóé|HÚÌ¥';d “ÏP/”ålã.Êf2Θ¨S2úRVòJªáØž:bêô™ìYó¡Þ¡!\£ŒÞ0Fó#/¦§I’nQq[¬dTÇÓó­TréÚX©¸~©¬²¶Ê ­Ô5úUŠy~]”eVÍÚI~éÖ™çÄ8k.ŽÌû¹VÑû@ï Wï ½wôÞñ6tw¬o^‡g,L0Y7Õ}þ›i…uµë6{ Ê*.Qÿ„‹ŒuTu÷Οڥ-kÃ)ˆ#D.uLPM˜êžl;[µ÷½w\£7´ÞÐ[‹òÊUA:lHÖÜ–F0Ñ,Å„«ðjåíªÂ¥XÅ-ÇêQÁªLÂâ[¥òâ}ÁÇxEe =šƒ‘vN:ZMß„ø°ÚÖXF›!ƒ rÁ:ZGo W³7½7|Ü,õelE(Û£æ³7})”k%çØÝ¬®ñÓo›ê…’øRžòé¦Ç7{+vS„ILê½z­Í"Ôè‰çRE³5që}RVk7ú=#$ÔùNÜÔ•êŒR¯)ÕÈs¬2¦ÅmKè‘wx*÷fB»%gé`ï2†Q¹U´XÆÛB»?”m³ºJˆL2©¯ä¢*#!¦ÝüpûFk7ÚÝ*¯Ý:ŠÕâÆçªµM>‰ÜÕ¡¼Ã&È4­…¦&éïµè±ò`]?K8Çœ¿÷4DõîQ„0¤Kmò¦¥Õ¨Ø1di°´Š¬ ˜iuû TL $8}ÐV„´­ß{½— —y³ª IJ¡¨ÔUzoRÙD¥,oJ57…¬YûØèW|Ì=¬]oWïX±1%”èìen𠸚I–m –ãz , 4o¶¬*-¨•~7´vãj­á¾;ú}g^]™ç½‡¤}K˜‰£ÝìÙ}°yÅž_jQñÒû.;<ô9ÃK(ª–5Ebë)ª˜W§™ŸMp–É+‚-‡X`X„ü‡Öîœ8ôÖ zéÒÖZa‡M¹J9Um '/”C¾z“Uå ÌOq²Ï¶.ò’PÞäd´ñ£ùŒœ•#Ò½·¹¤‡¿ÔœbÛI‹‹wlνÚ}£Ý7®f ½ßw¦Ôçs<–¼VdSϤr…-}™´¡klù&~ 4Å'}Õ¼o %@­›cO Z•™óî•sw›ïO#žuy9µÐ›QV7Ï|~þõ{ÀüêÂCLïÅísNU ì÷(L‹`Ûk_ÞŸÅ‹Mô´ X”ž,¤âdâ±rsÕjð¼ª`†ô’¹cÍâ&ùÖÊOÚmIýóóѱå¿ñùþ(>ÚÉ[ånÎ3î~—J–úX `úÏž˜¥ÓÔx÷˜.p÷P Üë¥GüL2ÄÛÛÅÿ‚<Ñ ÌÖIEND®B`‚openlayer-2.1.orig/demos/gamedemo/Gfx/Background.png0000644000175000017500000074421610377212142022722 0ustar georgeskgeorgesk‰PNG  IHDR Xšv‚p pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF½«IDATxÚì½éº$9rê–jJ\DR¢j½âû¿¤ß•˜™;‘§NõôÌÀõQS]uNf‡°‘qâĉ'Nœ8qâĉ¿C¼Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉgrâĉ'Nœ8qâĉgrâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉgrâĉ'Nœ8qâĉgrâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉgrâĉ'Nœ8qâĉgrâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉgrâĉ'Nœ8qâĉgrâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉgrâĉ'Nœ8qâĉgrâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉgrâĉ'Nœ8qâĉgrâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8q6 'Nœ8qâĉ'Nœ8'Nœ8qâĉ'Nœ Èi‚'Nœ8qâĉ'Nœ ȉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉ'Îäĉ'Nœ8qâĉgrâĉ'Nœ8qâĉgrâĉ'Nœ8qâĉ³9qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâÄÙ€œ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8qâl@Nœ8qâĉ'Nœ8ñ'Ý€ þ-šÿÄîë_ï?¾ÿXüøûoçÏcþÝõYü“h¾Ž?›ý7¢yìZ‰¾#°øÙ¶}ü›`Ÿz\´Ÿ¡¯ƒgÏû¨CŸü<ôÝ¢QPÛ«O(}¶lŽ›—@ßgå£ñèÓêàî[?ïk'Üv!6݉õ½ÛO,'Üb–9€åDšw…=ÃÍ„D`ß.Íû>íÄîÁúg”nÄâ³ÏžMƒ#J^Ýõ‘§›Ÿ<œÍÄݯâé·aŸ“±úvlæ€Î)l'ó³v@ù,–,,ß w߉ƒ'Â&Gb™/K&B7ð\Bž43vùOÙƒÁ…ϲFÛÏŸ}BMM›}úœè»çfM½O$X-›U»zªëïM ÆÍï¯_÷/VžóQµpÓOJHxú߯o«AU•ÀKŽWÛ}¶+k6l0aó¢¨óáÈ9y¯Hè‘òýÿ Ëâ.ȼ~ÿÇSæûk²y5DþøüŒˆÌ÷˜Èë›#9±äl5ÆáýÍã‹DDä»àÁhæüñòü)ËPݵuìñ\I;›âï¿F97"#ú4ˆÈä‘1eæ¤ùÿRÇtÆ(KJ€~:FßÇ»g»â1é‘1‚|ÿu0Ûu þëy0Ûæ= çP(ßš–:¨íw© i ÞßÅo÷cŒHŸ'_Ô±3'–Î:l4ÑÕv)…æ˜Ìš*kí1Û:}Ííý®ÐÍއñ9e1M–káSìš?<‡¨- Žô9Æô 9›ïñ—ó€$í+ðãÙóúåü±É óôǼ }F~¸´Ïç¾{ÿ\^ŸŸ×!a¹‹‡bJ¢Âú ¼±ãBýýL9f®Í®´ÁˆºBe¿så¶/ULÛ6W៛Í1û}0:èÝœ| ”3ýRþùÑï÷øÓêéÚÈ뜇Q '̵B›²ÖŽ9ƒ+?vkV–"k´M¢©àR['Q^#8/s ¿1Ú³;"ø‘(rÌ#×iÿþßóqA•ÄG£;c½u.©V¸Æò{me#>,¨GRKÉø÷9T3I`Ö$s!ÏŸs׸ò9Äëü;F®¡aIùuIÍmWZA¢æWèÚŽYX›_Cš×mêj¨¤9“Ëã´wN”µ4íÀ Ák—ÍãDIxàEÝÇ/ÏÝœ5ñ¬C¹áAÝ…Z¼çôûZ@Ž>cv¶=êìt=ç·.‡¹Y×C·ã_‘³ß`õ ?c©8¨ÖëYÚázX_çG¯1áè…~äÜw™+¯ò-as”Žò=p~,Þ£ÀBÈf'¡*¥ ÇPÈ‹NJÅ—³pCÎä{m>®ä—IߟcÃs%öë;óÝàÀ|F®±<K 2Æå(‚žùj¡«¨Íw"¥¤^(‘c“˜ SM¾ïb àueÔ4¼hgú†*G!8Úµ(Ó‚™\ˆ]ÅQùK¥ð *r¯Ï¹žõ=jRŒw :1É“³íñή  ÐXK:¦$‰kœ½N®âÓ7—¼ˆrá@Ÿè slÂw ™£ÀH¼ÛWbÊYÔX"ÖƒPÒ¯GqšÃ‘¤46¿/ÇÆÑv ˜ÉräuàòÝIutŽ N¶°ãÈâýs®Žƒ9@ˆ²Q¸Š>Ð÷Šå±9š;„ñ.!ãKL¤ºüèß™s ;z:¸¹hª\ãöG7óçfY0}öù?©ãËnR)‡H™\8]m’º©‡æ¯¼2Eæ;÷€§û»xOéËYÍ€u>< ·ã&iþY¾°õ%åÄ4Ç®=¡Å¡[ïŸ+µwFÿ´Á9~J›?Ö‘‘ha‹Ôõ-“6¦9XÆùèàižB\óçú½¼6°‰‘/Á%°M†C|®M#çŒ2aŽ­¼þn.5ïgš¹çʯ×ÜM\ÅKêmŸo`Fá ÍÿÉÅÆf=a‡dœHé*1sER½2Ç8Mº š!ýÈî*€1òè}¯Ác¶¤ÌØ;¦ÜPòŠŸï\??ÿzJ9Þ}çpBsh¬[™ºƒ¡ƒ#-T³ì Qn¡5½£ä"Œ ÙXƆ2)“Љ™cà¥ñX0[ga®ÏèÓÖ&XA–ac$¸LªYS6s³@†öI=˜t`7ëÝ·¤ÌIÉ«£>áóåyõj§y°?Ç £®±ÂóéGn–Ÿ+Õ\[ê†É6ü¡Ä :n<ßÕ-Is“ãßrÖc3O¿Ã;ŸQ»Æ„ý«œöf6‹õ{½ N žÌ”7rèéß1Ò 5|æÈJïbqŠ£ˆÌ9ü?“Í™\®ïœï¹N‰Ÿ&Ïu‚Ž?Ýüÿ%\"nÔ–¹s;fºÉÉÐA:7çÉñ{Ñ•)të9ýµ Á~öÚÄŒñð.¦h€Š–ÑVY—úùAEÍÜ-`~ÎØL‚®Þ0Çß8±÷Ò³£Íy ]ã3QÛŽN°1ö¿4QùTâÚ8%opç{§œÂæ{£™£8ËkbŽÏA95H:ÍJ:ñây`‹0·KÒiqÖCw-ûxá *OÞ‹xÚâ†ÙWA2Ûi6£»ß¿“©É á7~4'Ç|§EÖúýÊ É ÆUL¤ovrž¤ÍÓ±“vsô~àÌÐg¥wK>‘ÂuX2ÿWo6›Ãz̶uC“cùýÇæT ]Í´9?l޵-Ã9kµk~a¶½œPP~Ÿc}©ð—”­½¬&ÒÆI_CBÎmœ€@·mÉТ(iþFØ~·<›2÷›Åo¨YžµKÿ½mÖh^ÛkÊÍÞ»ßä~õÅè0èÚ½ëïÜlüý¨_žÇO–šòÇ•Ïzþáêóá ZöõÓ:."ðŸóTbœÇ£Ÿ@¶?Ä¢÷ñôçü×ødçÃwAìå£'d O÷é»çêþŠyF·Í9…ÆÝ×ç®?Ӿ䓌û×í¿ù³‘òs¿õÅÑöèè‡÷˜uÑyú¹ß1C¿-¾:E›û‹¾?óËýû–V{8þ?Neß08vóìú³dE^X}Å._!¢ßä£<¯­?p•³–Ï¿H«OŸ÷Óy¼\:Çá°‘ ?|ð~ø•k¯³²žÂþg›úmYÿåÀÝšú3­±¤ÏÊŠx¼ÈÓß× wuÁ¾.yRs~åAYªá»Fñ÷­Ó?×Qš+q-lo†¹ç›§=x $ •„Ä%ƒŠbV•¯k`ÄJ¤?£Î..K6&òh*¨nzd?žÏÐÿµ¦¯¿Ë­&rI‚TóNœ¹†`Š’d-—´`ƾöKû¹ÄBÊžæ‰^UUÁìOeVª‚¡Ê…Ï$Œq“QPJìyU<)å9T9µÎ/tòðœo|a@SÀ› Ìk-IIŽ´²Š"AZÇÄ”¼G˜Èv›¿Ï¸)ÒrÆÑ'å$.r•]?•L&~­ßj›$ZLùÜ€óx3{¶sÌÏ¡üTΕ Ê•.ʪeŠq,Õ½÷Ë8™EF?Dyò}H–Ù–ÉŸ›öÎ!›xÕLfˉgW¯µS/2®Šn1Ô&×·I$µ›l¿¤Œ¢F–.ͪIí• ±b‰îá ‚P±°’ê\«‘öŒdÁè-ÕPš{½] ²ŠV©i T«U2“fiòML1N!* ô e€Ae†hûWROŽf©p!N¥ZÁÊœTyÒ¹òƒÓÏX ,„R]šŠNÛ‹®sÚ€f)FxEb×i(J?½ôäF¨#m»ÂÇüi’¬Ñ6wRƘ~îš4˜,È2{¢¤ÓÉ\†I6G‘ñséèÒ^´ëHÛX¦HaF´’¢gé]QÄ®çÆX ¿PëBا ò‚Êo½r†Š žñ^üß\‰‚i+±C~tÃMŸ-ðAûÚf¢×bm, NÑ‘6]º2z}”¤1¶"fK›¡(aé«¢ àÂÊC.Úe³ªÚܪªt©Ã#M’‘qÎ ÿiy&÷ï…cªšl< %¢†õujœ_S­‡×;ˆö\@¡ Þ ZjŸg îЉKäÍáJØÂ[q§×ùFý´…¬>ïKgßì[@ö²S ºÎ©’d/«0ùæàuY•ôŠ˜EÆç²ú¯×+¿® ðÙ/üž >_ÕBz Õˆ\ Ò8?UÂøò«ø‹?ÕÄ®HòMrD»çúTmêã7‡¯ôÉASíwóö 7j"wjJ_ë‰ïÔ°ÑkëîuîĪXÝ£Uóøfɯ©®Ä½@ÐÝ/ÞËÑÝ%¾û^øFu¯ÏµçjY_YÌî>½ôïœÛ³Uè áQÿõrqÃDíqÒŽæÊ“~,Éèöƒ+·§)ïæ{~A2~fnßëѨ¯’ŒÚ7 cKõ¨/ Ë_TñÝ~6´^~üM"IÆçeÒçϵÏ+™Ã/|³ç‰%9ùljRLE'=…òïAs.1®ä'цŸ b³}`r´þ,K1…‹¹’†²ù¤6”(í”Íìl©æsˆÒVZ0þï)ÚEóÃ0Bl'Snp­jq)•rC(ÑhO œ€æj)NHÓwÚÈÈùiˆÉù Ñß.Š?{·€IÊûS¶òPÝ*²ã³=E%PŸš|ÐP¡ .£qFÇë&)R”1oHÕmÐ&*ý7Q É92%]fÝ‹c!Nj3fïªÈD‘¼õ…‘•“¤@óÓ[]Ia›ß˜„DXû_å~fÙÝ óà&5)öP<˜‹j^fÝÁfÆ”…†IO^xUP.ÉÉ]KI I> 1Ôºô a*–X /§"&ù¤ì5TLéâ’ Ò9eÊ÷œž$ßq8¥å«|¶9$‰= —uA4åBû,ÉoA ™ ©’îpeCV&ƒL™«­”1ÔM¸lr’pß9U„ Z;zФ¹%‰gmÀ¡ô2ëQ¿ªÙæ-T‰R¨YìJ´­Ÿ':uA J‹sn§Ü7ú1&×#‚4Elfy­LRS™hw‰ÂIqñ X-;Fô¨G)öëO™œó?HT\é°âÔ,æô‡dhÔÅ/% :*º6Š&¨Ä\m ‘ŸÒßÿñc]­E"œ†Â7®QÎÙ%Þq=ÇàZç;ØÆÂUç.€ÅLø™½ GÍ P>Ì%Ö-k³ù¿1¦“oQfí‡fqâ9xKWY R„ŠTs¼'´sÝy‰Rºî²¨QJn°ve6\ÞÞÅ$8A‡%©Ó޵>y×ëߥŸ†&½÷µ$üô4€zÇ„Ç4e™¡*á*;HìEtJ"‰ ™&ªÏcÞmR ¦2DÙ)ËéF‹]N>ýVÂóUýxÆj<· ­*Á;LXF¸m"ª @§ •ÿ’dN•Ìë_RN¹ hÞ ޳v®d}Q+IMÜBæ-uÎιT3hÒ $©U)W„1Ǭ´BJ–G޹ñc"WÚ‰_²sˆT'ó$D…E¾‹ÙZ9ÔÈø¥&\­­Þ2°Ò\ÑÉLí»ÌnŽÍ'›ƒÉ >wyãÜžÉO)_WÃëIà>YR6=L~¬ˆà´ËˆHÅEºNÊBओΩBT'XQÇM¼€´0©ï”Kƒ”õáËlH¦üf=œ9†”tÔNÌá"‘­PîŠðHSÉclù—åß™L(„—$%ÏT‚8µ}Çɺæ¿UÖRT&NÊš “‘àul¬³‹uÝDD$ °¬xÔ>ëw˜˜…«u¹p¯Që&VlCñ“@Ï $•+Çò]ºÊ€UÈ®§L>,÷aG‡¥#_ÐXª7Wµ¦zHCD7\NÀò()dÎyOjjšMÇ¿(h¹"àåÁÌ©º6[M">|+Až²èrºòVj‘lVT Þè >ÑlXÒÔrU ¹Äš"(¥2}Ý¥Û=‰«— qî©p«Û™»IÄOXZ¶vµ´PÁ–5jGLÔçÉ'¯]2kN§Ê„M»@_3¬)óû«ñ51°’œW¾)߉[^tKôå %«ƒe5é‹´Ûª¸Sâ¡‚ÏHÈ)r&£G†úu¢Ú¯ÓN3›†b…«dņ|·ää™BE™®`S%…s“ë‹qq»×r V¶4­ø/GW7ɤŒYWŠÊ•ìå"ìx#¦pC nõ;Í(j[6¢IaCú•nj䪅ÈýÝ&B d°vJϺJPvPE94J)>ÚŠˆßQáû<±ÖiàÃÃ%¿}§ÑpCò…”ZtøÈ…<ºµÏÈäéUŸžšìrÚB#jœX®âk“àˆ¢ÙLšì<_šƒÙrð Õ'¸.!ZÁ‹ö¨2]l0µ}ë2´F 9Õ“,´f.ûZ#£Úú=°ç£gnJ£/_ùÐ+Õ¨H+¬›‘êêÏ+ºh”CMvÛt Jq˜ Y@U@c-êQ¥ Åë«%â߈÷´Ü÷Œ*QÜ~FCñ÷Ë¿ýãKR•¢Í¡ŸP¡úÊóÞëg|G“|]á3ýŽx”¢ï5ñTÍk#'÷ Ú]nOð-ö3á÷r¾ì+øäá?ê»ï}ÿooaß©‘¾÷y–ŠÔf_':‰ŸoŸu)ó;ÿ¸«0žÏëÛ§Íî¤âöA~Jt苹fýoVô6Jxmnô[Û»ï0= O4Ë»?™âäv²Uzðák±Íýgä½’ÜÝîìËsæWM6?{Ö“ËBó{æúNºìÓ†ø ~øT•²;‘ÁWÚ}?l–ÍòEÙ¹Îéà§»mWg7ûqž³ÏÉ™€±Z¶¢„X°]±pN^Ðs°øSqºíhšþ›Ý,þ;ÊЇ½Ú±Üϧ(¤¼¨ä+ÔçÔxµDP,Ñ(ÏñZV$-ñ󅞌¹lkô7¤Sþ—µüzÖMˆî;±.P¶ÇþÙõ—ÊzmîÁÐÅ“±Ýà‹ïÈÛ‘Ž:Ç ý¬ïûËomGšaÏÜŠÝŒE£²`¬_xK†ÄâU°Ùæ Ý9Çjî?ÈG¯ŽvúÑüÛæóû±r7xµÏb^ßϲh–w ´ìºþ3°MñÝ3­^·ÏŒÐ|!œþEn ÅfÃÇt³Ôè(Cÿn¾¡_¶Jž1 ½2Û±†¶'^ôýØv –y“¿ïµˆÅ£¯a5c÷FØ µÄÕÖ?'õÃk=›5éjŽVDüÝÜÆZ$¡ýí×¾!¹«E!kôõûÕF…öë'îJmm*.ƒžðާ¹Ô3AÇìLJkéš…ÌôZð&û¦‘…ÔÅ–Ï/œ+l妠îÒeŸû¢H¥{H—dHÂàŠb!¼Xh0‚ F8íùÄ.[ÆZPNu%!–‡Ì_Îë®È5Æ Èt9Ç"ÄíÛL®H5~# öA¨YïË¢ØÄ½s1góÁÆ…­äñ3zÙBl7òÉIDlª"„O´¸:×ÕÖÄf£(Åy-FW v K,âQ À*¶‘¦ê§b1€*ƒœÞyü%ñI5yp¬°Ü¸¼¥‰„è¬íèb0]¿6×0œgQ|÷“â_UтĖªaÑ—e!“wŠŽ¾6p ¥Ý~ ¯ål5;ühl…ËíÂÈ d-·HYaE°#›$£aðÁWÚmæ{¿ˆ“ó`Ó¿Hf1¡sE0ìÚ§„)H*3¦VÙûïª À®¬rõœêO.YËJ99ÕüÔ9ÿ}¾H²S€ÒJá)"5—j•(aýh©ô%,ù˜š›RÅYèXM´TnKp‚LVÖÉ‘ ¯gaˆ"Ä?ghÇ]ò¤I›?.¢1e{ˆà”D*ì²…ö˜¿1pæI§Úóç3\fÞ "S”t¤ÈÀ š_ß륈,è܇—kxÒ^ø"=^B ´ W'á÷¢½ÅB± H‘ºËrƒ3Uë¤0c’­™º{e‚,'Å}‡ª%A¤>•¤Z&Â~ؤp–e޹–˜[f° ¸åTµIâŽdV)×)¢2Õ±ò-©—€lLREƒdÜy1?Š`˜$oæÌ,£”A„È,Óð ’Ÿ‚匓FLžÆ¥Hò&ýÊ\JArp£‡éjê²Ø%m(“1ç˜í462œO¯1AcL²THc¨S]ÎÖ×RSQoNL+Yõ‰y%ÉêeIÏÌ*RF —ç÷&Gö‹SúåÊm3Oä8DënÁïÀßñR”JqiŠA×@Ù<UžÝ“n(`E›K½§v¥&œžÅaÖßðuIÊoYT×aëà<ᓌr‡&¯‹%XTIvBI=¯‚l9?¹AJ³¸ÏÔÃ9Ö=JÞÌ$©JªËU«ÍCRîUâL]‡SíJªç·!'3cÓäU$9¿‹²'H çë¬X‰ìGÍQ9C‰+IÅËÔ¯zs*²Ñ ";¤.x=/˯ƒTF¯ŸÍ"ÇÊ,9Ô¦0Æ Ëm+‘Fþ޲Šl’Be‚Ȳ“Hþ®{/…>ܰ‹QÃú÷èp:¸ÆŠuÜv·FXŸk+dŸ#o¦f¡ŸñÛo¿¥>tÒÀ¥yÐH¶:é$9;\ª1…‘íô¬pÅ'¶2LDøË)ÇIv(_ÉcôËI`4wV«›3ù”F: —/§ ²™ñϤ÷vUie#ˆ+)™ˆT!â8E)%B‰i¬r*èÆæ¡¨Y4äà‘tù¶ÃY¦‚#9‘²¼¹(U]¤æÄL¬ 3÷©SÅh*À0ѽžóÆ›U$ ^™”aX¢%{²Š´p6@c;»" O•—9#Çf,yJJ&œT‚•ê‚LÇÐÎùN¬"š<À¤S–Îuõ¦Kéd.Œz¾‘üè°»aÒXªË¢OÊQùQ³ ñŸFÿ] =ä?ä¤UÕ‡ÖŒ`%FT 1+ž¤ÜdÏ¿ÎѧW® رHÒ¦œÕ…lžŽñkJ-³O)Æ8HÐÍ¡L) \h¡ÞŸ/-tZ[ɸªö–áFbÔ>Á ;TXFCúæƒQ“AÃl¨üŒXqÃdAI®«‚Žæ¬”Û4 E»¹öE¢ õú!¦–·ÐC‘Ü2~QKrÕ3>•ç1Á'Ïöo@Q&Rò¿Ý6ð^€”átégRµ©=R· t§È¬,×:M{ß[Ns5Á¹Ö™Œ¯9£mRTÔæ|6E.>¤Î=ŸkE5+ª0:²}˜p@Ô uQkÔÍVBV™ûIªUѪ-Åâ¹Ònmõù•âàë»ÁM¸>un„̇Š¡K^+BU¢ÒöÜ.C=kÊ4µ´ª0¢%£Â;\m-#Ф¯”´¡"0²V\ï&GpŸŽGýí·ßr¹¦Ê£Eƒjê‰1ô¯YO?ŠšÃ#¢áâ²ÈCm>feQ¯Å}OÂÙÑúœP±—yXMè5´(ÓØ ì?ø+Äû‡?y«ð ü •©V MóÉ¢“•W=˜Æøvìtï— Å¸èÕÑ:öÉ:tb3*šK<½J•ϳx¨ðÔ䄌%§b÷ùO¸Œ·4k[—T݇ƒ¿WkYËh¬TzÚϽ”i‰Ž+"nómfâc3o«š•WW »\»èhS1,ow©V†QÝ"¶ÏûE^h-bõ;×”B¿,ÈÙM*Ž,'ËÙaµÓåÕnÞµñ–¥–þ½~WÓÔUùI$bwSùawt÷û.üD8£Ö!n í{ºtûSòsú©¡n¸Û¼°ÏùØe–^tLŒ[;•ôúºIÅ¢NÛ‹NUµ2–²^®Ù‰½òÛM›÷Û¬sßZœoQ -äºn…L:5–¬õAïÿ„ªÄ³2c© 󤃅å›;n,ìÑtÈíÊå×ÃÒ¹!=¸ÅiÞÿö'æõÝÏ~òû? ËQ$Z>yÚÅÃŽvÿŽ—ù†ÏTúmû·ß÷¼~Ýû>ÙËÏÚôð/z½»'Öïø=gÁ§€¨æŠùís»ÛÇOõGkµU¶„¾ÿ»Ÿ<Ù~fó+Ÿ­;æÌjiú]»ûÓ/å'Câ~ýâ{ükßÒ¾7ùáYºù–güù×Ykžq÷Cß<¿üqf?Ÿ?óÅß•w|Ax¾ÞüÌ×òøü¨Ë¶·IÁ<ÉË… ˜ˆâ ;¹0‰0óPëÉI`YA(™±(>iT—é^zZ÷ Õpv=!¡i»V‚:VrüØãÏ ‘v©<À i>GÃâ”’ÿªWSa¬B!ì7\Rïtå%¹9`$0{Ó4gäÂJ9fPu!W肉 ˆ µ?rUBCT.‚0¾Òê »°´èûD‡ŸBû½Ó6²©+3¯ôÍõo-)sÿÛ>¡ëQáÂE*q-öÜèíâH7Új.šaÏ(žÒèž:%— èÅ®`Ý^øÄ½: ÿó`ñ`%-äÛªŒôÓ0Ô>ìµhz7Êsˆp€¦}V2O­"£êØõS.ܼ­iðµ’£: 3§äSP4ä€~¢¢Žóþ¹;•9Ë“´¾jö@3´rÂ\µî ¹k"q@¢Ô,öÒ´p,“k¸È¢!•;Vnì¾QæìÈí鯪Kg³œÔGoDS®¾ÈUßY–ggp@×ì2gÊDš­_Œ£ xŽÏõôkovÑ/ùœc«>¸” [hÖÁ89`©Õ¾À›k·i³æH®Ê[u.Y’DW¬6ÉnŽå cðZ U 'n6…s–mÃÆF~´]¿t>Ú›i)ñWØe#­•ÍÂ¥x JHWƒe15 xª«í$bÎ ™DȺœ/Ç&Ì rˆµùƒH•BlÎPõ‹ðBÇG™lDÎrJÑEdÇAö”Ó„‚>k \UÙHˆ: DïDÌB¨»»¼ªAêøNþ&iIyÜ‚BUzxTeÒ& ¢±»„>+²(W«­tÞ@Z’‰’t2QÜnHK ’Lܤ6-V/€Ü¾ ìÍÛãIàm˜8 c v=ù¼<5=o§ì‘Q”†¸p‡pc³HìÂÜØtA4˜³>±ÉÄ.oûpˆ8¸ÊÓàØ€ú×szŠ “n¶0eùߦK1‘–ÓçëÅ1šL÷‹à˜æ¬Î«ÆiÈfÕX ¿xbÀU'GAuçÊM‹ð ´d¡R1‡©£7Î’SVtâ­|üÀàfo“1yh£`„7fÐa“oÔ¦¨Ã _¢ ¦ø—Ìžæ¾—ÕAçYˆÜuG7Ω`ÂlÓcÍâÒ*›Ï¢c½abµ”“ˈ„(šĉÉ_BÓqHµG Œ?IlaæÄT‹ñÉÒ®µÁÅ“l0³l Ã6ucÜ%+;²ûü¼¼8h—¸„©5Éø½D¨O¾i£qÃÒq×Ú™D*¡ åÁ$©NNzÀÌQqbˆ”ž«"Ýó|bQ=™§Ô>`•7"‚f{dwPg…ôU%T$ž¢/Ä„kÎó¹@‚*”¡ïáø +ÿxö*I Zc“¨Ê—Í ºÍç{ÍâÃÊo`±0.$ñ[ý0B yÃjoL$!”´‡œÂ%~ØlѬòAuÜ\'çì .l¤^5ˆB¿ýö7‰b[¨ÄZ18d§©˜é,¬Ì)‰çNÖ*é;œT}á{·.“£•¬±„jGg1ZÂæJz/Éy9ˆpnæwA¨[˜zSè»MÕ$§'NrÕ<±à ¦R‘83‡¬g«O%˜º#Y;G"g4¤úªòV§Ï Õ˜$Xµ(WËtw ÐŸBÜÔA8o#Ûñ›!m3‡É²rŽá&†â“òˆ$­N·173Hï½iuª¯/Í$avŠŽ*šÀ(ðÖÙV5œàs)ù&²\„:¦ÇT|èr5œ²™Oì^ŠÚËMÀs.vÅ%×\‚³¹é(ù"ˆë¥¼‚’M˜ Þ…áà#Ó¨È1HÄaîÚó5Xhƒmuƒžã<ËM‹ýN"VB¸ D8ïbLãÉCJ¸ærlÌ!“j@í;þÞˆë: ïó0Æé “ksNY§„|Û12RÆç HHa7©}Ìó$ ¶A‡‰cVFЛdÐü)3ç½æL¡„éRÏëX=¾OwÇ&2öP0¢-Î,Á-¹0¸¿Œ„š!óSÉ롵GÎB·J¾¿ðý2é°®, “ -|†Ôš„O‘AëbšHL¦mRMÈ&.“*¶ÃuŠ OÂ^Â’õ±pBHŽ_Ž&E@$àF‚ $œQõô En’{í41i/Z/`Ní‘Iÿ>.½/xuc¡Œ”í9¦š¤ZÌçæ¶ý$â;¢u¤TûIýAK  ¤˜ú{Æ L=¾roå¿kq'9MÄFRµ¦À@Žœ[ Ê=äÊÎköèIڜ෿ù›dvEKÈqZO´Åo0Z’š©~Ä-Ù´’·J1ÝÁ(Áš P{ò¿$è¯Ú8káUîH´iIzAfòb×_a´D£ž‚OÈê›ÇÞzRó‚5´W|Z"ÐbZîì¥âÎv“²UWXpÏ» +ÐÌ\VU3t d¯*Såšôô}fëçâê&«[`vƵÙÀ"ö4yÚH¡ªLõ d>—©Eî’ ”²÷}Ö¥ŸÉ®€WгK¦®Š Mý3î#‡jVÃÞ]|¥¸Ô‰m,r•î¿6*=mŒ’s{è.ÇTªyl]Ç»™Póÿï3V„õ¦Ýk±†…ÈIÓÖ®ª³ºÉB¯´àç7cÖTÈ `™'hr$T×P ÊZkE“&g”ü·’hÚÞI߬¹hlJ$Ê©%êÑ®¾ëDqj^äwQ±lª¦ôÊÅvBAö¤mý“ËC¹Õ„«jqi·e«õ¬©4uÓõD¾¡u!×ÃÕ6_§Šd, †Âá½ÊÏ;å§ûÊó7ó»ñG?¦Âm ÈŸrŽ×?}ÿ\=-õ3ºâWIR`7ü?ÿ'ÆÁ‡Zðs:ÜO¾DS¬‡ž¡|+‘맺ð»çá§,êßã©~!©ôëãù&A}òiw‚?ûæ× ÌïýÅ¿tx<ëÏoKä]q—o¾'~&xô¤n¯õÍõü×=[ÿ«Ëåãúãîw¾úŠß!h°Yx¾›ý§îço{¶‡)óžý¼‚lçáÓ&»'ЛÚö³¿²>ß¿átB· bë Q‡õ¿‹F½]Iǯ*ïúzÓSÈ&ÖÿO~{»øhæ_ujMkÔ žFIÍ ˜àÖuÎì«FhøeÅSe|jFTüµáèÁÏþ]ö!Xc4Ät:ÚÜÔvux®Ð·TRe6và,LÛ¬Íít~ûD˜ …ðrPˆ µ…¼&ÒX FŸ[@;Þ µàp‚¨ñZ"]äÁùCŒ{^¹¸WröàmY=Wæ8°&)¢èXÔæ‚Ñëàc"ª‹xeÁ÷bÂÛÉm>ôÿ„Côèßw?EQE>¨ 3×hð ŸWíó?93á„U¦@Cß±1‡Ös;*™ºµN %øßõ]? ÓdCAþ:ê³!³ú!t;ìB‰øÍ,æiRêñoñ›´^¾—×5}|Ù¨ èæÖ_Xæºf¡jŒj˺i‚ ˆu½Ò»éljåXæå²2¶QØ4Zâ!¶'ÿZ]Ô.âÆ*cÛÞn¯¢WÍ.³³!™c1œ¯æBGÚ‰Œ|ØŒ­›JÛ¹Ð:é÷ù¹?œ!.d˜ñ­å ‰®MÚ¦·š¤®ûI™ 9e¹vø¢µ,_áy/Ía‡Í~½mïsè3^Lðö‰~á1þ•pæµlŽ"vû&XÈ,„'6uŠ‘À¡W„2°r’ÖR² ¥¢4%-!]¦ƒŒÏÉ.…¸+h’¡ò¾º®á“œÚnnˆà›âRi½&¢*ÚÂfàüÐ$ƒ¤âŸ0Übôt uqßÅ E¨Ûm‘ʨÜ4<“PÛ® BTŽ×6Â&áÙƒ þc§@#ˆ¹Û½5[H&æ¶j"Œ¬U  âùÜ å«ÏËL¢ÀN½Làä$Dê¦0cVnz»')© Sú ^”‚vey,“œ£õÇ”,ÍèUoDèS2Ꮅ° ã’i™m?°-«“ L™‹<.ýÞƒðÍ9GTÌØñ7«‚páHhÄŸéu¤¬+ì¬N *¦fkÞ—˜ ÷H|Ç“oÛrô#Ÿ ‚Õ²‚Ñø/_ ¼¾¤¹°7›„:y‹B›ŒI%VpÛ³ˆš“‰5ÇR~¿N$‡_6¥¹iK?ÒïIev*Ë$"Èõ8¥Èè Õ Þ¬gònŠHÁ.Õ7ðA ¡ÓÀE Ãj1~tÎ_5¥Kð–Mhª`ÆÌS W†ˆßªzé<Á ñHÛ @ë²)åq‡¨õàEE{°†]š,þý¿ÿ÷©ê4Ž8ÊEO÷Ö–…¤A ønË®#º*^44õ4¸×‡dé%5öäîŽÍyC9î›ZŽÏÒ-2Â)ê=ÁîÞïrr»ù™g.™¹€*YmEÞP\ ùÐN–Y½)›ƒVQlê8i.ƒØ½“. µ?WþÚÏX¤Å›•—²ÛoúÆ £¨…œªp,­å}ÓÞØ §·ssçÇK›jJØèœÇ™PšpÃÜúé[—ÙŽÝ’4±KSþa‰»U³ÊêÄrm²ÓG Þ‹ìò¬WÔ—!ëYí¹ü‰ðËzD¸r§¢Œ·*Z»î"B6%ÿmêÑ¥.–êUý1FÁÊe=¼¢j@"En÷ UÞ$Å× p?P~l@:¸ÝCûD¸rä/u•þ;öž«õG"b>lÄOIB?ó]¿ê~â3Ö›õSþÞïèû‹Úû;myí8õ?->jï+íOMÕÎý'Ûå±-òõ{‘ÛñWÓÑGmüëÞ÷Ûçíw$Œ¿ý;Úïk~÷¿zø=òŸö9vóY_{ö_7F?Ÿ»÷\}ÆNH`EÞKŸ¬«­?Ý|þè¾IæIßüúŠç«5ÉïÐW›‰wW¦¾¼°(›0Ûµ¼]:ö¿gùô業‡hv&$ -YÉMSì¹¢³ß‘ ÓoE‹B%•EL§?ŸâúðPòŒèaäqumí¾¿wÞfh ™“uÆ@Qû hˆz¹M(ÌÙ£¹Sr¸Xú þˆê†Þ¦xüÓ»ç¦ØÁíú~#Œ€öuP]ÏÑË¢Zg+á+ÆšÏÏzeÞJ‹ÏHô7štëøÜ9~š—ãÐþ"ÇÎ=¸x´®æƒÇȵÜ'fÍN~Ì µ ¥Ãª“uõïHÇ…ÌK9¢Õǰk·1ݲ] ý4Âx$MÞïܸý«"bá¾{>ÞPÖ‹lºë2ìêŒç‡òØÜ•Ùe£*/Œõ ú…™sëž…À±”>qÚ!<#Õ±ªbæ ýо]T„AÈ Ù([duÉñ>‚­“±&p#bαhGTW4ÜÊæ³Cø®)ÆÇÊvÈõ2eܤ®P(ëpï5Åÿ•ÑÍ\–J±X—k».ÄVZ n[7r‹¡f‚hTK;[Cìœ×C¼oh D·rëW—çF—ôt†Œ;ƒNmÛ¹ED`¡ó€hD¦kX©Ç,§eU9ò‘‚ÔÁþš$LR_„¨8¸‹ë ]ñµºD²K©¨ñ *“‡cãÄ5ŽI’óf²ÃôEê£)ʆ‚„ý°¡ÞàɕƎÙ9Íñ|âˆ1ßÛîd7[Ìç›f‹˜XòTq¡²)U¾H66â Ç•¼¯"(Êu!bVVN‡["ï³§o€U€¦Û¸:-»3'9¨ÒŸ/bWÚâ:7¾.2M-‰mâQɵ”.”S^8ö xâÂØÊ(rÛN!¬«1O‚„Dy &wiŠ€džN-àÖt>ÁøƒÄè$Z!TCIƒ Rš7k›Ìk^q”ns‰`ÏïbdÆ„ÔËi5ÙÜŒ…x¼¥ä~þ SÏ„vð; ù5é°‚ ¨Ä”1G^(¤óáLsbàÇ,!J–LÏ“m¯ $Þ1ÚLdf~… Í=šyÙHå¥Üã=W z,™e#yÆ™“„-RÆÓäKNw^šOôÑÖ ÍÇ·ö«¸‚ùEᵂ\çÿÞ_˜y‰©Õå4>Ô„žä³Åpèö5S¢CÈ%çØn„‘º5}hÛ% ¿0?GU¬¨çòsüÊF#C–s J@U8?i®ŸÉÂp3I¤^RPœó#ˆ³Hü çe[Bܼ´7%Ò.tÿ3Ö·˜SrAäù¤|‚±Ͼà­ÈL ¯ïJW9õcL4gæROÐJ©ùL„F6¶¨Åò•Óì?›öêäÏoˆK6¥žùÕ©« J]cÅ9~ä4¸1¶IHäIò£ÎÊrØ%çI©Ýœ` u7U^Ÿ¸&›×k=;—ZèeÀûóHFV™UäV¯cöªEl󜺙š)+çrÆ9Oña¦”$8Å¿ š§W6Žöÿáßÿ{b¼õÂ5Èu㎊´ òwT]R¿èŽ*»TÂÃ’k1»£v¸ìtüçŽê¨ÿGî¨! îüÝQÅ®4:÷ñΕˆLéÇ‚ñ=î¨v:XÜQeðÝî¨t^µtG…0™DÖ‘óvܹ£ú‚šWe³'ÉHš³ÐŸ[º£†ŽÁÈ"¼ðmî¨BÒw§áÆõN ÿæâ=åùSœò>ªŸ³ŸBŒŸ “OÂÅe4ùNÓŒŸVðãs´¬LásÆæ²Ü\dù]Î5ðñEè>nΖ=S7ì\ $Ü-HÉŒd/Ì)8!#S‰¥ŽlN¯I‡h ·Ìû.›ñÄf¢1 M 7$ý¶°.°Ú²s׫ü,ÎênŽ– ݱÝ¢¦ y<Ø“o®C–„½–o‚“DVŒ˜ÏFsݦõÌ|©ufÐÁ òïÈÝÖý¦©å,ÆÆä•ó¹Mb#ãy—"oÚ›šòÜp“87(M­™²"bx,¦mºäñDÒ×8Y¡.à3÷Wgúæ©â5ÉÂ4Å!>\Øãïæ\„äÜ å)t¿ß¢2HñQk¦Y÷ðåqªj}ÎçÈ}¾—1Âó+çXÑÒlnB¼¶*Ët O•Kš¡MÍ›èù;¡ËJåªFá=¸ë9døÿá?$;WÚòý1Ì‘z.êÚqI,ûÚãÜþî盽;~¦Õ6ïýÉoÞþ^¡³?x×X0÷îܾ)ú˜ëñ̉9ñœTúÅ!³äQ¯~oýmÑÒ*W™–غ`n6mjüÕox©fcÿä… NÙO·¡ï‹æÇSnáfþ€U¹ýäJ@|0Ásq}o®ìqKìí–floYœð,•O¾c“nH‹÷‰nGó]Ý+èÝ6£îP¶ëúÙ:’òã|tã¾þyFŠ¥ÝÈÎ(›ú2™lšŸgõÝ<¼ëžÿxÉ‹|Z 8ŸZJÿlÏõïïâ—ÎÍâ÷sÏyKø^|íj.œêG·# / ‘"«Þ¬>”þ!Í>;ðXOÕ©ÉÆ·¦Žãˆ;I™Ç™r/žðÅzê5u›ì·áèŸYÁømYÃCª¥EÔS„–"Rfý³<µ r"ÌÓeï°ý[s˜Æ¸oi”+®@(Uµrób|0!»uè¦&X9V¶}Öø6`Ñpnë5Y›üÚ6zÇk[§‚E–.0ÀÖ ÷\ÃÓ±€u†oL7ãÑšl£¶3amhˆW¤Ð ¶å# ¾ÙÔyÕu™ªQê«Ýnl?ñ`½hë<ÿš9Þ^Ñga´kìk3úP2ÍÝH]ۗϘUçÀÀ“Á“ïýæavˆ^– ä' ª)TFÅÕU‚ïʾþP®R4DFN ³¼$‘Âç½ðr¨daÁðf-Ól°[÷iBê¾;ñœ _°‡—m'|RI[0Æ’“%ÊG1%nM=ÅÝ'¿l(dx€_ gì!U—n•åä§Ã:Í;ŠÔøÓ0# ›f —‚q:Ú(7Ú6Qû™€ù^Àw°‰º!Ëî¸mbìÞm]ud“|1Í­xkÍÑø»Ðn–ÄÚ(e>²áÛC0©°ÿ^J¬p£øõq*qì£ÅÃ#•Ñ%ðRpzAÞœì°I—ì“ÚûÊAÜü—Ù¨‡)ªKÓJË“¢ æ ¤B`k«9Mi°<Š!YåÌô‡•™Ê,H ¿!÷(|ç‹"=ó„)g…|¸’äm£pÝn& /«—ðÐ<‰¶¨”#`øjÓ˜ºQàL‚Åo.Ð;)h(ONo*[WÅ™fj×lf•‘cÙùý¹™Qduù7%祕9yG¡Çé0Qw»B½³<™Ù“Ö9_ñ÷¤]êr1Üw®J¶O›?œï.s–šÀ&³§ü3¿ÖwÉ"è@@‚aj>¨§äå`täw±‡”õ¬ñ$R9[_É„Äû1ávL~Ïë´3pØúm ÷ˆ4p æâ°ÈC¼^Oˆ þöoÿÃ`J\còt}/ ó¥WÉJš“~×Ò‰Ø Ò^¹ \²™©¹M}˜×¸ §i¼CpÜÉ&-¡²Ë¼è1¸«œY¶â)ØÇ ëý|®<¢á{ŒHXÙTçî }gîƒMlJ áÍÊ÷Ê¿%Õ»d†S¬ ƒL™B’Ê|T³È`³#†=V-y§Âò r—p àÓü+§ÂÄhæ4? ÃâóXi.Y°Ûf€9Jc!Ù†)݃ &ÎyrR̳x'/ØhN‘bìDþêO_·(UÃ0 ÇA:5 T^øŒƒî$‰¸R~¯ ¤àZƒL!ÙÙ™ùABI†§ Éò¬î„ãf_i¦uaн’o³g'.ÆZ`K`h%›V|WŠqàäP¥íªHl"ƒ gŸöØe5¼CLnG˜ÙÛ|ž+Ê¥á¼#|Câe v‰tpa€˜Pc2å¢4ÃxLÓ¸mä¼d3H¯MÒø,1æT3£Š1¥Åp%¤ ­LÚaî%óå‚ çl… Âæ³!Ÿr+Òrf—güS׆л}ŸG¼>çéÈÔ¿Æ[z?¿Ç7óØ’ø)%w±…FVèJ î*tü°ykW/ô;2!¦r¼v²£yÅL¥ð‰xTLJ~ÊzðbïÂæÉ"gÆ{*¹jÏ á”ñŠÒàØõQhýR}UVð¨ÆT“WÊFÄ)JMfnJÏ̲Æ\ 0OGŒž©ÓÓ­NѰûR·‹b ÙXo1Û%Ó71´–AëKîu sÏŘsN"qŽ„‡,6¥ï”þ§¡û·û·¹›bÕØ†kÑTÒñÂJ© +‰àw¹Äfzò5³¤T±Y ˜`´2lÕl]“øÎŒQRRg¸è8‰»ÃÅ«–ÓÁØ~O¬Ío æ²gR¦¼“éÙŸN”½Á•-Â]3Ú®vØXÀ3iœ.H_ÛgÊ\C’éDg« R_ªËt šÉuÅÖ s4 T¥c=«7ôÐßKv¬Qˆæ»ñéÏoë†âa åËÂK|òiËI9^ìø5e£JÌe’Ÿy 7$®=›§—ÃŽYbè #¸™cÞsKó7ù—^ƒm£éð }8pAÌ•<¼!xҿɾ.жDQäéÔ6sxIÌõRÕ‰¹!Br š³´¬ ¦Åµ1¡ë¼ÓÂ7M$Ò"ˆÚŒSc&«ÜíLÍʆÝæ:?c›Nú©R^Ã7yknäaŠG«õ©iY_§E4BïêÑPEÑò£RØÊÚ½o*ý¼Š8ÄÖˆ7iCW´ó|ne´¦ nÀ¸ô´m‰‰ZAèÏò©Ã®jYqTWœL5±~Ì‘XüúÕd‘CßYÏaE$дPÉEh×45éfÅUúÌñГ8×à Ç×{V’ëà …Ëä»Ékߨgüsh°ozѼÅ?fÒ~ðÏß ð”l÷W>žžÿ, %þäÇ}ÇÝ~Küá’ÉS.ççSô[¤:v»…?T+ý aó1Ûþjº¿Õú›ôz¶‡oßÿdO*ˆxRøŸEýƒgùÓ>ßkt(.JGÌyNŸå¿GGLj‰çöi@%º¢ê®/9´öQ%P‡‘ QšÅ+C8ÂXÞ-¸a”“ñIÙ¸'×Eø[ø‹=·2UÝîÂï½í999¯h)é…1Ù°ˆ±!w£ö$7彟奤'³ïnõT`ïXT/üy±\eJg*ÂðéhפV åÁ‚UÆ× ‘Y˜Gwüñn¾ÛºÁï%ãá‰èÅvº®Wl ¶<›Ž”Œfœuùv×ôK‡…RMáâ@ù;ò[¯êÚ²¯/zrþl›—ÖR +ç2ò‰C[Ÿx¿·N»±*CÐðšq;º…@ËÍÌYêD[Ð?£ðÛØÄÜ*á5!bm~Œè…"k©q±«nûò§ŒtuÇ»®Ì†œ”¨ÓÌe «æŒ;v§Â%@ÉJ³Ar^¦÷ˆË_b|ž$šéDâÞsý%àAÖÊî–‘ jr¶ Ò7SiF^¬<1à°«F ÕWã¦Z4p!+©izdTÖ¯³bÓ‚iùèÿ0~.ÚÅpD“® ‰„+(ë{²VB0윹æëTqÆA0&—â2¢ûlJqI¾¶D=º}"û'¿¦ygSü%ã'YuÎ ~ÎJ†ÌZèi× c溒¸Á:în1ý„}Áq= +¹+üE&…x׌ gÔƒtg¤ eÓ=<:ÒLŸ0qÔFQv/‚Nùˆ! òýoS«¼L¤ÈàT­h^c)J“¶˜ ‘—á¹ø\¿pΨêH‰aQ Äb´uÍ»¤œy €t㫈é“Á¦xÓô oC@unc¸Ë<€b*dÙ"+tlð‰ gÊTÓÝ•.½ã•‡Ä;Ù¸, Äl­âÌóIëú¬ˆ8Á¾™æ_!¢ ÕÿŒJW—q|}Š¿AQÝã±”…Š2ss!I©æRt§›´Mß^"½˜“IÈ¿9y-ª¦’; ÷A˜-峦í̳S'½ÆŒµœ°Œ¼;ÌËê¯> &Ù¬Y‹HõLÌð™<Œé’ÊŠ‹s$ð`ó*í>Cþ7Cø&Ìûá~íÍdz bú‡‘1dÆû 9Ñœcr5iÍaN+€$Ü$4‹rrö÷ÈSœ‚ÍŸiØ:7ÕJþžÐ3Ê5•d@%y΃˜ ‚rÎôòÊ!:lvøwûwdBŘ3Æ8ë6€ÈÚpæ–þûUml<ýœ›Õ¨‚R¸‡×$…’ã’d½5d¦S¨£²Æi…Ë„ æTˆq-h®¨Ðû då!Wór•èN…®íÏ<’*eßx9‚hšñ·† ž„¹'A Nð‹Tã-!?§ ÞgN%\qÓ¦¢9@Øãiz5IÚ0îÄÕGã;CL.ÏÓ7Á•ÓŒ‰Íj&UpÇI†|TЦ”  ÆOŠqžð x¼qQf°im–’™^ZgŠê[ói«?ȺlLH„Ï$f'‹…ŒOzï"{Fxç­A^ Y ñ°ù›Eèâê?%I¦¹Þ y:BòPaB40á¹Y‰b‚*[P6‚vª€A'JÀÚÁ´ËhgÓ32íén37ç^„ÎoP2PË.Òj©1鵺Šš¢¹™@MŒDÔúÊdå:qÜvöWQ´ÇéóJ¼æ2 8øšš(›Ô”Y€²ìjÒòD˜†ÏØæWÄŒÀ-$–4¾”ƒdLn¦p:ê(`#;ñbqã8‹—ák1Ð,›,’²š§Y…Z s=Ì<6uÓ$…§®ñL„w´§®³JöÖ·1q3–„ðÕtýqŠ“ž³¸‘†’™á«•7ZÎ4óê\ûŒ¥Õl€­;•¼ïâ4L°&ÖChB†Ä•¾úÙ˜Ø ÍW9¬E®½¦Ò&¯Ár`(媊± Ž ›ää¼W£Ï´\˜Ez<['jþa$§¤pŠÆæÙelþîïþ.×”–ROòì X+ÊôC3)aOÅQîH©ÏɈxø¡Ÿ€k†ø½0†O0ÕŸ 0?éïXzQFì}‘>²¨úReQ™Ú6Y×wžŒ›c}@|i©ui‹¾o¨cMƾ™¿n<ú³C€ÿîùÌÝK`|>ÓãÇä~TØâŸñ&Vþ|^n¬ÖdACûEÍC·c;îúD^ïK/Ðg)>¾{ X|Ô 0×Ì݃b% Ó‰ |Š­òx{aؚǹqæcžÕƒâÇHwÝ ‡^>„>ŒòSiŒÏ—xûäf?ôÀ¯<¸š¸K˜K—\ß?c®‡Ç.Ag9¬Ù/6ñxû`šèLYïq·ë¶0ú4auùÝ —§¥À®4_6-ýàK®© ܽ¿DW‘!†ËE 6Æ ÎN¸+NÁ#ºŠ±\_…¯žb‰Ö^~ç’Ñàá¢`ÇÓ½*ô¡~Ú ÌíßÙñ3¢?!º]Ðûí,žoåZìÌö ÚØéï^Ý÷`/]öÝ¢e†³Qšû>¾x /Ų×®^"7ݼ|™ë÷_òL¯ ã壆 €;8Î*ân<-ອ•ºZ6ôj³U3êõ÷ªM ‚›‰ìý÷œÊ%¯°ðÉ[çÍöy׫.>Ü-æÕÿökÏê3Ó«qgõy„fäÆ ,ûÕ@zSLtÆ” ÷²¥w#Á²ngƒÁmÞh$©a¬fqè–HôyyÍEZOŠ—ç€æ÷^X.B…gµöIêÛz5À=»—Ʋ¤àªØ›µ.Ý€é?ý7} Ï„æYÛu“ó*û.ˆ/év—úbä, •×5Eíø¨¾„î’»1}ù|yu *y “✻ÏØdθá.W#V|6,V I³¸_=¿åal]—Ó Mm GË]ˆ%Mô%Ô áO‘ a6hRÕÄQB*Åœæ¥…Ž‰¥ŸW}†¼8ᘴ RÚ1v´Ùu d²à—3Šê¦p˜#JÚ'|>ãJ…Œ‹q]~¯œ^ø4Yß wÃI*Ša ÃÊ5dg̘D¶VÂUÅÛS"çì§DmÏš˜}G[52ѸßÊ}ÐOuó&½¢lž™Ó‘l yâbòot†js…Ž@ÇH>N-2œ¯bÀd¨Sª_¡Vm`ã$×ܰáj.È/ÀÌí˜úðc,e!¹>J!ïY1 ‚t‹:€$ˆ¡:샷Úo݆W ˜Ê&*>0ꆚ 5»s„’Ú»ÕM@Íý¶[uP,Á(uÐwÂ0ömŽ“»lÖ0âNe-_ùDŒqÖæÂëGÖ;J3I gàbÆé¬il¯ì|6á³KpøÉ~Ìmt²‚s)q{öd‚ç!B‡þùÄ9óøbì9P•ôǘ„g¬ÈTì<ÈË£¢šiAï#èvY¥t’³ÔL³˜Ñù;ñf©&W…³¡sËý˜ÆèÎ"ÔOäVEyå‚]€8WÉx&óÓ }yéÃ$³» "MÔ4·fƒ"°]˜œÁÌ žò6 &z¼WÈQPNs¾VõB?‡mщ¸>ÌqŽ Í&/#EÙhðLü$—¼ ÎP>²Ù£bÒâž¼ aþ”ðô²E[üø «5ˆ·1(ÉûÀê’s‘Ö)ÿ¦{1ƒ×%ó;¹Ye:Ê$YwÂoRçñ)aRk «5Ôl1íä<Ý()÷À¸¦¡b*^kט³LË1L¼Ê^ÂàùÂVt_/mÅŸKŠÚ\…/¥:7îå\%JÍ6øl©"I›0§$à¾ÝåÖ'™»ç¼/y^pÐ9=\™† “Ï2L¹1ùrÂ¥hpF•º5x.R7ç•ØZË›NJ,=ÖZÈáWÞR2ÖˆÌêmT…öW™‹ÏD5{ºÿÍXŽs'çÞ ScÏ|AÛŽ³ïVXn{ªšsßB¹°¿t¾ˆóÌ[²ÄŠ_Øü];Vž(n»=…ì'Õ B ÀÅùè\ü¯iåj_¹0ÅââcIñZ ®§a7ïÌá²ôKÞu2~!C6¦Ð~ƒ™Öµ$ ô„4M Ù6÷¾^)®î¥½‰ø¿ÆTW•þÍ]ÜMþR`]ÑÑ,•ºÎÿ_Ý·³:8Ã9 Í’îD½ÊߢÕRóÚjÄÝ,ZL~L#Xð¢šqÙ©.Æ5Þ†‚¸=lC@´ó#cMõÊÕÜÒçêj–ÆÔÅ$µ[¿³Ìý5¹HÈlÖþZ–†ÕEñ ¦X÷u4¢-Ñ S¬ÚgYSô•koü„ßý'ªõÿþïÿ>QHÏz¸Uär·h¾·œ-ò£§FW_ïåKÿìçѤoüž¯4;ÿÕÍ÷µw÷ |ÿÙ·ŸñyC|úë{›ßdÐýC­ä+Ý]FT〻ÿÍÍ·>¢\ Æó ÇúÝÇû³}u4|ö\Ï^ºM_ ¿î¥:?ø¯'¥®?[¹ýŒ,;ûßø©~¸}®Å‡Þýõ¢±oß„rÖg¯³Ï_ñÑ<{¸€¬Æpû(Oó1nm›¯>n™\~eøpÿÊÚo§û¶X¾çsòÓàÕ0íû?]“?]Äפë}´<ÆÛ§Vtyû|ŸÖׯ޽©`…h>`?`nT ¦]#3&Nð~- 6°ž*„`,yáÑÊŸ7¾sFcÖ‚ž'EèÉllœî ¼bCÈò ÑzÞ™–z0Ÿ&œe°'f ß…™“Z9QÌ ÓñH±¦ÉÑ·‘Wûö?‚¬¾<Ñä›Sý>Šß_ég®…"ÌôÝ…0¾2ThN$Xq[õúsi.ÑØ‡)…)WCÞí·@û0R%œ»Eún¸>«5™ ³íiU W;(,,èåÒ3PÇ„çýêÙ¥¯=éxI¶ ª-ƒÊ W ™»@ëhÆÖR•°ª‚}¢ð «àC'À°V’ÛÏ:P+ªm‘ ¨nˆ(Ü®¥ˆJ®«UÙ¢E…ú¡ëÏBŠÈ¦ÌÀ² º¸T­‰(ö—&²ÝC]§G±û1æPŒ²ÿn2h“ÉøF¾Z²ïž¸“ \¸¶IJÝ l–ß„v@ÚÆI[¦Ä,Eo¸¹Ãí |9æaˆ‚˜Þ…^ÇÑ.ßõì§xaá`⥶z\;‡’ðLü E^›vu1hòRàRó9…Ê?›Ô…—ÏE‹Á#l_t÷ÙÛ£š#†¶|9PÓ4Ó÷'¬?Ñ„M´W×éØõkø2Ÿ‡x …"XZ¦¶g²&·%2fyÖÑóŸÙ@0“0´Ù`H“81sáL"Æ%a(å¬"³½ H2bÄà”é¼Ó¿ç4àú‘s0sÆ8ÎN¥‚5Ѓ™© ƒ:ø8¦L8û'íºÚð ·=9 ƒ§… Þ’tÝ´@¸890çirôÐ>'¾YRŸ£¼è®—U›ôN úLòâBu@L’ñ·A~4ó4ìò ¹Ú7­àJö8 “Mæ80.#^à¨ãyÒ8] O…™cø³ Þ&Êí\“N~6Ý-fTæb²7½•è€Ñ}:‚S3Ä\TonÓÕ¾“êƒ!c€ò'séH‹ÿò|‘”LoÿZø™Ú582ðÍ—ˆ7Gš roE]G/³àd±räÞmí¥ö]/#˜ðêÛ»Éîáµ[¼‘¨}æšD<9æ~&µPþÏô¢ŠéÓåQ@v“3M(“ÓÁütÒqû½ŽFnì&YjE E(€ZxøqeY߸ßÅü”9T“MŽÎü·I•sŽÊENÏpxLþÀO úÊ,9&®_|w&¤2¤z)±wWÈújþ(1y&ÜÎì-óoÉ„¬— E<›9FŒ#ÅÿÁešn·UÉ)àœ0eù“Ú`rê¶gæ&šù,–Dœõ(J#‚Ó! a¡]übeÊ1ïçåõhÖ#!Ü´YO`x£"ðÿð÷9ˆOètâ­«RO]Ú]¦Ò­ð¸ *ÓÍ¡R‹ß´»ÅÅ7À¿5T3Ç@ʲËÞèŠðeŠq¡?mç·„¨78÷õ;Ï1"É‚q„]mízâ-¾”ùÄ$/ é;"nŒƒÝ”ÊÌî`ºêÙ˜u#£Ñx¿µ8á'Èé®>ˆ]aÕ|ƒÕc¬ð¬¤Ã™ðSUœšsa™7 íKéãæMÛÛø„slC*· Ñøšˆ‘hJξ~.÷è[™…:GÕíK·º«Xþj&…t¬Ï­ºddc}Aª¼Š\_±ìý®ü#S|¹Tl¦)zí<`6Ì1É[Eì…ÖØ8òµËë/Þìúáòòj¢)Ô²Ü?*‡—_°êü©T<ºÔ¼R†ÉLÓÌ»ýgD ÅÞMÓë/ÈÂ?¬ìБÛÿjžø‡øS6þ âOŇùÓ~ûwášÿzzê/°þ„ ú—Ù—¿è­þèõKŸï×¾üÉ)=íõˆF§Áÿ²lÏ1þ³iØ?Èc¾ªË¼þÖ–Uúg8H|©n~gœ*™ÿXñN°Ïim$šüfÅ!:F_µçñ°_OÙA>Ó`î© á|o÷Tè`†½ÉŽ­×tzסÒxyù d-bĆÞlÊ=%ªÏ‚fGÑYdõ í8âèL+;,|gÂÙŒÄw*íáßM­Q=—°xMì§éÒ¤nG° Å/[?¦wÆ5´Ÿ9Ñ<¢m~â’Õ¤Íç­Çà ×Ýä,þïÖFþ( ÷­ÕZ0Ão(‹ŸLqîZ­ã½(Ds:Ú^{{`;¢–\ èËÇ™‚xI¸—œ°¶ GݶãŠÛ„¦m¶I\~WÇÛ‚+ÉcdðN ö7M>F·b±fËFÅ{7øþ/oËþÖG e±5îîóW÷jK¾Ër½ß°4}îžPXÔ2mµ}iMô¢ã¢¡à¦.kú´æ¤ù×”áé_åàt…Ü.loØŒUNŽ’4 wÓ,*Ÿ„GW7fÝË©òQ+¼}£²þ.z¾¦7:Z?¹Ú/èj‹ÂOÂvð]}¼˜oÓç”yµÎm õþó+ˆáL­¼HÖdB†a“|’-$ þ…ã4ïwDeìóð¤’jR°±T€¼µ³ÁI6 ¢Céóë»Y5OyBVôà+1Z Æ&7@PÞÉõŽ)žóÍIWÄë'ã0+e¾/©Ñczt þ ž%ÕäoBÍÁ{‘6æÕÚQJºî¤œj$5à|uJÒGÆ0û&ðà5\¼” Á“ª ¢id6`~‡¬‹Šé°ÃºÿˆŠ½ÆÄÕrÿW“¾‰+Ÿy€¿§«÷§Æv 9/§/Z„\껉\:±:û«bƒ”â Ž fŸ]Éþ ãàj‚dŒˆ qÚL§™G ܰmO‚źôƒçÀþ—)!j1ñH[´Å’»‡º‰F£WQ[”hlØÅ˜êÊ«WþÓ™]YM&²³«²ìÒ!f D¸¾àâß1ç3ªÀ|8d5§²9]ã#Ð=|›\d’`™#s+híAsHàdI¨¡  õØÔoÎmæ¾s”B£¦Icz¯±I+ E!®\1 AiPSF~ *Í´2Mœ…¼3 ´)5Öy8•Åœ\ˆ_k&õ ½!äâ,)ß'h¹'o?ðƒÎµŽè>ÆcÇ$çx ¨ïPo‹úÿv‡ù^K„„ðžÒVt‚=Îô`"Öà Ð|}qùÿ'4!JF°Ã!ÀøÙI@ ÊcéIóm™-<†â5 b®ƒÑ6”G/¿°O†™~Ъ45Áámç¡þWS|âònºÚuz¤øæ]ƒP‰1''_Pî‘ðs@Ï¢ˆ–*–s®O€úØ7îç{N^ÕšïÉý'ëI|Ê÷œB:Oùžøÿñ?þeB¦#Æ1uæÇؿϜNüyŒ„ßõc¾eþJCßohÿ%Ì–åíÿÌZåOó,?÷­VeþίðçAmø½M$>ðø]h¿îýÿÒfïŸCŽþK«º^㺤ÁϵøärZ€õŽ µÑå/x`þô…ÿ‡ø^0&4ÑC|›GP oƒG÷t- Ôpn+Ì­â·…ˆÃt›Ý{"Ôæ0)­ 6Öß*d`á!á­€¥ÝcÖvZ:©,úaüÊÝr¬h+½OL´#°ç-:É?½7‘éùNå_×Xß‚ï/<ŸŽ¿¥pDíØ->½€}9aÊXuþâ|.¦b_í\-r ‹Á[:—ž ¹]cÑ‘lÆA€`ÆY¿ùŒæóÚÁÁXý¢ßÖ¿ý¼á¿Cñ˜@Ë—¹rD¶HmTÞKTkDƒÕo¼¶\`3:.„Afc‘›¢Žæ-[.Úl´™#6^²Ãy·¯©k†ªfÍãJoã ŽˆåMòîýµMI¦¼á‰9æMnÔ¹Šã¾–*¬KŠC³¸_±ÈW¤YOŒs4ÖÉ~moó‹BRÑÅ¢øx-i<‡yíGìÒAéå.?Øš­4‚…§’¬ ˆe"EçwÔ¯~ίÕZjU¡qÁ•ßKpuÍßÑó”mð€ù/ ‡¶Ìh…½LXS+ušêÉz XTkÿ§–mE‚M­°I4¯‚aZìïŽ ,ŸÜžž7Œ,7t¼A×ãz™ˆ.4êáo§I ’]1p·1nô’DåAØí÷ïÀ0Ï\è¼ù$éƒ&£4 œ N(ðÄ 3¾}BÕrrõ¦ 2“b!Øl¥Ù¢Á‡z¶ÿ†yz™äÅù >KÓ"ݬ\ºâyá1oB7:œPa˜O5 #¶Px`¦NIÜ£{LŽB·(2FyŽºù •SÓÊùýÀW­€BB4ö¦n6#´o‚pûCÜfö¸˜m“Mñ 3ÃÄe&ÁM¾P0ÖÓ7ÀIUPî€ÃdM\ÝÅfw:c<²`\\†Ï±™%’öüIflcL°[ÜW"˜®SŠÿL!d!S ‚`ªøÿ!™ùï_™”¬çfSzWåæTèžÚ¹ 6¢L%9^&tl06®ß >—±$EŽqŸš—'Ü·šMòÚœ{$üƒë‘s®`ætN8ÉŸ=Òòá‡Mû¢>-”Œ·K9 %Ð|˜„ÇþeJQ8Nõ@)Áë– 5`®Áž!òþTÄ^9s¸I±é‘Ãbh r/‡ËoÌÁBsŽ¯Ê¦o ûR·‰Ö÷„à%펙+ÂçsÓ;+†÷’ïzRVâɉ^+™›Eyc®û˜9%±<ŒJ&§ Y€l‘ÓáªÄ[b~ñòÒ%_e¿9ßóâ;ðº |‡ùnÓ&C¹[Ü¥YE0¨àO@ò’òîåÿƒnÃYwq´€B¾7É¿$=}{&ßtÌ‹‹§Eœœd AÄ+×h¦ gèš æÓð˜—zÇs3í‘»ìPHQŸÜ¶ ï¬Rªròœh1N,ãåýß­‰üã?þÇlEµã*ìØXh6Ž`@FëPìšãM¡8ÍŽ§ÁxÌY|5hÐ$|{jÑP~´Që®7TÐ_Fd¶¡P¬ž–¼§š­ˆ<ê™QWyÆ$3a¯Q±ƒŽaöS›‰µLMuɸ¿”I[p™Áx}31l8E«fذD vzáÖ-à:Ox ›îh©9òàĈ ÍÈr2“;­qû|i2Â4³Õ§Ùdj²·>îôëWÜœ öI'­Cµ.16ÅÔlbfu}HÇ$DÀü(õã$3Éõ¬”"2åù“ô¼Xiþ¯°îÆû åm%ãc‹Y«Èµ—£„(ýÕ]Oã …®‡…ó&<ýnÎwˆkЃvT­<åç_õ4û0†š¾'ÌP+¢x‰¸ÙÖª-V!µ­ºª<"ÁvË!›ENïæ¿`52iìOsSÒ6Ñ…cÓ{&e{®o }óWØ®¨d’ßÈŒÆe(•-_k€õN†Šií+ž6:çk¶ì°ú(ÜÈË gpiÅ@í°ðz‘ƒ2îž¡ùòßÕPùµòÆ[Û¨TA MÈvcšÅÄúzî´M|fVÓÓ¦˜kŽÚ•kÒ°)fÅR82u±xfÅÞ"¶6Dç¾)'W-©.Š7Há]¡ÎkæÄ5ᆠ:­Þf“Ö–KdÏ·šÏüÇüµhÃCø3ïëÀ_1þXÃ믉ú5,ÿfÁRgXŸñsâtì÷5Å_WÛü©Þö%»º*§/ÿ þ­Æoƒ§ÜY¦}Ñ×⣛oÂö#ºÕôÛ°p 5: 7}7¢6½õîM¢ã“À°³7~úU#¿ÓöGTT…ÎøÇcýÝŽI7¬cÚm#Ê8êðúþç¶‘j\=åFu\>«6ÀjgŨn‡>CýèÅÛK£›êEÐ`ŽQõÏq7ac9j¢áeáÚìXµ°’êw×·e‚'êkß‹œ‚%¸¶JïCÇú÷ÁÂ{Ã[ «mGç—Ä’Å]_Á:hŸÄÝÔ[àÁ²„ØÛ3¬<)–ÿé0ƒfíÁ͵yÐùqÀÝ,XØñµÐÎÕ6{ïæ” ×(A .ª"!Jã#"n9j ZGÏk@ãŸÕBè°ÉiÑrëêdèsdëˆTêóYè<~6·Î°5£rþV> ¹›pÀž'SÞǾ `É銵GôúqÄŠ‘*ùµöv־Ě¯‡õÀß|÷fõÅj=Z~ý±YG R·Ï!ÄvµBç­ùì6S;¿§}—f}³~€ÍÕÞ[è®0Œž§eÈ#9«ÂmnÜöxã{óX~-àÉñï7/É._Š™“æ…ÐÔØ&y±¼®ò'dhø<€d7dj^W $«‘R½ƒN×>cP0e^Oä‚Ê"Oš:ÉI7Y¤vYbô}E•oŒàu•ˆùäßðFö½!Sú­ÂCF'¾¯Ý*ÂA=æUt•./9•߯~s¡¶qÝ–,‡L×—†'¿®Pùú ¢ó7±åF5ŠöãsRðŒ9 N¬i}µý5v‚¯á“ûÿ£_ éÖ˜m?°)ùµL×ö)N®¤èÌ'5?ÚR¤©ûr‚ÅE*ó¢Yú.I^O®r/Nû,°+i¨¹nä»ñ“HžYÖ¦9æ“ÛrßS²ïÇ«@ü†ÌpTÑ_\`@,Þä£4~ÊœËà!R­öU¦ƒùS=@êœ^3לÏP¸ HÇS¤‡ÇxJºÎžs²õÂ`ÿîaê4½gä  R¼-è,Aðx=“*­:ófÌþäôè\€´ÁÕf$éÌœ¬ ŠîåÁcª¶Oë'¸ `p'à žš×ô_rr¹C>QÐvk!‚hó*™ó˜†ÛKñGªø÷ƒ$ìø%•=¥è i•!pÝØbJN:BXˆÊáÊÔuiŒOˆ·ÏÀÜ/æ£(Ð7ÛÌd¿v1\{ÌLÝ&dšY› ¡ËºLò«¯ ʯBÈ×BIR¥#^ù:¡[(ü3Be¦gS*¬5³òvd.МËËËIæ DòYAÞ”P™ ¯%Ð¥ÃP¯uËå[mí­7Ãêàÿœ‹ÿ¬–=”¯êÆýpA}£Q5°¶Ì^,ç’³ï-r>£´Í¥á–Äûáá­#¨ÆœeÉ Çœ„huãuñ5ì•Ú —‚1ä²”ç¶Jþ_<ª4Ø1þñŸþ)a:Š…NFÕT^F7øh^¦Ž¶€l(Tt ¥ð-ŸŽñ¨þmHì„ ZÍeÅâv:Üùàœ±Õ3—×`lìâqÍk%Т £ï‡P&†`RçFnLjD+$PF°)žºt2çBKD÷?ñZ¢º®l;;s{Z¶í«ä¿áÒ0æSð­=z~éCo¦=›)Å+§b5W`Ö^kž‰õz „JƒYM¶¥—F6“*K?òzÞáJ×s:«ïÈ(²T<Ÿ=˜LÉEQ#”Oµ «`ò{ο×G¡ëûu*ÊÛÔ·Òô§º¹Zþ”O6®CíÚÁ–¹ÿ!•&ûÏ/œcÔø„q´’61³¶_sûryâ»à8…¢m~ÃkgÛÜTÇÖj\¸ÿ{µ€òç’ïõü1Ÿ$^SŠß¯ÇkÏŸà÷‰ßÉó§a€~âùc‹†pÑn=VöÀógÖ šÿЮ¹ádÔ$6æ©çÔ*Ÿxþ¬²ç–mZ½Õ"~Êó§ÎûåC/óf­k¢áL5ÉìcÓˆN/òÚ±ÎñcÞ^"ÿôOÿôÂù?¡Ùÿ»ƒÐô4à[1t¿ê]þ„°ÄŸS<øó›ÐÚý×±Ñß'üŽ~ÙÆWæ.SŽï¸bÕŸüÙôrŠþ…/¹+ù•ä±f€|cê{ô½?Õ ¿8ï}ËÇ?ýíÏ}åI¿óÓ/õÐjéõó“ð{ÑoGŸ ú§uÓWÛò+uÙw¯.€âåO1ž Þoìv¹léÆâÏöц#óì[úŸzÁðŽ ,cô¶ë#¥j?ïa¢U®ëÝïùNŒ$)±ÀN:br3tØJ~>v+€º7;¾:Œ”kc˜þvAX¦{—Ì_,:û0†ËB½`m.—Ô÷Eìô^ËpŸƒPÏŠ º]ûžð¸M}ÓŽ¾´ðµé°ä0O“½#ÌïΩ¡Ž¨hÞ½g§T!õ5÷)ÊxdyÈ•2x4m C݆¤Ü¬]s$îSÛÌ$çgù¦=EqnC×/$'©xbÒ¤ùURT‹^äZ¿k¿º}©#KþšŽ ÷bÑç Ê3*:ä3¢"wé}X¾—›MB.<9[Š— ƒÏ²Ìz1Ñ‘ i1®!ÙaÖ;ÿŸˆåÍ&ÄÏbñ³X-^*|H çÉÄé9Ò4Ûà¾O,{ ñÃér\ Yãf.Dï×R<.)°[ŽíêÞDrv¾W =O¶´§^åËêyƒÊšñÞqv˜ÓFk1šuÖÖ†\p¡tD@ë£!“ËÜ4X•ªV _4€n–ZNžsWNX&½Ý¾_ˆ\¸×%= Áâ9>GÍøž7žwXzÞU? ©e>¦¦5r´¼6ÁrRÓXÕóÎêš4ç¤|âk›û#‰×A ±fš²¼°õ°úC­<ïHRžææorŸ&×zÁŽÔ• †qÝÂq€àƒ<±a1qmYЄ¦û]‹L&$ËÈXO¹ MÆßÆÖKÓ¬‹¡Q×ï½?Œ9—Ä”‚Üþó Á¬ˆN¤hðg­]î’˜òorÛ—Û+RxCË{âåªúâe„bχÏI¤Ýú)sœ_'c€!›©«“¹Œ§I:pãÙüïh’xÌÀÃRÛ£½rŸœ¥´ëm7«X5˓ɟ¨rªa™ò¬Z@Í wÂß&½ ɼjÚµ·HÉZB–ñ·( §zýÎÐgÏÉ5cF²ñ–Ô{ƒÞ”<áI˜”a¼*–Ü0Îâsa‚÷œ[„§ÊøOLŽÇð~ ‘2®.á8?kà¬ÉÜñ‚pß¹ÔO&ué’ÅÂÛà¬{]×_yå➉tjjBÎ~C¸ÏDžº ~\~Aäòò 1¡TNŒ`È`‘—´CJÈÚGmeÎaÅß [Ã!¼ªù“;¡.†¸ò:(Ømˆ|ûœK4ï‹«Aõ”-'&>Þ<á± žÉÌCÁ°ùwîÍÁ;S<‘Mµ·uCJ(èzÃ6+@ù+üŽy@ˆ}pã¦ÔvÇS+â/ Ǥ¾ŸÍÏr³“߯2¦—|ý\oùeR¼ s&…訞$? kÎ(;Ã:¥~ mŸÐµßå¯Ãj—‹ã5ýeÈfp{@<ÊB# ˜å¬/§‡Ê»F±qİo†q'娒s©†I~¿wrüÒù,s$oö ã“Þ’l@¶ÑJ±3LšÙÀR©À…Éâ^/—g ˆkËý;`QÙÌYú¾P‹†ÙÆ“óv­›";î5úõ<ÿôÏÿl4Y';¡p æÀg,ñåØÿ]Š–¼tFÃQHÄÎaÃH”Iɨ©Ü†En7úÓãDß0{{k)*°­ÒH/¾½iÚûZ¶Åú÷ï\î¿Y6y¼£¶E$Bh‚Áçñ¶Ã;—s~8µAá61 º;K)Úù|¤Ü2^âÂã'Ú+ÜOþA† 2¤D—¨"a£ÓÞ7-¿ ¡ÓØ£´¯SðÙí t.LÓ§‹ÁßÒžäëvèßk"w¹æµøXã©yã©På5LÂ_—ÁC6_‡®Ïÿ«.~#FàíÆk{ËÐRyˆ”è½~¢r%V}ÙæÔ²M¸ø†/¾FF—ß«¯Ä2s¡JÞ+á£Þðúe ´ÙóMö«…×A‰Õ éÜMjãPˆÏEíéc_¸CÄKYs"Ýe†Æ4ÃdàõˆÕ&»']&µØ¶ ]eíxƒnþbQ¥tŸ—Dùç¿[‚T—X¹s·8¾Ú&í“\³ÿµ=˜›¡—b»~hxK¸Ãbܨ<ú‚B ÊÑÃNk~¦}µz8·¸ü¿ã(ðÊícÁþÍÆðÏ`öëhž§p™_‹O¿y1×>¢<Ç>u¥‡>e©ÅíÏ“ªI|w»°nô¯þæ³oÖÓ÷e;Ý4BÿÝØ¬F¹XTâÙ|â&BÃÝXï¡Î9µHÌ.!Øèòã_æàÉh£ý¤»ù<¾ZÛå Û™}áïÿÙZÛ¯¥÷T¬ÚY  gÓt3ö¾6ék_•önæâÝÌY¯R} ža¬ôñÑïûnÜ8±ºU>yZEHx»u¿sW²Ô‘–óÙôÞ½÷Ï^»áÎ{æbæÚ“{Ï<$ƒ–y»¯VáÝç¾À…;R6Hrµ†žåÂ`ç¼>œít¥è<½½ã /ì£à¹C1¶Í©²l:ÇCö=Ä8~ Lñª€âÎÙðã×?_XawÅDôúÙ(;y× =Y‡q …a™Wíþ²;Ïì)??·»èláèÙO‰Úž…sâfHáÓðsöÞ 9¥-ù͘€^;Þÿ·hì_ÐAçÁù!©Cžðo„l,®‘Š,½’K‡¿ ž'ãyPø³t”àƒÞ`(®´J+×Åç¦ù„ð;ñõnUI®çŸ Q¬‘rËHí! ÜJ®·¡Õ’¯ïÝßµ*ü;0NIsúä]½I«š÷h’ù5<2Ø_â'KO–”s4Ç„cHhCûÔ {Éó®ç•eᕌ€‡††â.ñ4ôZU7gŽªÐŒÜ44}4ÿS³ ºgw² DQÿ±px`—'Çzë|Ÿ™»Ê³N ¶J_ÐÚåÈæXÊti0ýì)S8M(k6ÈOF#èÎwÕe´X¢i{Rãb8ÈàB¡å2®<ÆJ—µoW„/Ø\÷^©«5SeÁÑ𥀠Må¤ÓqZáu óÖ¨sHÐUÓu¼] ¾7rá=3dëSƆγ0¿¥+§¿D9k:¾ÍÉÆ#™ƒŒz¦™€Í7]».ùí4Ã2-{1 ]WŽ|RaƒÍ×9ñ™ˆ²>‰_™7¤FikuÒƒ–ܨ̀gô¼Q”?²*ölO—=„~úoå§“ÝdnƒàìÈ+#4O&™]xñk§£2Š1’Ǹše}ñkÐ&ûRÄ»°ÇôPðK8ÒžøáÔ„H˜M' 1.. 'øüüCÑ(ðƒëw`ZçŠg›žãZyȺ¹F7T–K‡œòt>$©Æ¸í$Üþ¸_týï«PÖ?v—+KÆUÎE7Gž»æ,çŒ\ '–J%ì{¤_­«$ëh;í‚Ç÷+Ìw0/O¥Ìƒˆê3æI2Þvü—Žgœ'ÆêÈ€?Æt’dO 'žœuÀa2²¼¬^ã/2&Åm²sêü ߊ í§ëw3B¥ vÆ‹Ks4-¡1ŒõLÙ(¥ÍÙwózœ žñþ,M=0õ iH"¤©?ù–ðÓBÏ­÷AA »–N¤¼á’ôÑAWxã—)ùŠ5ô3Rnèf¨$b–æ\ÕÁ ’ùƒÞ‡Q ʺQ³ÜÚÀf.6Qz9ƒ™…N!67òåéíˆé…Td8àƒç€—ίCÄ1ßå@ѺFÐŒáÅ•(â›A’ïPçäv{xˆÛW‰[°þ×ZÍ>€þÞ(° €ò&®ñaä "›Í:„ëáV¾hÌõ½ðÈô.YF–à(ãÇ.®Œ )·‘çÊõ“{ñ9rОÈ$Õ]I‡L—3õ}ÇÚ›vk‚¹ÁÐ:Ñ¡¨Ô¾IÛl*×H÷㙟aü‹ˆá„E›ö]RŽzÊÖvpCÇlñÚñx›ˆ«ée1ø8…¼<9ä ]öȘ,w(ˆcKžg ëæµMr·û½×ûävRã0YÓÂ\R댠 öL­óP/ÓlUY†õà]½xmfþÓúçl1£–è?aô?®ƒú_¤ù—^‡gÛ!Ý«"ã+yß[ŸeµøÑ\yitøa·¬ß£o¹%¾²ŠŽ?òÒX>ÉÍ{<Ær/…Þï¶ÍvÆ0_{ÇÏ¿ëóo[ÊÇSgžçê -e^8=N»^afñ/²÷«NüÙîqòm(ΙMÓ:†ØŽãòè{oøJ´ß¿£!*ûg¹Í®7ÿâ\Š]^zö¦ÎcÄ'Æ;T5$¢•ü7üTܘIí(,âÔ ³U~tÞJb ÿÒ ª-bI¸zŸ#þ?]O¾öan_¤ç_ùì\ðˆ>¬Ež,uñÁãIÙ²„7>+7ëKç/ôønøÂ?¿ÎïGŽxfàÛ2ò·U»!Ù/«îwßRŸ¼ë«Ê*F+‰ˆ­žClbqwÔ†í§Jr|¹–ê2dE>+#ú@¼ô ñU…ÝT¬­^µ@ªf,ÐH›´$ê6>ûµnÜ"‡¼¾þí䀔ݹ´)?§]“/%úPÇ•Ã-°Ø» c†á¥";‘q ݵ쳃Lüû黿õ4  ù”Á¾h»½˜n¹Êön.ó«HÙl ¹[Œ&4Oׯ¿VöºÚSq>F ýæµX´1–Šh!I<”æ¼x…I6Ò»Gûñ_¯®ìil’®Ôeõ®? –TŸÝx¸+,°È¹/‡ Ôz5ð°ŠûÀR:ôõ&.ãDÞ¨mƒN‚Õ×W]6$(ì/ú¡ÚùûòÜ÷ª_úÞºVÅ#C|õ¦š?|íÐþ«Óí´/.ˆ‚_|õ9í.ß±´ù¡ŠÊÜæš¯N>ýÜöiŸÔiÕ÷ ¼VQ"oÚHåÇ®êVâ—®i±€¢-Ó™¯XÍïcÓ^›œñjÂá ±ŒyT…ùeÍÒ!Û"Öp¼’¦oås#€Wt0×:Ð#6I®A•£Ô¦«: «1 ÔÇZ—.Û‰Yžd1Ô)§¤ÖZU:è¾£•s÷¶¸Æ'š"&i Ðõiö !˜;aÊ×Ì)@£‡< &˜êr0Êb‘•/’ +8dÃdXçUèÄVüõ¼ªD£J>&ÛÂF‹ôk6Æ Ò?œtÂ-Û5X›¹ ô}é¾9õÇÃ8?SÚ¦Âû•$Ào£û­ð«¹Ñ,½j'`´yó JQÛ >éÔŸwÌ.ÓoFÂ.îçøNÆwÒ»©”o ;„Wâ›5̱œŠs=øÑ§Ù¸ª@_É3Ð'*ø·Ã3‰ºa“a\©bŒ]öÝp™>†iNÞD]|˾iåtF·/*EÙ£*9:%1C¯ y>Ñw³l«dÚ¤9…©zÅPDO¢r§`G‹T§Í.\ PBÔ ›c÷ÊÈô‚w^Û£‘ÖÒÏH“ò ñ2é‘0;w—*_K!ëLpËIkSP7™]Fi[!‘;V– KE¹•×M<Ã1a9ñÇç#‰·”Ä‹""½"µ¨ƒýwªŒ+ûw]k$–! —4äŽýDÊ)¥]´^ÈpqÖJæS…IçÛ»é[‚­Ö¬Ô14¾`uÌÅkX¬óÁR.EÝÌ9d©¿×îhMZsø¨@^L!™k]dêÉÕw‚ñçü+Ò÷Y½3ÒÖVdÉ«þÌìYɇt5bù[j ±°5ªH‘CÖÊB™š0šµú3’x©óÜ×Y—Ù³%µ¦¼`úYj™‡á?Dž3'îišw-sž`mòœQ¸D\Ž÷KC¿ÝMæÿ%s™’9MºÎNÔÝ{¾þ§ÿüŸÒïL¦n~2æ‘ w¨Yˆë\´ð@š‹¢rõJØHò‹€“h3«\#aíõq슩 £’nQ?Ï¿= k^$!³Ñæ'^ŠŸè%OÏuzE.¨Ñ„CX«¿€Ã‘XJ/k“ùXÂ3éó«Þn¶Ÿgþì v_Kö|ªàð7×’|.ØäNyÑt„U¿\aEƒ{cÞ!CO|)¶F4ˆ¾;V¢ÑbÈÙ’ç’¨¯1ƾÈ%›\fjQ4ôïaã¦é/îb òi «[O•¯-ÜV¢µâ;x~ ¿Ì¸:—@ !5YsdëÄò™„3žœ#â#xo»\oÕܶI&û9F^ÝoT t%©Ë ] „÷Ñö Iº: # Ï +ʽeœ$ „GORᦞ)kÙØÉïKm_Ç:5–I-N7Q+Yö¥ˆ%øOÇ/¹´ƒö¹*pKƒž%`Y‰û1ÿ .W,2‚“ÎF‡,õû¥z1ñtá5tÌÅT3†ô÷¶yϾ^¥?ˆ™|³D^,Á>CP¨Q4SÑe×û¶˜³‚?u14=#°Á*áœL'¦ùZ2EcÑB}Ý`.àŠÑŒbÙ¬eµ/h—<_ÏÅó,/l½¤±“ÄË(™Ì •DôÞùzÉzÚ¬'<¥/.\Ú¡[żßçZàß7¸6ãݳ¹Ùªã_sú×ÈàGÍðòÒiZ<®ÿÿù?ÿçü÷Ý ´ßïWÿбVaþsxç¯sRþ¸ïÖVÅœòGùî?¯úg2û¦=ÿHðÇx–3,Ÿ´È®Ô;qí¯x§O^ò¯e,~…k÷ç;˜âK®ö]²qY_bÍôºœa)W%éîÐmv3Sß*Öv^mpœ7†–)N-F¯r*æ¯(Ôoø$]ß®k£ûá"ÈŸž×ÛÊ=ÃC˜I—®-ÏáÝíÏ"×ú«ws\?\Z· Û^¹åªfáXk,úUÜ>—ºŽ(|ŸM¯6·òÐ2¬Ú¤×Ù>Ÿè9>ár~ïþytêUa`ÿ¡Ìán\Ù8Ýá`Wøè‹†ÿÒ47ßZø„å—Û”âýK˜ã"6Ë×êXáí¹¡mÑÊgFDvûêÄlòÅîñÒ6E?wÈó‚y6Ð4*dºÌÿÕ³"žô+P3îZ<~Í;Lu_ÁWOYú¶¼¾hþ#Ðÿt ³Žmc¡_[4­cE#ðõ³HB·ká†óåo†~â´LHt 𼬲ÀU§¼Y„ ´ã>ôÒØ-¿14,Ù7Ëœ²åŽu<áí§- —P¡v,‡ZÉVŒ.§F1&FÃD§Â\l*÷·åùWä>kôyIsL3ošfÁÝ¢ºÈÎeÙÌÞ¨EO³Š |]ï‡ ¯¸Ф(Á¤XVv`IUÿ– bËr…Tà]Ü€#–k¤÷uv(ÜáºÖ½d0ù*jÈÿ>7Ô'ÀPÁ"]&Xïë{ˆ×‚·fZöþq*ÇF2” Gš<ˆ)ÁÇr—ÉØ?’@c8Tv ¸Kêµo6‹cbÊÆ†É«Ë øÌ¼GcÒ„$¤`R'⢧=!EÔ–$Ó™Œ/Mâ”\øÊ¡IÒ1¥¡ü KÔÁ¸æ …ë%Ë<[Ì·$ÁǼÜe’Ì‚HÚøj±tÙ¼ÎàˆØ''˜}"ׯ€ñºrÍÀbó–"íq›—9¡RÓç€!Ä a¸M¯4“¸ôYRàK,ƒª¾*(Wÿ`II¹JWÞœŸä¯#r§ûM#~Â®Æø ‘ô×ÞÜÃ+‚æ‰i±¦‘þ/HeSʧc> …¤fs•Ÿéž5ªr6ý X.tBŠ ò‹ÖS‚9(‡\¿›s,(DqØrÈå7òÒ›|jø1¶r3Ç>›˜Ád¹'d¤€–)p˜$ØK)“·Ã}sʽ¦ðØMLhÜ„ebÈäƒL…’ñ žp·Tͦ‹ãäb?ÆrZßççIÇ)…7Âòä¡:Îaò÷ä70½Iæg1$é¹— -Ê"¿+²ª\®‘ƒ™Ë¯õzÂßlX›d^ù3&/•åùK1ﺡ2ù&Ñ?ê4ú ˆÿIhM&'ìøNpYoÔÁ"§Ü|0ËÝÁ&§z=MIˆ "8`k:Ãæ<…Í«áñ¤Ï•wªÛÜN³þËò¾Ô‡<Ì€:'éÏ—,5㥎íwΡôu§nŽÍwÎÿÏÿò/ÙJ«v’˜„ÑˬÖìE“~A>gg§MAìUìÝè'Åå Óžï^²×/KÜþˆJzînz Æ>£1`ì/ÎmÇÄï¸øŒ,5 WæÑÐtªŽ¸$ÓvkQ¸7Ú¸I÷N’SЦ¨. ¥}bê¦ 2|Á¿ÁNj3ëd…ƳëÕM{è?éÛÕ相ӕX^'X-m•fn¹ÐOlyawW²ÎI(¼¬g«u Ä’;“ Üvñ)k¶ÐM¾ÁzÞsqÜÁ×|^²‘¨q˜äå4Œ½Šk‚{ûцo.ó¶6ñ´MÒ¼9Vùñ ÚïNнÐSÌŒõNÚ·ü{*ö?©‘ ï(½+~ïÌËä[Õp¨ï¼ºØˆÐg+lP:üQÛ¯‘¿¿ï[ůx6¥RC•®Os£¸^\ŠÿƒÒB’ÛQŠEMåbÂÑ®#Ûµ½ã+vÜȪèS`Z˃¹Wì‰ÕvIm“]•¦uÇtíèeeˆWIWÙü0C›€" ?rYù9ÕtOy•w@ª¼yžÍJë"W}»®<æe>“콯&ÍÏ„fñ/ÿò/ù3è.+ž*ÇÙþK»3MûaÓ@ØÎî9âÎŒþÃO­Øþt_Y¬•®…(¢2ë_ ”¯õlþî}µ†õƪ…˜Æúà­ö£ÏòìÑŸôê>üžú«h¶GöïÈvýmŸáîß?žûùÚ z6êÜ60Ê­\Ä÷6ôíÇ}Ò@0RmÜÈÜuV|oçmÿ£Oj¬ÕÄ㹬=·|›»ñú¤Óv¿×näêØúh<îb_ƒ6}ñäÝÛŸY|&MÈo››<°|¡›5|[U‘û™õ›ßŸ¿#>3«0…bžÏû¦PŠÏrŽ'[ž<ôÿ‹£â~LÚãîëÜLïÉÜl7UÈW–÷^T}_Êú±¨»_®}Ó‹uß.æÃFjžµ]ÿôÕ«±{Ðç_Ùo˲L¥à_«å+ä:œeÉHºwÜ’ðuåT:I†UAüØ«Œ=5t§°âê©mÐà×Ç;ÌÖ¯.Øû˜–rU™^vÿÂÝ!HÊ1X¦Žw¯(lãjt»@rÀ"×ð2\æ’aU(ºè¦?*Š|„,¬/iÉF›¡JŒC,ÊK|}<œ»ÑcËÙɳh)öØÙ0NU ‰Ä‚áeÅ–>͉ծbª•§ÄÙÿ’¿ÆÂïÝ»ÀMÃä¡cJ\_ò"€:¤EÃä@ƒÌ>É=^d[Ý“„pãP‰ïÊK3ç0™Û/ÜÏdŒI^Ÿ+<“µt/ Ã÷xUñÿ@0dFõÕa¸óGß’6à «DCàƒrC‚ NÂÉÚæIùKœyYúÖw1a½" Ë9çšã!—^"Á-‘s<ŽY!ŸÏ§¥ ß"ÔO¨ŠÉÎH«Pôt{¿?K% ñZÊRÖ…ë…ulàhêèŠQ/ræòÌ”kh ‚Á§å%É»JäJ}3¦ë*äP:ÇZކ1 œ)oÍÒþ³¹ BdÝÀÚ‚å—‘6?C¥Áy¬ó: ù!lx—)ï¦Ë VîæŸ ŒÎØN©9bÔg"çj’û"yÂ}ÃGiÎM™x42oµô=1} ‚®Ñ¿&-Í•‰ñE†Ædé+”}Må ã”õ¦òV¦¼sR%Ù{èšã¡æŠ¯’–ëžÖD!‚ž1¿0¶ÓÐ9*y5Ç™ËΛWÎoó&Ͷ E†’ð¾|60}î’pÒæ¾—÷K•G˜zºj…ô7ÉD^°/¨d«àôƒ øv’vM+ ÇçÉlŠ®žn§nB‰ŒÙ£ 1YÆÉŠB/«,)CꯑXK½]MÈœÒß¿Z _&;a…¸á9†Lf'ùö˜GÅv@/z㢦Óæm¼¦Ä[f!ÒNù½>“ª«ü¢@¨rº^¤p— "B Rk¼çÛnð–@Ò ƒ33Î2t­€x˸Ԍúã=æYÔ•.CraŸIÿNCc åTÖÇGϸmZ@GÊñÞ¦\|ÉÜÏyB}—Œ!Ñ»d »é(µ;]±ûÆ$º‚>'çËæha#¶ÓNÙú‹èý€^d¹AƒâÏÇfž°éîïá°ô«ÿùæT õT˜80|¬UdÁŽÉûã¶f´·R?$Í¥ÁoƒJÒ_Pò5öd˜ðÃ?ÂO=ìlŠDá=¦â¸ád&d“¸sóœá·ç?ú9Éçfô™øð°Ÿ”ÝÅú¡HÒ ÁM2͇åO¯üšú¼s]ÕDÉü”ñ¨Ì«£ubÊ3ý|äúÉaÒÖá|˼­´â³ÊtƒüNÆŽ,ø¤е¾‡ãÖï­p¨Œù˜ ³B;jÇrÊS¢Ÿ+y\c$©Y‚Ÿßç*Yî8æº0ù@²&²T(¯—Á†Éó¢‘8NÉAÌW™ë|Ê!X6íëæ-ÅÇtàÇ3%Õ™sª v”Û.ÞkÌ5‘Ÿqð6’=F~xÕØìs~ã$ ÷’E™Á¬¾ÕÖ§ü·zÀCkÄ„2òº§¼Qw^}ò_þËÉ*ͱÄ_ û¤:?ÿؽý×ó$ioo}ÞþJÞ*ŒµÏÏÉê”±æêlýæ³Űyvü4ðn©ß,ÇÚ…Ÿ‘Æ~:´š±²óÞ¹2&ú”Sr|Ç©ù©ö¼ûîÄí×l¦Ôƒçºc8ÜÌ»¦cÊp‡û¾}´§úÎw‹HGXÜ|ßãDûl41Wän TŒt4`êŸ]ƒ|¥°ûâÄç|“Ûé wsÉ©kÉlze?¦z?Ž£¨xþ{ÿÒ({Ì4ﲕe sVże¸ÞJ¥ÑH!®äs±rŒ^j¯ wé1ž/'`¡ù÷Òñ¶Œ{³q1N_:V~h ÛûÌï½ú‰ˆX¨®}ñ«`zÍW—ƒ¼íÛakZÆÑÉ*¾eI“7è÷3¡kOu.Ö¯jàƒ%GòäzÅj¦Aà­Íðn´,Ѭ1( ÉÍ¿!Þ¡[ß°l/ikélüRZ•a2k޾Ók]÷¹u]iÚ:»»I7}ócÖu0ú0 _ûò/×6íTm§«ùh3˜$vq£o„IѪå–ùÑÀ5Ñv¢ŽËßÛD±A÷Œïñöº~öeóu®ÿ/ÏMp“ÜéÛzí¨cêUn¦VU(:9íW£4‹N“aм²ÂÁn¯K ÖRãí$CMI>àoþjêlåÞKµˆJ/håu[‘gsÃ’C©¢°30ÞÌ$’]û Å«”AR€rååîà]êH¡#ì:ÐàRS{ÌhM˜îŸ®v>Zìä’Å…Ju^W¹,%\íM4Ä$0ÁRÃJHDðU˜bI‘Ñ®GçÍ3:#×äŽdy¶ÎU5¢(­L·LÛ’2,éj³q•öI–›_?Óuà€b]WêeŒM¨ZÒ5ôT¦Šqeȧ+fFP‹¨*HãÙò Qײ¡jWªW“L¼·±ævœv¥›¢þRºa%Ó"(‡)ªä¡\ †~¹"õÇ% ¾ •ØÅTK"¯ ún̵){Á&”e޽d—Ü4É_‘…Ui_†<1N6›äš™Uâü;$áÂpA‘.í°³éh˜ÍñW„Ìco@Û`ÿÀ9…Æï/cá«}L™p塀W'V•›låì’ Wf›ƒÏ2ÝcÎR[ßáâ$?É’á,YÊyXÛt‹ì`c“Ý´ˆ Dq@5®\Çòx·#In¸eê¸vu™l&”ÓNX™,}å6l§¼¤ÒéìÏUræ4Î'ðþ¿Æ q“ÿ?̜͋ ª,q Ô+n„´8z%Š`¹ÔÁãù^’¸¡àªdø!h½£|öc|(¬Hùê×È\ã±=z‹ÅhnLÅ^Û'”}‰Säø“`qÃÍ}@Ðh~$OO–hN‘2Ÿk‡¹ÉA»Hì$¯?/ˆYJÈ–Ú5ÇZ†ÄòÍA®’ø¢É°0ZwªÕhN‘\ºÂ§RÚmÖ³nJqÁÉ ¬1Ø!´‰)Í>Ë_’]ž›,Ñ›$û¦F$U-RZºç„]«òÞõQSž7DZžê›Œ¢æë¤Ôæ1¡ê,Ã;9Ð)ï+õºäéù¹ø/ÿõ¿æú†Du’4’5™Y-HŸ˜¯qŠbϲ“7y·«¤•mIœðóÊ_ Ìc³ë½SÝíafÒž_«‹åõh•$LÂ[B•Û;½Ì~§N׿(ÏÈ9ˆX.Qá!s³Ù#WÒþØ7öm<¸]+×V|Κ@“ ²;HÏRvV®M‰Gå|6)ä|ŽlÞ×>?•§T´•5yôrG]¿®q`4óÚù5 èF–u7³;œO7'ìßÇÆ!Cr“öSÊFíN6²4x#]]%ÙK<³&‹æF¿‡eÙ/pah·óÐéEŽpõtŸ7ÉcFrU+¾Ý,tMBÈî ÿ„)®CâV¶¼OÉ,±‰Íü d(–yWü…½Âù ²‘!þšj-ø¥ìž´2ÙÅÖ>;à æBŽm7ð>÷ ÊF– Ý쥼x²÷À“•C± I˜w¸Œk›/³9°L˜q n+Tý!˜ãRí °È»â¡ ée_kÖcUŠSòÃ"rQå«£_eæµXÈXK£69¿Ÿ­ÝGt%F¹5Aá%ÅÚ¥0G»è\ì—» >G¢÷³²4Fkå¯7l½çã^÷~šg¢I¼—EEÁ¼jûwü×ÿú_×Z[d—4IK6’Œ½òW=s™ÃÇꎮQ°ûP­ B0Ë¢R5|ùÚ—ôßÜÉ!ß(Xú©qŒnõ{kÉÔ2]¿¥o“áüPÒ÷ñ üÖ®©§y¤ë{¯‡ðþI™èœOÞê^;sqsôÑT™‰+'õ›µ3—Ö;¡P5‰l ?fw"×MV£‰¸ËKw=¿oOÈi'âNÆu5¿¦ùx~5‹Ãç’ë{i\äN8v%çûTFu7¾øÜdø¸ÏÌ›'éJ¯ëO¥[AT<ù½¯è¢.æåWחͿ߉ýÿ¤˜ö3éZêœÇ¹ü+¯ü`Î~öÍj ¼”î¾i„þ»WÙq5‡ h”Çý¾S¥mÇzŸ{w ·c{1õa£Ë?/Š?$úùw²ÍdN$ Á«;]óN'b*^ˆ¤ÜûÇ“i:%ºë±ü‚cñ»Þ®W;04Vºî„ál®¬ixJ°ì^µ–R´x‹¬%]ÿƒU Jp ݉yí8+!Ø×ä§Fb²;ùòÛ ‚H¹1—¼¢Êç†`Se*A•/2£ÈOʨj¨D—êÂåï@‘ó4”¹&0yTX+ H¨¦ð&·j8ÇvcÁƒ`Њ‹·B3¦»n†à†¯9ÒJFƒÅ$l<9«IZå¾\c²ÇÓÎ#cŒkbö¿ªš‚¤\•it—ɵ¬ãËQñ«…›‚©:wz*†Ý6 ÅÅp5_€¿åp!pëé!YÝ!ºÏM|—iò‰ € šG‡næýOI2‚asIB§á°ÄÚE°Á++XÂæB%»›O¼púyéâùxÍ)ð÷ àv< õëdi“\Á¸g‘ 6Þ¤éó ËZ(©JÒÌ©#e] ”ôÝ“/`7 vTˆ"ïͰ5Î#DÆ÷R»å㕾ËÄëBPæ!òϵ€à°ÔÓݶ3ïÈTÜ$·X <‹L¿®^;¤ñ¯ôO¨ë3*Ÿ¤ð2J^ê_Ÿ|~4¤ØÊÝ´ÄQàXb+c¢ç”]·Ô›§cžcHPwœ¹YTW©vP‘ ùÞ¤›ƒ vl7`ÒÈ0®šc˜- ž@É‚áRÖh8Ȩ\YØì@å¤)” vÓ]¥Äçáþb^•n ï³ <Åk¼I¾£*=¿±†žBP ÀïímvQùƒqÓaeXβwÈÿBC1™| ¤êY6!2 üñܸLIA‚¥U¿tMœ®| 4k6 ØC?†t©*·d86¢¡W²0*Èè á0¤l*&\aºæ!ºdXí,Oß<àD|MEXQô[P‘À½º˜´¨j68 I†þ|Þ1òAX``«|üçÕž¸ì ~u{}NŠ!£’e„é2kÝjRÁ˜×Æxàb“Zˆð‰*y|ˆ"púVŒ™B£(r—4¦‹š¹€Ìé”S$”óËã~‡æ´ê»Œ_Wœ®K3NÉî´bpòfÊû$!©›hº'É3ž>Ë /vó™!òº"z/˜ åAÌÞD!è:ìuÊx”Hùo¹±W\†È®f($€W{E+ÐÒ–*Í®4JS7å—Cò ñ¸øžPúLÚ'éû“¨Y÷e" j¤É’¢$K-¯\e´+Lz"Îü³«,è¶««\ÂÀÊiä5O¥æ‡FfÅÎ'oBRÝ Ö< ’¿Þ.^Ò%çpçš: M59Åc'ÝõiÎÍ“3âeˆ2¯?b¾WÚÅ-„7`ù3¯ŸjK¡Ü“ÑM‚Å»¡ù„§ˆÝªcá¶õ@BØxÈ”Ü%ÐF²¸ê¿¤á‡D­4}„™É¹Cº`nmÒ(O9g5}ã=É´á*˺äâA'&>DaåK³[f¨Wšó®0e˜E8'˜{Â7†ƒçáôPõµPƒræŒHÕÞMPå+ç%™= ç†ÿößþÛÛ´ÄÄÁ¾EÝô—K¤þ Þé FГýHÝò^Þíî3ïù"ßàOÐc¨Žþº§ûâ'URú«Õp]>ýÂ/Ë)îÆZç~sO=ÓÞ½ùþ_"ß8P>üvÀwì~öüŸË1ÿ1Ö®?ÝjöEIà?«UóW.O¤¶ÿhï×ÂÇ’¿Mvÿñêïi¹çbÄÏå«N+ÿ~P=þô6O¥á_Ñ -ŠSíûGçÂø²ûg4^ž½<ªºqʵyó«h¥ÑJKÖ{è¯ï¶¢wU6÷Ù¾ÂG‘E+¥×]OHD•Œ»‘U i¥hÛïNÁ¸ €!g&ýkx•ݹþ¿W´ZvEÒ®¸÷FºSݱ˜aCsü¼ªw£K9ºâŠz‹XHøÙ)V¨.T‰;,ú¨›,Xê77AEÝ¶×ælÝSwJƒE)·¶á«œ¬7ŸV@±•²\Í9Þ|ÝõmpXê¥J-‚×^~1¦Û–ŸŠ´¦ý>Sx5c ÖÝÍ G}º+VgyEu‘º©èdo„˜&õJ~õE“«UæWÁص-²”_å?¾ú¹#èÄMŽ·ÜʯÆB~õ{‰Xèûvw‘U ·Jub;Tªt ®=rÛ…¦ãVˤC{ÐÿP+#Þʼ#ZÝ^v?·Ú§• gè×¢™Ak•¯5|Kÿ2X.¹ù…®¹°1ÉCXä¸s¸H+#–fªã¯^íº…fÃ|ébA Ï÷*mfL`¡g®5 ¤xÞkX¦„æå¨kk7_"3\”ÅÆg½¬&•…@_Íå“›‰)uW#Ï»¬1_qS[®&i…þÆ8ãñl[J8jUÞ¨j+SRB¡ãC¼ùì–ùãß4 ¥I¢ ˆHò™#(Ù¨N—ÊpŸè¡@1m$Õñ™wlÅí4¦”Ú¸‚JÑa¢UuºFÝ·ÓUäpÁ “DË9f¾YNâäþ­ ®,mÐ&ÁÀ×ýè]°3ù2TR1Ô…9KÁF׉Šô µ$I‹:¦zÁ×±â|^îÇûˆ,Ág÷@®Â¯®Ê¬2›ŠH‘¬›“HÑ”ïòûŒ!û8åÇ•ð5þØ–%²ƒäYÚ˜dVGK²„2Be ]<*ûûdƒ‘t¿žÁ0ÖZIBt\Ý•3/šÓAvJ6Ö‚ô -K“ä1Üyvª#ŽˆücVùǤü‚ ‘˜rQˆJæ …h"E®õúQÍcÉäPΧNŸµ,¹)"¸ ¥Gs ª¤ð»8£ÀæøU‡‚O†[ñ²Sù½þ&é·áò|©9‰S•Už õLLÖ‘Òû"1‚— ' –$œP/jåËq¸ê K]†9 ÄôRô!¥¦hnÈüe9eWCòš`|6;vÃjŠ¡ÞÅ0kì3÷ç|6pal“¤/9ÖhÄSø/hýJdYWST©¨= ö˜)E1-¤YNy•I©¥¦ûtDµŸ¾ÆbLVœ!Œâ8Ïói¬£SεÈÞIÑœ,²ï¤²Éü‘Ãf™oƒf¼4x…i0(2¤¦Ь¨²í†[$È´çê,—Îcg™Ü˜¥" –é5àPc{cØÁÏ•tÉy!0¿df©¢(Ó^cìê7ÊAÔÓy8qY „§‚$›\)ßÑ@`C„- nê¿ÿ·ÿž"5ö3òs`"ùÞÉÏ™,ÜGòsuc°“Ÿkesc'?§Ÿç KuØÏÉÏmuŸÊÏm;ù9zÿ ÕITþ äç Icç˜üÚuù9lï'ÓÖIl®Çï®—·ñ _š~.$x˼J9íH·/Áêá6wµî£Ccd>oVyÊ-teÓè­Öéîò;nÿÞeÀ½ E>QgJ"ZÒµ m s¿~ŠA”Âë1a¬•Ûíš»Wfµyisp‡=ÈEdö'ï._Î<¯PîÂîƒ2}º‡ÀÒ¡¸™Í7?³ÇZè ß¡,\yÔ¥¤e -Óûnº¬ØßÙì\˜»Ï”¿“¼ÓC.ÚõÑ ¢C õPÿ5bĈ0ü™^„ Ö7YÀL•w-v6Z©ÑÞbb2gž£KkV't†ý¬ìÓ¶M?¸¹ìä2OÝ¬Ó ŽÓ*ÿgøAö*e‹·D>B2 h ^ÊNGˆÿlžÞCÒyÞ/3ˆÔ»ˆ¶Î»]þõ¿ÿ÷Ìöš2å4ƒOV%±»üªíêRváÑê‚u’rŸ(q¶²­<ØBRÙÿ¹eEcZó4î$ËV?? ºå2K›=ñ,}ä.þ³“|$v¸Yý‰G”[¨;¥Ì½ŒkU“ËÒÆKáÀNõ´Ñ;nç`Æ}C½IseUמØMHDC¥Ÿú¾ŸÊ öÖ7  ÷ˆ‡ê±‹g. Xè)bÈ!ôZ“ú‰Êð')$âŒë}£v”Ÿ4>’^u„u¼¬”§Y.b·%ÎvÀ.[rûùMMãϸrçGù·êãfÊ­€·¾çÐÕÏÞŽ6æXÆþAMÁ™­¢µXlæÎ¢FA³+-*¢¥* ¯jæÏpƒÈK›hN%Ð5ØÄðÓÏ!ÛÝ FtÈp“Ú”+¼wrô,!7$z³é-ºÛXÈ5DÕÄå¡8wÅÿfTµÐ:>3‹:‹ W‰KZƒ$æ®í*©¤~!xI ÅÇÄ.)¼À—‹°žaÐ~JS‚¯P*¦€ˆê*@ñçŽst¹cSX׋‚?UY?S -Ó×gí« Ó S1‚à®Ód §â[@e%žw¡Xã¤~๚\Ágƒ¯¥vÏ‚ÿ$gZ× . yŠ%/ÊC¦¦>ç@j#tÁ%C+ó—š(jQbÉžÆK¸ 0×Ï$dó4‘ßB/€“ê¼éb(öÞ8‚‡†¼ABsµØ¼7cï1öžæ*ãØÑ—Jʵ™ÙtN¦Ã q¸z)Ê0l`ï¡m!9Ó•IÎEÛ;"—ûIý •iî4Ìú‡˜s–ßÊ¥/©Ÿ&bÁ9)~ÃÎyBÇ$Ë“vü))ð¹Òn ©‹2,sFå&‰“:d&*l1ÂI@(s cÝ+—tx(<Ò" Vmãù­E…ºñ‰ôLU)RØ@6R±aÜÖÏDJN0)XK¸s(&|¯æïhx½PÈ(CÍ\) >eÜI–]¦ü.LAUdš±‘¹ï¼—Š +lƒo|2RN”WY$žsÖ¹W.j=eÓ1o\’êiYù¤l õ@Tî)óÒ†ßPEÙorMšR³3WZG‡B[aÑ’BÛq$F¢ðÒ‡ý×ÿžåòíö]yŠÁ‹*ó¥X>D¸crã~[áAaŸ¢²b ò«6ó0šáêš«­zkk®îC2ΙcJ³%nD+jØàcÑÜ\TG­íJ¸æ‚ý]30†=§ÜÛ‡Ô\¥ÒÕi¹-wØ× ³á†Óů—¤5ŽÆå˜%ŸwW·{0Â|•¦¤°Ù®£Œw´×±âJºr 'IÊ üsla)&†~¡ëmTnû‹Õ¬Áyçï6ÏÄÎ ü”°Ä8$I…4þìB‘,í»ÞŒŒ´?–öé@¦|Ú½¿Áò[¡åiu·îàDû‹r!PO”y´3çÍy‘ùöÏõ¹½¥ Ø·df••çzÑŸˆèÀ.yÍ\¸,”M;Ú¿;÷ ô§ƒë@¡?L©B€;`T…¾®æ#.¬SÖ®ÅÙ«üÕj=œx¦ƒv€âö»Á·G-ܹkÿ´Ókn“$iå¤1ê”í+»¦K*É(úþjs&„Kͯ›™>§F$+lŒåÅ5é§ó-¬.2Ýu¾ò{Û’¼Zî'ÿ|x“kB—çT´pÏ Áª0÷$Éë)7|ñšS¤ëÕjÁLzo úœðq*Â\¡ «uhºƒ;¼¬«¾ve3]`}h’ú¾cæ¤J™:ô_ÿõ_?ò³ý#Ç÷>ÿwâ%îøCkôï~¦Ÿü¼ñó¶ò¿Oÿ²þýÀRøÎÐû» ;ùû5ȧ.ÀùW™cþZäùÛD¯÷ØÊƒ™ &_}; «Ü’ JŸaå¶Mï€*â¶O£¿Ggï]µåúÕëTÛE–ëáFzλÅeìÜ4ÑQG"É—¨n³|âJ®3 –7ôª®I†C |Œy?m ¹Êï®> rщìNE¤*"Ø:ÝÊgR¶ÊSÍÂ%ñügUŽµÞƒ@ŒSû«O l| Ž`R aH»·Bà‚U±ŒâUj¹ô;ZOrØä ÞMiT¤ ;É\´¹­¤r"5ÁE.ë—Nþ³NÌb¬ŠÆL3ÐeƒÍóû–?ey\D¾ÊzU¶J^óq´i~Àµ¶²åÝ;y_3*¢™°(cKØ¥Ö€¬x³ Õú§Ï‹Î Xg§›«QìðSÄ¢ª˜» é£$€9PúË•ŠM›o0ëTiã`ÂÚO‰µö.ï³l}•ªö±_!ОÐí Àë f\!}¿…_Ħ$*ÞÍ;Dáºf'çÐy½Ãn—ÌR7å‰áà r½V¨ˆ’Íšï1ƒ1r$ ‡1®<ä >éšG$JÎÌ1 A0×Í)j×d¡ð§dËL‘»KÂnÚ¥þ€aèfÌÕš¦<»‰"Rî2ªòD¶CŠsÄÆB×ô ¹½©`ùνb9Ò‰ ŸüŽ˜Á$ ‘ i•$ÏLŽª¥j^§;Á˜é Žaøûá@>ámŒ%N"…x‘[nðd¹@”zPÜ€"é—Á®´fµPsÞøzžÒÎI0BvKëÉI’÷Õ Î)SŠ€åeQ‡H3gîño,c©}^ó’Üáó‚Ž…fºÐN¸dè\Ì Õ)ž&ù8üœú§\»_R–™Y…Xè{'ç"çBÍrÚ9}EÕË\§¥Ñ‰§‰Ós¥˜á­s’•Î q}¯ÐZ[Fÿ¥ªî¤†©Lä€@ÄpUÄ ZËRÒ9ËG†é圿œ•s(ìh<©JÁ¡ò²”ˆçzBïÊž ªUÄÄ÷!H¯§°²D Ò‰ÇÄÊ‘ìŸÓÑZ K–ÇœKTlÏõ•€ ÍfyÓ“t~v÷lÕÙ$OÐ8ŠÔõ®òÂáìL‘oæy[ÜÅ] Ý&„Q9Æ›„´ËÝ3NkH{Ó\óL6`Yl Xv5•°´ VTR'µæ#Å„“ì°;“Ì~áçKYÍu=ö ü*@ÔQS)¼š¥yµ&…ÿ`yBE‰®ºB%Rò—ÌSe«qH“s©  sA#T͆0M±Ð|©2³Ê¥3T“þåfhÊ{³L8CíPEµk\ÿýùÌazO Wÿv#BöÁ">p§ýÌO^ûKNÍIËÝ'=qæl…c;PðOšd”ÞüÃ÷¹¼îô¿ÐÓþ|Ÿ>h¯®¼èøÏí­Ûlä Z¤|c%üékÕÈû;ßý—Fn+;ÕÇû¼°šßø–­bj'Ê}LJú¼w XßZõS­§¼ˆŸÉk÷?ÜŒÂÇ+ë»3f–ÎgŽÎò1nÆÁBYû±£öFþükéÿù¨ÝJ@?œ›q°$Õm>üv]]|ÆZcøÛÚêwOèÒ_›ÑO›åù;îIÙŸeàÖX¡ÿôm\-7ðQ½:ØN/,–P¾ÑxE½šçÛ0¹ za{“X!»ËúX\wG¯Òë«DQ—@s¸.ÿ?š÷Át1Õ+¯¾]‹>Àæ*=öοîqê.³¯îS^ìAEÜÕëQ3Ý ïŸâ>Þ¹Ò¿ÿã¥WÃ-eýiÝÈÑŒQï—㮥­Â`?X9×7Ï9‘^cž($jáW탟¦vˆè!T0áë_óxycÔÎxó¼@JªY{tPO_怎íXŽ`qOBªÆ4¡Š<±Rú“!¥ã@ó›poê~VÖŽôõº½ÑZÃËú¬Ÿ€;‘ŸÏ€g¬f]Â3¸l7k>çí3v§~õ¤sÎ6PâˆÍúÅc2´#zà£4Æ5²ø3pMZž`«1°ÉÃÑäáyâ%êqèæ\3aÖyØúÛ³›˜¹’ób•k¹]ãIWÁÆÌ8Óx¤—®¬ÚלÃë  g ‘^7%?‘ç¬7G=žÒ\ï‹ÅDëñ5;ä™’{Ʋ8~–Ö¦ÿñ?ÿ§ÕqY1Ä;9×ñXéöi{Ò[Ѧà®ò(¿NûÔ÷ñöôÉuÔÃ+Ľ âⳕzkP «Öܶ®ä™]Ž3vîî7wzÉòv›ËÏ)´ïO–?¶'_¡Êv½ø·\m nŸm1Î÷ô­ƒü Ž£”#ãaMøì²7eC‰awWÆ±É !ëîS¶Ïð˜2ï¹8^é‚–yÙa¨k[uý¶E ÛÄ <»ä€•Ÿtm߬ž7ÜÏ_Ç4M„‡£®ïÉgð –ßL÷Æé¤¼Óeç%é:#EBtŸSï`Y%¾;8çµÉôÜ·DkËúø: ´¾¿W:½‘r#óº ¥r/Я;%¿.mÆûÒÉÄ»|vë.ï}½AÉÝõü²îújåÂßÛ~µM’KªJK$q•iuoeÑ&P/|€ã~å(D>Üwcå9ZJëd笪…'«ªKâ-ÙjßûÚCXÚ°…õo”’¡¯ÝÚ±|í‡ÿçÿüŸ­¾×ƒÈf‡±ÖDÜ:Jþ°ïÀŠŒ#‹ÝÆmÅË=n-gy§ªz7Öž| b4oýìÞÑ»}ׄJó©Jõ®gó;#å*›y÷{êÚ¹ñ(¾iàõõjîÜ„ŸÌû_}hàºþ®µè¨œvw’spëRÛY ï¾óæo·föDÈ^½4'–9£?â'=ó¸OÖFÕwNØÕ‘»ÚþÞYo’ÑòVìé¨ÒÛÌyËØ8p¯#aÓü:QTîºY]Ìy½S¶:–µcÛ‘ÜŽ±(ã~è›ËMbXyÃï² –9ª¶m}ÈÅgšh@æBîs9ºï¾/»9³úžv,ÑMûMîV³êv¥–“yöøl=x6.Ÿ6Ëâ'nËŒE~¡—*ùb=>ΡåóŸjÍn&ýjÎ<¨–à ¾a' ìVȹ¬'²¼öCÁá's¦›lÍB¥V¤~ßåëH×g±\ãôëèöç&G•T YæN_KÓ/ùÛŠð%2ŠÙ¹mB´Å&‘¤Â\åcÁì0ñ{aNÒ¸×ļñiå7sºSŠ{)A8Ù žÓ‘`.ÀTˆj/d¬ª›*÷9M††Íäpó]s£‘¼†'ÄÍ—”R¥T§.JRÿİ»½€E•A ž7®[yg(öE€ýû8PeH‘ô¹ævž¡= Ï@§ºÇÎÌ1Ç_8?!ƒ¾2ÎѰh ?§(.³ü\TÉ^@Æ´ P/¥©4Ù>ÇáC˳Ëù—û¸à¢]6žDɆ M׳0Žæò4”‚˜K]е¡ 4Úõ­Å®ËPã‡oèÑVEQ'£J§{âB<ßiþ[Ò¯ã]d¬‡£±sƒ²Œóé’;U—†ã7]‘GƒJ|<Óò"íË'x>$'ýNú„‹P<æ&ËGrš›´Éf»“4H±o¶Æ‚Àº( Ș*2hç.™FFr8/Oum…£ŽBæé©þuy&i;î—˜‹?Ë|¦ãÂeM[HוÏ4ú¤« [.Ÿ•2f$ß6¬Šd;µ5dÄ4ã^ ä°^ûøYcÈÚ+¯ÓrsHU¡Ž*ß [ã²~ζ¨k"ê½³9¶pÕM°Z .¸NϲÂãº-yLbÔ#"=Íeü¤Ê KYçÒþç}H}ck¢Ü+I1Ù]]”QjGN…¬éòóépÏ‘èöÜ¢}€>wÓæ«¶ °û'ó|µ4U'u(+¹ù‚´Âx©:nmC ªd*—Ëc(çœÝÚ’H¬žüÑΙ /–šçý¯ÿ•å®InïS0Å.Y‹$"Ψɜ»¦éœ7—×Îî<¼f(H„…’Kº3zçäÞÜ^Rª¼8Ûï4fÝõþ*¢8^¶ÀM?‰“mÁ†.¾X6ãF‘îY×(‘P掞D \u¯08S®5Q¯q³¸Æk‡Oª ÿøä²9æ˜!a†*j®Îé÷°‚À)w¨Cd9)“@E*©x„µ¯¸•‹sní‡fe‘ivÞle„Ë:ÅàÆr‹((΂<Ô7wg™7K.„ÆVQg`Ç ;¥É6jïÝ̳ìÏ Ò\qÃ$$½qo› mªÓá»äŸ!3L%@²§ÍÆ‚œH ¯mQᣞ^SæoG7b·wmB’å$îËÈwI¹ ;`V,$½±:0XHgBòʤ[¯ªØa{<©@âvð›¬,w‡¿YÄznÖíÒ¦„ ^ºˆ-áyÕ)úFVêÙ"¶¹AtfÖ¾Í%/>«M/©’Ù*á]Ê…ÿD,ùšsÍX…c'°{¹¤oan¹A§XÖ•õ9 ‡úhÆÆÈO!ÿ–͈ Êen/.9+ÿÝùë"–ºˆ• ˜€ò2Ëaw'pµˆÉÊÒÎ_”Ü]€ð—*ó¨¸)ŽºõRYUxOµø±yv¹õéå——ðöáÿYã– ”îæ:±Ü´=˜|îyvÓû%ËúV‰ƒ··è_îçOoù”>ùºú ЩŸ¬=D#–`¨/ß–ß'uíÝL”;çê5Ä®‡THÍDê.ÐIz %´¹b¾.ð)K¸Ñ£[ùêAÿîÞûñ/?üçÈŸ#v>ÈoëyÞüžÉT8–:.~þ”ã!ôËÇÊwzg×IüÐùlL øVû‹ãöËë˜]BC?ì†}åñø?ø™ûñúííWv5Àj‰¸ïâê¯e·{yóÎ_-^¾9ÝþöÇE¤¼,÷é+é´y=Æ…j&EŸ¸,*4`  ¹e ¦¥ëU$¸¥B§ÆÕ:]1\€£Ð™üúõ#Rä";u,[-}¶0øKN 0þä1—ÔÕ˜®ß‡¤µ.|ª“R˜Bn6y:ëJ°ã´º1CÁ´n¤dímìü Å¤±aãžN-v†´¦h%Oˆj"ƒƒPî™cÇážv—(›Âîˆ6còMD{ä[ï’¥ËÞJÐÔd@€JH1¤K÷Ì5D$€Yº¡&CZ9|#â¼>š ­ùW€l7îC‚7 øƒeìùcE†›Æر›úWБ©pñ4™Xů†=¿qÊR±ýCBšÓxl%:y¥ç¤`@-ž‘Q—|6Ce½Îã’8¨—!²¸CZ6­¨5ÈcE/BtÂj‘‰A9_Imuänä1sÈTcHx‹ô» àŒ #KçÛ•L*P$ÈëM@ŒŠ„oá2Â:OÕ࣠£ã¶K«'RŠø$n2sj{!Î[²>QqY†ô]RþiPøA£¸æÄÿþßÿû—\ôœ8qâĉ'Nœ8qâ„ÇKUŠÍvøÙºüª ˜À¥Ìå@½îdå 8P ÏòZ1-WØóÙÔÁ­’ÑØû£9Ѳ“ºÎqv’7þ®°P¡8Öàm Ø-ªBItŽê¦‚aסówI £sïf¸ŠÜþÕ«¾(ÏÍiTHVin†æ¨bV,\†jÒ¼„ý[ëþÛ¸º/ý©›q­Šösý¤©ô¯©/õ6Ð #P…ª[ûçÖ(UáPA×ÌîR Íóú\{ÇPx{@¡ Éch\Vu̸¡;¬#'j9ÍEÍYî>îWÝ¢¦>„ú÷­’ÛÊiv×ëÚÇÛÏïí–‡uVGhÔ¥V¨i«F¡®N,àAö+C^‡Õ†å$ôðËš#Ю ÓDØÁë¶ŠE0Jh_´VãÞw®–ãÝmë °ñ’îò½· ê‹ÚvÜÆîí’‚øÂc£¬ùüþ駺¯_¡ëÖ}Îõñ˰‡ïÖÏ€­a(ë@SmøêvîpÝ®¦­à£X×úöÙÃÔê¬ÆÃÒè=ƒXÀ"yþ{_‡._0ÅÃv)…¹Ð%Òèó«öw4ë¸B›;%½R»šú'VóÊÛLTbë8è¿Û>§¨=ö颟ë ºíaáí^-‡›£Œéß"ÔUr—ÇJ0uaHs—Ÿëp’£嫬’‘|߉·ìbˆ]kÇUñ¸nT…Œ ?pGÆy¥ÅÌð¡ï—Ñè­\ Ð c]8Û4EH.Í€bf™ÜŒ"›dH®Vsš›K°K’æÚzÁUæÃ݆¥-C[ü]IÉÉ4I‘ W,vZ…Hªèõý€Z¤¹6NÆkG n´¾o¤dº¸%ŽHrL”°±wAóz¦¤g!Í –”¾fø…'’d•}¢yuL×°2r2iŒÂtìG†Sì*_Ô·Þ.©e¡ë[ Šv°vÁ§Â÷àŠp9ÁG>vyî@ÿÇÃ0¦‡òHçŒæãpe‡Â¨²ªQ1ÉSßg_ew\q›I,öƒäòžIHt–B³ï»ÿ+é06”¹Xæ±À°©àžCY ¢Ìiz§W#'Ö¹{ÂÕ‰°† ¼v0)[Ó¢*ö¯ˆ…šŠªSô´\ ¶ž1\ªƒõèc¿òPòÑüÜAì`jH`Hòè¿—Â=GܨÁÕucöŸ u„A¿Ð¶1­ :¥U°zéôè Û6^á·³Méá¿÷Z 7«ÙfUuÌä5šéÝf‡fÐuåÔ‹ÿuNôkb©‡¾†B'“ _wk•  y¾‚øXx•º±À ­ÍKJîVR¼Ê±iW6>F~||µñüXR—zC†zÓ€¢½¯í“i.¥¨Lrê ‚ )4Å„ôÅœÇSe‡­Â +Ó˜¶Sš«CñRŽù<ÿRÔDh¾ X“¨ÝÐT%É€:ü”•ò‚®©Ç/#ª4sÄeöŰ»1w¯0`E<÷²(Ä gÝK-ëR/qÕ¬KpYñ* ›^J*i”å<Œ•àL‘Ê!AŠkRW'ÃMÀb|âQ$ŠX Ha¸+ÁÐ:'e!©DÍåð×IÐÑ#n†ML„ õ…®Èì-IQŒs»š¥™=#ó«í1a¦—Y¦À,Lvù2ÞUå2‚)ñiò€Ý¨‰™Jð¦e'©}Ô¬Ò  šηcܦ̫¹N½¿˜ï$š°ÅÌjuù‹´KˆÁΨ9 žs+ì— çYtüçÜM5 L¶]¡ÚÌܽ³Ë‘3NÞ„¼çj’c6Ãw]• SA,gMVd¾õúv´éµ.°a5slhµ#'§šir õƒâ&¥Èrµ,·MõT‘td5F…2‰ÙtªZ!›^?^3µÖ©ê¬àz•ó $ ½¥ïùùB•ÞÆO·!únªJ;L(]7æº5Ö:Êw®º9Æs5ÿ÷ÿüßLůFV£aK4Á~‚ óËôåµÐÝ=eAy=MÝ]¥ýª Ï'´ |öœ¶`,®5ËÍcs½»ŽÕïôäÙY„®›¬ë»±¡a¾ÓRóIK¯ Ãíòšw7£÷ð™*רþ佸ùÅg4~K<üù­w‹¼xpèœì¡_VèÐÅ_¬€&wy'£ÊIîïü»±[7æh8WSÅòïÓ6wÏ>à§Àd „‘¦¤®?ü¿ÀAp»ìn"›>¹Í¼BÇAëÜ©7v°§¬râÛÜP®n¦»ÜÑÏÎÑ3 #Íö±æ˜èÛŠ¹MÛçòÂyÛ©Ùð"î gy³¦~N´LÂǰyÐòm¾ÍÌîñ1„—w‚›õ°«1>L_O­¾GÊØ‡/¹\@~í^N<^Üä(û«Ê;yò|¯‰à€¨DXÈR¥Á8ò/º4{…bŠ:š{TR‘›&´/…è®ù u…‹Æ ®ÜYÒUV´Õëý±¸©ìžr£&#Jí³.0 X@uz4[{õÚ+ØU¢á^v»2¼ÿÕiš`¢ÉÐ\} Dn%:ÂfФìÕ™¹‰ÎVJHP¿NìC¦\W -"i ¼òî½ I XâcwËÝ]Ëñ…þz¿\ÕG¹•­Wê ÚJÁUXg*ñc½šÅ®kÅ“(~‰Ñ)òø„°€<4Ê<~EUÉ£v ´t›Ðã‡Fð²\=Û4:3Í—)Ú ó“Çù2+36ÄB6f©º2! /U lÔЊÁ°„Qy ôÏÎ ­ÇeQè³oû1§"NG&¨•®ážy™r]ÓÍk­¯ŸRÁKe¥þÂÌe ˜§wSßÂr>×¼ª©ñzã“}šÃÖÚ¢èöÆša§ä'°93ô|uÕ¯hÃ^0•È«”yYºÅ÷`%wôêû\hnÀ>·¨•®T9uÚnm)e†™ô¢/‡;™ZÕËe«ÐŒA¢Bk¼ÞÕÔþíeí„bÍPtxyòR°W+œ*ó¶V@hD8_ˆÆÜ8ºâ/:È:Œ‚ÝÝ$-rD£–Õÿ®¶D»¾¾¢@Re^½:©ÐWTµ…’îû%†"rµ“äÀ™ÓhDÌÁ¦Yص!…8^U³%9t!5—”S^ÚU²3nNµ3¥ÈeLHC;İŒ¯@Ç5­:B°$XTÙÝeë”9Î|Šb”ªÃðU]Ú#]çÏï'… èQü¤Í`ãºvR‚ˆ±VÊ¡¥€=ØDí‚\í|]u‡)ÿ\æly'2øãS‚ ɘbØÃ7ò—©fw|†êð(ŠóªrÍ=‰ô½®qäj5—¹œŒ:9]Ê0[4SgÊZxäJ­Ž•n¦Ú‡Œ¾²µ»k`ªž$&%«™ÑÜ'Ø 5‡‰1LkŽÏù³‚©¾š([*<Æ ÆX9”`‚¹ÂÎÅÈl®—åThþ½+¢MõVC‹èa|jÞ1Ž äTcÊX¦&ûZ œ&ËÜŸÏ+È*‡ ÃE :À0‚ ­˜²â ÿ=­#æã7 69ßi@^‡ÂÝTFBf{†võiŠÚT*¤qŒQØ`¦‡žßó-éÈ|šû¥žˆÉÄÌŒ9ÚWógUíN|e= 1ðÔ<-Oe*óLhϘgdb9àKH»W É` XaÊ.#Åäó¸æ3.¾¡™bø8ÍÏR6EÝ绂´½Á°¡EQ¨ÿLÚZª²'Æo™¢CµZÛ“!sn++µ+`ñØ,XÄ£ÏbœQànŒG²¢·°Â¿Ù˜2  -Çüõ׳ ã馋°{JZ#ó ƒ¸#&t·C`Ô,PEWô§ø¼þ@Ú9Ôø4h °¾œëm²šV¨‚d˜ « &ºÚ´CšÔm­C°›t1fÓØ1ÿTù’¯œ5ød‚¾@¤,›ÿïÿû¿¹ÅSÔ[¯n]ÝKLjšëéÚwÙ¶»RJd㨽‚Ù…»=÷=²fŠhþ£¿2^Amºï¤gÅ*ÓÊ‘šdñCÖžz ÁHq Ç=l%UÒoHrŽör8‡œßµ€w·HÔgËçëÆF†ðcî›h‡ÕÑM¶³U–wš‹|2?Úi+‡Å ]†¶õT~UƒÀÑŸõw£.²Pu×ÕÙ§—-¤oumnLjc-èp"tmPÍ\³>IP<š<¦@ßäyõ]²L÷ãk•k¹˜ÀMóct’±óõ°~¦GÈ¥æÙIò[…›5,«l1;éGŠPYÍ®?>Ó© ÞBŽà*ö¢f¶Û’DðN²I›ºÔôÙªŸ³ýØØ‚ï0LÝ$ß- ½’vDu»Å40Ù []Í_¶ç×L·ˆaªçná[?-!,&s'ëæ£¼rD‹+_®±«âp!4{"49f’û•=²96¿M\¹æg;,m—®Õºµz•›‰óêŒÀªBG´f^?H "7¯dÐëº6Ãk Üãl©È‹àf0xM3à°Á(Šdå 5!%WõPÙEk˜Ê׫¹Fs’xÍsn6œ*Ï`·êšä‚ý¥*A: p¼NÝE® +´eª¡À#^ð›}5æ{5Šp/kßõC_J‹½¢Â¿Šú ©UÀE”œqsÉ.ÏèÊ3h [¢ÔÕ´¯èa³@Qº)ÏŽ^'1¢ƒ·Ö…öÅŸÈð‘WôªY+_µÑB/3ï´EÆrS„©Ø¼VpÈ9þVß‘¾}5™lž°ñ:µù´ð‘)Ô®5FUè’§x5ã¡Q(씊€*ùŠÜùu’£ Ó…ª&ÅÈ‹f(ç*eVõ$¬*…Qéu$Q¬tÏâ² §ÏEÀçO´^×’ 4 ’ÿ†…½0!`[e(Ÿ£û¸€e9LòÕ¿WS‚"Tù‘kÅ~ŽÔ¯S¨Z­ËfJ|µp=5¢„*zÆE5åE™Aµ<æu£_àÍV ªo#BÒpi°{| š¬|]1“©ÈÄ纞Ky™©æc7„óŽ -ãZá¬. öCdò]íN˜’®À„›ÓŒnš½AY²>©€1”ŒÐSÓl†pfs’1]Q!7Q¯à:ƒœ7'iv†b]²G|½Ž˜W‘Ó»U6¾²»~6éoHåI”˜øÂÖN˜UÁbâØ4)E­#çu±(Òd96¸Xš©©M€ÔÌfÛÓM+7‰  €` 0ø+kˆž¦Á&t0Cu¼“ 5I. ¾A"2iBŽ Û¢`Õ‡(ié˜t…=¯Ò RG§2¬%cGxΤvacU¸`ç)2Ì”¶Ñq>!SS® þásâH»}º @f–™KK1¶LW'#¥štCA)1CM7 ”Äï_SÍï‚`i–¹9RA»Þ‡óïü·>=Á j·PøENÃXW<’ÆIk1¼“çcùÉÙfn*+9†3¾ü±z•´uº£*ñT8Cg²…HÅúM×Oq˜›ê’#‘"‘ªÐQŸq® ³Ndw¿Lßí—\i¶÷µ~LÔmdL£k-%È)§ÑlLìœ`<#wj´&øiñTÒÔ£ä4•±¤:á¼3gÎ1 YÔ99†òV1OMFZ_°8;«F…—2ÚÊ4ýTåL mÜÇ)j—9TêTáoÂÚP§Ôió/¸OeM1YVC׬wV 9ÁuLÁû2 –f6”-<…ô¢¹‰2¨‘¨CE˜¯B¯Óí“rÙU57®ú|2Œ» ¹é¬¬1†Øü•òá4†NnŽFL*Ë3PP ådX%çý÷šðÿþßÿËz ßÀz¶ Q±üæªY0e±PgY]“U™Tì˜üEU«W·Òk`Va»Uþ‘[QO *Ê¢2ɇQ!aò3͵˜ÝÅ’;³¼ö¶ÝUþUT9FÕŠ+Sé (O´9êMNdägÑÜËërŸáÎD·ªHÍsp!û‰‘Öít㵃´×ð!ü5Ú]/n»ù WæèêÒÞÛ¶Ÿ³«›m¿BÞ 9íº\as<†n!WÀHÌl©§ú½Ãú5CÖ?÷­Û©¹ÙO–ïê` 7{ÐBr« Åƒ9ê¿»pþmÚÏ-ö²>ÑÃ|h‹ã¶k)f•ðÞY™t&ª«vùÚ~\N.UÏEÈÊVE•\þ"P@Lá>ó»Û¡™ÊÚÞŒ[’~¸?ÖÝû Ex½T’‡oÊÛ:/TÒòþóF§Ó6a-¾‘Ù:°ªœ4avl«5cÛå'pžQ8$èB}£z‘jêIùÒX­·à¸"or.°”ÛS㻨:†‡kZŸ,׬àA! 8/šOÅ$®C”î Z)öñ›¼Pw5·5UÆÅÔhìŽZþþU¡«EdD¥˜ï‘ZL£Cã+é«Uc„ŠC†æX}a÷¢|RÞdå9{µ†Aƒ䢛à Ž)ì¼Ô¤Ô×B†5¹e ù3<næÊ«@|¬ðïc¡Ô¦ï¸IÿQÔ‡:t ´M;…J€}N<´d“W_À¡Ç²½x$Ã!šœ¸±€þz¿âõòœ‚vMBDôZ3Ø¡ð`´üqóÚ°eˆ"Öp6‡¿¡æ5Äj|F¯ÙŒ]•O†ã»é6 ¬ $p¥xÖÛBÊ ¯KZ•-hmWLž¡ÐK^»_bÒÒ#ŒOãg ›Ž+N§H·cÇV‡-^S¡ ‰`Óé˜pD ~þRãɺ׃—2Bá!pR©?3N˜:çmgám˜4°ödbÙ‘\Ïö¾ˆ¢†bkaxñ´Gåõ“RÆ&‹÷×%b\Í7]¹FGâðzÞQ‚Íö”e¶lwæ¸ÎqýJÓ>!òMô›©°’óK6Š ÛÕæ~<j€èù™" ð á[$ctç¡tYË”: 5²lœŸM,›3Kò©oDqd…'®ØtÅœ#à§Ü*©œ])/kyŽ^É™UÊjÔ‡« £Êǘ{X#š¦xS› A»NÒÐÓßár¦c.æ"OQ1±¥O48úë]/È’¦šEHÆ(¨¨¤‚Aʼšîûû¡Žà) Ü<±M‚Õ$C)¡ë@–MÝ,…VÄsŒz®„*GIß'+ ±N?&””æÒ¦¢˜#GMÓÝ:Þ§šŸŽÅ¤Èh2vÈjn›1&•#”¹.›…l2H ¬Äiób:ÍѾȗcB€/ËæÖ¦ðí@*SO}áèÌšj4T†×;Tƒ„ü<çMÀY¤x³;HµS.PòóÀ$£aîæsœñ\3[\—äÜj<£¤¹®‡Ç6ûeÞ^Ϙ¶Þ‹q3åôñ˜5þíßþ_²4í”d‰³ Ô©ƒ½,cÇ|/wk­bÌþâªÞ=€btª ±V0èt‡^k…)S!iahX\uæ”äŒ"ˆ¹ÃÂÕvîú®`öê>ÚvÍ5;j=‹+u‘º,(¢$™½r—.×v¢–QWSºÀ $Ä/ëIãª×óA¡dËŸ…ð’H#Æ”©lT+Ö*AO¨zµ¶¥ùW}Í!®„Å}©Å‡;¥µìàIwê,œ¯5¡ÙY® ÌÑA ¦Î&‰ß¤—™knb'–&—7ƒu­X@!RË•ç4¤ÌéðEá“¡“s¬Rëb"†;KŬ\}_U!5H±g«Fk©àhryeÈm±;‹¼à}úPí'ˆƒvœ?‰4nÖc¤ý96Æ?[M؉شº¨pŠ8g³@wkK»dˆ3}ŸöÈÙQäuoà¡ÑMÅUÏ5ðëeͰ@&ÉîsŘº|dƒc wÎÇ­!h3fE¸þ¹./¥p±˜„§‰~¸Ù`-š¤M·®˜ó³ÜÞA” ÿíßþyg‘+<”ü#“Ì£pÆÆƒ— ø°¬7Âe\ê3d˜œ<íŽUí7t7¢9zõÓ ÒNÓ8ú£B,Âz÷Ä‹VjÛ¾ ªùI:j£€‰’›'þÖK¹x7=Ÿ²ç¦S§X´}û/öÑõgVŸGϽþJUÖPX>‘Ϙ÷²k%s«»|ÔïÐÿPÕ=_70^„ú†ÿøIôY¢xUD77l/¦À¶­×Î|ôàa»iŽõø5¿¡Œ:×ÛñÖåŒÕÿvyÅìqJN Aƒv„bÙí¿´MÜŒ1¾!Œî!— ÏýÄX ·eþÛ4Pù]o™ÝïLñŽy«X7Œ±líšw£m~¯P5Y¹ëÄÅ‹Û mÚªsÛ,ÝuýuJ›Y‡O~(×KÃÍÔoinûyû}7I›=K(‹æðZk™¡â6Ÿ·ìÂÍšH–Bû©juœwÓ&£éí~Ú¨nÈàÛ32ýÍJÕ¯èXe¾>ØÏÿ: öA-Pøã§Bª´r®ÖRñÒ2’qמ /ƒ”Ÿ "D¸i7I_ãÊ>'ôB®W·Ùl\—d“r õ|Æ%nð%€#¨iœt‰HÕ%{†8㘤¨’a*g€ !󪉯'Sd]'ªÁÒCoEž«t Êí©Buäû¾Á ,°ƒ†CÌNPˆ y”ë`‘6Uwp†v(L3Å_uBï.“7ÔQd• pAð“"'‹NѨ‡—u×àQ°ð7Ó@]Ð+o4’ˆÁ }Ù™e‡XwÜ9Ï›0'fƒä„zLE>È©d÷I&¤PžVáLAÄ&ж»’_º‹zŽñ˜Ž·f©âë´;>Fè¦.T ]ò=H]õ·U”j¿î™iаÛ*J'¬¦C›E}Ⱥá9Y YqØ™9a@ŒÑO="Ïœ¾†<êRA» 2¬LåI6 ®‡(Ö;ÊÓß„°‚È„+:à3á(G%YFœÆ_+ñ Q/œ+3³ˆLnÂøש8æœJ@V#DÂ$É ®"'ôk›„9WT2S¤Xéû/¨á¼ÉB©ÆZFO†ÁeVh,A÷ júÿ³÷®Ë–$KR¦©K=tC3Üš;3Ü@€xÿ§±ù‘+ÜTÕÌcÅÚ™U§ê‰Ð'+÷^±"übîáö™êŽo^–ÐZ Y›R×kÙkΞECÇ$CÔY)ÂîC¤ñµ:Å„¬‘×!¸‹Ó$äIê‰BVfN1? …KC¶y°’}w8°ÎÖ¤KŒMz•yj^Òxßß‹Úë {­3ï›ÿÆßüɵšÅí%þ'‰L7`«‚Ì ,LöÍ餦åhHBåKê2.)æïãæØx´Q\dºða<-å;3A£™×hvc]cjq&Lðot«R1Ïך2°†bE¨¬¬e G|NÜW-)+ÊáYµ´ôñ[ ŽQAdRi«T§fɧNÑ•Ô\-f”6çô¿gGÎ)§lÔü\Ûܱ³c!Œb´ôñ^ 1=½ú|Ñ,‘H< gVç±±¤îx %2`™¦JÖ\to`²U¦òþ¯Å™TòÄðŽ\o´ú`@[R™ê0WäSïbz†Ö$Ž¸â®ØC•ª:ó…¤n&C°ÁÜò‰µà¬£Y©Je¨Ò"¹^P<‰¸3#í2ÃG¬u@šîœYÎtVŠ{ÇÉŽd@Ï#¡«ÜÅ;šëÆ8ÍØ‚ úÑÑT1é4üÅÇs‡„ÓbÊizÞÿÁ´6ÇÍÁçÐÍ·åäÕõ}Ì}Ÿ4ï·î°Û0UÂ׎°8$3DâYJëш9ÈÈWŒ CGý0ÉÎå ©òçñ¶¦—þ`E½4Äø™›8«×6EV‰ù¨PVÌÀßü‹¿™ç,î žÜ&ÕàoOžŠX‡1kˆÃçfæaxÓ“Ôíð{g,íƒÜïñŸï°Ã— æÖ—Sÿùß3ôqÈõ?k‹¨‚¹Ìx|[7©W¼G¿Ft$¦\é›®ó¼ëƒî~‹bÍ1ô}ÏÁtdçE›ý!·xˆ2Š7Ç4–ˆÍtè”íV~ëÀÕLÓä?õ.«<`'8_(¿ÀÔq²iÞtñÿáÙ¹žO0kÙ›åwD†1œ¾á+Î3øüA–m˜¸‡ûq3c2„ç ¤9ÇÔ·Ôß{ÆïI_¼_m„Ôñ6§ùÛÆØýƒNñî#ºó-"÷òϹY%b3–7€8ô°‚¿dyl4ƒ¨O{ñ-ß9£z²/Ã]\·õúÍ AðÉWãÍ£y(;4À{p^%F>ì—r;œ dw1¿< cñ-ºzcÇy‚Ö}?ÛÝ¢<>^å‘+ÒS9!Š?I¹Ád”GR’vߨj²î4í•RFÝ”’êÑ09XjªÈ\Î/¥cιàUq’'ëIŽ3MÝ“te)\±¢«<@Î0š¯ RhZìz¾ 5µcc5RX!)ìŒ wÙ¦Ÿ•ˆ§;¯ÂëAiÚ†Õ‡8s W×\˜£æàÄ~µ“¥©]º³©OEtE½¤·õ<« BR†Á©R(¾š%TL‡RøEõaº*üC$mËòì9ÃŃh2œp¤È¾©©\5)d¶)Û÷˜‚t%©¾ õêׂ*N ¶·–µ q¿æWŤ ]Y‹ç!o—Úʦ¢º¨œ"ƒä5„BÜA£c.]²c()ùõ?! S­TXö5¡§V×ßMÙ¡Nõßþ=Mµ,ºw-}éPî~–˜J¨âRÚi½Žt•5ôøû€ÂLÂBC "†>A˜ó‡ÐyRHQv3/kã´†|1ŠÅè8\)–¥`¥Ž¤4¤Æ^Z»hfÔåA_‚©Cv‡æ¦ä–t™LòÎ#:žŠ"¢™Ùò¸¦>²>ݪŠPeDÍÜ1êÅX0ƒSŠ­J;‡*02~¦Š•”¡Úû/{)V]SÂ9i/BÆt"KÅÐ ÀcÓ,õ BŒBHP ‘@ÖԴؘÚÑ‹_IU0CTV³=ƒ¢M¢Hij­AZݤؙ*9Ëø"­_|?[ÑÍã¶áX;‹‰”ûtibY¾a(šç´ JW^a‘Œ5†âÇhVîÀ¦¶˜“|ÿ_üÅ_¤§u8]'j"Éj sfõ6¥ìiÈ&Åv£uuЛÀ-xãÑÌ«d_¶ù¾Ið>x9c_§ô~ÒùgÓ%ýØ}Úp<°(„½ÓlÁûEš?Ð`X$í!†x¸¥£8•™G eNßf7H‡Ž¥nP§ÊHª\ÑË8®Œ¦£~J÷$©×½ËdŸ]“ÆÅÐÆî ^©ŽÕ˜pÆ”ðž¼8ö9+V±ÁY ›O)›úW3€:¦±-,' ̬Z3Ü8Ú3vå‚ tN­0.Ì6Žj–§»ÎÓÌâ厣Ä\;›>Œ ½ïËLÃqç¬9žGëÜÉÝÆòãÝ™º¥ÙœW°Z7]<Òž®{w¿Ýu¸æ‡:v§•À¥a@ª4ø‹VU¯ûÙ;BpÖ>I‡.1â>o$«,ðÍë+cã¾®˜NpÓ\¾‘ï;ýèÎ+îHúÝxÎ+Ó s» -E‘mØ;ð>ï€WœEÛïÕZ‘ôË8*–Ý|ÁŽÕxú,þ6©ÍE›‘ÈŒÑdÊ”Šƒºƒ°¯»Á=‰Œ¸Eª÷ê~½ Ã×”y芯aØÕ솛¿ü‹¿x›™|"*1«Ü ©°xÈQ¾'1:¥Bï“êü^áhǧŠGÕ:YËÌÇØÀ'YÛ隬\ hLÔ ê[¨–”=s.'€â‰âÅ]¿5|ëÖuˆ'hÜ3¥IŽìkÈûgpu‰ï“¾: 4NÇ-Mv">™7Êq§6ä÷8õÏAëéq£Cj}ù:*;½G*š È³G½#mø“§ˆçRæ÷ zv éÞ-ßåÑzH£×yNÇ@~Ò(ùɳ¢Ï ë<·Ï_Ìs0†s÷8ÒôÔFÌï)3òåñ1q«JÏԮαÅUúâ ß„¦YççÙ¸z×½ÛãávmÐì»ï¼Ã³&rýÁí{<{(l57 £ÊÓjã\ÐOÇ”>áŸi±ˆc¹À„|@%½Ûݼûè!Ö>Œk]ã*ú褮šºœÝÇÖù¼W%¼Ã*„ë\2cIÚÒŒ\¢©AÒ~ß¹ìô +H?fÃwœÂ2S-áÓA—¦Ô/£˜‰($ff’oÍ”0ÔÉ8OQÄf›6ñ›_æ`fŒ–â (V¥K !T(9\¸Ñ¥Ò•Š’9Brb<‘VÌ,‡…|ê°•8³ÏêÍ`”“á%`>T´ ð€ ·AÉÓÇ®vvª!˜ˆa im÷áã#˜C» \“K®§Ÿ[ Š¦î1™%ù=†i.ͱO«ÔxR|/jfÆdPÖú'¡r~fŽäÊ,Œï‰L¡Ÿ‹Afš*‡G¹áŸaT‚ pÑ`÷•-3;Voƒ*j]*"©î±éH‘Ïá$Œ/Jጰ1ìdA †_aÈÍz‰µÔ§~:ˆá…1·Êgè@Bñ,«ÍØú:|¸EÃ2¨¥´xÝ0l˳º¾^vË2}zds›WÕ&Ušߨ6Ók(†¨ØXÛáǯ5cPçdÖ‰amg¦´1ˆ+¾Þh3ØŒ8-–5-ê -¬ÜÞ‡íZÖw ‹¾¬vh¦¯rZ"ŸéWóVF׳P¬œø#&¬Ræ“@e5”1κ?¹Ž‡³»<›È’k³ ï{ Ý ]‚0á÷âkÆ ø Jû€±º¶æD4XHQµ³½Œ½J øZnhì¶¿iß;§*‚7 Ô•i¢5É{Øß9{%¸–+ÕÄ¢(Ì]Œ›J+Å?û@º¢+ï H–ø/þò/KƒÊLCr,L™¥ƒº›ÆuC¤há”–¦vco˜§ÔS}%N‰öwDØ,·äÂrÿ©\]_œÜðÊðƒ,¬ÞŽ¢W%s•Ú$Yv‘•4ü1Tœ2].×2ãqwkñ; hÌ£º«PÇnÁ£˜,ËyIW¢t¼›¡=Á&…³R=:äh“îq›ˆ×~d 2F ›_;ˆMõ¦Sí¶sÂQÊ(•$óE×ëèÓÍx™«ˆ[?·“ñæ£1;9{sŽŠLj¦¤’®ÈÁÏrjj[“ê‹ 6]h‰UÍ$W|ñ€àu<ˆ{º<™Ôè*at[xÛj¼nxgšëü8ÿãÆ,F3[ŸIÑÌwß Fì˜\Ò¥ï¢å4wùÞÅœŒxÛС®×k³ñ†ºSs(¸)nb fïÌrmb ¦|†øÞÇ´« ù¿Ï1í¦ý=Ǭˆ­§‡{7ôƦó’Ö—3óÛìÀ'5µ©®…Ô¨l$0ùº‚Ë^¥ èˆÛ½gˆê à+Üž_‚(BtcUyY>àŽ·®•)ûØ6O$îM;âÙ-Žl5¹>ÛN” #oL€ßÛlN;û1ÛI{ù—™·éÚ7ùÙò²8!>vm ÕûÄýG)æÏfç´x0®•C*øœ¡%Œ¼Eµ:²5dßÐ< CÚ8M/G *ï°O›±ªÒçò&·ããŒpΥߞÏû?ÞcHO¼îÜèñˆo5%-5'rå§ý™ñÛ2™91¶é7€£´dÒK‹Ña®ò£¤‡jÕ¢I0a%@‡•3Q­µ¾&E3Q2{p%ÊòŒƒ™m±Ã\i¥*…fÁq<ˆ !mì”jWêï¢[ÖÕ²)/ÕX€ ªhŸ#õ9®¸ÇãŠu…!Іˆ‰£-ð0e¾ùaFƒWV5C‰dÝt#¸3OŠò=Ð!šÑÍ=ÑY0@>³ —;û5¬Ö†5¥Æ3 )„i°ÿŽKƇ3Õ8—¦fÖüS`š`çX0]Eø_Ž B{e¥OŸçµ©U¤…û!ýí Q± ª³P“[Å~’âXF3¯„nJ“hB ª“;­w\õQ`¯„áÝ].ÍV’F†% ÎÈ#Åp9˜A3€!YýXªrçÞ ¼b”ÆX›j<ö1”‰¶—jã8Ƙ}¿Œæ²ºZö1&Åî¦ø)ø¹)%ª!D‰K÷Ê•U[½®ñ·þÖßJM¥PW¿CaŠÉ‘Ôè> åÉ0”êÏfLúæ÷´à¥².9è®u£Õ7¬ÑqKȦôól\%.Î0s¡^Ÿ½Ûc;Å­Úµ/J¤UzŽ|ÞqoÒ§—á­²¶1>7¬Gã:bKÜ•‡½a¯i¸^@ÎÆ6s÷}•û˜V=á2Iw ί'ߦPÇ4i1¯wBá V7ôëÖ÷jRrËï’¹ykªöþxô PŒŒ¥ûÄÜD\ÌŸ8Ë•Aަ¯ûØ’ŸëD}ˆ•|ÿÙÃß&0Ç~š®=£V÷j'6zw1z>òálóÅè¯;|îE<´Â›°ôv¿"´ËÎÑÄdQ˜ã}ùìU>ùø>y˜0÷ÕÊÓ-Pö±QÞ[ËÍ/μÇKÎíâ5ÓˆÎTæíµêLŠC5å²Åÿ3òz«-tï¼ë¯[S݈wˆ_ÛùÜ*¢êÇR±ªæ¯Ú`Wpô6¦“Ö<´cœ{âDy¯î8,>ï•Äh.ÊzDæ¸Ütt±"WòºhW³ Ü[bø=Bÿá›ú–Q¹G«?}ÁYf½ïU߯üJãë;Žã0wôÿÑ#ÞɸÚzwŒíoâhœ—ù Á :©0ó”ä3½ECԄʆ7ç*>¥vAd²†´”}¬ ³b…&Seþ9 œBI«‚Ø-I·:E ¡@14e¥2¡IOu%§g1ÍJSƒ6È$¬2èW Ý ‘XÙ€îú½´ÜHA «ãDsOSxȆóAÑ4°:„²©0‘ŒI½ªåP çž¦Ï!iZQ ƒ°‘žRSœ`ƒ¿4IS s%x50$´g¶#žII¤¥FÍñêêÿTÕ«°ƒM„÷išr…ÖaRáˆ)o¯ÊJ—Ä ÔÎ{’þ {ã#æcfØä †b?´,Ä3pÀJ,]íF]ž1Ù§aPºm{¤]r8 Å{,[+±%])'_¸œæEu y_¸VЦô%ñ>Ý„,+lÉ &šâœ ¤ÛHMu0_1HãúP¿¹3“ô›mÉL»æ}7€Ié<êNwZ_³‰Ð½†ØSÕ£w]üÞhí¬w7á+Ÿ “cJú4X®:-ÙäØOуó¿|ÑuŸé1Ÿòþwß}TJºƒO£)»¢‹’¸rëã:"¢bG 6^ÍüH©eîc0—lñä½Öݸ9£ˆçyÆç#Ó£¶û)âd#·Û3!á UÑPß9>¾3i»‹unkzjç'>sÛó&ÕÏ*žâ§…v4£¼1Rl润žygš§y4 ÞôŠ1WrJû[¥†¡—ûDÕïÀÒ¿¢7àT»x-M,ýÀ1ÃL2”qQÛç‘£Ôö0FБµB(Õ?}ÉŽ(@²TEéU¡x%£5áL6*å±ÊJa˜¶Æ1¿È{[¥Û¼LfE‘Ö 6!õ-C7UA¬ø–m®'›BÃt2l} 5=,Ï³Ñ¥ŽÆ±]T4-i×֊߬p·û+tÏ!&Ÿ¼2œDNÉÙØØ_ly®§…<ôŒ,d½*´Çã± piÆŠPlRêr^Ž€é>N÷ Is’ÑzQ•²ÕQLKÙœ1´Ï3 ‡ng_KB…ôÅZÌ8S·øòòÔнe­yÏûí©’ïÝOô›²•©ÊêÒÿ¢4˼ïZ“ó8Œ8CQkm/…n< 4½¸†N±wM ^f&žjKº_tØHõ·ÿJ•èæ¬‘ ž¤Ù·RÅ”Q›•S`ž­9¶œ }ˆnT8åkâ2Ƙä”eù.N÷ÆI5"p‹¸yÛ¨9D¯ÓGã«xÕØÊƒ ÷ÐO× i/çM7• ®A¥&“ÇM<=|hç¹ÍÐIÕ£*´»1S÷qHœ,ƺvÏx6ëjK‡îT‘r§Ð é)¿ˆlÈÙw+›óðŒØyÊW”×Z;{¢þ`ad¹æn8¨û¥Q®€ÅÎ ¿ÚѤ„‡† œp C8:”x‚–ÄˆÓ Šdƒù%ãC8¨Ñ°yY7u³˜Ûbú¤¿6٫Ѽ9Þ°,p†…¡ÓÔŠ/šì¹Z£?ÞýÛ@óöùñ&{'•¹y¬Çh 8aÌ4þh!œÏˆ½aé÷¿k¾Ô8="o=Àqí¨A*ÃE&3K¦ït,GRË6À£‰¯ÍÙv÷n˜gkMǨSMʃCßu4¨£d-q0ˆcé!Î3&Õæíˆ>¥îa¡{Ó™"4•À;´ù†­›{¿ö1ÝìÚØ@Qm{3vaU%.³,,ŠÓúÿ&ã¯þê¯ò lvPn:‰¸(ÚCÉò7>sO`Œwº!š.ôw7âoÆŒ:r4+.¥-j#·™÷›”åÛl[ý‚ã-rBžyi ¿Bõ┾ ÀÎò^>.äo;H…$>U;ygwl§6½Œt°¾hòuV“t ²½g“¯AAf4ùÂ~Á̧Ê0“PÎïÁäë(6jï &_œ’ŸÕºžš|©‡R>Vc¹3ùŠÖ7oL¾îx>4ùz¢×âñþ½É—+$ÆA”mÞ+á hZØøÚR³Ñùᯘ|ù/DG‹³Ôöý[X gyÔp3ñ'hñ5šçÇ‘v 3˜HÎ¥cÒnkø^ý«íKø%è¹ÈßÍêaµ¡õy<„šé"yACÊAnʉý»]RnŽíoÔ0üÎ ÃÞ*†¨ +=Å„>¤ï@¦C •Ÿ+lŽrp(ÊhCIÛËiÜ[vËå(CžiV½šdì Íy¡qHQ³Uø J× YünEk ¿+±Z))P‰Ò‚¦÷‘Žñ(êÓô„V!ã>à”l¦)°$5$hÓÎ*H ³ÞU¡›¦ Þ.%‘:¶«Z­· JUw ˆ²K°é™£X—ùMB &‚î‰ñ1KÑ,¼ó-ÌYÝîiƒºdņ¬˜Ú'áÊ;[¦%ÉÔŒQ8Íž¢v¢©÷hi_¥0ª`EÃØÀÇlè1“x…†HìSR¬!Ä-5SõÚä#ÂÔç"¡H†a7ß²F©ˆ’âR)½ÿdü Þf Ê ÂÁ ˜šj#@h©ñJõ_™'2è¡N]"2à´µÅÂôvAåF¦¨“ TƒÔ^ÿŸÒÒ»æTŠ–v¤P(Q™cf0Ù„êš§òáls,ÃÔ‘Ï#æ'ÛÑ^Y]ÝÇÝ®ÆHÂe,ÑdÚ#/_‹WòƹWÀ³âŠ)&=÷×Y ‡Öžô¨ŸŒQ¥¨a2â‘F¤hF«A¥QÃSU| ž¯á&³02ŠŒ‹ÉhŠomÚ0¢¦êÆ~D*#š R,|*}¯îÑÜsZÐP¨*] NMùHÿ7e|ûË+˪èh½«Jl€%‚0D´Ý‚˜YûPSVD7¯Þ‰ ›‚i”9r Êdû+Lªj†`%$Ö`Z ¢+U%WNðSçYßfAÖRn¨-ʱVH?c=<\ŸéF„zú°»ê¯þÎßÉï69Á!µ³ÉÉ=”–ð»I»ÊAB¾OËM )îéöFˆã”´ùPÈ©c:©È›˜+ŽFu݈脥ûÊñãß)E¢îÚNs8l©ë÷Ê-SºØSÉCúô`F×4„z  6ܯÝ'.ߨÆOcLN™ :í¸$mOÈÊé~¸ý7ʇ,ÔréCÄ Ìåj1ÊÉÝœÑ4nÞa obÊ4±]-Ë}8'¿Ð>†'%§BŒÉíˆ×L&“ƒ /GêòÈDÚË×g/Ôg„×2¼¾‡Ú$lLÍТlè„zÍh6hÓö¼ÅÐs¨ð¯^ ²bTÜn «óâw…™Îõ… Ÿ·â:Äygä‡Ð¸Vï˜SR¼Z¼æUÏTio,z@‹¼“o—dÕÃýΖ~ Ñ¯Š°ô#ïLú& ˆÀB×±Aoœ–»ôn¢,ÇTµ ׫ÅÏ!Ñ…U°æþFtR¢yŒ,»éºî ±ý» ýK¼Dt^hŽ9­Ýy¿ž±µ}‹xQ{Ïž\Í¿b Z°þúéëaá Ó?Šû£ýý÷¾š±âEñõyYƽf>ÑBÉ·1`? SUHØ&|eúÒeÁ`æÇ†4Ɉʅ¥â-éˆÌUT”9œ0Vz*Eñfäü<¢ú0(ulDÀ6T–ÎBDŠÐ2¥!†u2J=#k»ð03Ðc«ògNT}¤Ô68…Y)>±TäÉ ³ýK4ƒ´ä±ÁæŠiòuê{;kjTMe+QÅŠ[A‚¾³él&È;]öü¼@7¬f…µmÃ,›©Ô ô%‚`¸ X=tz*›¦”£±­’&÷ÑÛ­¥Ê3%-œ6–ì«cýI¨Êر"†VÅ‘"©¨ïb„²1¥¥é3;.#Âp-CÛMAõ”[q¡œ¶ò‚]ä·SÝ´6O­í¸”MÒŒèèf~ÁéõêÁp–¶Ø¿Œâ„2‡¥âùäÑŒS¯ëd”9§P¯ÉÐoBÔŒd䪔†˜8…Áòcd2çè*!Ç1)EÔähzÝL’áŸn:CƒRX Y|ƒPD¡‚¤¦”¢šgÒ°¹a¿*.—ç£u”TÁ¾õ«„%)HÕZ”ajTis )FžQ«Âc ›²—|V,”¹ÚM ƒÃÔ)¹wC øWâµ¢Ú˜÷z—⼇^Ã8´_ù°¯èiRû¡ÓwU¨ CÚh•è8¼`!y_‹¤F}˜©sE¬sx¡ÙkÏ¡hñ…ksÎ6Ÿ0q%'ܘR,AVbäümîdRM­µ“É2:u½Î´ ;¯ÇrØÊh UüðXØõÄn^icÅôú”.ä2CMÛ\JÅt·r—Ø~v” NÝç©‚] .X#Â]ûN))ä=âv‰ÿëïü_Y™Êç ·)ž§(ÊS*ëD®Ü\$ãA*êÖ gxÎ[…‰s3 ÄÓƒß@abÂNŽ©´ˆ·.X7Š"'ø$ uÁp³âгÿz¦0ñ~¼½UÈŽü=­îÆN¨ÂކaÓØüdÊÍjm³’Ûà ðdS_Þ¡‘ó—ê?Ï\ðât…)Y/ÚOòýš:›°eƒ2àÐPi/ÝGFêvBïË{lâì±pö#¼ñ¼ço׈<{&õ…YÆg“ý„™˜‚ß;Žñ½`a²ê&b©ã/†Eî¨ZÕm,ÕÀ3Ó°ó¼˜Ö‹u4öÈÿæS¶6rþâ§&¿ýnöv(Ñ5ãvèʗ탑X|I‰rZHÒúmT<­Õw,® Ãcàt™IÙoºç3’vÛŽê}3–{?ï³X±º'äÎÙ:š‘o Š«ÿÃ#LGÙ|Ü¥Ô ;½Ex»iòÔÞy؇?€¹Ú¿®°·LÏë€sxÓKANZðCöu”)F“ÔçS²u½m­á­ñ˜Î‚iú÷B'ìô7œ¬Ž®,Iê[èõ@ËSO«R‡=ý9ɼ®¹bðÁÀPto)ÊVÚ¼”Q™Z Ò„mó­úßñ‹ÕÉ&ú!Œ¤˜ô¦{ ¹ã:i¾µôЇÁæ?Κ)e ^$E–"ÇŠŒ©kðÌ)ÆìÖ\¸iõ4™°´~‡§(Ø’ç6n‡³ô/¸Xx ^7abð˜Ãqåˆ{¬†›Œ\];ª²¬¨TÏ•§”õú†=¬èík`P÷¹vŒ]=KÕ˜¶Ê‘€Y½W€eÔê#þÓ¡µ`1$æy)qiudk Æq â%…61A`9îèÜE¸ÐCÆEøgm‚Â<­®¿/‹£C<ÄëÕH°µ‚3Dº€cf¨^žýP“èÖF‰à¸u¨‡ÏHäÑzŒ'|ôlÒ‹Šn„îahëºÁÁšßSkF®×´JÈ,üÕÏ­á,ÔëC‹O¨×¼¶Mëµ¢ !™GŽ–ã^dRD5¦ØD'Ø« kЍCÑ÷´M´_š)Xˆæùák’àí“£ìkð(üyl¾5;&(31í³Çø¥HØ¿Ó;pÀ,Ô×cEó„»I²(³˜ ÷Ë´À¡NÓa„‚ë9~QAõ’ÝܦW©"€.éšÒ):­¹%<ë4nÜòz9ÜÅêô†)ï×}$!èFòu Io}ØŸC–‰¨2šb$}irˆiºåPƒ•µX°Ù¹ÙBzÛVÑäN®ÓÍ\ާØéÞ ]#¹d)èSéá ¥Ø^ìØÃEXûßR …¦×wö•H¤ÀÝ:µr¾ øf ¬reʼnWgªš|! 9àôb¶“ŒJצ(ÁÑ÷©_ÚF”Ôâ‚Õk²je×׿ܩõ«ð¿PE”"+E½‘*9%¦3+6 J×ô… ƒes÷-¾·$|RŸ¶J¬ÐÔÛ6+ŠñuN4܉"LcÂwA+?$IÕ gÍG¾F¦Î›í)‹~˜¼¸K6ÒÚr2ŽË 󲩓׭÷î§÷×$yVq©ùˆ¦Ÿ½ñʺqAþõÜÍU™¤‰¹`:]¹.“žÓbôå£sY]±'ù:)ž‘ ôbÛä8M2ž„b aº—J™ê0±— XHÄŠd·ºØKÕíš CUµK  R ™êf¿q‰LËL]Eº4ªX˜µ2¢y²nE¼â7©{%ÈÐq{"€ qyü&©vAõ0dÝ=#Ø$8³ÌÈöJG†y¢ÙM‚šã¹Lë£J$Tô"3F?¯I8ÑG;sB™ZãhÜÈ#¤ (|ž©f6¼NgÃÎoë°z—jÖøš„»5/6“EMv°çX Îe“ãeüëZF6Ãç1ö¾¯”F]ž—äqqí½*>º’å–*–MBì8ž‹“ilÂ…,³Œ5O6ûIq‘Ö•½/2YxÙc;Ua†Gà$̾íµÄŸ zT7s¸ ª_÷Ê.{ sþ0ÇÏ ÷)‚<Xio·ãßý»7éùQü¢9^½:pÂŒ¬ÒéìÂtµLå |s“^»O÷Ý98~úLO8Œf[(r‘òhõÑ=¾ö^ùãWJïY ¯§÷YEçö°÷ vô.½6 {øe96 ±GÆwO”¯¤÷Ÿµõ}\9_æ^íÓ&ýJzÿþjqû<Ÿ¤÷Ÿ|ëdtzn«czb<Èèo‘Þo 1á"Aw’vž¢XOB~ngs´5‹^(ckV_‹x«GxsïÝTï8Ñ»ˆß)ž=$“6²6Ĭ·Œ˜'ÛŒ¾¦ß4>Øf¤e|ï6ãé¤ßt›qêCa?ŠÃ½Q>ØÝn7¸p6a±ãva81 :gÏ}?Äчkåí*:íÅS_Lf¶‚Þ¸…>„£ÕìÙÃÓbÔØ•‹c”`-Õ°G“C➬²b8¦ôBÒúh)Áΰê@¥Â'¦{Tà€ ´¼£kgsÑMSf°‚#ihšŒ“`’ñÂPX4pFÛñY0‡~SH‚å3ýèÊ+Üáž!·mÌFSªB§üh ô¸,žæYqK}˜ŠšcÀßÔbÃ$ UŽ›@!Qfš–ºˆ¦ˆ+­¹xa•>\S‘­Äek!Çȸ0Õ. $—L? ë ®Ë|&%ÇÓ†ËЧì¾W7‰²"ô`u34½™ÇK>™!D±؃J—­¡0¶ qÚÿ 1sÔð¸ºEG)Ð?àHRï{/Lá e›Úb¹J0Ö„n¨û„eß©ÞcKNß±tre4÷! L[Æ`8M ÷½@<Æ=§à¶Q¨Ú¾w`TGÓ=´+Ÿ xþaŸò‹h!³ÊòF–b§3+Åæ-•ÒÑt4½Y]Hi±³"T™Ë¡ŠÅܸ%‰§)ÖCgå+K)Éë9BýOåMªt¢%¤öNÐ[´¾¿”ƒÎ¯$ )åØS„e˜’zÝŠ!„(`dÆüT „B$¡¬¤‘û•™¢x¤P–ɉ\R§i‡ƒlª5ú„  ©ª%œ²h8]³;!ä „ÏÕé{)L§1¶y¼0w„îÇÁÊ…•ÔÉ9†§Óia 7î0ëu¹•Õ(©JÉj,õ²üJ™Ç´ ÌöÉP¥hwº÷ºñdœ«ŒK½,;‚e)Ý‚˜p9ÓbE4Ê‚Åi¯ÀãH m3˜a¸`*œ@§Ý übÒÏì{Ò4¼ÍÓ€”HOb7öyƒŒîV½‘rF¾çœPäÄí\6eì„ÏéÔ4>¡ GO ýÛØ`n=žVZ½Ñ\Ʊñ'?Œ]‡šÁßQÓƒøñLE'{}¦¤lã(ê°”Û½x¯m;þ³]<Ç_ŠSì7pÅ,„¬Ïè4S©G‰ÇA*’ŒÌ¥à2»gŠJ”õI ÔëÙE»£¡X x¬¦Ž1aW„E¢gò˜Sã„oÁNEyK2X݈_ÃÍ ã¡µ˜ñ3Áhßîòsê©Ã1œF\š‹‰Ì@pm¿íE¾°öѱÏ>¶MA¢!CŒ–D†Æz*Ž%Ãä%"+Ö'ÇŽ{…r¼G³žï3àgÄâN투Xp²‡×ÞC«*Õ^£ a=Q„¾³ªï&„„„&áŸæ]äß1ÄbÜPÛr¯›"íx ´4gô—–Ößû{/ïÒ~_ÉP O}éÔ_¿Í7Æ[áçß|k„qȇ}xÿñ–iy›Ÿ| ßæØ¾»?èþ5°_c¬>y¶cšö̈q(|dz~‰ Œ¸boêôE_šr“ÑÜÉ,ñ íù$ÍÿækÞ/_ãîŒGï‚Ñd–wËJ¼½µw…x¸ˆLŽ`7ß÷8Ð>U¿ 1Ÿü(ìŒÈæ÷®A¾RDÌîiCw}•ø»}öŸcôçý½Ñw­úÄúàN¾ˆWd3"½Æ>[Ÿí¾§ß]'²Ö‘¸ çÔ€Î)4Ü)o8è¼[Ú¼!n?¤’½êžðGÇbD)!´XÎSE{¢æOšKô~ž&kf€SzS3 jd-5z\ª†CO©.º–ALé+äó³êSýÇR|“Ô)e ¨þ6LÅ¡ëLÄ€RL¨XŒ=o7(³ñ·ï˜P”@i¿EX}‡¼w¥0ï‰ *Û“O¿{¥f1´Gc™–jÑcrÒ‚Ibl‹a>p‹¹' Ñgu´r{8NÆKÑURd,UûòXi–j3Ê”Ж¤ªùN mZ[á±¢ŠÒ5è)®(5Ħ²çq­o4–.ËCLÝØÀ1xts4ÅS½ÿ–õæ|û4oYoÁñØÉ{¯ã«¬ò†aÜÆ¡ :š‰Rc&¯iÏH)-Ï*ko™ú]P‚Q n{ x¼¬q ­­ }Y§5bé}`Ÿ’yWó^]92\ynèWÀW¥Ê¥/ö(ÒW7kDmrŠÄ{Ù~Â-3×Ã5bŠ^Û Ð•2÷^cV› BѰùó!&Öï׈Ðw¥/0ž´:bÏãr¼èÝA{(ŠÇ¶ÕL=ПuTË„­KzCû1dÍUQÑp²¶ÕA(ÂãÛGzÃÆÚð‹ñ»‰¤Ê jNuɪ¾—£ó …Œ+ÅÕmÌÅ»a'œD§„ÈÎt´vW¯0~D÷Ÿú’«®Êý¤JƒÁÓa(u*°N”‘•¸ƃ\õë³|´`IW›å6꺌Òįiq_cCô y~UCЦ§?f=JÝïk“2 L=B ð}&´¹‚©!ezoLIÔrcÜA@š¿)Nèl¥öÎ3®@ ž¤ÎµŸƒõoHñjz‰ËÔ"I5ÈëZ¶:Z°âcu=™à㥩s Í|‰?žìÝe*+±‘€j[sŠ_0Séäî#ã¼2+ÓÁ0ê,>Æ}u«Dšâ$C¿qU((?ãñΛ±¤ìè¥VÄ‚dÔÏŒ—DÑA- 1~’Aén;Þ_W£B$}¡Æl¤”ç›"Š\º4 õ1¬v#*V×Ѫ‘ õÛ`ÜRÅ• †ìå’Ž¨BaâBÙjNR÷b£V¥×R»Hqî5N¶:Cz‰ž„säV­N7òYÊ>z,­8qÖ4S;‰%É/0'á.´J›"inÆÆŽ3Tih+>G멦£ZÜ]‘ ]Ë¿!!hãÏ}gJMˆ6‚0À<2«ìe–¡0]÷™`Ÿ©±2®4Çt]]“×CQÑÒ=cD¼FL‡r)ÝeX"ÅV3Ý$5”ö=Úî? ([õÍçT•Íp‹@VÓÃ6YÞã;oAU3Z&†G îÌ?¼Ç$nv£Í®þ$žAA{9èš“¤öÆ5E<î p¿ëѪÒÔÄ"‚ gCTÛZÍ{IA»º[)L¾æÀßÿû?ã7ûó+å‰~~uBèÓdÝSì3ßU#Ço8´~­ñúœí£”8~̃|Î'†Ïó{úšøÝ´ïý¥_ão¥y>CF~Ìí} Òóá#ýêãå´F}e^=Q™ûS6Á÷Ñá_–üM†Ê3„óO° ý†~jƒßnÌ}?ªö~=þ~úɤ~æðý©°åw ì›ßo#MI®þÒEˆ\5Æ49@ÆJ”Ai/U‚a˜¼sZ~ã°† ¹4ÌL}AÂÄSL&ÌÔÈ CÕQ¥R¥)!j0•¤½¬½­PËU³à$›œT,R`š¹L¨¡Ð±/pótý¿€Ž)Ì9^;E>ŽÝìnL9¹á–# _ãÅÁ@S›1Þ`¸G7ŒJŸšË•;ldÃen*8b^‡ÕÚC‘V÷éªa%0·ä÷;ö†©jŠ#8Úá ¥ÒÙ§8X%õñåŠ*¤ÎÓ—¦öÔ‡XYÃé²ÅQíFm Ÿš”·V˜©æTÙ`¨LáfÖbjÏ£Ù_“œY¸_W4c $š™²bÂ'ÃÂa-h’þmVÍÃ`xêíƒáÜV‚oÈ„CèÅjŸ37ëÝÔ>Í´Œ•t0/ÑÓªÔÃâ`í0Æ536õß=‡CfUŠa¯0ʃi¼1,\î&4Ñž1(ý™Úå0 €GLžï³pZB†=ÄŒgŽP"»Ã¨¼5ŽÑ[uCX5éc!6ÀM?'ÑÐ=ío{È×ëL˜ò M£…“ÕL½I–ø>ûÞdÆœýB„²a[mÏfû…a¸èæÐ˜%¸š° ÚU\øºõ_¶²»µ]¿˜…Ie¤(Œ4…“ëî u 2…j)3®¦gå-:…a4GEs(5Om.Æ¡ØÁôjVi§C¿2ɤÀâ²Ü¿¤hðí4å•Ý®dÖÂý ÷È&Tlôè˜HI‡Òúðã¬`UjK3b$w®­D‘Œ… Œ£¦#Åú¢ù ½•bZÈè§üö»É›P†÷K}QJiêR7õŒq¦€ï‰UÛ «˜ …’iŽ_€6ݼR›zÊRFc¡j*Qé`N_ó ÉF†X½dˆä’¬@•¶Ù6#/3)ãÀš¡›÷òå yÒ9)nì±Í†kÜ>Q*1AC€USTm,XÿÎÄ]4HU¡‰h&|Á*Áæ¤ef8¾»½ƒ1IÓmUcl‹ T+”zØ8k”áfÛ\Izû‰ÆêXQi«ó‘zWÀ‹+}†©ˆ‹×øgjðr´bà wÊfüŠJèÂCˆnŽºÕ‹ ê¥Å+ ¾æQ¯y¬xÁ„ w QŒ›2ÁvRžELÂÔ ¥ÚˆÑ”LÆ‘R±°é`Ôîô,¤ãDÑ1BÖÉ=>È‘ç«}!Ué’UìÜ5þMªöò5)Éœ‚5&,Nǰaä—Ôi I¤¾ÌYr:ô ŸI+“"ÛÅ-ó‰÷Ua/!Û§r›šÆ¨°EoëºÈ‡ÒɈRZÜB©i¦×v’Hö©RjM_V»Ãù?Ô'Éma5¤´8$¿„ÈÖJ†êùtäáuĘ… úºë‚&úšíå¼bPÃ1[M±\CÔ×Þ"ÐL•/n@Ü|\ø¥…UÑx#ÿàüƒ´­ËøŸ¿ÉŸøÛý{¾ßñÕ?üvn.¨?ºû¯ßc£ÿ¶÷é·}Þ·_yžFõ¿¹¤ø¸þ>›ž%WÿTS,nŸ·ÁorÇv®‘¿ÓéóC.ÿô"·¿÷k-H?êzô³qù;\`O1çWŸ/ß±À>¿·Oúï÷±ïø]þùõØ_áþ~­Eà×}² ?+ÂMÕÜ¡Hòt¦§ŠßL)e1êf*žX!ÏB`@BÓC°b,É8 ¨“f¯Ìô •zŽè(Ò°+ÊA¹áÿs¢_*Qy›‡žî7ŒjP?é÷o`Ðï=#0˜JÁssb(ÆgiPcK;»I SŸ¢™Û4µ 3‹;BI–‘i†wÇ18v†UáýY)ÒôVÀ¡?kìýݾÃOœ]…Âñ±â˜®7=Q6ÕJ S|¢4}ê˜iHÔ¢dúŒŽlPÑ6F´'4£…¸vz„ƒ¨ºÐ¸JnJe.×ôÿÓÑ_àq í+OÑ#zßv¦KN©šš–ÇÂ#^ç1†¥¹jÓ4CùÞ4žSDâV3KÅHÚý_­™#Ñ|x}cã<7¶óþ`D©±(šª[?×¶Ö!÷Ìe°}íâSvšhkŸc%Ú‰Ž>ÕŒB±ã0ÜèS„z%„­e¨lÂѬ‡˜¢£n@C>[;„÷!“uµnúisC÷€8[,Ÿç`¡JD“ú§»# ˜ñSlFËL1l/÷˜"Xõñ ¦8Ïàö€?êŒ)æ€)&ï!ã Ây(Ó‡=? ÇM `5;KW½ësÔq*˜I úTÖŠ_>/})Á0a“ W­ Å!ÛþTûöiÕF6‚†a\jI›ÓoéÔl†m2Ø<õ[(^¿wi'Ò7ƒÈÔm©oˆR ©HžÏÒÞn¶7½’AR÷©#ŠR¡ã[Wš|#%©L)˜ã9%  ñBÁ^]Å(CX9!‹*Є³yÒ6N»P¤8˜@Eˆ¡à·~>0…¢äÀX¥Î¹Aêä€mU¿Ï°ßô•ý……ú,¡–A¥‚¢“*o0¦‘„˜™êJ j‘lJùBó³À ¤æQ‘j;¾”@XjªÞ5:IÀã?_ø…ã*z{i&RŠIf»ÛŒ¥˜~Òùá²¾ÛÕ&’¬¥B iN”™cþ•j ©³Iÿ`£4)…@-#îsCB“U› UcÔÔ0¢Âe}_æ‡õýûظO)LW>äçògH$˜_š‘ç0v¼W\y9¶W­˜¦Pú<.3#h,lLÖ$Ø¨šƒ¦ ´úÒ]_† û b¶—ÈÔ€n}²V-¶¹Ø«KV:·<)ÕùØÉù¨IÔÌjLµ¥ô~K=À ãµ ›¬¢~hŠšo‡jÑÉTN)Cç45%tD?öÚ€ÔC¨­tFj€2‹Ø›Bå©$ae¢J dvlB*2’ºÖî)h(º¢> Ô òûbö(o~f^jÎÑ÷4M}“÷8ff Á„!cy›‡j| Ø¢fã” K£)0á #[™ßÐ54MýJ0/+Ð¥°[äpˆƒVŽ+»DR‡äuULžÿá_ÿÃ…)Y@ÆhbV¤Ã>ðéРpl —ò=M‘ìšÙiž}*+Jc–ºÖ T*’C[œ32›‚ŠjIK«+–Є·ø9¡™=õ€@¸Ó‹ÌŸ„šob2±ò¹íW%£FÀ§œvÒÕŠ^᨜a@äÔ®ðqd†dÚTtM¹ÇÍe\˜zG¿ôdº§Ä_휀þdiIŽ£`Ü7äà2 3Q¶¸õˆ‚‚Û-ÏnÖ©èKÄÍ„˜b“ µÖ¦Œóæl~F }¦éT¦°l¸/º¸Ÿàw醓n˜hkR)ô…ÚïT|“\K° C``1“îÉc3ºJLÇ»õûáùÈþozE ŠÍ¼çâýdoËJè¢{{5%6.ðqޱQT¶‹…Aó +(gÔÆGËàë¾ßL §?ÙówþÉ騳N{W±IR[:{Oœ~tkm`8ýÛ]ëêw›Âuß©©Ê¦ž)Fžnpt| C7…!‰—¡à…lÍÚãٕƆ;ë–÷§»…þ·´ô~6(6£+ØM?}ǹû“¾Ìx4zOD©ã¹Ò`Fºe×6 =·Ñ‹_kEæ(7ýnb÷q“¢œÇkU»7¤˜ Öá›O©leÒvæ¹7X Å*œža/‘·³3t}æ¿¶qÅ(sR“ÞÍhÒÀ}R“ÖpÒÃí N —ýƒOm ºêÊ!‚¤¡½1ô™ M1ÄÛoÖûÔ/eǤNλ“¶¯ò>èÑáIäçß›Úâfxx§XÏm°Ž{ n`™çèës33$•6‹+i/nnn;¯FSž¿”ØÀnnjǥÞGfRî©ûK?6Mª*ŠºUuOM*¢²gëÆ÷ÿú¯ÿ:[z…S/—³ö]~ø“|kÄAl«Øø|K¾ðÂð6ןò>=My“uº¹ž~;¢‹®ÅX¤tqƒ§{ºxÄȰ˜7ýó>!öQJrK'>ízJ+޹ðÞñç^êŒò»tò4Æ?'B@’¥¢>L?oƒ¿š´{ÐF"ó9bu"ï¿+ŽøÂÔã8Ÿœ+jš¬7—ød^Ocäì&ÓZýÈSÀƒ{{X ÞÅ€ãfòQž¼ï}ÆSº¼‰qCú:07g4­õ|ó,6ÆÙ~Õç±~Δ¹Uºœ‡œ‘¯§ÛñðS‚ÅÏát$XpˆA'‡8ÂÍ?¼GÐÞ 2]?bóùùâ-ãY²¾ùˆñ¼¢9~1Ýñ´Õ°Ï|*8ö%Ü9ú `û·Rðu@lýðsD§·“»ùï}5Åi’·?͢ωÉÓÈüDGòf?÷Z‹bÜŒáž1¦yï0­­ºI¯ ’Oô‡è(`ľÂùgïË|õª"DJM"²ý!P)OŶTåj+O¸" #h¦Dè L7”‚œ”!ÄA°7•c³³lÕú¢‘<ùÆ‘ÒHi¼WVÆÍl6i>IJSç(ešýÑ]jië} •äÃR/mƒ§õgæ 8×V﯂T܃áPÉÌHÛÀ6âªQƒùŸöÂÐ5ˆ q¡ÊCS|P„F°$V+IXúj<Ù=:Œ‘Èo/‡¢¬b)I€„;ÐÒä8?ºÒ((BfÖgªÀ½ì:‰ EIUŠºNýM½FP»]€|Qm%ޤß§PPi O+á 5³*Fí(.WSè¤ùaЫgy=£ÎKÃ'*õIá*2Fn­Cf<9_óß ð®[±bú \§#uˆLšº¨HvP äù”)kJJ#Úé>r÷}iÞ^F‡5½-êÓða€ý|²ay ÍÒ¹=.üeŸÐ$È~\×NÆ ?6†Au«NÂa¾Ž0÷ xUªŸ¥ÎJY¯X€ÁøÍÑÅ‘r¼ÆUªŠ„õ2ö¢šŠAíi¨\ˆâÏó´õFÐLóÝ);fxœF­½ "oFs€Êáø)h ÖùÀñV!¦áåCL3ÄÜ uÄ.Jl†'Å@~9ƒ«ƒ1î—8Xúf32•5•õÌé\²,̓]ÃUÉ_F6hëún¾n3=lÒˆêstRÚãIÚoPºì/Š¢f ïÙ E‚…:.?-t]-ëÙ0ð4õ8´Rí©Fí&`“{m¢2ƈÀ?úGÿ(;C4g{Z.,I7&y¢˜•žº ™¦º\ñdNN Ût(Ô¶hà¿Þ@Mhs`ƒr0=Ò4àç)KÊÌÎÑS}¸á(Ò”J†OÀ=I®aÊïpÇðæ|>™åÅž’„+Ý=Å ‹™îï`k™l†g­uÂ ÒæFXºÇÙp󜧔ý³qøîwˆ•)F>ŸZjÚæò1%ßrîmù{<‚O¤id´µÄÁã5@‡Óãëv>Ê8IEØð¾/f$%šdÜ1V=Ž[CNà»çÎ3ï‘ÒÛ3xœ CÚé;Nâ}D›ÇçiŽíô?eì$ã ýéqz^Ü%ÎsFÔ;·¼AD"Ž\àz4†ÖèJuq€S÷<ÚCl›×cCÒžåÃz65Šyû¿öÞ®û »ùä_7£Fx{CdzxÂ+‡­¤øŒë= UúÕ§Øy?¾Î!ëDÝ÷ôiÌŒûзú)ÎóôÉJâóééÝ<ÒËx}Ť_FDt¿ ˯«ÕU×ð›WúåuXòf¾øjï=C¾ý;ºÆ<ôÜäÛ¿Ñs =×bJõTS'̧K¤ñÜ7 LÖúà[1Hw# ܲ‡ÓKú®ÓŽÞ<îmqÄ…\÷à[ÑÏhöﯨ ÆëATŸîaÙÛ¹ëŽcò¡˜D–e3^ß¿éìÖ›‡M 9–Ìñ1‚á$PÆó4Çèdh¡{kÜ<È5ßV?ç¨vÇŠiÊ´aˆh5e˜úÚlõyÀ9ˆkêËu_íº0ÄœŠŠ_ƒ:9m²6Wû¸™^LºæÑjªï—dÁš$N'ˆ1%4Ôkü öË`ð·yýß…v†èÅòSà8‡z>g~"ìH¿†£åÂ_Q_ã—fÑæRH|Ç(æÑôLN \0_îAÀ£yµþîÙÉc©ìà½ãù;÷ŸšÉØk*wñ3¿VŒ}­Ù|oëŽ×<é_C“¨Å!hLr7¯Õ[M(aQì×sÀÖ_ V6WÌÑ]Ò8Öa‘óJ+û§Àp_=&N§Ûkð€!Žëã«ßB×=_š/ÕË»ç ÝÏ:¤œ__ˆÁPc ’ï_§urÚÕÜV(Û"º/Ëâý0w3¬!ëu}ÏÒq¾LȺèaˆƒ*ŠÍ;n^ã§Þô6€ìàp³ÏâaùËF°’h.7ü‹*‚ݾ¨ñ‹9»|C¶M<{QØä¾Þ¾ög-ŸÂEßßþ…4—÷!.¿¾×}Š. ÿ.qx±}6ê¹"õ”áB­ EääíauH|X]…“CÁ»ù´BÐW¾"™­X.Mz:¬ÊfD•‚ìÓi: w]ü4Møþ».gìl¡Y8õøð}·2ãr†$'g± R7FB5"ãÏž/y—†xiª'3“¤.ØDQ—ê7Ò67,iåFwϲ‚;o?9yÝ{rª?Jõ&I3žuÁ©}®gص\!Gc—üuhžËA~„.x±[nýóšSOÖQcÍ^úålÛ‹)£ \ó•Ù"_.ÐòØÈˆ^†™|:í™ÂÔÓÁWŸpmœ$C“ï'·Ÿ’xЇQò³g]¿ÍqÖ§§Ìn…PÆm(¶Ü}Z˜š¥×Ï>Û µ4ð¶×× ¾â´f¡jOWüÌúŒZ4ÔwH…È#f£< Íj§Ë7`Ï5³uTPf>M¸R7)É­ÒáÏv0’â°”:¿‚ý|ÆñÓ–ß(Ϩµ;é¡YC=Ê¿æê-’¦z€¥ ¼.g¦Vš_cÕ ©€àÄÛö‘⬈îg­œY@ã†ü5túBÿ²Ó°ßIª Öl}5xÂÑYc}+åbì7¢™G"²Æ0×[±7„Ç&AÑvTFàꋊ/!kSM‰$Ï´ÔŒ‹ç¥ržçjॗ«;R û5ûʵRZ|Ÿ4O@s·æäþÀ¼W ÷})ÿ»«è{Ç´Kp"Ó ® ß#S†¿ÆN¦Ô]^iµ†S¬‘µZE“’Æé·½´£mIû Þ7Z Bò‹d¿“ Áëv’y²Û€êhÿ[ZˆOÛ[ø~Œ>þñ?þÇy+Lp/ZðÊóæZ ð.;÷\yáñíÜ%¶¿N"SþOT}ÞÝ«îÜå?o“wBYGœâC•’÷0²€Ï¨›÷UÕc:û–ñxÞoÊâD§¯¿†é<‰O†OÛùGMèÇ8¦ÇFòò}\¸ãë¾3€ø‡5‰;Ý›¯7ò“ñó£âî÷·^­Œù'ühݹAÅz+]‡>¶çèyœä–âÃø†¦’ïðÒO;šFæ›ö5²ùÇ|:Z¦ë~´·ùÊÀt£OõMH=výÔÉÇñï60îîëÃúþ$àbÓ›%òíÓÜàYïïñ{‚ÕÝþ­oºžÆªG{Ø7û«g·û`n 1j—{Šþ”QA(êÒ3ÞhH€'m¹îÃu¼ØÜÒÅc¡füÿöl]¥#ÝÝs~~ÏJ\ã ˆ#î!½/T»RŽCBkH[›wb&$ÂHˆÉ3¢¥óGLàõK 1â3ÀaÅÉ‹ íê¸Õ³¤„Ñ€e}fÅ¡Þ~˜þù•^;ìE•> Ëso k~ÈøØ-Ì[„\sw¡‰G˜žù„ Øb sOUÃ>¼{_¡faDø÷ט 7ˆ ‰²æf½0ÔÏÎxòWOºÆHÇ”ŽâœÆj­vš£þ}èXÂìÑýjí=!:1ør1„ä¸q’¾]1eç’\œÇ]3ª®y¾l€cÎ{ ü@/zIÁCW—î¿.cx?N%Ž(š!EɈ¸QÎhž[ :κG £1xµXŒY8øÒD[%nÃÄ uÏ+ASÛ¸Áˆ×øø@óò5j5ÜO!:Ù­8×Á«¥–ŠÝ¡žFRÀ-ý@÷ õÊY6I1¬õÁk!ú=Ç(ZÐýU–ÑÁÃ&#Ö'â1€ødLóá°öyŒŸölËá$ 3lôÉ §¡l{Ø©/Ä„2v¿'´1 7烉Lxü³²6/õbúåMÛÜžzß®Ð~Á´ÿö¿¿ì4æ•ö~ÉTlŒ‚RûM«<+”ŒFpÊQÑy„{oH±p+*2„”š&e?f;­Ä€Ã•6KÚËS)¹×µp>qˆò)}üpK+ýLª*Œ°éÙNŒ^©Î6WÍz6’s `IU’ ',í¶ ®ë_mÀ©éàtaVºq+y¤,i…‰"þ'dO¾ Ë5ÍYˆÎÔª¯ŸÝOnÄïJ3[U§ˆQ)Úý 0b„*¨¿éäÔ–th©ÝpZ2A8 éöÝG‚/rVƒä4=·IA‰S7l•Ã…ú,‹Q× ãJî‹ì‹6¼–ð Ö‚ f7L*¡ ÆÆx|2âVJLI)vQbËùP ÛTz–dY¡'ÑNrs§¶­¨3Mî<ôDb²H˜áWäNB$’ "B±Kèõ’ðGò$¶fý»$ÚdѼ&BvÇÑ=$@øÅxò[I2"ÑSbB ép‡Æ+%ù°‘EÐæcjF Xñ·ùW*;)f™bÀ÷ÂdÐÒ0vŒ5ú^'˜¨bqA÷¥êJ±ã#Q"œÑÇ7© ±œM_ 7‚Ÿ‘Úbx¶ÖÅ+~¹øhuµz2ðzš`Å1К‘û%¶Fa°lÐVëðà•ƬÂ]~'ÞV1à*Y eøš¢˜–´yOVFÊ즓a85+An/†2k݆‡&±,Ñà:0Éqaû8èZpÍ‘½Ö|«¸ôíNR¼•tßV–*ÍÎ8˜xß% ¹ ŨhN°h‚`³"tÅ-†w1›d&šPÑ)å¢Å¥ÈÚ?eÖÚFqâêI•5ïE…4Ä;l_à ÍkÿË8a¬ ¿7âÙjߤx¤²gˆD<,Û†ˆÀ?ù'ÿ$ïs4?&qÿóÏ!~>ì­í¾óþêþ?ç¡û{íÈ?Ù}ýØ/þÊáçŸ?¿±øèRŸ¢4?7 ?‡äùÎÞ~ä ú5îoyñ|˜¢U˜¦¾*3`TðéZûÑùà¨êàÕû®ˆI7zú) o”…Z3@Óɵ˜ªMÃÏäÙÐ1Ó‹¾NOXëžÑ+Æ$D5¥7–^c@Κa;1à!­y`xQã‘X!]§:æ“>ùV€èyì® B6ô57h§TÑp@0 hlÕµÊØLçÒÍ{Y¶É+ÅaÞ£ ʘQÑÇeóù²Ø·dJÙÞv¼?j‹˜±p÷!bt Ó<xu˜ÚšãlãX^}©Ñ`µy‰†Œ)^‡Á×DïÉÚ™Çd ~a¥ä4OÃHa£]¡!2U±AX‰¡TbØT¯¾UØ 1ÊEa [‹t¡á)CŸì!ɸml$y Û†¹Jƒ3}˜§¡ÞMº«8ÁÔ•KXD¦­³ÓÁ“D¥{ÓÀ86»Jx¦p})Ÿí”n©5Ôû/$Eì5{|Hf> 7 süõeýß“éwTg¡(IéÍ–Âå{Å1Ýt'+ÑØð]O'üE“ÚœÐdÔÉ\)߀úüšª„V¨ºf!¥þA†‡œ§qPjk†Tظ/—R,ÒšßÛËZŽ>1¤Ýc?²qÛõóëyÓj©ñ8i ý J)OÚ€Æ]JÁAšdÔY†Yi hóIh/:„_¦¡ž6ã_|]Ý aÏ V¬"….¿Ëë>d qá –Q×Z£I¿ŸqÏ=’ Ó+1%öœÝÍôBÑÙcŸ°€kŒæp“ÒŒÓlËmwÍ‘D$©‰ql†™Á βnÆTe¿¾SC¡Iy©ë\ Xp™Uâ%²ÅôöY.öåµíR SÜZ…f\•.ÉÍžÈÙÞK­!å:ŽÈv0›ü2é;G‚hÏR(M0í›.´¬èÅBœE‘(Ræs­ÃÅ,B””¾8¦3Þ‚î †ŠK…‚… Òê¡ø¿Œ‘¼¢(óñ ‹âÞk ìQ27UàZχÃYÖ3lã(HyÏ<™Bü9tíB“ýUðÚ?æ¸ßâ}+EˆjUúw%©Ö59Mõ×Úf¿/Ô<{oau©u ‚"i(£ß\V°I©—ûo¡búi¦…ø§ÿôŸætûÔ´^CR¾µ¨—½³ ±¼û¥ýJšèÃ~ù{ìß>ß»8wɃ¯x÷Kw?wÈgôɯ?»äwuÌ»BÁ÷o¿ƒ ëþ·OîñGÎcS‡Ç™.Ñžkß6V~Pogãù¬~?þo¿òGÝÏgc䳦°_¼ùÜØÿ·]ö<¾|umøU[òÓ§°Û×ßç³÷¾gª=Þ‡Î+ÃôgiâšNv,]X)ë4™$õÆc1O£fÖ¿ƒ5¯$OÚÛeC¿¼£ÜíÏÑN×AŽå|/–þƒƒ`ÐÄå Á&8]˜•Í:íÇìôhé|4‡R7†ãÓE>Ä€(,1¾f3a±3˜”Ò¾W žÚYÔà,M½§¢—økêÝ‹¹º`D`8Á•W¸8)i~6ì¹`—'¬CTW‰>rZ/íùW3‰tµG)½½«¨ Ðã |Æ¥²y¦‚ ÕSϲ14?0´¹Ï_X¿M9Ž>îX5Ëô²æišJ q@QÜ1ª)ìÁLÊ®ÿ¦âlt°†ã¥b­[a&ŠðSŘɪ S[‚Ìô}:VtDʉÏá·¼®ÂD\±.¢e_E¤R<;eaRÔñCÈêÀäøÜ5UÉ¥)F¥ár, €AñŒN7áØ$L…Rs9 ¢¡ë†Aæn´µÏFÚ5ì´7C-ˆ×Ñõ,)xaÞ­Á‰ ìcZ²tÊ÷©T”ÈzAü‚ü$=ÒÑêYÕ.(^¤ êŒ†×5´&\2u-wÃL¾·¬6`õB ü$d?ã1žÑêÁ™ÕZ‡NS”¨0ù…aP¡û ÿÎŒf|'1gtæ9Ò®Û9Gù>¤¡·Èö™6æ¼'údRi»dX1x”Õxæ¨ÙíC±/š#2] ï/|OÊ©\ q4d­¬$˜¢Ú<!˜ðkÝoí—ªèÊã5¿ÀQ6‹¹ªæ“Q V”sßZ$.SL›`NµEx݆o7AJ8–ÙÀH—Mt¬Ù„.2&uV½]®t7oÁn6·Éè\o‚Ì\Òû _vÐÛéï.-œJq²jbM7¶à â”vNïÓ «µèinØikæ#k¼nz!A•¡8eœS ›ªq€€ \•ú,ŸRÒÔ¹·c°öL8Ò¥¿á¢4= n„ÒâRJÝr™µ5ÚÓó]÷(J(ûIY*«D}¯¨™ÕVŒ3å  u/Æ]ÚXIÝ$$©äeÚË­KŒÐÕ‹-›ˆR¿S¤*"ñP$VüP!£|Åpø{’géõo"‚Y`’в y B~ªÀñœãt¢ì¼ÙÒtsRÙ¿ü>Ñ8&ìˆÌ–"ÌOP ‡©Vª{uÝ\"QØð½·ùØrÛÍü™àËa4,~€JL h¯_y>ÍtrM7wEýyg5ôóå`ýQ§é»Æ#¢¨S¶9%hp>“C4G&‡õ|È—=á äàà3ä¬eËÚÉO†ù‚Zõæ?‚˜S~3%åWž2pñ~MºŸuóL;Q‚g0QS‘̹-„WØwß!o›úî^ãÌX{ù¾´âM¼‚UÐåñû},ÖmnàØ“O‘Ÿ÷ãìÜ®¤l5å» Ï»ûò`é"9YîKù9ŽÄG(R_]éÙDÏ»q1ŒµëÀòíºû4:L0Ý3œûH£p¾ï£|÷Ç ø»­LŽýäé¼åýKãú¤aý°93µ"‹ì,AN-Ó«àöFDVÐQ‰¶W´‚{QêšÒÞˆe`öw¤£>/Œbß—¾´Ì…&Þ%]º1’Ae–°Jå^R¸IIÔ½ï4`jZæÆ¸Oô$ÕË'djÄ$oç×i J]MÓÒíõ‚–è¸ §áM(”¬2rÐÔòëÔ.eæiÆÐ©)z€k”÷¯¥¦Æ%JÇ \[½}S2ÿ—ÕBOµ¶BË(¼ÚšÇw(ë[»—7(•®'Ÿ0ÄoRš»NÊSÆsÆ€]\cªÄeÂãÁ<'êí„ÉY RÒ›”yØŒê‚y^ÏÄè[ÒÑÝõ{é8BrO¥êTØ=ùÍŠ$éê{iê.Ðkï Ièõá`WiIKikÚ?»1–Ê4Y¦1 HF×u&0 +…Ü8~jcW8³¸pÕ7PÑxrÑ•É4½†ã(®À…ä„‘Y;§a#;«~K†â~ТåÙðR—Þ¢È2ÜUONöÁs×µ:ý…¨(‚ p!ÕrÒÉk˜’ÏMj¿ƒô!ûÜs­c¸‚Kew€»ÖB·i ÀC),a5y‘è¨Bã‹Qª¡*:œ”a˜³ª‚%µ‹ãàBiÜ$®ÆvÕ“v?Ô®ˆ¶Ø÷‘Ñ({ˆ†é8Æ v•”ùeß],㌅#:Z °×e\:/óĆÒýç´_ A—Eq‘°¸ëÄ>^Þ_-ÆÐzxµ90«DnŒ9Ñ1SÓÒÔ)zÛyvaª~¦ g°µ­Ô¬RqcWNÅ€žQé@v²½JR)Âb\Ò=ýóöÏ3qVìueàTäÄgøÌÉY^àªôô8æ‹·_NUŒÉJÃ1ªu÷ùÃÍg†]¤Ä“>qî:|Ažÿ^[ÙS€ï¤˜Ó‹v;‚¼i—›o#u³>=oºÑÝ—Q¿ËxKB< {ºþº$tð,|EDþ0zk¥fâªó¦†æJN-7¥)}–Ìh¦V§1xê’œ(>ÒA‰L¦q¨_ˆr#‘>N,/<æi‡3æÓÅ>•O½ŠG³âøiS„²gXùQ¨!}yžëÑgäùÈ } ÌÍd¿}˜»Vü~Da%ÔôRŒÊ Ûm“bœ©HnžÚcæ):‹Š†51¦˜Ûã˜^ÿnÝx`DCæñpíÒ±=ý$œÉCÀH»UEéŒØŒVWÜÓZð~,½ Ð}v=XDwÈ¡Ïß-²Ž„HÇåP7ˆ–ÎÈI^®]ÿíž!S1¼Ã¤ž#äk²ÝÒ4kOcwÜ‘´ö ¼Ùk˜dý{4…©¾¯-ðzÓŽ¡«ÇÅÓNrÚwèóæqM×µl ¶ª¡EŒ‘óØ¾¿5•ÒãjÏÆ‡§-é¾>·¤Øh²½ŸdÑ& i¸b?F-sœôÏV°¦§g^äµLß¹ëV×Ûâ²`»Ú DXµ×%ëµ—œú; t)K{ýc˲yÁdÿ´nƺ î‚ÓÎ)¤Ÿ´/éäou-çIN¼yh罚‡´‹ÃyØž‰Xò?sz°|D®¡¡ 8téú&< ·"ìDÿ[¿¯v ñ&si> ðœYzÂ/næöÓÉR EÙ‹‹±u¿=µÐ%5¾vÂB/¾Œ–mãaCŒ¡øS4âÂaì ¥'I°GŽQ+FS?¼Z߯ŸN]ÿoYäÂË OÇΟ‹oÏЀÀR=ÿIwCÖ–eãÑ|4Ö1;úzâank¶ív¤ál‘eA»¹Ó\îþ`:×¼y¹å„¬õ, â¦Âô±©Ðýu¯Ëë%*R5/´ [é"@0ûûTˆî5M<M£ß N$Ã^³Gæó…ùÂÒ1¾ú#÷Ôˆ¦_šÏ cIÎúïüpÂÒìwG¯^ˆ9&ÎkÆà11Û`ÎÞ=0`ð­Áöâ¹V»…Ù‹¦©…6tšçÓp¿P¢§×Kš$7§gÓuÖý‰Î•ìT• q¹¸V4êYÿ›XP)Ü%&1“ 6‡3WÖÃNö‰x}çžÆW^è‡Z¼ÒÁ¬“ÏÅc”ÏÝMé¶TT(œæ3bo¥ûÔíUdy Ž«€I_'š™ Àïhˆ'Éf1­`¬[gT} ¿xûK£³ú\ žÎÚénnœˆÞ®É‡`ó–6/¬/‰€ÓÚð¸÷$ Ý›àR©ýd<©Í­€/sx]ãlçÍú¦ž%DsFDô0§ ²ûu\m¦8¢”Ø 9=²,èÛ/ ÷xJNÙgÌ©jdó»ØZü‘T@žÃI11à Ê¼Ší³R킦¡×!dRûž>yMÈÉ—xq±%ÔAR7IpXЬJ ÷ý¡ìErÁ#3ƒüJ¢â»‘v´%eŒ§ø>qýšz3Y—gl2·üöl²#΄f°¹ºÏëŽ9×÷çà×d'çVçW±‹3#$Âæ5”Š7%­›)zü&"üZ_ØkéB^»íM¶­É^¹˜ü*â5! ©­¸b¨Õ¼ÙDŽUíKSXÉ+W|dO¢-F‘{Ø^{ dÏè\s<ùåDN}ɧ(³ •÷ʦ¸‘Í é‹íí#ãÑöS6y„¦ˆdd¦(ÊÍü>JðƒÖeöt ñ¶áópËé¦=Ÿ^‘–Bæ×·9Ç| ߪ¿³R_’°N'³à&Iú2äQ°ú mÅâìf~²Ö§dyËWÌý¸jà—娷‡z\k'Øï'K|²IÊEÉŽ{ŒGþI©°ÿI‚Ä\èûi*ñ\öA‰wèi“¸d³àº´Ìtÿ'⺦î}&øÿâ_äã,îÌo’š·TÆó\ð[Ò%žA_{Ð'W{ðkŸÝ×ÒÝ×Üq2qúüˆêÄýL=ÞÆ„XõÄé{;VžßÒ±6)ž~•î#†têGqƒôÜ“DðžšQºñ>•~¯Îiî7}=^«TŽ€÷OÓïáÃgŸÏê'Ÿ}7Þoa·œäÃIò]sªã¬ú.”˜ãò;èöñ¦ýÆ#–âÙõŸ€°>Î>‹7 é\pžônΜbãsqX“ÞA+Ÿw¿„Ûê3"!ç¾½éÄnëúôßñGØ÷mp$u¾8r‚üž'z·ÃØIÜ´ýÝ<Çw†¨º™¸ß«}u [wÈï÷P Á}Ò>7¨âƒ½ÎÆûñâ: ™ë¡ÜP²¸ÊÒµ•Ñ ƒ+½Š–Õ¬¬]ǽ VîœvoEe`¤ä`tAZškJ£µmÏZÊ ‡ïEC|bä1.D³Â^ˆªßËúü;uÊýpªXO0êV¸Þ|Hú¼² «ùµŒ‚íTd½¢©íl-Ñ0¿©Ú RHÜül;—–ö×Âõë㎙Ñï[hµuUi‚ö4/–!ŠñˆcïNKö1½b(,†;†/´]ÃGtÎ-úþåm0¢JÖ"å¾*óË¢XCšû€:!š–½ûk8¶ÓÓìN¹¬˜B cC_tŸ£I§¾ÛŒ,CÍÝѳ©Ë‰²ÈÁÏ4í¯ƒ•çpµÍªþ¦âÏ:ϼ²ü0ðƒ„;†âÕW`YËžÍp€ 1žg’¶ÿúšqÝÆê²âטðÉ$ßOâ Xºàbˆ·pYôè±Æ<ÜsD1T¨ßÄÆ/ô>VCvßl$‘À‚ǸŸÄ!Æ6¡›“Ö¤¡ÁâSñD±œ YìŽÃGÇj`6£g•L¯ 'Åð€Ùÿ ~ÑùËÆuÂæI¬ï{졯¥svºÇôðºŸg™ÈÍò¥ŸpÙù›Ýó¤Ñݘ(¤½Ìô"}ÝÄa¯hømtA¸¥D7.è‹ÙrçºÕ»"º×•¢„Ã8¿. ûsÇä1•ã×5ÔŒ``@P(EdºÝµbñ¡5Þ§Û M_±¦¾HpŒo9ÁTJŽõâ=EÑhsëJ„`Y0 WáT×Îbf÷œ`lm,–âÔ%+ëÅ¡Ü^ªzÀøP½eÎ…éìY‘1œ:¼Ú@Sí†m$khû®E½Òð8ö@ZxWZ4Y㟭ví%©êSû‹ýQ’ šÓ¸±ÇúNÛrB\t¼C½N2{K»¦¬‰l…qÛ³`w;á@€y’¨¦þ\uîÌrn%6‘–Hú^ÊÜ\Jlé/ ‚vÙáaPVk¶ŒúÐ!”×8fU0åó->–Ty¥•ÓÊË©“•±ÁöŽ?$¢çÕYŽ‚_ð 1IÑg¯ J¿_wJXLb™‹ŸE¦ÁÒê¾øåNû;~Ç\‹z°Ô"JÁ*‹¹À³Æ0ûúA S¬hwÝF²K‚Ã/Å1úYªWEÒóªÖ½Üì)ˆ§á¯¼¡Ël/±[¹(³³{x@P„êìcta]Õ¡eeö¢adƒ0ż’ä<ËüWý½|vfõG¦5‹{OÊÚ³Ú–Ñ/j43•±´xå?ħóiÒ ¾Þ×½3^…PÆøá›7‰©†D~céXi6ñ͈AÑ‚H¸¤a ;i¹‡MB èJ9J¤šû6DCÖÂæ\q=Un÷W"²I¦úôŠà3ÜÀÍç[… œhjDhÙø|Œ>—y\tµ§¸áj]†Ø˜ª +5Ü2F-. J0O R0 'æŒØ¸-e­tÚ0F7½Þ ÕëŸÿ˜cŸÄ'Ü"E|Ì;#Ô[¥© 5D †¶œ¤¸L ®xÇWÐ\ý¾<>ü7x¯´=É4Æáx¬„4BoVØ~ÀÆyðýÅ/Ð6„Z;MêJƒ3…zgétÕ6cØ¥Ìq®ouã>þL ›O‰wæÿÑý„®zÚx,ów£ó7‘ ‚ìCu/Ø£ß,lÙñ1ÈwaT#œQ~ŸL“„-OyCþW”µ#éWóÍö¥ÃÐø¥«BP²HìtË•õã’MÇN5±ºúV7@æ(•ÝiL*3dÏò$Õ•©›~Qúa…ö IHÑ⅔ʀï% +ôªeni½clÕ ×G'¬® …Óü,×ï¥àjF¤˜zCßi±%k…C KU‚P=R-,ëRHºRòŒý4‚R˜Ù£IÔWBq‹}_lXÇhDa†ÖÄÊDÃûb)†€ì4‘ŠŒ\ã(“bR¶M0§(›¾¹!HÖáÉŸ)šF0Ž  ÔŽCD.7wqïäâ4ú~rxÞømLêÇ®»JH]•6Fó(HÁ„¢×ciÞšrF~ž›¦Mï\eÖXJd[8Ø8Iç 㛌­dŒ¬râgè+ÌÀUT~d±au2¯ó>$˜=Ƕ‘¾”³§ìÝŒÄà!)yŽýhís“…sש `ª"–~x5U‘³òS*²çúµAÇ^Æô’jÎvá`YªHŒO1ñ rLÕõ°ŸãiA9™­&¿$P³×y÷ "=ÌÙ õÅWÎÛaíªx“ŒiEa2¡tÍC∆¸èФˆ¨*)ö´\)`†øü /z¯v̽ïЋL/j¿‘ ël¦)1Ò*mÊ[\o„¿ëè¨ûØë¡=3ÔçºÀO¯I a~~ ýs½C›màñíñÜu5Çíx9?ïç]£²„_ïðÃïØMçå›ùq?­>yêӀ׃‚'óÿ“±ùýl7˜1o|8°~Ȥ~8Ç>jŠç±lìÿÛ.{píó?®m¾Úx—ä:èä ÎOîçƒkó¼?îîn{RbÌøBОZn'ÓhÊpY¼ìÔ#,SÈ(©o&¯,«¦9öÖ½֡͘½|íÄÎÈ¢hñ”Sã„a’ÃËJ3#ÔÓúëÿe[MP¯ý³ìûÞPÃÔ"FJ¬–Ña•À$ä·<;Q5£LÚûäP®P~ Ù0¯3ÙÑÀÁ¼ÃÏ™à¥,fšE†tÄNµ5|óR¼JU¼¢Ô-&>­a1ÈÚAL¥ÒpÕÕ†‰“@&i\lÅŸ |%¡žHSh/W…ºhŠŸ®Cé>DgpÄœ‰Œ@JW•¤ žô•ªL;=k¢]¬Šp½ˆ¥š½í†ZQ=kig}í– ìÆ[0#©0åœ 4!õœddRÅL‹Fð1–6±ìÑ”=@EÑôôs«'匲£Ô©ŒeèÕóÓÈ0`›¥½„ šÝ¬¾f›Ìô—¼4RÆl–ûžSRí1†Àë O™†«Zí’TtJeÓütLqÙWS‘àê/”̓€bƒ)“¥ý{Ãé84Bñ%5ï²1ÍÈŒ=5<”y>¨Ùlµ¤½-M1eã® mãà1í}Ü£ÀáÀ”ŒÃâVDSÿ™pJXíGÒNl+L kæv„jø8½ŒäÃ3Ö-$0ÙÊvÍä¤íÌRb)G| ›L5½ƒ3¾iI´rMMFGœÓy®°Jb©{Ql£|4Ô$ÒÑÄÖ2ùA†h¶E¨¥É~–Ó Q pÁM¯°ó¸:Ö@µXŠ©¹°»0ŸSVÆŹúÇ c²D IÙB#6žñ8vxW&bÆ`¾ Û·©zA÷3¢îÄm˜bŽZ²R¢W˜¸¨Bõ‹µÏ-€×Åìr|®Ž¹CdÙÒ’e¾bèž4jîèc§°pRõ*gi™Ó³Ëiómn¢cÄáñ$=y¡úsè–MÉgaßÍæ%¯%–¥çgY­¸|ãiÅÈY6Qóõ[Q3†u†¼MÙ¯+ü£ìì£âöðv­}´ôdqõ±‡µy­ÁAÖ€E×Ä{ ¤¾½´þC³rkÚXóKÎêÞaÞ`S¶Â‡ÞêROŒ×˜YqòÚ±¥dÍ?0¿±6g–zÔ×ýºsxõFÄ$ŽÑw\CfžçÂÂ0¾tÑáŸ-D‹! =fH2j þKT$ߊÝãì£Ð$ÓÇ—:ñî ¦!4»{Å´ûж‡,ñiÁô"Ùö¢ƒÏ×K×[&°¬—Ö )Ñ2òËcZeÿÕ‹÷…¾‰¹¯÷¯.ö hâ “¿à/›¸ƒiqÛÛ­¦!JRÚ)ÚÐU|}½É餟,± {F?IÞÅ©'6"pRè–áµêN ö(ÙÓž1!&Ýû<PA&bë;K±e’e}³¨yšø÷]oòöv/½r."ï.0’šB¤’çi핪Ëþï„´sPäÄ7^Y™}²Zç"É×ñâ`>( 3™¡Eyaȸ¢s§½ùÍ*xÇèL4~¦à ÐËH—â–ÓMÖ¡w‘ñ‚î¶$dˆx¼ŒµToŽ´ÂY» ûÊþw]ï=IóˆI/êôMÚé:¶¿®LÞ/SH|€Èÿ$Í¥ž¿Ú°åEè„ìŠEˆÐ,d¦KÖðJ-~Í¿«pUÚ7õx’“¬×À…iØï¢söÏ(Q‰±’‘Îl\­1rI§tii\ò-0˜^ S‹Ø÷©Üö!É& SNûƒ¥GÒ ‡Ì[¦CÈuJ¹…KÒŠÊ“E Br½I÷t²Ë~*—WC’O…a¥Ée^Ig½•1©ÓÀ*~Va‰x×M-®Þ¢¡Þ” ±úTÿKë?µÿ%Kqµ¹øTðºY/ Ù'´UhŸ™Â`}Y-=©çâXj Ë.åîË–ùÈ0Z3vì/ÄÑ¿¯±->H¯k&‰.¤Ÿs™ÝæµÒ‹çÅjÞSоªÆ% vÈ^†Š¥bƒ&m—üâ_";È$ß-óJ^g4á#>T1d€’Ö¤8Mt!òz’uIã&¥æ#ln°0Jí-B±·ÄPÿ ÈyZ)^Zó«½ÑÊÞ”ú`Rµ}¤,E²Ož¼ªA ô·Ø"Rçg¯p—y~¥ˆû¸ç¢ÆS“(â~ûWÿê_å©ý>øîZ¾KÖª¯]1Å ‘k&¢É…'Þ:Èë÷´ë‹ÑG Gf{$äDªõë«¢…©|Ò¹“‡¯×&PcºÉ°îé=Ïqz¼ 5«:þÂñŽÞþz;™£ Ê×&Áð¡ã@=ÿìíWåÍøú/’ñ…êÝsâ•ïç¾¼€¿BGt:ê’¶²ÞÜ\™|>l£ÛA•†!z¼;´Áóôî—¾>§l<Õ~/>›ì·ëôpïâåóFà׌0ÄÍElΖó=‹Ö]žw„¢^Zo‡ð³=—ñÏÔvä§œŠSûþ؆Žóñ œÖ¤ïØ4µøóA0½ÝŽx'eŒ&°ïBü}<¶Ó€cFçf$ŽÖ›½WâÍÜÊ:ÇÃÆ<ÊS8»Yƒ‡ŽiW>nr†€þnúv¡yó³f9ÜN’igч6w ÿµ*IýÐÊ>†b#O× n­ìáVöq `¢%kŽ!ne¿zÚw êZTkZõû›–§ÒèچݸN¸¢?=ÅçÌg+m&‚ç„f UNž/ÛPÈ ù‡Æïé3aF™0BÂ0¸AWK=kÿ.KPÂ}-0à@CB|óîi`×pÇ!‰¿&dž±´qÂþ} W—ÿ»&ÜC‹Ú›ÇÁ»¦TøŠ)­=1AÑÚ 7:ìÌm-.@=Ü‹âŠëå7áýã´`| #¬¡1v%pÐL.‰‡¤C"«?æšæ+Fæ7%é5UÑ0ÁÞ΃ÆÕ¶kî,w°8ç¶ãÀÁ˜è< )sáö’p§T—\R -qÇ|zø»Ã,Ì ÇÌËFÚeM߂浾,Ì¢çý‚†w´à¸!8Hñ²LßÃfÂpÃkÎk—bKùÖ@S[`ð1‹yoáû«¹½”(Žc°bh¾,ŽþF}•Ò}Þ泄¸ûÔC(XÄÅDdß1ze acZÆŒ‡ÅaP1ÀÆÀÐÎ6xþ1þ¼æ{#¾Ž‚«W÷ž‹Vô]èüê1eˆÏÜwö÷íÕf8ël¬t D<„Xå>&µŽÆ­¶Ž"~ ÍÜh¡ åïv:UnS l“Ó‘¯·dFˆP¹$Ã0¬T¾¼ÔžöçlïEß{ŽÒç ó©ìœ§é1Xn€ÔR ½\Ç Y;rl$ƒÞ~5[zã’kæC)êQ)šÔ¬.T8ãINcÌÉÔbÖäA—ýí¶P4 kš­%XPéí0áõ) BžNDÊ] ƒÓå¦sˆ¹¦W}y.8Ê£>vzùHPúš³[ìmã~[/T<–V¼…Ô¼ê~#uÐW©R¤LjPÁ·©jÉ,F‰DhHR–kç1‡d"g4D?ÿ:ÝjTQ޵!Ø'ÃÁ7Uˆ€`“Z”|áWûiA§âkZ ‰žÖg5ç¹ÖñBTÌ'Ì{ݽ0dcƒƒ„I]7 Ã&¥ñ*X±b%°ÂË$Ä“¼ ²NÛ&b‘´8"–¬mO1Eüo"¦¢éBÅ®ø ÕÙ'ïÖÁ¿æÏ5Æe OÈRÁJ*üMÃ$Ì_cTšä%DhÐ-8–\(3a˜ $ôÂõ¸H9Y4‚ŠP·V”×Õ=¨¶ˆ)§ïÅô io Úÿ…yE÷ƒ¸¾ëZQ¸šøMAÇJ†ÆÇ1õadwÿÚ_eM0O*¥Iò**êê+ǽiŒ²¯ üÙ •$Þ€ö£9™ÍeØÝ˘aÏ…"2µ@9s—‘Þ'ĉpîÝg<ŽÃ<ß^q*_—›ö0i‡yŒW{|à=¶ }'÷ÎV\ÌöÏ1<_MŠƒ%¦bùÊž×2UñE$Ëe_GXÇhñÄ El[†jÅc"4™v¸ƒ01˜ qM(göÃD—µ®ÄT’4·ŠqÀ>Ã÷˜ý¯ÿõgòÃ?:—úã/øÝéÑ_å~~µëþÚ~Ï÷ýGlÓ?ê8øùç׿õØøõ¾¯S.¿ÃqÿkÜÒñ;¸É?U/üyG½Ÿ1ýÛSOþåçxüµþ,Qj€gé9+°o?1‡†ê“ë­Ž¸ÛÁk‰¾³‘CJÈ3áoˆpêbÐ}¬æM1&Zêsñ±xF´üWN:âýï8`NqÐ×vDë:¸•Öì¿ÎÒÓÒ˜Õ9T)nP4_šÿÔ LmÇ2W"tŒ ‡' ©ÀÀ=à„kÙ¿?ø vû óŽpE¡Qš£*aã8!uÄ=.P›¼˜:5úïbPîÀè% Ï%yüöYõe\‘JûßÇ«ÞL3ë%?ˆO&¥ùaâµØë¨Xt”:¶5DÑox2ﯱx[” $Î÷þì8©^´«ê8ê!1oè?GÇWíÀ-ÅIõ¯• 1õ ÝëòçÄQ³iŠçxO…L¢‘ÕÊD,š?7ù Gc 8lŒšê+Y. Ï"„¡Øhc¸¿ Ábx4Ï)ž2s¯'O7P¤”ª+PuP}0˜¿I¾%$¥çÞ¢‹þº§‚¹Lš±,¢)hAöô¢¡2lpØŠº4å­–t[ÊXmýü0dfc)Úâm"¿+CÕÎØÏÃY@®çÏò͘ê­TH„ )¡x¿¦AßsåL •"·Y¥_¯1»U/LmæúÆLW")Œ•;9ÚÇ"aÿR|A!ɪ‰Á¢RÑh/¯îK3ù{è¸kÒ¿:?½î šœM¯eÒ¡+ v;•ÍØ\00øM¸\ót¢”æÏì!…¿9({º´±ÈsŠæ<{Á Ù€2öœâ"Î=ÎsJ£OgbŽœ1þh5ä™ÝŸ†‘Ú+ TÃMЧ¢dê;®=Ϙ¡%QØ÷ˆEJrx ÉT€K©ªšã)‡Qé¾Ðx¿Ûn«'U\S1Ô{ˆ×VnòxΊ‡D¨‘Y˜¢"{:|á*9l  uMtÅÝU§n†3YeBÚ¢ûs É%™AØ® ^óS4¸0–í©BÃ=½h:}üƒÌ-ÖñóÓZtˆcšit«_ÜÒ|¢ý©¹Ïæ|‘Z;¹çfªÇì@L7çâ>Mר°Ñ‹äsô©É„ùÏø&×T¥¯«²7÷k]$¬¼ B ýí#6ŽL ÆóàŒ¦Xa¶5=Kõ ²µ¯6Í¥þZ{&¹ÿË¢÷šb*´îýf8¬´ßVDCÇö‚ñNòjâÍ=Ç[y=I1ƒäyÙ²ÎÖ¬új“óoþÍ{ëèÆ®rœ<¡[¡ÀÙ]¿ãñŸÑìwY&;=„é»ÿf´·‡HÀ>}Œér±¿6–‡.ùR[ö~6ß¿Çׯf=£ÕÈ|t[ï~ùøóÞÏ݈ñkðŸ?^ijïa¢àÍ3œÇ]¿sÙ0E¶…ákñ€NÒ3›d¨?àÝ,×.™w>è—y–Oÿ:ÿôãç~üá‡?F´9þü9¿wû€ìí>_郂۬áÕÆåGñõ“Ž|Û˜:kÅꛥâûãϧþÞqúÉW}Nx챟YäŒÍÆÝý¿M{„˜GÂã)³HÞ5⮳º‰ÌOv1ó¸ýêoßó—úMiÎñú»_Þ‡7/¦U{ÚŸÈ}è÷Õ¸ïx°­1:<Ïy>w%صîšg‚WÞsѯ¥o®So°».²cIÿ’´ÎÄ(ö) žöïR6zò©÷Í\‚ÙäNùfGì ?ŽUD¤>P·Õ«OP)G+^Á’€¥øô¿› §¡:!,è*A‚£äΊBáØÕdãã ‰¤-ÁØ¿é Þü]9È0§Ã0å.™SÀ ü5½ºÚ®ó°Ì–;¾Ä @ê") ƒÜ ê~а3¯ˆWµ“†QºYNã$éUE¬þÖŽ|ˆ®È:®¤BP¥œÐék•MÙ’0´7tÕ+Çæ¨`†Ym H˜ǾF®¢§õ®9*æ¾ð 'WÔÄ_ÑãVÃl˜æÊžæ@ŠR¡*1MÂg@wÜt+&ò[èÜÈñ**l4é­OºÜ¦TöÆãd:æû¸UÈv ü·.Ã7‰ÊÑÙ[dº«dc!êè|«þ O]ó¦ï2ðV*?XëæW2bùݱñÓÛš×Ùnþžƒ“N„¦±â »j “¸êVÏÜ}†!Zðï¥èU.kn«ŒÖÚ¢|.õ)\Æš¾>·'IEÇ+»o‘ëХ蛾~×¼ß ·¼˜¡/Ù^ÞeLF ³“¦Æ)ÃDÊ c°NV³ìì3)ú©mí¶@ G˜b«y2Œ·ø9Ž÷u?Ê%°¾°e¦¡íÃæ²8xrªF×íèë³ìBÇ!0I ˆPB”’Z°bWë  ÁÚdýLvŒS8;=°-›O†€¢…8]ÿ¹MœúªÞPwjŸ`“â)v†©~Q|¤‰á[8kÜ~{ö®ËCÔ¾õ+Ò­y¥`XÇÔà1 ‡vsW™KÃAôÑ Ë~E¼ëªti“ó&2ëR{]Ÿ;kïì-ôd#u{ƒ­y–9õ¶ÀI‡~6…CÑ]/bá·I´âgÜQô#9FlÝyÅ|‚®…äé´@à èéL|ÒÄÇ޾߆þ–‘i'Ý[rð¸ØÎàj¯É ‚€î‰0¾¹Çpòë%ŽÓ´Ã\àŒâ’¹iY ò7 r±Žf‡Îûì»JÛàmä9UXq«ëÙËõ&‘ÿ^”WÊã«eŸä|õ“3¬þ4u5ôä:>÷þ·{¨ Úæ  -°ln÷q$óÁE%Ö94¯ óT²Ì®Ö4w9‰o'Úboa=°|°ÀæÓê^L–!€Ç·Â\I¹»?n³«ï–žLO&1dŽ‚ 'mþÚ¡™Á5‹—`Ê«ÇpŠ{濵êÓî²ÆP¸tO°újÕ„;&.LrçßywÛ%Œ`ë¬Xý ¼¼’ééÓ:q‘vºÿŠÀ0ø×ûuËÅÐ×6nÍÅcÌ2.}cvûìËÇ!f¡øº‡ÿ¯)žáp§#,¦‚qLEØ=át’rÀa+Õ…5ЪæÇUT2„^G3Œþ+þ-wºY£}´<³>äãí¹–ÇñEÞu`¿š¼­-†~ˆCÍå´\N6#;zx!;}à—]<Å'¯·,`Ha„ù¤:ì:Á]ÔS¯a#ýì'²üÒpéÔs‘Ó+Ý“©õ&»ð(9štÒȺæ)¾Vý^o“rLR'w¢a¼OAr&É)áë’5¢£ŠüøÔt,ÉÉMJÑå·Ï¦; ºT€×Ûû.’O Â+¶Sq¥¿“õ÷¹Ÿù´G+«“ QÇÂÓ¢CfaDbr±"§þYW>©ð½(Щ^úihDÓÂV¥v£;Ý›~1œtXmú˜Ì9w•{™7G†hÚ‡¿vH–«ô¾ÅÛe|OJˆXÑú>Y²sÌ]4_òaÚüؾ¹ÔhØev2i_sm k»§Ì‹l)cˆˆ^Ôʱz€­Vý6sVÏÔÃ>p\EÔÕ^‘ê%pÍyݰ\§x5÷Ø¢æxjQn†jÓM㞤åE‚ýG8j¦7]HƒžQϵkÞñ<è#ëZÖ³^ó–È—øC¦ °±ÒÚ1—$ÒýìÄr‹TÁ¶¹¡ÐxӸطläóà^ Ò^W;p¾ì»-ÀN;9íAµÌf¢¬Ò2<Ô½x9j`®?¥HŸƒ¼dˆy  ‡ô– â5‘âdˆ(@ˆ˜Œzþ’jsII´¸_Ç­v{Ž+TÀÙp ¸ÏÂö;±÷(ì(ŸÒ§i¤&W;³wûYMÊǬ¶X¼c1¢+–eËâ^kóŽ\3‡$Ñ£´9¢;åLÆÉ‚Iðì·{F…úü‰’\¾'pO+ÞO¥¬ûŠEaÇåÑc‚@‚± Acp}OÙ^B²u+ÌÚçwÚ%ñ¦¥²ù›°'ÿîßþ»|¦[žÇ4ÒÇ)µS ïG\ûó¤Þ³ÞG÷ÑÍdð$õúž)¸'›ÎàÊË9Â0Mó•–ø1½”#ö¼ã¿ž~ß{yŸvÅ=å€O2÷ÖoÓ«¼í„_>i cÚîp!òÄî<Žc|¶xÛïPµOGÀ»õ´Ëî¦5žÍæ¯ÓäHíÜÝCŠá—îBM2ïÆÔGÑæ…:`¨K<ïûï®ek`_eöì‡ý8ž×,;J{w¦àý<ûn~Òï8ãÛ¶z¾kùº=ÎWçþ³è'3nb«´ñíPû¹öv#6þÚ¹wïÖÁ›ÕùÉ{?fŠð~ wÖöóé=<ï²þìâŸíEžßåé5¬Ãž—‹/ñ‘mw˜ì†R”µ†ô'”VX.6¼@/naN¥Ý¦Áìä×SŸ]“_ ¨ÙY„ ¹iÑ#`Ü€½Â™ô\ãrî^ ×`oMÕžÞéòUý,®7:ôGGêèÞ 3…6À%XšjmXG(b0¦s§1Í0ÃvhøºÉH/¨w/OùC³÷žîå¶]„ާ—X4ÉÀ)Å+‚'yN­¯>»³6<û0j¸v °b]ÔÜ^†Û„a+ÎuÏŠ˜\U0i²³ž|´— úü‚sß›a:ÂîíÜc×ܘöñ‘ ÷-ˆæßÔq» öâ!³ÈãâêÆ»V4ï -ryÞ´˜;¥ö/,a­v.c!E©Stp‚(Œ¡á® †ú³—@`Z ¿Å£ çà±¹z—FaO&zÞÖ YÝO&>"°k÷I;ã¾£§ÑOyZÛRŒà‹xÄíFÓx°xꛘA .‰‹§èhÐÔ~ÑŠÍÑ xlq\eÆK×ô¥í&º—ÉË mbmíëhDû¹^sEÇ%u<6ôiû¼Dˆ8ÂqB÷ʰgÇ(aÁWÐ\oUÈÞFyY‡ ‡¨‚Ã>¸ûu¯Ys¼º}øÅÄåÁ©ï›0‘s¯ç]Slçwô2¬NÖi Ÿ³6òõhl¼x!XzäMúêT0’¶Ûi8“ŠÌ¾GÛ¨ËNý"¥Œ.ÀuЬ¼e§(YøPrj‹Rrœr…åÙÅÿCÒIu­ŽbôMâuYEdXy+IM¼‚àֺߦ©$lB|iÈFUñ²LäÊ´Ám@p#ÓçòJ)ïâMBL?Úzð‚óúâºö¬ÿ¾ÓÙQ–Rà FÝeJÑÇlÓl žÕŸM?Ü[äÛxº4÷AMQžA©×ćRìA"( ¯ÄÅÈË@|J›ût œ"(í=0áVµ)IBuˆÖ¡àËÏW cN/¢éN?g¼“SðWz˜ÐDŠßÇ5ÊÀUßS½ v¤_*Y™¶Ø™¢Ð‚Ÿ²=Kª*˜ùU‚Nð`øS”7Bº! Ž’]sLâÖ5 pBÉ'¶‘Œ˜:û-¨~Zl5¬&1þŠGF8îgò#¥,—TP ¦^ÊÉèô¹;}°oÎZj^û{Á’K OñéI:ŒRÄì­½^Û:tÜå…TØwñŠMË‘¬Õ"VТûhÐùsÅ^®?KK¯‚‘4‘TŠL¢b.„ž©$“"¯àÕÒ×äl‰Ñ¡–…BD÷üñÂû`OŸ$¬•Á¡'û ÖIÚCØË£f&é3‚«UðžMfVH¬ÇúHÛTo¤YA±uãh2bcÀ…p»/˾Êf×0ðý©gÆÂ sÅçm çùãX¤x¡dËlÀÖ°wÓMŒBò|§~€r§Á~Cé¾o¾Oe´Ò|³®ëîøòºÞÕì…”9$5L1ºš)éŠ(þûÿï qãïþs«±þóÏüÏï¨_±Ÿ#ìçŸ/·ò÷:rüžFÄïoÌü_•¶–þœ?ׯŸ~ްßÁ×ÑS_W¡œ 0á('ibâ¤ÀÒ“ƒš^Êa@G 0eÑ×0íææq §’¦ÿîÚè#×#zú0t†õšEåiÒ´aµš:U$ä¦8æJ±.Ñ o²P‚ ˜šÒ€5•»×~Oqð4˜ºŠ±°®ît’*“SN+£å½ôä­×÷šþ#Ÿ®C’Ú$éóˆ‘A`T8sæy`¾(m (WSy Ów§Ï‹nzt-/˜×Ç A F×r9CÕq/~÷uYÓ¨":þã*0â·ƒ®¤ÖümÔBÆ£*­Å¬0†Ž†Â¼50¨“E˜j`œEò €Æã¦â…h÷ÞZçT0yÙ ¿úx+z ÛÀ„>ЧO­É'hX_Ü—¦cEæ·0Éó`sœU±vh`k† "ÇÆÐØÊŽ|Q˘æ0šyÆ$L¦Š8> ]õZR$q@iòBèh&Å$sK˜|•æÈë^.ì—…î{$÷hp7ôû»çCù%1b[{$÷(‚"ðaÞkp5Ç<Ö1o@~7ûÇÓ6ⲌÿCö¿ˆ‚ÊV´ºRU‚2ˆK'©ª¸ù’è‡\*V{XO¿¦z²BN#)FIiÛÝ.„¡T«2‡È~¬`Á)8:õÛ( 4I3‹ 1èÙ?¡lv63j݈¾ôuWJp¬t JÅ2fÁj;†<.°û¸0Ø‚¡Ú›Õ•T½ŒRž¦R’‡¤<á.ŤN" Y0îQ 6ß®ÏНXÕ#N<ôÕO®>£//œDÇÑ´Ô`’Ä8jÐþ–Â×´½¿àhŸoôã/DòÂ0\QIXI÷é¡…ŒÑ(°I„)å¡ÙÒp»–ò[Ð÷±âZõ—l÷Aá5¤Ú²SéÜ4„Y¢ù?Tz™ÓÉ’FŽºNH:Ú\k¯CО›\§£ÇT >¿Ë8÷Í ·n£B­Ä• šóÁJS®ÚCèÇV~‘Ê*påÙ˜×3dS”«çÏÖ—`…@ÆLcÁa<–…è¾0¿=¿5Ðø[®y™è˜-…¹BŽø+l«G ·=ã"ß>úR,ƒ»pÛ| ßTÁ¥åMwã)íÏ N9pk›¦ã¡Ò.hŠP×s»Ip›‰Ž¤ny‘.¿„$T;+Þ±Ÿx¿£~!õ}ä‹1§æ““ Á)4¡©k>2(J„„JÉþ€cÌjÐÊj]¥fŪ°ÅSÕév<¿žÙÆXd³ÕÁ°Uó’Æ9È?… x¯·ÑhW‘bÌV˜LñIÙ!Žf}íêûký¯õ²TôxÁÊ©5Ư8ñ K…îMÕíŠ;¾Sf qW³ifuR}aKõRr³*žë„5¦£td¦)übËËDš’mÅ&™J©¸¡8C^qó?ü‡ÿðÌl~p4ÎcÞèÎ7Þ­åO¿;§Œ'ZôKI­s\¬™O“fmÜ}ñéyïnsúéýs":u{ß$½ÿ&ìBëÞòÆ_%|é›Ûµ^˜í5çM“Üx÷¹&C:÷õ–é EO‘†¢æƒ68©þ¼O»¦õ§ÜØÜ€§'þh Ÿ:†ŸÅ|ÚòÐGc¸ùÕòâ_ù†¯ÏšÇmz Ôñ`¥ýð(l=™ÿC›Ý}çÝB5á·ÿnP}¥Ãþ8o{[ݵÞõrmN?øG£õ- Öº{¼ ;‡èþdY=Æï{xðþYßì%¦·z·>Ì}ùÑÜ|÷Ë7}-wÖχ;®a$H¢÷¶ÓÞ?íÛíÏyWPëpÞ ù»~žö èÇvØ:ÞmCîö¡ï±X.ºö±`?›æëͶà³ÕNýê´€/fµn i»´.ê„®@s½YYQQXd4•˜ÔS³&àF-)ìåõ£)ïLjÄ$¥/5;L;i‚:z# Ђîy§X •hFqtŠ;uÕ8l$¤§I¯,Të:Ác±†lCØWŠÖ‘çN*E†ä¨BUBÇ.*³b§7äüº·^¦&„œ„AP¥lj@“ ÏÕw5!à&<æPšLl¯Ð‹ë¬(GÉÂPh[DSÔ™¨“ÂKJ¸šÁ¨âPŠjÍÕ¿ƒÚ hÞð`JÐ <ŸX’œÃ7%‹Ú´ÐÉ•(µ XPÆÐ°ÃÅÞ€¦‰&™ÆŽ"˜* ÌdÌSã3Tç°3Ó ,eRi`ÿ&ãŠÔaȘ(¢@1 ʇ:/{ö£úÄ“¥æô÷Mb…‹HÁÆa×=ä¤ü”z‰nº í?‰ÕáLÑ2-1´’ s×Ü0|#-¾íïž ° {M(RÃëJ^>:;Þ—ŸÔ~V:¬põ·à­̨­P2Žöï s¦wÅ):eˆZzªR‘ÅÂ$Ù!d§Â1Í$5eÝJÛcd7UÏÌr’ ½CÈžaÂg# ¥à¹è®@y­CŽ‘!”DPU@ò`ºú/UgÇeXLdóHòd4Þ3~¶ßØó7­:»ª˜ip „T ÉJq<Ð,Ÿl@ÙO‹%åi}Hdí+¬ØÝÁl´˜‚§©[V\´fSFK§Ê»"!|è/ØDBíùZ/U&IÔâô9Ø@4»ßfò/¼Qv—Ù=¸þ=aƇÁªP3 ™j8QJÃÔºvL—*ÀÝ×÷10»#~²ÉÉÉE™Ô …’$^ês¸â‰#?öòSkf¦|±Ä¤e 3u{ ÉA&Uxh¼!yXÄI°m¾a/2°T% “›ð 6|Û©ßb¥’_„ǺVºþo{lX†ô¹Ø\ÇYŠeÁª$M±EÂð¹hüëѬe¤(ƒ°¿èéF²X—‡„Ö¶ØL5$LûÖL4åÔ/{UJê¿'/†;f˜V„š‘ÂOš³êA ¨ # V‡ƒ©¼™â?bZöRçÞè‡Vm£zŸmƒ6Å¥taÒgôC 9Š5 ÅckB•¸ô ¦ºeè•õb1) !‘6Ö̉ÀpOÕ; ÇÔ×`UÀ).xü€ï’^ºÂLå®qC/!ìÿÀXYGÏ_[ §¥Ûp0éàæ¥¸ã8•«RµÍ&™¤‘‘pÚë÷ĆÌ#íõ£­öÐý+fʲÕL6k½ÌÔ=tákŒ s«€ß¯Æ°ñ%Ä6©º¿énåÓ^§adõ,·D¸Â,E¡ÊŠìý$h¸m@í'®èpª r¨ÌF™pÆŠsIìõC[Z¿áY„ÉÅð²G 56lî¨9Á{ F²lÎ|‹Ñ¶;8ï0’C§ìFÒ÷ @;/Îè5é{27-¥ñ ÎV¾îcµâoè—Ë©]þÆ¥‘¦4Ø­~âè.K!Y Üo}ôt ej¼¼ÆÓDºí¥§81œZ_²Öîì)§¬äKÒNëàjÚ|±%ý̧îílõêæÕ}F"†2=x nI èE7Þ7M‹]«P1lCtÁ1¾b_~½ 5¢ìÜ-¤šÇ2g@¼Ó† ¼øÃ¸|­. æS³hœ ›ó°6FKY•¢¢Œ¾ ¶0´¢„¥§¢‹ý†h2­¥šã×Y«úJ ûý§Lí sÞÆÈ4®í” v*ySL(§¯ÜTË­'_ºñEótìO´ŒØzyl°ïÄå=1ʈåè.&>gÛ©^H6wßwßÒ±ÑþùúüêBÀ²µIkE´Fý€zaH0]ÿ¶4†^¿»êÁ=Óä‚#C ÀÒŒ›g"ƒº{-ÍçÁ^d&_£aà±[Èü¤°%czù\Ö>š-,ï’ Ÿ¤¾_YË&CèK§ÖÞìCƒeëP+Ÿoâ,¼ÇÖ5»ýü vܢwm¾ÉçãºÀãj IÕ†1†ƒG]³AÞ-¿€ e_'…5„;'¥3Í1ƒ´¦õ¤T߆Â5Ì åà¢õÒ”NÙ$ DSÍt*Æ„rq Šëí}ŸÄeÒépjO¨ÿ„ùKZ;JYª†vò©DîÓœ«˜UÞ´“k-¿$©¼XFÖô—srzó­/.¸Ë:!ÙÙ“Ÿ‘á`YN4Ë’ËÚíÊ'Á‚©§Š?«ª9k F¶û?ýôÎÈ$Ì'Óæ 6 Ó·Iý%¸@Ÿõð­¸#Ù$B ©«)é$'넲tÖ£´è)%Ò½Ô@œRm…íRx‡:ÁŽ ¯ s¤È”~¼úžgøuâ̾{¶%A:ͧãfHS#ö×׉ÑÖ§€ eaAóŠãøä2©¿Za-%¹³NÙ’NhÕÊzzKAyÏ;=ƒæá¼yé=§6_¾i*À2~=¦Ï‹CÎÅ©ì‰œé£»Æ óÔ“¶Wž4Á «ÄŒ  säŽs~·ãD*ZB ñ¶â¢ƒJH¥Õ‘f#™b™Öà˜¿eôx]ëÅÈaõdÖ¿R$ÏuÓ†|Ù¿,ññØäÁëw.®$ß.ÚN;DÍ2ñØ­Íþ/0rAžCÃ÷ðü™ÒpB”h››ŽÎº]Äœ’áÞ¾ôýɾ„ªW Ç­‡LK/mŸ =MN®y“q•†éМMZ ·Cí·‚ð(ñ[ÊÊ\6ÿ"¤’”âAvb%-ƒœ´žîL%y¶”MíÇx]|*›p¥e(¹ÞI³ ;’mZF—ñ>'i½K­;¤¸•i{ò IBœXÌ&Œq!Îz°HFõY¶9žéu;=s‹ ï*° ïåØoŽãô5Ù¥K‡¨f/ÕÏowßüÿ±×dýˆ8Ø×—5{j ÑLçŽ7t{gñ“é“ïcPˆPG¶7ô{›îÿþÙøÙþqÿû…´o%5>þpÆ$ÞDê&§¾í×;}5«@µ¶MR÷º{öÃw¿íS2j÷üîJ¿`êrµXûl<5dàÙ¤ÉÆþ£Ï§ªŸèãAsÝNû·'ƒþ£!^}f{V¯ÔZä ß§þšǪ=ÿ´©ÿt<ü¾GWtu°©Ïßu«¯fL«kÆô §À¥<ƤÓ3e4·Ùgï8ÞÃé}wÓäëózül(ѳv³&ëȉG38×_TÎ7äëÍÝ=ÝÅØ¹_æv;öáíWNýw Ofrûs~n:áѼ‹ñn^åƒ9?ü,ÃÔGçn»{³…}•xÓVlð`6j[ë ²š…Oûãó¬†[º¶0ý}õÄ\#„4=lŒ§¥Ë‰Ã¨ôÔRÔ‹µ[Z!(hñWŽXÓñV0SYcŒEÛðz ÀjE—âccÁuÿBw è¾0tKûN¤´ÜRt ‹ù©jïÿhÚýE.­°_ÖÔñËÒŽ¯ë®«/VÇF³Á;†ƒAôÂB×8Ó1ÇÉóƒ´™úª[\ˆÊ8V+[Ó…ÃÙÆ6Å÷ $\®kƒ™Ã@'lêäHC;)…ArÔS·†¾-.ì<†2–¤xið @Ç?Ñ_ÑG<k›j…€þ}†`&À4†¡Ñ‘Öf+NÊõ0#4ü¡Ä¦pL¡³Û᤬#ŠƒŽ°´ø‡q έgB —¢]íã°©‚a…ÕñQ`úìWœª©EÁu;k@^^cð tËÄ%0yîÔW{TÅK0çF˜×Ê`Þ ß‹ok¶Z2 ”m þ4‚†bb ÈÜG‡×®×³3<¼«¤«¯6ALj«kÎØúÞÞ{ªAÖHXG;‹\Öß‚Š/ÁoˆCliqô[œòedãÞcàâ¤uðZ2%^wbkÜËFqõÞîKýL®³ÏÊèc³d_°Ž>5 õj«ek`4 1þó÷­¶MÂþb¾QzbLdÃöƒ×ZLk€÷…aRmuuZoÄÜu~cù@kŸëw~ÉWzŠ ÷vÚ,©Ì„«úœ¤—Óìl)¶A«Üx´ª³Aœ”Z÷4=4Õ Â óÑ75Nã¦B¸1 Ö·&T‡ÞNÓq²)t™õÄ9`‚}Çæ´n˜Î·{hkÚŒ‹Â2 /cXŽŠ4Í5Vk†N Ž¯è¹½Ö“/†¥Ð[Aà¥î¿—¹K ÇÊ>.$5—2ÆÂpÀLÍýnô¯îðxÎþŠFnªñoE†ˆCb V ó=àS&­  Ñ”—¡ 9ìeÄàš·]É… ãX¿Ñî;ìÄgxé á–r/4äB®ûó9ìÏÔ¹¬Â+EÝ+I±îÊœ¥!'‘p‹Â ’ `·ÊZª><õ奩sÛa°ñTަ ˆ¬ˆ‹y/d"À÷–Ñ× ÖbÌ$Œ.û¹šˆ[JÄcRÊ£7ö¤ŒÜu/¡‰à !ÅÇ{}¢tœHŠø+®ˆA#IHâ­òߌðZu’<Æ æ]Ò ¸¤…EPö5HÝä Vºç&'õ¡1ÿŠ‹,Àc‚Æ=¢f–÷ûL(²â’ð, B.Œ‰‘ßDŠÕyT1 bS–$u‘WõÐýM-õ訸ÓüJ(ÎðIz¾wõ/õ¡BL#º˜ ‘ìoÚ{œÚ‹qYû;lƒ1ÈÀ6¿ £3Uä!ÔâB! PoÂã/ÂxvV˜Sz3Jè%(ÒºLóÌDXÒ<\3ͽ׬±Èþ'²W œ±¹¹?XVÞ<¦B¶‚{üÚ)!dèáZüž´ÏBZ\Ù>(…£…înëa~&²æ†©WF¨y'û-á?ý§ÿ”_€7~ÀŸßî›~þùólñŸ#è9<ô³­~ìÈú÷çˆ+þŸ0ÿ†¿þ¡ù„vü)žó _ûòú7÷úý ð±úxûPéŸÉ:ûs…û#öÏb‡TÍÁôÈgôÀ•iôŒZ3­"^~Mi£r’[ÔCTiÐÔ¨ÂÔ'ÂôéÑï]çZ0«ˆ#;ØTFìd·aCN˜5/¥›cº Öüéž©c]ëŽi„àg®4†QÁƒpNŽXÏ€ñ)áѽ`§è®•Â^%®æÑ=`LZŸÐS“¢{/7?¨­qªV4µ¡ØÐÕ†X™Î€€Pá¡´‚«aP~ƒ©Ìé8™5Äk$ÑÇWo`Sï1µ­^”S¦Ã :Ã}aÖ4‡ú:Xhj7£®¶“?§©…KiJOAŠ~ƒŽJŸ+< Ù[b „0ú¸éúhÒ8/êl§Žó|3¬°Ä"kȬ8Ç®ÓXómi¼±þêŠjð:NÕ¾]šÐÄ¡ë[»©_›0ÅÀÛÔbŠ;¤Û˜ì×1[;]Ód®lí„⬌Þw?LÁ§c˜°{Võ@4Go—Á6$Jæ¶úRtà7 é1îf@^à E×7­Á¯=vDDë³î1ÑçPû>*u¨¶Þð>™±¶|÷j€6_›‚l/ãx¡?ï€w²¿Ì-l_x¦;êâ±îYÄsʦÓÞ¥í÷¢¡‚ÀI·mÀ|}¯cxdWS3ÕGß7ÃÛÍ?°ÅÊk­zñ‹íݵÎ#ÃMS¤™*~!áHeHDæÈ RKÉAÇ:lád¢3œ!)v°1 «%¼ÞÖߨÔc)L¥mâÎ`ÕtZÿÒœšéæ ÕVм:~A+{$㢢«ÿwŠ–J¾TÏÀšÔÑÓ½Ú¼þFºÿ“!dgƒYÁ†ÔêŠæÈ“bˆÇiˤpYØFV:}‹Muµ N{b+-©Ú—Ö·f¡z¢ëõܦB³ÇD6µ» ??ÓBŸ¼Rõ‚¡‘÷Ž´vMõRß 1¡#P¼-9ËÁ7GÙ#B¡lñáAÙÖ ŠVø&¤R¥ÙƒÇiš©$)l…û­H˜M³’”EÀ9núQÂ',°aÊf\sz鎜íËÓB–I8óÒYþŒVl¬¨žqã€QÊ>…ZôZƒôûØn@0LP•1  åÓ’ú<‚cRœ0uB Iš¿àSî´Æ5?¬1›m©~HBHÔ“E”îP:þ½=%Rq=÷ÿ¤‰Zy\÷¢TlÜwÀëZ³O¹hH¼úZíhN§•mìj£«9àMîAëbVŒ÷ýAf—C|݃‚eÎHiëÚ_¤˜r14ÄŠTª´X¨fÒ½w_µ@£[[‡yA0Šõ£’¥…Åäø…;ͯˆÑ!ðZ8¼0\èLÑÇ^~Þ~ÞäÓ@ùÎxþ¬TZýëÁŸå³ÇÃÿƒþýqó{¯Dezö&ýúæ;¾dŸýZœ~6Ejƒ4ÍÍ»Ñ'bþçØ:ƒ>âMLû}C¼yNý>_Ãê?-ß¹{8,/óÆç1ê¥êÉ~T #¾#zêçÛ¥ÊvçwD†ñ‚›Ï•Sû?X>ùÑÚ)¡ý–†ا~°”,§õCD)$ÃÌÔ’*úÙÌIQ'U½B;¹êf}!΢ ”r÷«Œ®æOãúé‹¥¼Uôüu9ò `ƒ,J¹œêu ƒåñ²² UϬ¬ÅiSÔù¦S™³oúè©v¡-+q%-ÔÒܶ5û¸‚»kÃMŸ0%Z©¯|C¨h \â°„lúŽ€d?.¶´T©#Eh}å8zÁßQKëFËPðI=†TÕ‰=d\„xy¨A¨ñ~rų“æ!n1B|ÔþU¬ùj³TCL4²$cÆE¡©k3Õb:4mž¶Eš¥užìhÎ>õŤÃ•æ“x.Ñ”ˆÒú5:F Æ\Iú]}F 1{F_{-ãÍ;LËПeÈUBjYG]ª}U–PÕ"€…ÒäB|zFü‹QKî>!Þ÷Ÿ‚̪4#sµGUòÒSwˆs gmù» (2dnå^_&T-3¢!¹wòLIëZö„:†îfqS®m¥§µŒ²^{™ZK!É™xß Æ!. Œs.d  Š¶{_Õ1ÏÝ”½Pób(‘0)¹Ó6¯=;‹¾bV6‹2ð{_8("i¼2DÇp°îFïh`ØÞÄÖSCîBú•ybÂmFå?ØÕò&¸dY7FócìêOJ@Ìl#æ¬$gÒYí²¦ ›‚[ E†bZ }€â¼>lÔ ³j½BU%CÆs#~i-!$e‹¦ì‰ˆ¦Ú„èiO}šÔMÚ—0+8iJ¤Œ©W9B£d‡dütgã(õ*ì/äiORÈ|*Ci÷—Œé%·Y™(¬þÒ&{OíGtÀ`H„)=h«šØ™ Jd žâ/—Ñt¢0àb¬“S /üJÆèënRÌ‘¢¾i0) Fe‹0øÄ$Ð5Õ¤iã ®¬Â*7d Wýš‚M¸“¦º!Ëû2›ó¬ó !†ŸebH/æ¬-ãÂáè/QMµJÒÛ†æñ‹j 3&‡Þí0Ÿ©±jG©„<•Ji8MJ82YáËÀ’‘ ÂÑf®„—Föf­aª[¬¦&x@WTr•ÂH>1ÌÏSøÚ™v¤jnZHTD¯!Ü/‘|ª¹ñ§´³ì¬¿hÍšÚº²ZÁß³!S_B’c˜lˆª•T8ÑpÚñ4ÐQŽtõ9͈¤údŠÞ›®ÞÖ×U)J ¸eFÈ–mŽf›E âé0£œÛü…%޵lI¦$LÌÔ¯ƒƒIyÌï½7]¨RUöC³ÑÚ¤ ºAç°ÎLóÔ5õjÿ§aZ„!y¦ðH™JYúÁá ’r #Ë¡Ñáj¼+cÑŒdY1¬[!x’œ«B$Ät9ßiŠŽ}ô—ƒJ†ííÏï<:Û{v1­æk@TM‘Ð×€âƒ'Áñ³pñ[RèÛ´Â'o{ñh'½//ºjÅT|Š×Åô‡"ð8è'۾ЋÊüôlÔËÇ­¸‘6®‹ßý´ð*]´AX7ß-zå¤' §î1<Ù$Õí„óP¤ÜD`ž2ËÏ+^?\½ã®P Ã’5ù™ -Ìí%åPd:ô£ìˆ.‚í$ù*œFÆvZ1‹—uªvÙ«zWÈK΂g`bÈ öÙ¡š³‰x€Š§ûûp/,o/ÜPƒ&´ÌÄÐN-†y{U#ø\Dĸ¸ÂŠáûò`ë0œºú<[1—„Wä¬yrõÝ:œöᘥíŸèLc=|/4÷gXí2†¹fYÚ¡`&šò¨0´/?–2_1dÇ¢µwa Èô$!¢ÎF¬áÎ ³ákŒÅðq¸ìT¹‡ã–=†ĶbÚÉïe«‰ß@ÚŒž˜Î?Ѥ­/ÑýCúAØ¥4š_†‹a4YÛ`õÁî¥D‘\½®ó£-æ`ËÚäEƒãiÜí6G/‘=vd]_²·q`4lÁÖ7wÜßMÛGƒ Îû¶ãE_§' /\Ÿ‹Ð£ Œi˜àX‡xoG'`®Ï³× ¶¦GØ_„;i4·æf}q”m½4$0¦¹ÆöS9mÂ-ž³ó7JcÒ½™æ¿j;—þxÒ ~È›WABj›ÑÜt§“»–óÒÛ X׿ ’ê­’ý$)Ò Ó!'ôI§®`]æ«X:¼XH¯íDâºviHk½Tn4&éD6õ °e#Pºìt²’æ_°}E‚ü"× ò’É©°n¯ÁƶʩKö3¢ô·üœ²Lä7€r¦Ï—~SAKò5!Ý÷à‚ùÔ¬U cSN3Ó ÔÛÖ¯²9d~.ÍhðgHG=J¿?©p?[VÆNT2¥u‚«ˆ¨bËzEú7b”ù$¨ŸÜã…N‘RŠÁ_Oã]}>2ôtU "“D ØÉKÀHjV4ÑNŒ¸°Š=ÕsH*`Øã%H`ÂÏ¡9ì7Ð>Ñ¢èWôÝcœ‹þ)#’4É(i|æë™h I'ϧyJirÕƒå¨4Q¾O4ñ9 (åÝ—ÏL†Áƒ8ý¬Œ¤H“Èš„!«ÍEeî’ð¾d_2½âèä‚ÏLóUò¬2 #$}oÞÓ2D{.WŒIØøLÛ»=õÕ§<ñ“²ëä­¤›´L>‘&¯íû£qZü’h jdµ{R²ùd>N1'ÀÌÇ¥ˆ õâµQ ®3ØC«æUPA¿ô±o¢d<§YKA{BFë¤5ö“6Ƨ_Ïá¥vj›´Tý—ÚÀ^PŽCŒMÅâ& |:ïÚÁ‡Ð§qæ]Œzt½7…>~Nÿîëq&s)/WÝ„PÇgƇããm#ÏñYh ÆÏ£îY›OSO¦å“ÿn£„¯­g'’÷íý}¶Ÿ=ôW×Á66§ó»iì´Á…Ç·<}t *iHîêÓ3¬N4¯%w3hž–ùÁ¿þζÑ¥U¦¸r8%þ8æi|™,_d ÞõæÝOŸ=o?3Oz}²•¿—Þ:­onîmu¿.\»Ò&çÇ/¬Ü´ÕXJwâ5ãŒ16Ñ´“Ý×ÁësÐõÔ[ÒgIáTZ“²íÀ¿‰.-„ôö†¦§½àkÈâíçY•R¹}&MùâÐaZ×7iÇ¡¯å¦#¢1`ž•O¾ÖáûZ6û@š ±ލXº^Ò‡”Ž^bAcuÉØÊԘǾ7‡~òW/JÉÃ0¶~)ÒÚƒ_ÊbÔ`@Ö·ßY¯{_¡¾Ë± …§Ã„xðô±‡ PGVБ?E¢-ÃЇCÞ~¬½ ©ïë¬PÌG £Ñ%V9Ь(„1ø`챨-W›_»wºï1æ(JÖá5ž™” %£Ï¼Ôœú4¤þùÚ‹ÒúégÒú=gÜz‡àZh83;¡3¾ÐŒþƒGŠ!“¿jV¼1‡12 iÜÅÓÙù`džr¹ÆŠ°zÈêµ š(1sí졎€O/Þ¶ÎŽàá€mclSn™¼—p.£t@‹OîU{àŸqÔldÕ1ndÞìÃFlmÞà°°ŸÊ8 [íW¬YpÑœâüñƒ»røÙR? /!@ààq¶úš×¼ÏNXì·Ï¯¶_%ñûÉÖ¼§²I×Üåh¯‰!qïLå6e[Ï “µÎñ¿TµÒ½¬çÏ……;Õwé·1Bc¨ÐGjÐÓôÜCu±%8Ý3+ $•§ô:áWÁ%¿áa…Ü”–dE=Ö±f¼GKÑî4[af¬PúÜ1Ôõ7 ¼Û›£¹LÑ—A+‚ è17§Ý …sRCž)!èuíÿnúá9?odá>Œþ蟅‡,_Œº‡OˆD)ÕÔéqhah"”1“ò­ÑAPˆ{ËÈIÒ¬¤¢Ìˆ*ÃVMÑØ†ú .Ãs>á©"ñîã!…‚¤YŽ Ÿ¹¶ ™3»}$ÖXl¡˜“ ]íø÷B=ùD“/\Åq6×ɯcÿ Ä ª³=8tcU±æg4¡dW¿JÜÒÀ_‘wv–#ÙW#_ŠaAŸKõ p¼*¬`{c«Z”îYžL=©¿ [ † ﯨd눜˜›™'v‚ŠiÅ¿!“pA ^O)K§x¨¤uB+‚ »;ó©53­(xa.Åiú.?^d„í Ee‰ƒ‘ƸРÂq#ñ¤b]¤m`ƒd>6&B Â%P ÄPí½&FØü%¬7jq†c±Ab ¬÷±cÊ´7¡˜¬-¶çtyÝôÓÜžUu…Å$„®>9Éݬ•ºEùmE÷Ë‚#—O{|1ÎM¬.£`ì妴²‰¨u6Ï'~BÆÂeïcî@4†3BÐ-9Ig¬—ØÊ|źŒòãÊ´9 ¸-$Û¶Ñ)Þ+btIضW¶y€·ÀëÞb èß‹A#ijÿ£üXÓ÷µ£MAfVz×"7D—•¡&åŠ7ÙUBjÒ[‡þpÝù8ûvÛ“®ŸÝdî\òÖTÇêÖpFºàóížšŠøB ¬yLähðÅ>Ð=BN°èéÞSƼ)äÀæ¯)íÁT³ÜCž¼kÈ+„ç|C\Øï@ƺç #êÕ‚Ñç¢ËŒ››Æ$ŠLj¸õÞŽÄ8C–Žéž° õ?â¡©¤HlK‘hGW¾SO§É¿JÛÞýxÜ #:ämæã¢þKêa„ÁñÙb>0õÀØ¿j³„Y= 'bT áྲõÆ9höH²/wD †^ú\lÏ­ 4˸&wrø35%»‹®Û¾" 35eHÙOÌ+Ï$ÇŠq3¯a~xøLßÿ-Òü¿ ‹=!³,ïÞÔáû(ÛCøõ#~5¢Ú'nTÄ7§,ÞQƒïEŒû1Þ3G_¿ìv1Äø˜$EÁì«z°Y0ླHðaýpdÍú`Â/1±ïn™`1ÂÇù5?~AsDqE–Ü'ß`i¯£ÂRŠÑ¨R èÌð·ŸüT]ê ¥ pc(4TËSeIZî…‚•¤°`ÊLšA%/ÓaÑ® ¼F<#H‘*c¨åP/Žd÷jt­« ôˆTT¿«ñîIF~È“+J­µìCS»¶êPHJ6dóÞ5õuä¢fÑ´×Y‡žÔ´ OIF×p%u$÷¨HUišäa…Y¤ˆöš+rt¡y‚O¹Ñ_¶Š{5Ĥ>!j'@ÊSczyó43ÿòÝÐçÊÐÛKé÷TÜêšPO ´œ0¡g¬übÎ’bd›¶Ï&áx6rLRм(H±LpPõšHt#ÆFi4,¥H?€‚÷9ùÅ  ªM†ªjDHÇ‘ì«bšzRìùA3½è[UÑ Ï%æi‰óÓQˆƃ EèÏÂí!³AÕ…|-K)Ls>Ý!¡yVÊi/Ýõi²¿ æðI@!€K»¦Î”U»Ö$Á«®þ¿”ìPxpªÇ‘ !~À–“*€c¼]I©Fa8È~ð£ä †bBè2ISú>Á¡' çl'"ÀPÔ~©%tâ7ìmãïñ„®rPÛÈ®½„4„Ù˦7“!Ó;kÎg¤xÈ¥Eø/«/ò¬›6ð?ÐpÆ×Òâ¨ì »ÖŽî O7ožä>Oˆ_Pía!~hágI¬^W³bøPÛ™„Ë×}õÍ|ì¼?Êñ¨7lþº¹!NÇF´î ™÷ò^Ô_¼d=^د„ÕãÄä5 ÝkÚûoÿíËy³Ó²…4”]þÕSB.ÚûäÓó™õûÏêó"»«}<¾{„Ä.õ0nRοr|€CͧíëȺÆTöý¶dÌxÂÛÞ>b {wÒ~mý´!N¿×çÍãkrYÖø"ªz?0‡1|¾ós;Ö#°Tbб^ž¾áðØŸE|a.?š.çîzsÑÞ+Þzs»œØñï!I¦™ó¥ùännúýý c ÷‹Ê£Uà! åq9< ÉM3±]ðaŒ½™1Ïžõð¿—ïàûô¾ýhl¾ë›™x¶èÞÄ'Ãåã¡ °C0†žÕžbþ£‡‘ÿÐz—ç;’›u‹oÄÆÁ£.<Íã§ÁøƒNA“ü=Ï¡¶f~aG™ž—í/,Æœ†¦OµaØ>Ÿçøðdy¿Ç½[‹ëÆ—*s8v2˜qÅIeAÓj) ,º{åa)t …,že:QÚþ Ápcœz{C3N ±›'W5+&„8¼‚O%w††+ •ÒûejZ [CÜ ˆX9 tJ¨*VWãRä‘B×3’uª"ÒÒ}è©û«ožÄ#°ÁÇÜhÀ”äMùJp¨T|Bå jŽðFsº)“”O º oÇ"®ØâØŒ>Äà[ʰ©ÎP¤ubž—}þ:Å%»<äT â˺}v¡p„!/ƒ:Ÿ&mëmÊy†R`ÆÝ©V0&?¹kH¤çÚÅcü*åy‰ƒ:ÑÉE*Õ0‰ÿ†q£ÁÍÉY m1ž‚ÈxSÜA]Š1xcI3› Á¹X=NÂe:Ñ d£páËkìAŠt“9µ‚«¡qNâJ¢¡»{\¤"ZŸ,B°±kÞ¦`¯„‘àÕfÏ2æ”_‚­™š})Çr4²(¿)ò7'Êw7š =æ%ã8@'"Ø¿ŠG Íý„«æ©*º»²Í;´Â`icÍc¤RŠhÂ0Îòž%z²Ö×ö¹“©o¶5,ÈûIãP:DûÁ‘øA²ÔVÑ3CŠ^Z*‡ÜÖnP#Rö4Úkõ[ ÏœÕ_2Žã5Ÿj¾òÊê±¾¾’0PCùÑEsBÍ]‘tݬ˜˜0skÛDc_Mõs7z\Fû=¾@†„:&= 6VDÃ/bàD`¶¤A‹²‘d@ˆRŒ* Á"9Êl‚9®D¯ìŸŒLrM‘ Pu¾#Uª”{0e¥¶ÈP,­àÛ1ì!r^ا—ƒ,ý'Ê-ì½ )AQ?òE¬‰ÓlÉ{ŽT.VP…žø÷–ŽÆðýŽyÐùº#l:¯Æ¦Uâ5ØkBÀªdœsC{ꉅ÷›¥·S-å¥Qþ¤'IÑ…-À^& Æ:51%lǺÙxg¥¨¡šÞ|È¡:òBÔQU˜¢—Cî0èýÉ|hyéTƒ¶tiîù%$pj/‡yä² ûqd0- >—ûàƒÆat„!“7£ŒaD;8hê>.ßÉ¢áRMÅD6˜ô2ÎÏ9Ž'Ï覙èˆ ŠÊÔÞ‹±ô)u%‹Q¬º†™-Ï05ÆCgê"Œ×ô¸€QºXT¹†óJ4ÕI!µš/—‰X(Íûå§®Mí}@O´ù oI° e–úth±ø¬›í…ð£¿G°Wƒ 6ýnñÇXãi"Ÿ~,ö÷˜ÛK1ó©Žù9Á5ù åõ°S÷v¼„W¯¡Àª[,ÈY÷¢×±^Ã7VTC à…ôC¶Ýt³ûKÜÚ’×ÛU¡Õ¯Aý4^ ±z ÷ckúÌ_à—žCÝpz?÷£ëÑ'à ~x1±ŒG³üÃbýn:ÅX«ûæßþ=¦ê¨únÚê8LLqÏlœójøŽyâ@ƒy;µú Ð óžXÑ ÅäÈC#¿l®á,£ ,?•œNÝ]ôƒžErU;/X±û:dO¢ûJìí1qQÌlý½¥ëÑ3†àNY=¾süÆ Æ qïÃõŠé8Äʶ9@ËíÖˆ^ ?{é|k p—¹!i0`ð1xÍúe,;"Ep±ò:x³\?Á<ç‡lU[sä×W[ÓgeÖaŽA׫˿lß{µ!w²ådBôùÁ”Èè_Ä{‡¾G9eÉåL«Ÿ$7A_ëÖXûÜý·Â¼Z|m@ßøÃ½-Ðö€íŽhŸq}vöGNÀ´˜?`L‹ÂÄêŸcß¡uàôÖB_?†s8&• š×¹3 g2 )# _·`{¼YÉà^G-•8[º3X¯½4dmê—]&Ü¡™Pì½ö·Þùŵ’•N²â¤Ó“×tîVuGÙÌgÚ)Yòé-"—R€•u qé­sA8&rO¯B×L/bÚF¦Íί”ìËA'CTÅÅ`lŒQY ŒÜҽسí“ÀÔS©ËZ޽Xw?·¿q+Ÿ—‚RíöOõÕØ'öTœ˜–ØžÐöÚ§|Ê—zºlÕ€û^“„Öaú™š²«‚0‡Œ@ÅÍZüɉ+lÏÎ(Deî²pR@v Rv¥f¯…Òùn4-`u‡R.\k˜R?Ê8hüPá0gñ’ÝÔËçäê{1ÔžOt¢™ŒÃ@›Ã)Qyª¨|fEçö–>¥ÅŽB!&V¶² Tæœ9§ßSO{kŒ]>0!'EâK£)ᦿ¿± jìú9šŸ ^~Û[Ã]Ô`F3¹4ÊO¥H {ÈœÞKéè3¹=IŒ¡â.B5盳Ü$ÈW¨²<Þ4N¤di’DLxó'§2¶¶½ £T1uÍ ˜ðÅv:ëÕX2ι¯Zä)1Õõp±pª˜Éac±½¶ÿ‹‰ç÷ù„¨3 Óî¶9Õ¡ü‹(k”-Sœû$³Ö^FÉÔ°"Ũr‡)EÚkY £î%ɳ$©Æ”2ˆ;óá`Á^Fìm&ú”M݃-Å¿")¬%ðIZ:ÙÛ¤ûˆ]sðgJãi?ð^’i©Qn>Gm­•¡IcÚ|2HP„½mØCȘêce?Uò8â} ÕÀë2Ü– {}`/§Pb€iŠ9ê!“ä6ŒIÊ´f«ø"a•„'Ðj‘°‚ôÔâv&²|ˆ"‡u!¶aq”ƒ G¥¦å©!YSÎV%¥åôõU÷ó*8õ›Ù ¤×gþûÿï­Žd2UOGDL˜'ãüâç/xúƒ†ßïüá]Õ%>ÇùMmd¾âù)·åx½÷Ï|ûû2yÈß\«ñüKÏÚát‰Oæq«çç=~dêò¯wft§Àïkw¸ën‡F¦ÍÃWGë÷>‚6ña惚pú/ÝÛßׂKÒâëãÑ3þÈŽù, O³û&2?ÿÅÌ! Ü¯=‚y`¾ 4&/vìÏú6¦"ß3Œ£·=–cúbOþ qô]1ý¤-ŸïFIdO¿oª}¶[øîàÿ#6öd·ŸL«÷»ë–;¼ÉUPÀÓôŒ›)jñäËcüÍZrè5[lè77ŽânìvÆóñn:MÉõ]ï,Õ 7ŒÉÒ-b;+ýCMðT IÉ[mlóº ÔۄŰf?Ü·CqnZîÐäò5½Õkº¦5§þVXùóP³¿†4ßA{Ьj•>|+1|FÄÇeU^»§ç9‰íÅâ&Ía¾/ÚΚ¢-¬†‰ÑQ( x+C)‚ö`Òîïø0ûÂÀŸ=b@ù"¼˜Þc– ¬Ö6ñǸ Ja™áe¾£ÏÑÕDÁK0%íVŸW^ymêîïÓ¼DÚüY¡qF"Ê«Z9'ºœÍѯÈ6Ce½–ÙcêÂdÁé[˜ÈÅä±–I’§­ ÛÂho±¨Ÿ:UÑ_¬þkõ¹Œ÷Å´¨º‡†î.B=²&BÐǼ9†y„N‹úœuA…S,hÂG×õִǵé°Ð<Ú¦13¬ÖVl?ù’…øo8¦êñ~±7ÑRß0é«uí:ÝcÍ«ÇYOi7kI!wšk¡µþ{ùó2Ž×E‹~aíe×¢×BnÖ}6E¢LIKsJ‚U•xìôt¾¨—Ô‚Ä$Œ‚CA•‰Ò¼=8u/E¯0ÈÁræC éNÊxHú-8]Çiª~bœcÈÌVù iAë&tù|R‘ušàºx mëf9(@¡MŒ9Uröú}hz¿I±jçF»2ýh½á,•bŒBø¼HšSÖ©ªÛ0ßMH†¦{¥fÔwR™V \)R´U±°Œä‚³«›²p-ê8J¯B‹Õ¸Ør\Š_• Íôž¡([f{é×A+…¾Óìi)hF¡x.RÙKL¬BýÃcŒD$’0Ž©x—½ ’bL†9iÎT·¥ÆöE2I—"KC8•ÌB¼H½Ò镃¦APL&#Œ :T  P¬…â˜,4ÒŒXÈ#æò[qÿ"CK*ÞÓC Íaº¢¬z&Ç¥ ^V1F„5*[b,Uù„^Ï7HÛ‚üXxbks6A• £8Šq|šIB&iÅ òù$+è;ÜŸêšïIâ«ùMP±//ˆ±×_oƒØÁžº† sÌÇàF@ˆNŽ-:7®‰„t´„dÔSdã«aE·ùIñL*iÔ¬ï%7Ý'×i´ÉPÏ”¤±Jc‰ž'é{òº/9PGÃï9‹Æ{(æ³Õtî»Ûmø3ÇÄô=¤¨¨Z†í-å%$k¯b¾Y[€†×$ÁÁh}n¾nÙ è[*Ü3~Ù´óRb¸6 ±äöÉS$:ÂÞφ½ßHö63‘Æ£·œLÒ<ºM!œRdþY¬©Øð±÷ªó±2 üÿñ?~{ÿõßéŸï2£ÿÓ8ÙÿüóóÏÏ?øàñóÏÏfÿùç矟ûçŸÿ³þ,KÎ'±8ƒ7¦~è-ª«ú˜´\:MiÂàîªî>zztŸ2HT ¿c‘hÊ6” à†ô7uó±Pý} R°Ž;M À°¨;¦gdâŒþ8^Ñx4 iµƒ0”cRÄ u…6ìf°dôxˆ)åߥa`¼LÒ“Œ¡¨þ7<JéYH?vU0ö´`ô­Í¹<­r«CZ{Jì»Ú †HÑ4õUMßÐÓâÂ1 |˜Âæ&+¸¸¤³{àL¡c™’æ‡ÊÃUý’ï™—š‚Ÿä½bÔq?ÅC‹"MU©y˜Ç€Clœ%LO¨(0ôŸ–Âð‡ÉᛤýѤ‡%þŒ(Foƒcx‰®aÔüT&L4&í æÜv˜=17£\(ϱ‹¶âatìæ56<ö´8á(ËÂbZlÜOæÍ\9!Äm®ã~½š×ÚóÇhãçƒØ„©wÐÆQbkÂ~ùðqÃrÃê}‡á=#ëÑÔðºœp¨·Ø –†qeGsÇú<þP³¿Ó‰>ÔÆÖ3˜§KÛ«Ô$m|OûÇÝ·#öu8loëû¬>Ÿãˆjã‘}°´n`öyk‹BØ>fz8`͇ûb ßê/¥y®˜Mub19*ýJÞ9³Ò¬"Zìjá&¨W)Jæš«LHu¦*ðçrlNiZ¢ºî9m'«,ÁB0¡øLZÀ]mÆLPÿåµ!kž!®¤’±MóËÁV›Qü7ñ&á.Ŭ]}{¥ÈÁÊ3Qi½®â΋IŠŸ@š²T~+"½‹æ‘!JKÁFxAªEnaz6¨b +u‘wa7QãÖ0’pÂ/ܳCTȃ!D,]’>å9š†€Ô0®çè^.•’¯";ÞÐ'ÏÃÌÆàs^WÑÌìH<2JÁD7®”†6œ±À5lÅÂK’âR•ÍY5+›Rï(÷Æ`ÏR¸¡¹Q›£RïQ­0`õ?#IÚýʦ ¬’—¬u©æ8¡$ÔÄ+§á¤ +dvhu¯0Ü„`l[%ë2HÛL®Qb®ÚüK$^Îuź%¡kþ•©B2(²” ÷$Ò•·ƒÈ½b‘I2>H„ FaÓM6ÓÊAmýÉ´MŒI|õ”T•CÆ$¤„ ¢þHB#iíuŸŠwºñªµ!§?W|2 °b”Ž_5f¿” !j”!XD/Ý¿#x]øv QFdŸ‘hrwjQ² 5Þ'm';[Ù—b%żdäE•$áŸg•-¹ŠÖ&c| 2pLÓ²%qŸá >;{>ù£éf?y¿Ì;}ŠîA/sâÑí§Üs#›|•+›%Ü„š"ÜDlcV£‚ÏÇ´˜j=ýŒhü½#! MõUð«^âÏjg gÐ:“æ§è•÷!mC¾uûÿû?ÿgÞ"ø,øëd ^µýÚô¹ÓµØÌ*…[ýj˸{uZH>ú`ºi8‡¶~b“ïÆâ0†nîäÉ;½œ¾2Í¿ ™èßÕg0&ýÍG'q¬ûÌ¢ÆGøÂ³èµòͼ9µª6=kÀæwMí·Wøh¾õè>8íDcêÏãó4²Îmü¬!>Š"‡x8ÉÄÞõüÛ‘ø´¿Þ™Ï~÷Ó›4>çõà«!êÝWE>¹VÓÊ}vHZ:í—Õ¶6ßDÎwíÝNïCìÓG%Ùúª½»îI~pnøª|:_Û–êô¾>?A‘y³j¥ü=ö|Œ¾ëkHm‚Hÿ»Þ§óíÝÚòö£Ï÷DŸ´T¿ô¼¾ÀvDOçÒm[7Pîd—0Þᓸ ©ûÌžk\o¶Ú«RIÙÒŒ’âœÒ4˜_ŠSaRºp§Z i©èŠú½“¡UZÚµé6Pº:;ÆJ8œž„¢W….`£W%Ë9a¤¦¦X‹t÷qÅL4E_ˆÇåØÙ]ªà)50Ö0Z%e9ºÒPRê4éùš„eù‰•+üˆ‰Mw–öÊfà;OK?ö~Mݬc°Âl)"LÓN“ØI£"Rz—íûæ"Â!É>¤¿½/P'}-sŒ}"D9P3‚òr ñë¹ ä,eË&hžº6,àrÄíè ƒ´yºŸ1-u®D²¹;vf±gÐa?>iÞü:…šKûyhʾk¸ÌM½ç„.é®?z•ŠÚ5«l´bÁd0¯ñÀYÁº®L´h:Û¡«ˆ)L5…­®F舘Íka€á.ˆ×yÇ(;ÒCœëký?–Ñ,¬£%hë)[£á52æí$|gqÅ5V¿Ál,K…ô òuˆ°“QÃÞÌíYŸïµo`ˆ| Ç`Ö‘Rt†^v,Aͳ=>ÓÆ†µ›æ:ÿ=ܬ´£â¼¾çŽ€Ù³Ãp2Á¶èX±gœ8š—­ÉêåãÛ<ãÇJ^ÅØŽ ¢mïcŒÆ„ Ûn8‚™Š'ÓˆÍ0]‚… xü'0 N†¨11Cÿ&W›ðŸðÏd›ê僯“†œ½2¦Œ[C½2|óßM‰?h´MèvÝ0±ªJ!8aÐö.²?ôr ÈÞ&i½íi›R4ví}'ap™öûß,Æ&L)š3:uÛ¹Ê~%ÈH»^Ãjl3j¼£é@ý»N˜4¾±Ë¸µ7Z”ÚŒ/š3ȃ$¬i,¥bí,T2²—-Âqšr«ÐÐ`QT Ýðˆñ'É%÷à“-­§jû]:õý˜ ÊàÈÁ9˜a1Z$…q%Ä[)zë½MïšÊ†¢-šÃmÎÉ)©þ2·‚aB0t é’†ip°7iÆ´~LpbŒ.Ái}Î/!êˆh8ƒndqÀ5ĬÏMýø$†T¼@ft‚ãøÒ‘Ù—<'øP£CyK%1IòÉ/ü*øQÁÙóyªY^.el¼R’óS&ØwÓÇÛKHí+!WDµ¥LdµÝ›o!æx¸‡EòŽRü%™G){¨jce¯ÅÃ9°å­öEgs¨5a#F_¼7¼ÁÏÞÚŠ-0ÒÁ9ƒÔº.äU7£9F¹ùoDÝhßO"¤V·ºYj”]}€Lú€~˜ôBØ®{ã5‡ßl–f>„î š;›öÇdÎ?ËTõ¤”5·×÷å`/²Q—£’'u7_tmAMdÜëB©[·° Ç=1®ÀLRìKš§rFªO¼ñüGÒ·\{’+Šû²u‚±XÙãÈiȰ1×uÕ‘Êkg¹ækʱº E¹…Ë¡Î2eï"ëøeî(û,6ØE/eb4]öš¡‡ÀnÐmæ×‘°—âCe‹àé<^R°²ô}ï%L"]Ú v¸*ŽÛ¬8Y÷³šþ¸’ʉú¤ø=I~¹Ý¼'QFOv¤¤oþ¾Á ÷ ¯Á‰c™ä:¬ï†ZÛû‚}5ÚíÒéìT|÷Í?R( ÷`ZõÚ6Ë Ú¢·] …DVtÍE´ãËÀT‰I'H«wž ZçS¡gïÜv¢õÒ_K\é´$Ú fË’øƒP›Îޝ~ÃçŒdø”¹ö“N)Æ’‚ÜÞ£ÌloÀ æ×p;š/ýÙëcËN÷s¬)Èšø¤%~¶Uù6ö–dîV,@üc.ßœ}#˼}0ž¬.Ë~…°C úâÆƒföGØm¿êTo!š©…Šb\¾uŦ¹sµ„û ë œEò_`!ˆC îÍÔØŸÀ ¼ëïËâ1ìX‹E—eQ%30Œ}?Ñ—ç´Í#"b­8x·Ð³O0îÁ…昋9f ]–Š.´yL§Ä@_×äôü5ŸoÏèÙ5t‘ÖÛZ?¯Ë4ŽºPõÿåy²bÈX_ÿY–ŠbÀOª9zAb*ÈãH²Ð_–ŒÍ)«‰—¶IªyäþrísÉ1îý‡^÷ÄÞRDj ¥ZÐ)¼Pp_šËÂF‰À´ Š4+N¥ËÓ–ÆàSÀ6ØòŒé¼f6Á ŠOáј½®µ¯­M1~ºWУÇ-L¤Î Q´^³ˆÖ´5%kµEhéÖ¾óÏVá Ïnø`ñ #EAm°¬—¶Ç/°S‘}š’v²HúÙìâ§1`5)6_oòÉÚËrŒ%œeâäöõ€ôÞv+ó@gÊ0çeXwѶê•×+)Ÿr¤–’Ý=º Ÿ{ijÓ›tfÊÂÌÅ€ÁHGÚId& ¤œög^…VZ°~Ò±³u’U–´ðUؤé:LÙ'pxîÓµ]JEÅ×Cƒ ½ùmŸÞªS~†I§jŸ·lšžTŠ53½"”ôÓ£ú­Š0+ÍRúüI§¯|Ú®Þ-r*h'Ý\Œ.\P «t’R²ú)ûÔë*ößsƒŠÖÀðSF…Oß Úé!Y­—gD^ Ÿú¦×K%®Ÿ¸ò³P¡öãèÅÕV™2WkžìSÑ(!‡«À× ¹FÒsòÆ*ƒ3CìòKVo‚P@¶©õ¥ 5T ,.¹ 8kì]Y!dØ©bÚi_”~û%ø5Ö¶_l+÷|zå&y;4£éìuZìm²Ÿ/}CNq„=VH¡š¹D3dêó1ÉZäš»Wƒbü†à1:‰à2Úê“fLž ñJ^[W¡þÎŒAÇuZ¡8gè’ý\*Néù/gh»3uJ1.ûnQ„ü380ˆ}Ÿi³HÔ ˆ7µîgßhz÷øg*ÑÁ^ÓS*f ñ…}<, j, -t=€H/ñìlm-Ò<=<ŽSfŽÄg|éÒÀq ¹¤ˆA¤x19W< bâ œ’¹LÛ&Õ&ñúOsÂ}YZªXÅØo&íåcÿKFó¤‹4Dö œ¹K"6Èô…³±IŸ7««æÈE/Ø#yJTm–™ƒ N´ ´¯¢|eŠÇVŠg‘E…ê!ÐþŒ÷pÉˬý}jIzÒ Dü’†79[œcÝÆ€Ž„š›±ql3 ÃŒq\%`‘Ýad¶¢&‚18ëf—µôÆ75£ÌF¤A$a“ÀÓRž±pÄí÷L«)4›í²6C}îN7™UOå}ñä&Foª>0žšatòd;yÓÓ‚ZQ¤ÆCR³ÜV4ÅÚ)“ž˜ËºŸ&l/Õ{($Úi|P*’‡XF-Œ1µû…FÔ7’xQKëõóè‘«JN9¢~2N¬°…ço¥\MåeJ¿í¤/hL٠ؼSä²+˜1×qH´ÝYùsĉǮ¶±žv±™)5ð:ÆRnžÙö#á–åÓM=@ 0Ð O½Àƒ.ØÔ\‚•Ðp|M1ò ­ebd'k‘5³œOí t+„o.!`Ü0‡ƒ=GxÍ@‚p)çÐÙu ¦ÃóP+陪ìÙl5„­2•Ié;_llS6mÜY…I¯} ‹ ¦¯ã¡Ê†ö».$–~MJ…ü"ˆƒE€¢iòØïNÆÔþìf 8ÓC +³>Ý“ÔăñûQ„–±ãÂJû^Bï[«ÿËA÷é‡êYµƒŠîqÿêÁÞL÷~O­ã;Ñ,À*f^_—M*=3X±Í?Ã]aÇkæU7¥££Rë3¬…øØY=›…¿}]µŒÃ~hÚçá“„í¥mõšnU§ƒø˜®Å^}®ӗ[­WúhÁ)lÓBp¸Õ¶GKF3Æàéx8 µ n +‘Ínµ"*I#¯Pmn_hÖM/:”rn™¹^¸¹ü„tz 8¤ØgX@û p4BÞ¬8+hW*OS§;µ¹NœGï c¨ð™5&FÃÇú¸P臂8Níɺó ©>³v5€Éøè¨X±ì™ƒæ”Íà éZ¯ûZÊ[bÅQ?F…”€Z ´´‘˜$ó@!8Î éÝ)[­/n«­øMöb£e¡ÅÓ@a4-—l±hQ{S¶;“÷Äò—é£ÏÍj­½,ú¡¥ògÿ-æ˜bº|”Ögê³Ã)Ô‹¯½zÿ0ÎÂü–¤çg¬k·È QXó.ÓÈK4|rh$Ûˆ9"ÕiI0A»ž…Õ¼ ü]wD;»Ú׳a”a;l:¶êÿ—\¸-‚#¨PˆhHÛ²æ]нíh7xD€PkÁÑ–Þç!Åø'd¦K¡vo-+`^ÚŠW§ZÕ.ÞúЇvè‚0Ý>ž­O"šøNÎØk*—LÛuá¥Ã¸îyAE4v|NÕÇ@ ôؾWúqDQ—bš˜àðÚ£zÝêþùR”¿½)ïØ²:æïãÑ÷ ,®1!ÿ-`Ì(dÝØ÷¼<'U¤ïíæ6¼cÜú>¯'µç Ù¯2¶þ‹É^)±4Ø©0ØRn|˜¬@‘1¤Ðê­ì#":ãØ¾$U¼äÚ …ÆÎT©xÖ¢Wàˆ¦’NÔT†tºÃiôÀð³ÐÓÆ)\ŒiÚçëÿÉ©PûAôšSιCô›Óõ¨éˆR}m…`æ+ ßW@Ô…dE}–níév;É ‘Ñi(ãY‰®QoôÕ_0ûù•H^»ÃNÏì4?’N*2©È“OcíƒæÜiž€îOO)•þºDn¦§1¤£mÐʾGøAfõuJamÒØ' *:¹û‚O=©iù~㡢ݠ4x¶SéÔ¼qjV+…ˆpÓ®$­?å…„DÓKg¹OÁd¤HÙžÿ¶‚‹Ž)˵a tµ´õþb ögú DQ$5c#Þ)!¾$»À}ð›ÈP¬(؉¼y€Rd|BÿëI*7™ì ”Ö‡Ù úS|r'Ý~9urŸâKGâ uk+‚d*ü<3 ob‡ ÂaÍ~¥yÔ¤”­V_±õÛšjã—PÜ$t"h.ËÁ­”'gÄß V|Z( Ã.ªM7&ÍžK¼Ï€ BwMd"ƒ¼L¬B*Þ¯ˆˆ‹ráwZ¡pêT3_® `Û â»-ƒ•Êø¦ù…Ø:”fœ"à2 °»‘yîH¦<Ëh{‡p¿¦›9‡ìÞÓZe˜±*ã°ŒI2G";Ûׄ=kV¤ŸµV$šrs ?°çGväl¯5I5°yé:ž&0!©¸lY­¡¦=¯ghÏ<®]ô†æ÷ž÷œá_¨0‡Ä¸T£½F§ ‘–ʘÙÎî~Lç,zv'“âPÒ<ò‚DR3Ì×ïýÿë%F»¾›?þzÿ@Fc¼>þ²a ŒŸøüÙjÜÖ>Φ¶Ù}ö}Ù¡­ŸÉ øJ‹}Ømômë»/ûÊ >¹yï»_áiïoì~çðÎòy#ýØû9ˆ¬=œ}“e¾~,JÔŒð~Ëñ÷%OcÁɦÏÚÓÂÓÜòŸÍ«Œ¡Nã;§¬b…v.áÃ*MŽêÒð6º§lAñIŒ=ˆâ}Ï4ù¸Qo{ýðD?pê? µo¢Þ7pw±¯‡‡?ö`Ìü¨ò]1ý÷úçkýÝÊöÞ,)w[‡vôøð–ŽûÅa,¶x;Œ4×àÇ÷ò´ ûïÍ»0[s—?­5Süý|-¹ûŠ…ˆIÛ*†| ¥ !@·©L¬§¨ÑÅÜ 3/>Œ÷ÕS j ÐÄK.4/ƒés®:%ØŒé•cNµ©K㤴e^\W¼S“ºŽãC îx‡ °Ê¥5–¦2†þäÐ17eO½ï9¥ hŠ}œƒ ÂTËÃëº:’ Ù ¦—â7·—Д>9¿æe#ø‹¡%žú…{s ¡Šä×€©nËÓ¯¬*…A)o™ÊÕ€©µ;c Vês XOµqÜæAM–q”‘”øwhŸwæÉÒSà«i¯a„må>´h41 ýÑë`îb]„ÁZÀþmcj+äZâsálËžýR|*ùÀˆè–g)X!š¯G˜ a ‹½«ÐOÿæeÒµ~HÄÍ|I‰é0µ#Eu0Ó´¾Æ¬a=‘%ÍVŸ8®1Ö\YàÅ?Ÿ0i¨ZZ †64>+z…¶àVš´bõ¢vï^4cR=&EL^k µ†j›§Æäì$ŠÒ_è}†²0¬™³t>†È>×PA÷)öL‚ͦ³LÉoRYŠA‘Ò׺™"b:ºj”Ln¬eŸ_ƒxÕZCí…#ÝT ¿Ý³lXgÚËûîžÖѲníçè0aƒ×=.Ÿ/6ú†ÐNk`Ÿ£¿(KÆi¾Ê[2 ŘÇ7à XúŽq pÆOV&ÁZZqPjáNBð!6Á8S²Â‚Ò.¢œ°Sš9ñ…¤§ž§¤ˆa“^›(Ih:ßÓ¯’f…â;'yÜ`möM7‘Š“½Ò„hÈ=AOT]½C¼V(_‹ÓQ¡{&!aùk-éÚf4ÈÅT×™7R ³MŠf>D}NsÏN«I=ˆÅ ËŒÓ! q¢œÓŒYìM‚kš‘%)¿Øýª¢ m&Eu ‚µ©Š_„*ðÄV¬Ñ8XŠbiÊAR_uSÎ Å?+„š‘ëc¥ Q$½” ê*˜ùzðØfõ-šOåWo”‚úKHÒœ¼bK2Ö6¸û¹ÏÛ±VRÅÄ~K¸S@Q¾á¸¾Å…Bý{’MCcJ*cÃkdš rº(EŠy[)ø¡ûH£NÑ„ªX”ƒU}8rE„i7ê˜WÂî[rmlE)ñ….d?ÊófÇ´Á…}ZX\œ ì‚7Èé5AW›fe(vÍe´µ&›O†6üV³ ò"à 1ñÜŠq eOÝ€TPãõ¤ÎÅ„ezܰ­dïQÍ{íSÒb &‘ŸŒ³g¯­òq(ˆŸ´å£dz «è1Zv£×é%ÇðÁ9ƒ„‚ m«w€ØŠ“ijOÛ{%ø¡pÁ$Lv{¨ýïÿý¿Ÿy«ÿü3›çïäzbôóÏŸ°6Æï¤}Ÿ~ñÏðs¼þ|ÖŸ~öý¹ q•Ì?»ö}û«v þsÊÞÿYš‘äРbf^À(àéÆp,hª@h†zCŠ y³Ò;nfx1›HéÓF´¶Àù¤ PGGF=¤]D®„Oa ié_5ÚÃtÐAç \õ;®@vRÆ‚±[h¦ma*"þ®}ã)è38˜š‹b^°0tÉ88bw"åÑÍî0 zš§=@Š’JX[vA MWhjsÜåOcÕAšºÏÔq€ÁaXÿÚm·š²›dÁѲ˜ÁÜäȤl n²I‡d“ê‹ôsBÑ—ä;Y…lŠ}¢–÷ÿ³÷w;–åÈr.êFä ¶öyI€  ½ÿ•‹œƒ43wŽˆÌÊêîµv°VWeFÌ9~H'éþ¹Y‹‰-¶Á -ãÓÑPÉ l ¢ÕýÃpVñ:gÓÑ¢0Æ·)¦¢F×$¢f¥©ÄM¸G@Äq ¯7äOã£aŽF ß™K5ñ-¹ï6–0© º”¨a:t¤ƒ ª?4|M–¦Ð£Ï Óšˆ+”8nñ+î©™ÿÛj F†ÕqU5„UÕŸfvwY ¬³™ J“Èë°y‘ëù4W€&t ¢ÇÐ0­Lžªþ8¬¨»# Î™óWŒkÀ°/S¹tûŽ2Âü¤^ósÌ1Zþßiª{)ŽbµÊ$ª™Öz„jÄü »˜ «|Œ†½âмÝö¨ˆqIíu4çND1û|Ö5Z1ÑT‡šìA Ìž´ûU yl~,-åYå+JßAÚØ†y—ôŒÓrMlC%DtVîW5¢AÕ³ú&ÆKf‚V™é]tK6MÿS’+Òöõ¹QcÔ»éÊqûEœ#&Q§bø hç"TEaÓSǨË0±½xRTŽZp°Rvÿ€m)ãN”ŲÏIÕ?Ž™k>«ƒ˜0¹l],Í—C€ xW]žå45žƒ!g®ƒjRõ¥ê::×а—Ýt¾Ç2MíÁ)M•mÚtPüc%L’ðëªͩd›…ðÄÓƒ<ª*6¶äqa«“)Ê,/à˜üÊ3Ûjhìf;6ù=ê30Å´:Ê4¶F¤——ù-}~_1”èÏõ¹ë¦~¦þÆÁ?ƒêÛ¥ sŒCH cQâs[%HRP¢Œª©³F0_æº(rq¼Bˆ's/±Ñ#ÿŒDmï„ê&‚åsÛÆ*“k4•°Óf2Ю=ŽÃ@š™ÑOU>´˜DTc(ûS”Êlf¡$)êŸB‡Ç k Ê)5Q ÿ*†§—!âñx¬ü‚;.5NܨS¼lÏ“ÙLµíÌlµ7I¦˜â«2ˆ˜ÝæHÓ}eà ^5 Qöý¹ÿå¿ü—ïV”~¯"øÕ¿ü½-vÁöÍ¿6üéå@uvüg—ð Rsßø­/¾/,§¾ß­²2ÏëU| K·5ÆŽrzù¥óþÂmŠ„æý%ÄïýÎÀ,Ûÿ–§¢o£î¯ÍíoßÍÙßœpßþµ·ù+ßœ,5ÿÒ›z;ÓOÝ~¦¾ÿÞßbë8ÖýݸCî—7þÞõÛ_~ýe?¾Š«ÚˆæUµoÅjåЧ1ôÅÚÇoÚ_žÃ—Iû£ë¯ýܯ=ãò€ØrýJôûÅÈÞGÿÆ…÷/{yøµýÿý/.ž¿4ãÉÿ&ÂÕÇÜ/L˜ß¹gÌÉ?²°e€ùååávïþ¹¯oPÔ¿Æ”Ícñv¹«wÃ'ÐËqêî­e` 7Ùý̬ÁŒŒJÊñˆ¦4ôZ±8ó¢<™æ+4uÍê¢BÿGßÝñ²ÁŒðV¦Žæ-`FK´LͱLèF–©é(”üAÛ¹€VÚüªLí¸Í[™šZ^Ö÷©ej„ã.¿QÈpŠXøûd¥éN:$JÄ·25[™z(Š‹’!,Ë `0 2ŶðÃdÒúÍ25ݬ½Ã¬.p,SwvÊM³ÔlªY¡ŠƒJ•;ùÝN+:‚eß±L-%fÇ}z™“¹’dÖº—©Ë2¤¿]¦þ¼KZ™š­LÝD„÷ql¢‚Šºáˆ¦¶æñj³«%Ž“(”c¨?cb˜TªЈ¤z•§“«ÑÜ84æ@¿óü»z6€¦‹d‰bƒšÄËJ ž5H«œ8í¶:^ü}Ââ´x|tb¼A~.–,ÖdL7˜+ ¢F7^}u …†WšÄ†çZ¬qÅ>FÂi.°Ç =ãŠJ£ÉÈ´Ú…XÛ|¾¢­€ ÏØZo¨S`Ÿn#+/ŸPdF €ñn>{¥fØT$]ØBŸ;† ƒ®kS|=ÑñWkût#^j%š:~üZQ‰¤ºŠ¤!ç`Cs3æOF·‰Ÿ%B  o“ÙÈ>Ü”Ccç†tº—9Íí‡Þ‘X@Á¶?÷žmP¯:ó*BS@è;4'ÄÀJp¼m°¤ØO—÷d”ÐÙ¥n¥ÜIÙ,f©Î‘€f¼TÆŽ —0š§Ì_a Ç¢¬qìý²YcMNªž,-ñ‚=v<þD-ä$Ëøu),¹SM÷9¿KJî;ZÕbYŠTì+Î^¿¡rV ,.gE|øýu«àµ¡Ö>¤}8F¿*÷;°¿_u©jb¨´E³n~þš¼/†õÝ‘¢°ø–cþ´]ó…ÀlÞp-\F2ãÚ‹iä…gŒ÷w®hþŸVÈߢûw£{ƒÕ$ƒA2g¹@‹1Ï#ÎoŒÉ‚[<ÄìW3‰\j»¬f’1\ƒÀꛨÖ«Áh~·ÅFß ›ùˆI%t Clé‡/ß›ÔPu21ŒýûkXfθ;¯cùuEŒvá§Õü8Ö§³øP:°Ì•õ²ªò4¶¡û¡nÑÊÚ?w™t²M–Ø|,(ïG´é™åôЪÊ>™òiNŒkx2”¡ƒ z#§5u•öm14í)ZÇÑ<¿™7î&šÑ­kÃý$VïˆÍÙMy´“©7q/“F0JuD1¯ý'ûÞ´úä™ÅbhG±lU/J†´ŠÃ9ÛÒ2Ó€fmE'£§M· .0›–ÎuÓ²;ÌÒ;ŠÕ¾COÉ<Ûßø4ã§î¸4ëñi0Þ+š_‡6“}ó®Õ"l âL8Ò\³ú¤á_V­¢Ì-m†Ö~:>×QÙvZšüg¹ƒ+xšj))Io°ü<_iÔÔ„®Wu(¾òΟÆ]s•eŒIúHûªÿCxQ’J©È‰ïÑk}Ôƒ§ÛÝ»I¯<–d¯µª*ÞT­˜0²NÇ@¤¨ùE{OZÑGFØ„8ET„R²z ‹+t§Ò¤±gqe­ÑgMõiñêÍä ëˆçy¹é0z‰°½ÁþŽèÕ"±Ø™WbÏѱûÓ*²TÑÀ¡°f=°<ž1R•ø¹‰d^k{<¿•S –&ä¢ù|i¹&â•£ÓHZ’iuùªè56Óü¿Î89“&D£s›ó܆¾w]û}nWŽ·p5ù7¹OB‰›Fz&Œs[è MQ—¹6··§Â3÷¢ò™Ûº^Sà}Xÿ‘WÝ\ID„oLàxmMs;mÊÆÜv¡ß[iòÓw?àËÜa­½ÍmXó7wÅ÷A'Äܶj‰®É­G#ævZÅ„½”ØVíçâsÛã VЍÞj?ÇÚÖÑY||Z|œ+]óŒ-„*ÀéÊ–Ø^†td‘qÃáèT? õñ³¼#`‚áHOWÅBlœ7ª¢XHWaVàÙî†kZšvS$„ZÎì¤ ™&­Ôí“ ‡´^_hKKÉZ6¤Ëa²|2$f~QœjåÂÈd´ûS“½9Yy”|à︙”j’å;Û´ÌåÄ”×-hjÂ×2kÜKÝ­®•[ýÈ´"*X:p6Ɔ˜)VW$™33܈”B4MW ©ÀâÒ…•MuŽS9(p¡!) ËÐÇЀ=Xí–ýS¬AÕB÷dJ£ÒC; h,B 5ÀÙÞ|0ßLSɆª°z¯ÅDA™ÚlÖ÷ŒÂ$´gØ0DVV3þL\…›0Uk5H¢¡¡óÕùäq«~´„• ^¨‹ŠJÏË¥ƒ.›±S×Ók@ájJ3ëid,ìfrºÞ³ÔwŽ[‘ê ת h(kÖ¼ùL@_Õg¶ZЄD0Ö-Ù´ûèÜ›3S›R„Œu•¹Ot±ÅÉÀÙFñN5_›蜼â¢%ÐÖÖn¾\mn³07¦þ9Àç†* ý†K¤ÏªV cÏÀ8vÊðyxDŸ Ã(k•q˜Ó1è uRWŠd}Å4òžC]%ÓõRz2˦¬¦ªW’9·õUµ;?”¦­ '®‰Émþ"IŸæ¶]*^öLdSâô$éd\™_…†G·q‚´R Yë…S³ãsŠ\V¤±*œÀX†E»Xép•ÉM­ùñ/½Áΰ+k´ë«ºÔ隂ʪ»KÈ|AˆO'N”~>ÕÝŸe³™ùµì°ÑŸóª7t/Dª3î.á þÁiµÁ»œ`*—ŸkZòQËQ¢ËF6Ç…#-½Ù,ËÚºü} Hv­¬^"®Ôœ@EÖòCdec®àZk@ °ê§¾µÝî6F06"Öà5pÁ:ëefÿ²*yK(m3Å]rÆy42"š07CÍ èϼòïKa‹›fzö«Ì;”n)¿"rA86+‹ª Q··Ý}þé xƺp¾ÖØèóåùí%1bÉhH²d ÇûÞ=Lí¿pÁ26ŽPƒ®~ 2šúŠùahÚ. D–oÀ—Ê;Bt®¯'˜ÐýˆñZh>'W»é½ò¨.$¸`=6O²6Xsÿ˜ 7Þ™‘,[ÙÄÃ#º±ÛƒwÙyƒ=ôÃñ„Xuì.ðœUÄ2/”*Dƒ)Öö¯1•þ”‡áÛ®qÚ´6dÒÀ4Œ§ײ}ßÉ„êž9Pùµ¹?;hÏ£'PŠÜT[ÏxYmo{Q± ¡Œ{ÛÛÚ:ÐÐã<8ˆ}ºQ„"^ÒŸ!l@æ¾ àT,CÇWL¾®¥÷ÌúY¡éx+Þ"ºë»,HÉî——Î[Æ^õè!šæˆúSÔ8¦üÄJÉ(ì2ª–"syPŽsšvDƒÐòÛ95žR×A¼é˜R §7©Ê×.s{˜é}Bë²Ú¸Õñáp_Œs‚ékÙ\5òér¶Z’$5³z2D®WÏB˦yEßÞ¥=×®Mav޽w®ÁšçôþOj7]Š–ýÁM4‹TVºÕÌ<µ1Ñð‰ O’ò<šZ=xÀç( SÞG «œX” +}ÔÊ ]’•îï£"¯”1·ÑÏвýÚÎzJïu­¼‘1ð©hš˜èƒ5ê½Có_ASK¢¯.Ù¡¨@¥°‚û†xË*Ü…†lìwZåq¹ÜFuõ©ˆŸ@Ç Ð7yTߢx޹aTE!¢ ûÙië.ÊÆ³© âÆHHLD"Œ*ÙµåÌ  2©D£Õõ`0eˆíÏ5‰|ˆ@ˆ GÔq)kŽ"Ð|Щ§ê¯¨ÛÞËм  üÌ)bÑÞK6ùZ´#‚‚vq‡àf+ꥥÈjÕÁ,ÕÿD„|ucx$©oƒ¶` Éݱ­áqT%W¬Ï¸tT)‹wdHzKLVÜI‘ýó¿µ¶çÑM ŠdsŠæôŒ'ˆy 0ˆ^3éýãÃ5i0ٯ谌ÆO}ã¢]…5pW¿ñÜ/¿ž?“Þ]¼š„¿>úG†ÐäCöòpßÕø.òóÛÅ_>ñ·âÛïýî~ñYÓÇ~ó«ÆÕ¯ äºCWçgìò­ç3ÍÕ K›?£ƒ¯žÑ—ƒjü†o=ƒo}ÍË÷ÿFhøÞOƤ#Ù*xïŸúÝoKÓY|;ÖþþôóùÁÜ(^ù/ŒµÛ¼Þ"ûFúLj_Æãß|ëÛÇùð;÷½3¯Úß»S¦Ùòm셢埇Ã/ßÖæ÷˜ñÅU|ñ=³™ìß·\ýÊxün8?¤±O_ì;¿±dN³bÚ¯þêsz»ïo„é_[gvzïóý>ð¦q¾Æ²]–]nê;zÒpŸ^º7r¡]*ЕÕJlÝ YÄZÕJH¹šÐ oÅf¤=:¦Qšå¼±R¦Šˆ’Tu­ä,Ö€º¬©:¹&f£}¥·ÂUæyG©¾tá òïós¡¨I”p³¬7}ËØ­4”+ó9ްæºôšØdT‡wº³c·0K wâBËôÕò¦ŠGçêjp+wOüÖäX¥„¾ ¡Ò5«<_^.œ¡ãbÝ^.rA¿¶šØ{¤_@ÜêžV¼­u½' £¦½‡UW…¤Ž Ä<ÀÔC4:ÔEfëço. hZ…O<œ¡q%œ Caœ èhÒg"é¸YÏE_[Ì£!ñ\„:ÎGý­†¸—ìÏeé»Ðx²öú²0¿oü?²_í+奜KMi ]¨QUs¡§RÓµ©‚žŸ\c›†Ð|O # Å/te¼klCDzsÝ_óÃ}[3–¨ÿ5ôfX7‘[ß[]v¹ÐÙ·Y¹Ædâšäy#6á¶’Âlýï`Ä~›[/‹©?…îå–7 D´Î˜|Ãv—`݃JY7éXûÔÕ…¯SwÏ;˜ÔH›šìôÓþ>ûEõ>uÏ%pFüú:5©ò¡:jüã@Z‘²a%~Ô;áO%˜ækp~UÙä¥/dO2Ak0i¥ù>ø­ZHm’"4LfäSmTÍ/UéQETV{64÷õÐ\oËJ¼ÙÐGE TMETYök$ZyÀÚlé>¦IÎ~ÎÞ(‰z ÈœyÊùSL+Qå`T”ªéŠ{ùšmÜ*/Ò€¯JÑ;´@r”˜U›«Æ®­¿!TíLñž±™~[êiœÛþ,}“ËPL«©\©ÍòuÔÚ´Ù­#$²i 3Ÿr0à ‡ÁÝ8JÎ|ŒÊRéûQÄGËËÉÏøc d…²}®]3,0lfTV•ré{ĈšYþ´½€*pž#/JS4¯õe¨ÀöJËï’Ï…aÇWI±Iײ/ÎϘbõ¦íotÈ)Ц*J'˜—Y®¸”«4qS…FÙÌø þ …)ê»Ñqôü»Îµ£\HÁyÌ ©ñ-}Ï8^ ¢ÌCA´Q]0Y÷¤¡á®®¼(ÀÏç &wð>1¿µG™ŠÔ”Ç d§Þ3»úp¸Z[ Ós„¦,4)ŠYt‘µQU˜jÏ” ?(uüKðÓr…0@U‚ΚÃÏÚ H<²8îÍÊûj3›?9wþäúö瀿÷wßÁ_Ú’ü2çõO¬çCù qö·¾âox>òé.ϦcáJ5Èz%FI¦¹2U õŠRÍÄÈI²ûâ„嘩ÜLñ´Y|eÚ¿©M¨ÊÒPìÏ—2ÕPÂÒÔL¦Ê•¼ÊʹëRR“Ò&Å”V: ‰ßi_“ÊJ@S7ªš”'â9Ö€R`¦]ÁI4s²lš²*cúG¥SÆîŠ-6{Úxs#ŸëãUŽàŒŠM¥¨JÅøŸ*hU•0¨ß æ²òèdUME üñ©~_©üÖ~ƒ”k^û𥷀ޓ<ŠuûôgŽqV ó>bQЉÁ¦© ­fææBHiš7 ¸v5½R çæ¯Úzq^l%ë§’žÒÍ%šÚ̸ 4™ë&WYýß§õh?—sàbÑy‹ç¨ÙlsV·#mƒŒê²2Kí ]µ²àëè ¸…À«»ƒl h^6åCy ‰k SW¼:ÑÃÁ¬ti¿ãÕhfÉþ>W[ßR^˜ÑŒq —˜ô^¯jšÛè#½½ËoáÕ5*þa$5».–ãŸðêVSÑ0øý^úžéØÚ}Çàóþÿßì¾Wã¾O¹š]Îc²ºÍ߀Wû÷5›F\Xã^ç ¼zRÆbiî¹ÑM]¹ôÝÔ)³Ú!ÄÌmê &ˆ„Å¢¸i-ˆ2u-M¦›šPC7Sd:åìãs~Ym¨®¡:æpÿ›Ïò;Ú†K†[ÈC µ·£xÜ ùâÌ>ã)SóBEúâÐ|ë% ¤ÍÀ!1M4/AÜOâóÄSàd—ÌÅì®wO jj¬Öð7fª©‚(Éa¿ Ågª:¦u(¨Ï;ß%~´&ËGí®‘ä¦!e^ ¦œ¢¾({ŒÅØFV4 QnäUÖ3™Ë˜¢¦w®ˆGER^|1 &jµ©ë‚ ¤í÷åä+¡HÚL›K«¯fÌ›oVPršª=f¢ˇ)¹éóµG´cèñ:2¿ Á#9øœØ¾›á¡´ÕW1 ÷D†©ñQý‰Òü8†³ê–*ÆÉ™AT»È¬ À1Øy€ÅÂÿóÿüwzE?Àýu™¬þ¹üÃ?ùùg­ýòg¿úÁ¿z‹òýîgý‹½¦ÔøksBÿê+Û<üÕë¸þ<šqÿÙß¹é_¹Ã¯¾é»“éO½¯/~éŸùwOûû‡ýÞsÿW›_~`jaóýw_/+}nÿÀ-ü)$þ³žÑ¿ÂÒ÷÷‰æ©ó¯Ç´_ùéßÞßœÓ8žÿË¿_³Oÿ;¾ñïyHk7ý KÉ?O+ÄlüwÊRQ¬2”)ÊŒ¸ìmä÷¼ËŸw3¥TD “Á¡è¥¾š`ÂY:Jµ’¹#•ª( ói0 |¦¡aC©]Õ¦ªäX²úê7 /M¥èด k,¼Î×–³Ã ³*YÕÝ9Ã2Þ”º39ÅÂMsBYÄJíæ Ò -?·Rr jpƒª—#TøI{¹¢×1!Šò‰J÷Äâi…+`º_Eõ¹¬Ô½Üót°¸ÖX3p‘hnè £G¤güšäûáågìê`¶iX={êˆÂé¼LõéB+ n㉉Àb‚]Ÿ‰ƒ°e”Ï¡Æ2°mÞÍjyÝ¡×Æ¥=ôª6BuìÆ0¨éÛŽ3ÌXÚïVý*”âžÿV—åSÄTöðf>Û1f¶ïíCŽO„\”Á¿þâ,Æ«( ‚/ŠR˜žñÝš£}W{¾‹bV¦†gw†|QåDÍøö¤¢†p×»l¸å0Œs¾ =‚ 3Äì:==±P9jññ&÷h†•ˆ)HãŒ;\öø\t¬ÍâZÅš„¡®iT1c ûûMT_ÃóD[AýyæÚ˜[( ÇÚTT”ÿC¬»ë1šš¢šNxêqS3mÛ—Ð ÛžÍÌU¿ãÿ‡þ> …í)/¨oM?ÿòc+Hù ih²Ëq}²°zOÍóHÕTªÕQ=Hµ-9¸“˜G©%í¥\mKÍÿh›ñ4©/‘?yvÿ¤¸Ø@Õ/¥—6é V)’¥¸Ûö®‚…ƒghI%¯1ümÔL”Ĩ*UCJ *õ]© ¦eåï Ѳº 1LäyóV2U4®.Ri¿ÿlVԢ̸lvº>euÊ;6éº9Pµ&•ŠRPLC˜]¡¦¡cZ"Ö÷*s>„”εçüasZ… 0yßl ©Wš‘@‰áÒçÃ/Aƒ%E+5—|ÆI |\Šç…*‡ë»³È" %jN†.°ÌàJ'{üêÁœ³Oˆkˆ-K™JM‘ËíZ&Vü †zǰ̠®ƒ!}î†p´•Š©¨y—&^98lÕ7•j2ÆÆcôµ@upRMK‘'Ez·šW ²ÝŠÛF‚Gñ*Ì'ÏœáãivÖÝ*Cá(¦»:VÎ×J „ż¸dàžï: ;,ßÄ´+ºó!Ê~Œup_ Ýt7ß9#†/Î{N;†ÚX‰®'xîQ0Â}ùz”‹aÔF5V¤On4]Î3Äï¹¾†égÇg„ÝÐÞ­ªRòK²f—6ÂïA÷z2£Çöy€U@ëÕ5·P\«Jt_ö,fŠ(ûŸGä¯îMz’…-/±fbØ(£AdÕø9Òû³µw£U˜÷Œaý=º1âä#|eÛÈ<'×vù>¨’jåcºä=–'Õ>1áÜ_¼çŠýwàqêÈŽÿþßÿ;¿_‡¾•a†²¿ºW_~§[m²er°ÿÀ ßåûµŽ¿=iž¿ú+Ÿ<~vJ¼ýƒŠ¹ßxõç‘™áf_蜿D}›±«×/ÿµg1ýô÷žô_ºü/‘º´þÕøkãý¯Ïü¿ øÝOjQNœÖ¿û!ß¾ê_:_N˜—‘ðmÊá7Q¿Ý/Å×a{_¡þ€Àöè_óo½7øÞñö¼M¬ü…ü+ëþð*Öœ¿r IÒv÷+Ñø›WØ××¾+á ›þGY»ç_a¾ÿpäú¥XôÅuŽ{¡ìÃûýg9¾£¿²1Ò Ê‰÷Kïá¾´Ö$õOyÝ¿2xkœ(ñGË•t±g5üÀ°”¨d°ñà9‘¶â"$Kƒó߈Lžfý m§a †EÁd©º%+ #œÒ–#!R¦Æ)ûw’€Vò4ë+›1¡¬„ÊÐfFø~ä€@¿;xÆÔÔ£€!JE¨ÖԨ™Ç ÔqÞ=zAjR8iz•ˆ†æ TÖp)OW”Öµ|šµøVê`Ô1˜Þy%«›µ‡ÍY)’Rí=>É32ñE‹2ýÙ•³˜ ÄŒ “éd3K/Þe¹éÁLpuõ³‘ì€)ÉaR¨’±š*˜+d ªå4ËY0…Õª¾>ÌkMìoò3"Îè³|ÐÓ¨}ψ¹ãVÁó #„†þZ7„l Œ„&ŠºùqÌýÊëôTóU-Òz ©QƒÚ}`#% òVWa|\¹¨P¦ˆ°CCvIî£9[ Ê3nxLÊJ‘ )Å꦳éý‡âQ—ÑòšÒÄ@ŠaθU¼ê%(Š™Ïøs@žø™Þj VVTtÈ ‹"XË÷‘Úö|Òvö.)Ò÷JyYJ¼ª£W™(Ýl†¬qÒT¤¨Ï@”ºjP6³ìeÞ$RUòý[á¢JQMiî¼*W…Jt¤JhƒÆñ hŒ²¼Œa²$>&¦x&$¬ ‘CG±üþ5œ‡§èD¡ a¢áìÝ‹b«ãq”Ýùìî«én¨¨•)Eüƒ v¡'| ²1|ÁKþ'!w”ùX‚oZOyÿ˜»IxëÞÊm{nù¦S+ÍNë("Áй²g–}4ÔCˆÅ̓ª8Ê$*Œè’‘ät ÅE8ôMñÃP0EGE0â—3›tåaõ3¾Šë®r¼Šë”#‘%ªR¬î.ÝPÎgæ±™ì)A},82Š´ÃSÅÚ­k!§Þ05R=íàs\ÒàªÜ ¹ÜôÌA]d’@6YŽ+¬¿©)ÍLír4мO„ºB‘ íÙQ6OŽèêuL}(=¡û˜LÛáAÍXaEÔICâO`„s¡ ªPÕÙ¡e5$ê ¼bø+“ƒj&­³‘n$¬{ƒjÉj_§Jüí>ª–R‰ÊÌ7å]þ4C…!‘±£:ûHÂpÇÖϦ8¼Æ;&Ž¥ïå¨áMRæŽ]‰ÞꨰY…ÿ÷ÿ÷ÿ²W—~§|òw4ÔŠ&¤¡SJÞøýR±×~µ"§gœ±lÿ°ÃuϥƹØõ{•ÂJ÷ ïóV#¿–èøÞÈý“ê ôæÈwþbåø;ñªHñ‘}Ô%ÿ×k«¦Ç—ª@õ½÷@$aù(Pk ùÖX@y¿ŸMä&Äßeˆò½‹üîèÄ<.ïãÈfã¯|¿ŒŸ<½¿+ÚW—6ýG{¾·ú6¯ú³œoÉÿâŽõ|’?_Îë{Œ€þþ`Ú~HªßÜÛ:ò½áu6B×øíÅ®2åñëk̹4#Ç–pÞÉw’¦z[·¾Xëó|öj1é{óç—öiߢ‡RªÇÊà%6¶ÝÂxù¯ÄæÛûû¿PS—ybŽì÷tŒù_?Õ÷†…yøø2Å™ýªè½ ¹>~“"|ëéâÊ/÷ãóïòz¹PNň2VªLá¨*@¬VUK´$(ª(h¥cìLšÂÀS£Ÿnµræ¶ÿA 7”'Ê•“1”6kR±ÑlµT×^;Ó:XZ4²$‰h(ÃÅ(l6Ö2˜ý7czR&o†SQ£Dîe¶óTiü@‡î`5 ö©A¯/µj-U*L¡£ ‘ã=sõþhø–cš‰M‰ÝÌœ¨K…A`e?”@ž²>=Óª©pó¯‰hÔyéÞ"<1cB{pÕêQ=”VÞWU2GV$é” È€ªŽhO¿bSYøèæ›#ÓÌüð`$Ma»Òek¹\ºkV$²0«X¥Z mªP{äÙ€Ìy“ý)<>FŽû]”Y®Ìóù æ—Ú8—pÃÔ,Ž:‡¤ãŠ ¤oWŽ)îgŽÓž›©4¼‘UeÆ3ōބ¡ÐÏy.ðWIä<±L¬"5n¸ébœè˜u¬n’ ¦oêqö§ùwVÛì1‰:_žú/E6U&€Û¢¼¤*L‡b"L`§ß ¹uŒå¿èè ;WÌhX¶eè³50\ ƃ  vxC»V¯ËÆCÉÖw¯¦öèÏ×+è§Á{ï”Æx„^¡›8k,ô$“VÙñ§í[dŸ'¸Ø®ÄæGgKª´†÷Êsƒ'ÈO!—®¦–ÍäñÓJý!+œt ƒÁ"<ʺpGµøÄgŸ½q7†Úå £)ñA°°'`]°…*5<ƒN•l(ŒÚ^ØYJ³œŽ Ó«š I)29PC¤ Ë,9:TV", °ŽQ±•øOÙ³Dõò³,H"-DÅ6(e¿¦u%?KA‘tekŒrÆ}Í'ÅÐ*¡Üåß‹š_ }à7§Õ(í…*N–º]ᆸ˜Qž²a‘r%Æ„ï‰71 u©óg¢@ÅAQ&6²g ààÐìYÚámdÚ,=[¦­Kî2È1ÚKH<+0#„JR6&ÙaEjd©’3d¥A»œm]‰ à›%Ùp°)þt~»˜Cå˜tûÔ”>eyØöŠ±Ø¡1ŒöôÁ0ÕëtS‚dÃ{ôu–¨¢Á¸ls.xö!î-N[ŽñPÇ€­ò«¨Ùšå¨òSâÃT¥ L‹¢.r—ª…Wf¢{âM2<*„†à%÷Ä-‘T$ÃŒ1e>C½¨ÅsEÇÄ4zéCÐf–djL†N ™^vÃQHûõ_N<©Í©Œùã&½eÂY…0©U²gl2nI6«¥Ji~8Ó× ™kwL¸KvƒÐ.–è(C=1=‘÷ýtYÐrP‹>J-'é “ IÖmFHmÒ÷H3>íiÒž®r\¬ªAnE5Ìä²ïcÊßÚAÚ>IUå˜ ª¦‹xW#Ž¢§ÆM?܇y,µ{Fõ}‹¯,n²hÉ&ñ‹~࣭Ù:6'$Ö“{,+ªõ*? „UUKȹŠ;<ôWiòŠÙ_ýP3ý/‚i-ºál›zZè Ÿÿ¶"vÙÚçOZ³ýåN[š{=ÛŒ»•^æ i=kX®µ3»U'šéÇ{æÒÑQÙ}„vÊx–e,®Å¦«— ¡.¹¶ÑMp®ª°ªË]VÕµ·È›å¸V“ù;7±Tü²q¨Æ¹37ç½tô/wÕe—Õ%Ûµ§yì:-èrYÁÑeßè uóÕ¦ÝþfÕªŸÆ¹/ ånÎ3Èêìþ{‘ì¹$’öŠÍÇö;´¬>w`MˆìÍð¨ÁÕ3¦¬ý‰]2úy÷Ë<8²Ì«Kéîx»>Nå÷Уìu E6–šÜhïÃkö"8oš ¨|·èJ8ö/ϤX'›¸ŽDõ4 ÖÊá™ÃÁøTñäùظ¤±¤â#ɉŸ1é|貤V5÷¨:}]ŽÑ`[}-]–$šJ¨rH]UCǨ/ø+¤³ co×–XU ÝMÆ%HŸ\–Ýø9œVyƒ‰\?ö(péjïî¡£5lþ}ad‘‹U+»e¬+Ç÷ŰlÏ©< M(Áþ Ö~ ^ÑÍí²áRÓ™Ó†\5AÆœÖy5ø~é^*×_­Pü¡RöoÛ¤šN°¥yeO‹:/˜Tíåœ_ƒÓØ@~Â\ØA¨gð1 ‰UQ]™¦ÿ‚ hT÷ [²:ÏtU-ž½DÛ¾Ôž2úZ6øô9GKìQYS@¶&<ì*iTk6²qw+cw^!'`%tTW–H7ú:¾ ªhAC0دeP̪B=Çõ¢)%WH­ñ!ùù£¹Ÿ½ì‡% e)g#•ÙÒŽ ¹É†.øa‘%¢Š²1öshvö¿¦Âb}CÖ!S‘ì)“fXa³MIqв&5ìÉ (Érí98ű–3®5‰jVžƒ‰œ—±Ïï«A†Ö`®ÉS} çoi‡ÕjÿFÛ|iÚ›ä¤É¶D3Ý4â]u«Rý 驨+PÕ$cc£aåy¯È`Z:Úå3R2wPd©9ð#Â4f¢+Ò±D nXÚ™ŽÁUâ3ÃÂZh´¨w‹‡ÙBK2‚†¨â<[%ØŒ*6-`+TðôW4`KuM•¦Ôû¢¾ò$u+2}û oØOm±bÙÍÑ’gŠhž˜(ÎF„áªgŠSnÌÐcè®úiÂYxÄQ˜k”ç”Ì3©pD3Æ„ÓuÉj*9(kE¡lqõ9ª’`Š;%J§*Rp8À+1•8ˆÒç½Uè“(G‘*”ùÜ ´ºúÄî“©žŠ%¤ïš®Ï0þĀl_Wƒe!*Rf¶±‡{öiê|'MòzZ‡šÓ°šnЧ‰5¤4&²RC6«ÁFÐ-0CTÙ˜šYµ›Oñ­òà‡ºƒ‰"_’¬•”XÀZ†ÝŒ= ‚l»Bö匽µ¼3†%ãDdûlù‘'Sî&èP[Püa—“zÕÊŒ¸2kcÅödô Ù€©í²#ƒygY k—€ŸÏÑT'rÓÉrm ;çC;† UóÓ5fÉ`©õçÉ@¹§ò÷#~ʤG—`v\oDyk’?“üÞJÙ·Á!)pÆ,-Gˆb+Åf`8Ê2‰Æ ³¯Å¡‡}†›Ê5e—O $Ý$«ÉzâE¹¬B¡c‡DÈïÛåñá1$D)®ìx¡Žj²•®¯¹(Ä|h…BGhŠAQêïv㟠›¦j‹%šÁ)<±›8Yÿ`2xt¬lÂp¤“®ÈÅj‰ƒ<µ„•.¢ŒÞªtÇ\žgd˜,¯ª|ÖYUug© 1Þƒ"†B±Bb±vb:³"1ÓSjŒMy©FZ‰P4klÛ”0ž—ûqœåE’gôuÊ<ñо™Qdj›Ð³±óa<ˆ!}“ ©”yÕBâjèQqõ õ̪ ­Å¶šŠVÅ÷p÷I©(-9ô®ùúF/—§n”‡ôPËbF­vJ ³FV3,Uíì òÙôƒX é‹X®ÆÕ¶D“é÷½ûŽ^ÐD&FÄÀ‡W~ö7G­SM‚9ɱk¬'ZRðÏÃT¤B¨¢Ù~b„Ê(•ª‚wÖ©f¡½oDl£ªLRró~)ÕÚ è¤îk.§ÙÜ“3Ù’Í7mMå¼wƒ)ªöªòÞä©ãŠ¡¨‹HtªY+'÷óW¥Åú” 1£ ˧Úó¯«UX0j gÓ¥”vj²—·šc-k`\Þü‡ž²üYÙ ‡jÍž.áÒÝ&Ç £y5—R9>c`OÙoVV—¸óSéÏÿY3e1è¦ÏË~=©¥¡4ÔGÁ>cíëz>‡ø ÍЮþ„{]g[¡Áýy~’ÕDŒçöž«)+ ÐЭ‘~B3ÿ8U¤–ÿÊ™8š‰Z`ÅØ[k(åO54$ÃæëØi³Ó½Il</ÌV_µW‹5hxÃ&1­^-Ó|M¿~>V8G|žù€)™ÄìêÅ›);¹pi&× Dˆ@îÅžÃ:™ºå~H ‰ huýxÓ<]–ÄL“ô†ÆôŠ¡Í©Mêsãì)«"ÏEëV—¿…\DE†5Âä/sh? ì÷¼ÚP“ì;$yêZòNp³ý~1â«éƒÔŸÇ%€)¯¦¤,¹L‡=vN—µè<¿ _J ïS|µ7{þey‚A+zÏXjkâšx@h@Œ#zú÷å• ô²r¯ƒg?Ô×§›‹M¾¯}}«ús@ ÜŸ)¼Z2J˺-]Üw,[Ãmøón¥á¨Æèç:W¬¥«ïyäUÞÝêV^í= ‹\›HÏ}-™ÿþsKª7°û…DDP iд&§ð¦Ñ¹X7—Çp˜7Z? =6¬“ÝES°,9Ï ;•9¼êªÙYÛäIÆwôÌÁ ÛÆPêø4žÚËçi‘E)!B:j¥Ù®-…Jo®Ä0Þ*ªR5ñRìÏ]y¬¢$L,Ô̈¾@0³lÊ” X‘"_¦šÁÉ"Tù!£4@"÷ãmaÏEÃCv|¯vE‚€‰”I™Ø ))ï"3¿Žìy+mdÈBµ©•žSû\±Ã(ñïñLxNZyÐÉt@1­0ƒô\EŠŠJ%†º<1Êl›"˜¹¨Ü[”f+Lå¼â€£:”ê--¶c#›¶I€Š„PnD囪‘©Ö ˜ÎÊ=š¾#º"fC'ƒÃ~zW? E° 7¶ÇyÕlɤØA¸î,³Ý3((ÃQ9ôAÁNMŠ7ö4Þ*ãØ¡)xêaï¨F:Í ‘xÇÃbíañ©É reeï56±$iä·bs¿<Ë‚[/Û‰ zã‘õ Í¡t<6E]JŸkpœmjù}"¼e°QÅé2#GC¦îE:àÀÏ÷¯AeK®aE‰†gy_‡¡2_WJÌâ” 'l&ßæ%@e3í.ú…ü÷„ÚYÕk¨~öê–#.^÷ìåÕY· l”슢é#DVFº~ï’ñL5Ù} h õ§VŽC˜JÍlAÊÕArÄö^¥A÷ ‰àœw¿¢¡5Çê tám~G<îÂx¨ÁQ=Fú€5øÓ Ùl‚„ƒ×AöOÌ K®@ VU´†7jŒqy±­ª8\΄85ü-úvWnÄ*_;fsöÄÉõ*ü3˜q9'äã¦â^Á‹UÕ{F´£¢wf®(Ѫôä‚ {ª™0"Ò)^½.ã0}r|,#N=áLÎ{DïÌÞ¡VŒd…K²¢IgiÎxEÒü𸠑z8x«võµqŸ"ßqgë‚ùÚ^ö†ÛB¥Ÿ°êàºKÞêÊEĶ)¶#áWÇ< 5ÕÓcï‚%“ `fêÑß=ÆGÖñgTÞqàMŸµ Ì5ƒJk~fÃrÜ¢Šé¢%ð_Ýqzy%ǽ¢ÒY¾Çº"Øq½(üô9ÙGmÆ¢4¥úéÜšæôgZâH_<Ýô[X4Ëõd¨öñ(-IŸì#1e(EšVcFNŠiŸ´Æˆã´ùpˆß…{„¦æþNœÚpÞIž,Þ£‡®ºø“«4¥©-IO–í48S© ÍQ³±§¡Þ4Ã¥±k÷ÍS7Ÿjý“ÝýTy¶ÂO/£Ñ§zæÕtl‚ÚÜ<˜&ÚDã1ˆžÖ:º;«Õ>k&¥k”Þ˜¬ºÚ<Úôú|ž{Ðj—¶Æ2³‹Ô²/íy±Ü ÒFÈœBtk¢Nvþ ¦ / »m‰¿O<+*L´Æ\šô¢ÄO–a¦æ=¸UÞüb¶ß a~»!ò¨žšno P¬Y…EãÞQewq«œCrRéj{Â*hYâ]¡¯ŸX@kòO™l£G‡èi§øn¨¿+ÔÂ4~Á[´Ÿj_)† i°}â(޹?>¿ï p5O<Þ)ºnVTÃG[İ´"a—î Æ°gF|ˆ>ë“ÕÕ8?̹:{Œ§¦T´²©j%ùTaTdCÝ3´×€d©ŠçCŠldÒö1Øk'%K­¢ð µû•9…²Ç1W4—Ã}¾žûT‰hÍ”“ƒ}…%ÔViax©çAe÷5ð”¡é'–¥ÎšKã‰;)I¼×OœjÝ[Ííô™<âKå>EŒªExbD-L „.#‰b!`„”¼¤íòúh{LÌo¯D:·h‡YU&TÏŠ&¨0Œµ•€&Oçž1¡‚è ‚ú(i6Fú5¸Eè*t,tÿÚªæ_Ì^rEîo½¿V¦5ƒbSO[•ß+³?oháÕ'­/nµ‚^iÂï¨Í£&±²þUñÿÃü—JZUMC¨c.]7ÿ)Oˆ Ö ®¨B R¹Qí&T tõMÁf`þ|“w'EÆ’r Ê‚TcxÔrªË¬†öÇà«åX1ª´|U}Š`¤ïbeÓìªÙ†,^t9^–šÿèôRÓ]7œpÉ;\±cD÷‹)'¹ìµª©!5C<LFy„gÌÌE}3êJg9FЃú»âÐk60P´épVÖ0⑪%Ú€•¹ê(Hô(YŽ­vñSÜ ËYŠÌêq¨©¼_]òt¥$iÇGBG£^\û»`pÛÊ Rß붆È\Y6ÙW[8³YÙ6ÉùŽÖ4ªÆËç{E a}pÌÆaàjPPZ;ÔýgUnÚ”•¼æ :Œ{~`tÏN‡`^,p£a@¨¤Ç@âƒjv§:¶6yAä;T«a7ëŠ/ÏB’¾^4ì°%¯:Ž *h›Þ š±ÇâÏõu]õ&#¤i>›LDHL㳇;Aíö|±VI¾£ÔúY¼ú3«Zµ°.¿#°?²=×¼º+ ïAmÖVì:¬åòñn!b%I5ˆ^Ál+óÌ?f@ÝVóÂ:²Wûs]ýæŠ7»Êá¸ñK ðBú3]ÃX•~U&KqýÐlǃZPJׄ4Sj4»ù:ý]!%ÊV"£¹ÏªJ U£>³˜Ö¤97çì²aÑîÙÝ[·r$K*XÀ9øŸÊ„fè6j€ÀRžS¤6­Z¹Ë‘¢]*.„ÇÊçó·&3í¤»ñ–§Š"ŠæA (ŠA ¢Ñ-Ï 5Ãê38wI/>Ÿ*¸ÈAlj—¥1d„YÄצLj¹]Øl&µ¤ëÏc`µ¸3:ê·A«ž!°¡ô<8™yJåã¼#Ö`´khσ-Á°%E¤Ô;…´žk¢—Ÿh?ŸòŒ¿¡‚2gT´íƒõQÇçAKÔÌJÜr®0C8©ðAšßè7æ Ž¢$Ùm¾R'`ºªkCºkÅŸRöA\ _ú1„’’¡ÜH+ÏX¦6ÖA±÷¢ÅÍß" ­Ußgž(ŠV¡‘OÒ²ÂùM©°Ð+N˜‰ñž0–Þ^\é\¬c#-C–ÏÙÁe£˜{fT¢ék‹pc"QJ Ï .Äð4jPp,®äºR(`{ÿP*ÉÒ}ÁiUuúš JJsÛNì HuðDÍþ3+YtPšÇ·—+\é×%ó$×ã^éñL„4ð9†h‰ÆáõÂwé¬;”{†á›A;ÍÅÔСó®‡W† èa€VÒ&¾kõƾK°Æ]׆®×Høg㸉FšßŒúÊ(ºVVê;ë}Zz ø›ða†îQ+Õ;V¨>Ý÷h¿?ÚNÎÏÙ¾@±õçwˆ¨*1+6ú6‘eíùœ’7‚›*Êë","ªÀ Q ‚Û{HÇÄMg˜&S+xbjü\ KæPy,ªˆIϾÄöª÷¹†Á·º÷<Äjf–=Æ)”õÒ R+PÅ| 9g(½i}B`qÓý­"Ak\î }ÿ…>OçFàÉȲâ 3ʆδr;€ìÛÒ±‰!&aöœÝA`͹"Á´®Rž+'Q…ÁöjKèE¯µïƒÚö"Â1PU¸1ßÿAßGà2?o>kþ? ªÈÀ8«z„+·Ž#•üçýôÉÌJ“÷­:@ÉêiØ3¤ž ¥Ê²™ŒöŽ\ S¶ÐŠq‰ö=ÇóA X”6å#°VnïÏôLŒA@‚¢˜É€~RKýEWÚЬih£-‹ÚžYÅ~ ¥KZVɲt”v²¼õ 8§ššþ<ÊFuÊ•Ô,¼Œ¾«Ww¹{¹M£ßêÌVP©P+QåzÞÝFÝäùÄû<1‡®Ð%Ì)•—¡_Zïϳ8=˜zéè ©€‚`måkAÁM×èøLNOcÖ©´æx: r” a¾¦ˆÅPØC(9• XÐø SÏiRÇà L '“zPV½FÑéã©ì È3BÕÆçåg.Ã=ȺÒS®5ƒý÷OµH©˜ŽwS*/0„6*#t]°4 ¿Šß·ª7ýi” ÝF‰**ϨN >OÓ¡©i)Tý8›Z19Ëâ‰uS¡(2°ŠP b SÝÌpÆ·ØJïC•%ð Üùùä,ÊèHeñ47ñ/†,C' MªÌᓺ4#$sÇ“|«9’ÆË¡­Ü.}Š{¯Þ…/ ãP­reècšXîLO;-kCÄDõAñbÔXj%#“k,ïMh®¶tU0“ƛɚ!ó%bÌj#1cBŽ"^ÌÏ J?˜–± ü»¡BÍÔœæ<0Ãz¦G•°jÄÃ} ºÒ \©5¤Ëpã5vpòC+‚Qà JLÛ/Œ¤csЉ´êăH 3œ­š‰àÔj›fyuqvO³&[êø=$&ì’èT*Ð1æMM®Çú7@Gj’²“cÆÖÅ”+žuG)kÎÚ'^ÄÞPë&u¡ †~ÈfvÎ b𣸘¶ÕÉíîuýEâ€d&”õbEàhaâÆÌì³"‰9¦ƒßu¾L¡»~ßÄ°ó ¯ ˆÔ¹ÊËÏž‰ëãH$þÌa´Ãè $7Éœ¦šÉ cž O’ —u%û»šƒ9¤‡±æê@©<¹a­iòZƒg¼1­î]Dµf,4lS£J¶÷³/s£É»Ë¡˜Yl†‹œ×%!m+JŽëA†ªzj°õS(&íîZéõ‚ɬ±´}ù‘ÇU{0•×ÌXPYTôå!ý„,]{‰®`²@cß„‹EÕ(ó—ð›jMGGõ˜&*R?í°:µ.%4äæ?Põò~|¨ÝŒ ¾?Ô’ªÿžªÕŒì¨²†‘¹|\hé{6ŒÂ¼Øîç*SkõµLbm%.W‰Y×UCVþp GKUxª™Â¥BZbz[9äff—˜Äø’¯‚¨(Û0žV¼glDé͆îŒò˜ßËK󣑛üjù˜yed™|¥açl<‰—\7j¶B\#¯ U9QìL°ÒÔ©ÙŠlÇŽ´£ 8ñìj&q‡ŸÃÌL±ÓxA×ê.‡ö 18pçyÆpó¬‹9d^-Ô…VÄS!§=% ¦¯Â¬€Öî³^Õ™¹b|-6Ì–vpàf8ð &‰ õkjãdhÚÀ- PóŠiþ6/ç逶¼­Ëò-$7„mÅš;õ6ÊŸ­y­²ýÉZ5™_âÙÀ)Úž÷òÿ6$w¬ÐÞÄàõxð¬$U!ªX/<þØÌñ‡©Õ<»]wÅ$„©fᵟ_j*”w¼/ÜOâ©Üè†0tyé:=j=¥i)“2 …Ný ÑÔjqì*I”ì´Œ:ˆª¸m¤Dw²*Ô¬ºfõTýG³RîBàn•šÛªˆ…l¶¦¡/Z³?ÁšæBQ*œ£Þ‘/S³2d–t§ Z+€Û·zvC5MÕC„ ŒÍ󀪥FM’•«B°ÊŸå6øt¸ƒ™¸™¡–ÇOæK«2b'êÏûÙÈðPqÏ+\|Qº+²€iúŒ§r{F¸d©Ñ»mò»šqـݱe9èJaU¡rGwpÁÅ.½èá§4•x+ÿn*s9ý<Î è¥_ÖÜà4†¥™,ƒ1Ñ X¶ý¯åà3gÒƒa°0L%%4$ zÌ”¯ŽÿcJX†ùg–wõ€Ÿ©u‡(ºHC!Œ¬5àöyÌv}]ÑÍÆõYTWé‹÷šª¬º¸“dO›€„`j¥·8©Å@ž»t¬²€V•~(CCª`<ëÉk1L\›kpú”°š !‚]žš§Õ <™®Fù 6L‚su¬DbBeõ2´8Ô™ò@ ÝdOu/Œ3Ž5ˆ˜Ó`YWDW œok 3“ÏŽeÒç 7:ÞqÏmÄšâ_sLŸÐ²ç`è “jø Åç¾V8B”ÊR†Ó’®aÜÍE'dä‚áÕáæ'|«ý¼(úùø—ÎlJ[U+¨\n$¥:ÌÉ6dX˜[=?Z¦oÛRiñ+­+n>`§‰CW__®ëÌàHî¤Õ¼nÍÛ1R¤÷v×”¢†øÞiÛcÕ Çh¾©ñÃc8Éc]WU^&v|û¬0˜Å&LemôÝ ÷ e)np\É¡™´E¹¸£7èhÑABûÊù‹ æe‚N-x¥uM5kEšœc7G0¢~7ë2€—Qå2`V.CœšAZ 7¬©N_X`Ú}wU²Ä ºZGGÁA”zEeí¬µÚ…ÚVÕm¤¶ï^“´"嘟 †P´.%`ÛÀ¨z:R£Ý’‡‚ –R¦4µš’–áÍ@ñƒ²ÕÌð®Éh 1öÒ±Â~ÒT¢0ËÚŽòIEÄý¼@¡a‰Ò¹MÓXs; )7D&ÞošÆµ(¿¿Ê_Nö˜-\M4а¼ :jÓ\шº\T×z;x]z&†°Ñ ÀF–ée¾²‚i­Ì7©q|Í8TÅó]=VõdX‹×µ` 4Ò¯ÃUMdébj—I•&×€/aÕ¼½F¬ÿg¾˜šØ ücÚX{ºæd¤áß51ÍT#:u¿_3 õ¢Ø×Ž6Obî¬ÒÛ0rè«Åùû9µ×€—Õˉ :"¦{¼u;räª>ï+RYm¤Ê—šðæ¦ÜdÒLÙ1lüÚþ—õª9×}ì$JÚ·‘¼VÚ.Žõ²½Ósìq`Î1P„}ÎõðóäаũµBfòs½?<Ûì8‰5Vª¡˜ãñ)[SUƒLFE²Œ’¬šI±7öðdxÚ‘´ôïRÁFŒ¡žïàÑp³Ã2ÓSºI,À²§¤¨æcTõŒ¯O V ¾vF@‘­LtJxÄ1ÿ3s)D9®\ÍKŽ›- j›ûݤDSNp“œ£) k}WR8ÿΨ~©·AY zÛüRƈ4`wã½À+jP%’|c+4g—y•UAÌÀ±¢ R ž7.3'x‰W°>ªbÍÀ•š/¢„n¹ó q¥8{?™=yçθSÕ7NJ”K Ä´][”at®©’ÎyGVÏQŠGª€ŠNØÝx”Íã ãKÍšÑ`™rŒ Tï3võ.UöCÌ…ý Âäi#n´lµ[ VñÍç3™É ÏêB#§xµÃ0FÝOî¹»¤£Ús惘w©ª_T,œL °JЇŠjLuóà%Fx‚x0Ú'+¡ON‡þL«0'æ*÷Q·2¨R¬­îc›ãr??c[K?b|F¸h‰™=®5ÀGDÔ£*ÐFGÅö:·»²e¾…­ éaCƒÊ•‚*Ìùp°2‹„¢ iê=ƒjâ¥eÀ•-ypiÊüŒÊϰÄ$P¾`>¨ž…¦ÌiÅ”¶>Ÿ8\™¢Z%ׄÖ¬„–ĪrTÖÖ¶s°@Å‹jû⨙ëñבqVQ½Ù×®Þ^ÏG¥XM¦Ù§ó;ŸkRåÊreRÁ%ËDhÄ4ÐÔŸÄÀU ²‘JÓà2LQÇ>o¦ßG«;{]E„ÑDIcé¶ùÁ¨RÖz\Ár?Ø|Ýë{P ?ÌLLÄdVá&`VsÆ7þŒƒrfõ-4/\Kë®;¬«,“Ýé~Êʦ|Ø éyZgT$ÔýR7°º˜ob!cjð—%õðèD¯£ëÑù7´RV¥›ØV©`ùLãÁõøA×ß#{ö‚áB°€n4¡‹FàKH÷YÅc€Pøa(RÁ$bØL2 Ëâ€àA!H>›"Ý×U22«Cs°°‡‹Ûh`¢Ùób²ŠrÀr©Î(GÚˆq¸€Üo¦…àí~‡kä[ïþ‹âÓL®æÆKn‰Óûà_U¤† IJ“) vÆŒ–SÖ¼FŒ©É8V4û›u”Ù4sT"mÙ2€pÙi ‡%ææÞÌb§ž¶)“=JIù&³¡›2Ù¨É5­ÍØrc6!4¯r½¨ŽFhoãP˜‘¨¨VLÈÊ€2Ÿh‡lO8rÃU¢«æ:7…aÁ7¤© IµqéJ;ìûI!‘¨©Û­©1†R߈ÓjÅ+{¥)b÷¥PÉx ¥Ï&•S¥°½Í˜Í†Û¥x k˜ i­»÷KaˆD0³G«¦QòY˜T?9£³ÖO…Ø—`Haž!w*ÎÒб»­=‚T™Üq…6!˜ÔŒ[uã躖ƒ~š–|l_’`ÏX(Âѱ†X=¬¤KÀ/Ã2c©+Ö+ašTÕ7P‡ŽÍ’¸=ó›7ÕfP½´• Õš éLA`•›£éÌZ½PÀ10q‘Rj7“5T'çRcQ½ #‡·ÖKpƒòªsU]g ¥nýÏX€6J‡h5—N¨‘׳Bu]•§ÞÊ££6„û¦QYbmQ·•2yù=¸(RWœ.î|kF¢’ìуž±®HßBCþ´tz´ÉY åB3´›TÌd¢˜{u»Áç~‘¸Ê@V\|çJüs¥Žúî n~èG÷˜Z=nN ƒKYBn«–ésX}‘ÇýÄ€Ïv¯Ãuч~âГE:~Üq³ê¡bí1wc ×°%;êc¡¥8)Ȭ& | ñÌŒÛE§\TÛüèäϬlãnm•op)¶yÅe0`ÄwIV\º¼“é„›ød.°œ(¢\ãajn—µ;çe¢>aè™óNr¿Ï5ÌE„4tÚò­êfÀ€Íøsüë®:QRœ ßjÒDG ‡©íˆ4ò ¤iç}#¾9ÙÍÝ:c³+¡ªR]S¼hheÚ\‰muðëÒG‰¶€ )·­¶¤C0òy]³ ê ıÏá}`Ô)Ûs¤Q“žíyî73MG¦&Ù>õ|ĬLm?ëçŠ~rÀ×´Þ­'&l¦Ÿ|ÊßÌ,·•¹4[-Iw)q¦DëF2ôôhÙg.5:RµipÙ­§3_Íž²'Îý)ª›2ÕdÇ70´|{Ó2sR)–’[µÒ°ª, ™fŠZ¬Î˜¥æÚŠ"hªOš€´ª‚¡ÕoêvÕˆÚÙ1¨’²¥fDåÅÍæä¢)º0ôYèÜJ7é®PåŠù÷ŒÞ¢é£ú¦s/éS¥Öúî|Så!C„&Ó;ޕέƒŸxVuµêe}bØh磉ŒÚÒ˜RÍ–Éç/ÔŒ:>"÷ˆÄ\´/mÝLÓ¾ûÒfhMV,9E]“Œõ47›_ l¡rƒNF\u<‡óšƒÞ§9ùXzmh.¶F•Φøa¿qa0,ò­ÅÁx6\ÁG\¹äKöLªÊý° sk߱޼ OŠ2zæ‰JÙá,p¸¬êæ·²rë—¨“Ý*¤î9 ‰Cµ;¿vuO` j\>/*ñfãy`a3Ú+Ô8‚G¤)Qñ­LæsÓÖNÝg4Ê‘áC Ñð(¼”´ºÊíÙCÝ,ÖQ­ìŸ>q7Ç’Æèfk@!®ÐtÕ® =va¶×ºBYQöR%¢T#šµV)~0  &„8Jɚʛ ÔšÞF­ªPÁ\3 þp—B—b1«©â´ò¥„3¡Ów… >s“èu .yòë@F 5ËOiwÊ2Ìè[?º=åì v ²VW©QƒÀñVss¸“ý‘¦\¶ÞœPïW5‹eenŸ‚hÏ—çL ?n’†ÊRÃC¤Ûå²×´>׸&õ·„jp]mdÍAq QiŽÇ$³EÒQÚ8p„ Øh"ªkPD %v»„zØÄ°"ÔñªÂkËÕÆàBgïoïEÇÒºOvÿãpèùNÅ VE毦¦d ˜8Ãá±­óÑT1Ø-Ct›7Zûû8͈‚5œJͺàð`›,0a‰qWÄÊ9c ‹Áˆãøùþ ÒŠ»1¯:ùb‰Ä=I†™†Öm©Áp a¼Ò Ïgµ÷ôn èÈR.Öp¬åùògm\Wö©ã鸾aàËTF³dôØ{™UÁ³0îõò¬¾³©²N ÍtƒŽ=P"bë<§ EgÖ%QãÞ—t£ÅWŠ5®#¨{ò2»LrëÙ¼ÊÎûþ ²æ×`œÙ×byç¹O •OàÒþù‹/EçlVDAÊvÆ)™ÒÛ ±@ÑlòadE:‚ ˜×Aª&í IUc«O˜’ImÄéÒU/"÷µÍÊÔ_ôÉYcc·%O¥Äï™'QV¢—oO™< ÊÔ8[p]fQ°PÅ®ÌØÒsTØÒKŒ…-Ü'qðk>‹Lu‰†f.M™F„J¤Ôj7γ¶0£?}`f6Ÿr{fP=u±• ìW±« 4ýu&£ˆ¡¹³Hiu7ƒÑíˆN¹tªMÑ06­(î±QjøxJ VÖ6‚ÆuOž +NÊ B‘ –á¢IUÄisò(©¹R™!”é”šçAÔSX™µ?HU*¤ñ–bå ØõÌ1,µXÔ*Y®Ê1 -….è•®ÄFOfâx1oSU.Ó¹¡ŒN°ûlŽçú× ns /š­ÖTk“±¤ó\ÇrS² òÊ9("þ1`³N´ñ%¸U F©"Sü£l­3\7¬tsDˆAìwö}б¤RLØX¤¬Þä5;¸eî1„˜¼Q0샋´J¶¬ÿHTFÍEk¯~ì‹0lý€©²í1!ñS%‰¨U:Ý1„A¨IÅ`ó˜]ökR³a¯û|öf7ð£ÚñàÐ…4ö / wÕàX£«ÿ ¬ì[öKòžFµµ\3Ä pœÞð±T¤2åÙïtÃÞ¼Ò” ø¼0” Ì¿p±Cv#¿ sx€$(XšïCf­k~~›s9¢–{pO€YS7Ue¡ýžN©*h¶Œ©¡j™‰ç™ U9yz ÍŒ\Ewôs­?6óµáJ7 I)0CàîB½‰7ÍQüdNsV®nàÄjæ)Ê™aÅsñ:T§3a¨Dâ97Y‘Ã7ß…DqL¯£gUê.î`ê;ÌtNµòm\DfÅnU¨h±¹TA²þ‰¬ªFs«›![ýSÆQllY‡”>®_€i̦áîô+Ñ\t1¨w¹Ëgf]f·zÍЯº~Ô€yöâ˜Æ¦ZÏÙ `È$ÉFU?éhQ!É2Ь+F¹†×ñ’.OyAjæ—ÞèY=•ú<ÒŠ­ê¨JzºQE3ì†P²QßfÑû¯âê&Óº¾\©Þól‹pÐÕJ)œ¬žL£¶üeÌc×ô ¬Ê$ª÷ì¦f¬jj:´5ãÉ|é&eY•r™Ñ¦1!B’$²‚t±/ŸË5ŒÑI.-­ÑÒå~Ï\¸†«»ªQ!ðÜpà¦ñ§Ÿìh ÐQ¥cÎ'²ã­ç*IPÆ&/bFUS#‡µ@•™æÆüW7dÏÞàMļVéAž4I‚!V#Õú‡8…A+Ç[“èjôO«HqÂüª™n‘ÕâËuü´¸;àPÒ¯6uEÓ$æášwH<¿+[Ú¦ÛÌV#ɾ¶´Ý¥éË0~¦ìXla’ t"wk8«Kz›Ü5‡ŠàFÀQð³ò0 æöß~ÐÐdÈä?eûT=àU(GÆZD8þMfÒ¯ÇF专 S0禼‡¾—93O&¬4 êf\¡—ÉfEõi%+®¥ââFkØèÄ2¤e ®ÊÎ=Èn$±(PL*'5¡M`‚‹üß´ ÆÅ˜ÑdX×ËÊV[èH‘smC›a¡ìϘ7–ýzÐÉ–º(aïá1WZ!äí{)¦¶úîÌ9n÷ªåÆcè.K3.4Tà^ÏòeG&ð‚#­ ·ÔèKñ޹ÕFŒU„jÛÌÝùS$‚2ã¥ûóò Âj±Ó‘3 `…qÓñ¬ 5¬ µª zØ\¯¥ð£˜…f¤êˆ |ΈÌÝ8Æ™çsO u â@/›;00ÆÄ•ÌSÓ† ¨³Ä¢¥\%jq5„¡Š9G~+ÚâÞ”rpQUìk„â2‡ö³€)£¥ˆ¢S¼ç™#à—Ÿ¸Z#Þ(µ@Ç:²Yï*ªÍ4ãÅ£œµR­HÔÛP“1,ö§Ç¬ÖÓ%¬ÊÕübípu¥¾ú-ªZ³J¥ÝغÆ:_qä½­ø¡å˜îª£²ˆÛþaBÝ6ª¨Mõ9š˜j’ÕÆ¼É TxLJ×À¡*.wðÈy•Œy…™†Ä^&f=5e»CÇGË€Ñ :1ËA¯ õ:Fž¸ˆ5}¨•Í`«ÿ}³ÁÔ¶¹r_Äüê±Üðûæ%=8/m?°8ÅÒ\ƒ»;(¤Ci{9€4™°eÛ-ã;1™€! ~ìò’àã¿$žÒTö¡šyMrìÞº7|øœŒ­.2xÏu^Ü‹áËòDò³­N”@ Ò”ºH¡š‹´4cæ£ßK Ž3úþùÙäK¡âÓy†¯ d0t+W}tÌjй¢¢BLÒ'“‡á\?î³tlGaìÜ&V?ªÁˆäá˜Q?ß‹ƒ®²Ë²G8hrqzöÒ*ëˆ>¢¿ ã‡í€)%DY¿´Ê’ëûÝ#E÷£þûrmˆº¦ÒŒõsTèAŒ”Æ©rGa1…R4 ¨ÃTÅ€1q9Ú  7ÕkEr ý¡êM¹%p ¨^‘Å+/«ÍMñ‰ÊkBÁ•§° •+Uhr »(é·M¬‰tÞ±±Vq è)“ $£Ž#Ãx8ó†·0 U• óš×‹¾ÿ”à­ÐGÛî×áÖ+±ŠYƒçDÚN±Ð뎼iô@¡›†V"–¤œU²>½%¤‘ ¬ö,@Ut`HÙo†é)¼x®7"EJ'ÖXY°Ã®ö‘cMwckÆË£“>­DAé±KxµZÌÁ@`0Kc8‹++ð›PnßìrÏ?ß;®”÷~_ªøi= Ÿ1Ì™à`MÆÍ~@ëJ™©˜Å^E¢‘1-Ø¡‡*(ð'rð2—:ÚȨ¡ŸªÌx %ÍÄQúNØü=¢ÇOz¶¼ÚwöeTÙôr •^o‰ú†ô2„/FPnY#ã¦ÑùÞ†Åh"S†¹[Œ9À1««e•Ä+û^ég9ó»ªC|??kÍØT IƒI·Lru‹©\ •‡+²åSÉkiîaΗÏ]kg,¹š2Áš#‰a¬‘ðÊ2¯÷}àÅ †$`’v©»õB=ì˜}ÍÜü˜^’r&w@MVd/š¹.šÓW"*²!©ˆ)0sá^qYÕ‰ƒéwqÙÏ`ÕĘrÚ¬„„N7¡·1—ôVÍ‚H59š©fàf• /·Ö‚W*Þˆ'S[Ãè!w¨’Ù¬£ULÏ3ž– O%U=Ùã`ÍåçÐ… w/æF ¿6:ª«iञÒQQ´›ìmW˜Fñ(q:L¬µºD,±’ŠÝŠŠ,¡0UJ/Rß·ýã[dL´j V,ÎAÀĦüõ–79q_¶æ¦œ4YÀâ]¼jÔx›âYbEÓzv‹AÆT‡Šnsü®ŒÖKŒ.~ÛŒ2Ðc· :f–—eD³ÒkÞèÕ8겋DØš:áF½HUÃY.Õ?ÿŽÁ¹³Ú<ëê˜}ü¢^Ô˼û† N‹EÝÄ). ·âß{Á^ñݎﮈ[+ãÞ°öÊh ùy‘M‘q£ígÐÇîúüÅ ©)”îµ|]ðîA‘K×ÍÉ|} ¼™Žàqªßeœ_º»·}·+å]|ce1P„g͉}N“Ÿ§ETôÄŸåür™ÜîBñ4±KÔFÖÿçéUû‚MQ”§Qï)­É7E,ãŽpʦ̉‹ÓpTºÂ?þŠ–°üsCEqg |‚æMÚvN=(Xmó5I—'œÂë!²5Ù§ðl¼YÌtZ¹6(®‘dí{Ñ6ü½¯ ±+G+Œi‡óÒšjNT輇Iw[ †v%Bƶ˜ÑІlÖÌ@9Ð-å(^?±”ù)¶ˆ¦kØå:ë¨!¿ƒyÇa‹/Ò¶,ÉI®a}´â¼å=4ÖL²Ïp¡Dc¥gÈO¶fONUCÇ}Þ(w™“×¹‡܆…)L©Þ*²É¥{“Fà 8ïxÓ©;Ы N±Xc(”4:EëxÈnûs*TËw\û(°ÍÂeÓXQIU šl*z‹ «a—5 £†ÄN›HuQ§!3+šúú}s{0Ý´3^ûÙ<1·!F±ûƒh1ØÝ¸âQu<ØÖdkLrëòljöK+ÃW@4|v?Éì# z‡Ä©r°3ÁÞÔmR¹*õ­U'¢í/<)tÆ µ^†è™…Î=N\çèDɈ#ú\Ù'•=ÏÚ:)N?W˜SöqÃüÝb´Vv9˜=2å‰óœ-cO€1áUo~'ÔñÌÖ ³±TÁ:£hÏaŠzÖfGÛߌ±{ VS´ƒ²V¨dœá}}W.e¯H_Y¯£­ÂGþUØÅz”ì`¬çTý^~¯ûƒêUû#Åè&t!Ñ ur•nz3@Ö z IÛCò4àÊÜ3 Ä2­Üc‘RXÙ¹D¾ÍPÂÝ”Gü`0›W”•IËÝ2!ªÎDuüÇ`•QšRÖ~€dü…î2¶ B)«½hJQl.j©nwŽ"¤™ÖAðŒ¯¼î`]ÎY«| ¨l5…»õÁ´§{ë ª¬Z¶fâqRÑRi*”Ø33U@¦è8\ìÄý]¤ ¥á>ŠJæÇØü†éæTã¡ûˆJ?"¨«I™ ¶Ù@Å!#uä£Ü®o©a»>‹ƒÃœ²J0D’jÞjj\Oi?KÜ2Fã+ðU²É'õï#ã ¡ÄØÈ,21twÕqÄH`éüQ¼µÍœsûç€Îå%Úo‹…š‹=¨)™úø¥¢÷û‹Aª­µ&Vè¡´Ìdµ©ªÙáŸÝ4ž›{Ùœ-–JÏÂK¶ùÑ%{u_À0üŒQcXž÷2™ººüDž5ȸ‡¢6N½m>C‘õWÑr:ÈT ƒ6ë™»ï¶l/åz9Ì)ü&Kﱋ¨:¹\ ­çîáˆËæ—Õ½ˆ$N¸>©˜Å5QUÀ8 øì{“íVÜU{€Òþ/Q×FbP?£a޹×NtI\˜+»cn®ë0¨î5ÔìòX#À÷*ðØ×z­eé Di «z, \°Ýl§ Çô}h³M$M©òùÞ7C_´ñû}¨ÎˆBEXI_Aã‡2};üáJR¨Þèì>x§5Ây}HÑ­çS—ôDÊ;Œ²9Z*HF}E@Í*”íÔ8¾>Îü‰Mf=”dfb’l.ÐÐù {V¸–†qûÓÜAeýà^/£Ì–î†?§ñu4Öq«„KÖoUWoÄS$…Áb¾§GÏ…V®í6Þ×ɾʡeµ+\ ÜŸœ_ôÐJÁü¬éws78NðíšsNk¹÷z-÷Ä e“ú&ݱªU3•“p8ä\°…Öî›k®Id¢ÅZ¢&ªMݵ»*ò0&1L®±&L¸8á´)`‚Ž0ž$„¼kÏiD€¢ÑýC› ÂFDÉj4´j×ÄÈA{ ‡ñ‘âçsV{~´µOïqºÇn1~Tá²w²Ì¿€÷ +Þ4>,Öñ‚ae¦6ú(Â[hnkFæªáÀ¼ª[• ;ØÇne‰ÈÍ †Ó«#5ª'µg=XCÝÄÞú½×KÈ<›ä€'csœF0\5ÇxÁªæ…`N¬á*ª)n1âãúÍK•õ,àWÉç7–ØÄ´"‡˜ªQmj„ Wišj¡âI0£Ã\Y'xBÿ²ßÒþ]ß"fYä™Á¼TID’û²–«Ìv#*y]Âgä±?)ʳk¼³6£cà|­Ê‹^ŽmX…å[Ð]ˆáú=:ÖñLÌ!3~T€‚s4…i¬Áƒ^õ‡Ä:ŠûØPG`NyÚƒhbevïsæÿµ1vÐå £ÍÊeÇh¯!£1¨l8ãÊv« >«ž‘˜œ<ýµ‡7 ji$¨¦§L7Ò…µ*#ü Fвé9‰˜¶_ëe/ÎÓOÖ8nu²'•¼ y@¥®&u¬_ÄH(¥ð±szš2ÿ2n.±¢ô;wŒH,¤D!O3Á¬îìrD¨óZ3k²±L-~T¹÷N9^0e4gÁHÎ= Q¥ì½0gE 8 ÔxQ*±Z)+Q¹¹ö˜EL¨ töÞ¥Ç=P©\švµÞ˜ÀŸJp*ˆ©šiÃSþlP§še$Ä-fèß*u¾™¦gò1!ÌõÉ¢¦—‘Õêd,p<¨¡2…+Uô^¤=qy(ÕMîž;Mu(Õ ó¶Ãü ·ÃЬ©d§V¹A ‰Pʼn¥£«þ *{0œ2å¤=ŽX¦DU´.=}„#Ðîm–Lg?NìãJ1™R\ÚVmE”º482¹{•Jç´`U È’¯íÙ3IëÇE˜©£I¹åeaÜ °¤wéû_Ü®q8HÀT/`”q!ûkŠy9mu|DË‚ª£–çFÅÙ“pì¥@K†S÷jQÝRÚž ˆ)â ÇþzÀCjÙÖÃì=4›ÐŸ?õ£eq1—¢žHeU C^eqqKqr5fTcÅG‘ ™æSçv -Ý“‡SK(¸*)Aˆ´Šb™^ŠjÛ ª{lyÿãd)®ð6©²,_·+Îé‚K¤»°Ubá Q{„›iátò4ñZ¡;âÈ#Ý´-RÍUÔÜ|«™^*# Õ~$œÝ– n‹A°‡¦kðf•£þP\ 5QsÒ&åÕ9®Ÿ£ÙûYÚ&æî­Vzù!,–8"¨³¸¶©U™ŠF÷ƒ›vŠb˜Z \²ºàž¸F;°SŒø7ã :gY¥TN %?LÇàN|ÉÔféQ‡_u~5*¦ÂŒ¸ÙV8Öïûÿ<ŽÑ[ ƦF*!¢k©–«5>ÚxsÄð‘±ec¡2Ô´ÒcÛ£&b,íÓk7t>Ÿµ±MyÖ!‰ôë&•ÏúÛLåB¹j‚¡©R±!5íV Û[)·g»,Q Eºb2ѽ£Ò¦H{å½ ÑÃEzˆZ"ÀáÛAÊþ‰÷C›÷9Ê×Þ•˜ž˜j²Ô˜J— V¾OpƒHúzÓ(B´J‰ éÕýDÇì]Q·2Ÿiª“ HÐ ©iÉéô‡rìó§€ò³NÛ¶Y{àô³+[iMxzuÿÇÿø¬_ø§›»vï_üÞüP3÷?ðÊ=3ï[¾wwoßÿÍïCù—ûÍ‹úå_ûý›ÿòCßüýkø…küë·“üÃË·ÿöíäAÿ‹ò8ÿÊç~ñåÕý9þÒå~c®YùÍWþ{ö]¼¿E™FðïXßy€hðçw¾âö;_Má_]˾¾Â¯VÒ Æõ§bÆe\ÿ;îü;îü;îü;îü£âέ‰³|C) `oNAÊ‹Á›sà/ÚWé Š ÚÉß”kÑ]:¥ò2c?„ k5°¢U2Fåô†ª0ÆóLºãar4i†ûA»«9`ëÕïöL{—„©{aªçŽEÝ[ã[MY’Іcú9ÙÕjÒy·Z™X`LR¥ Ïó~¹O/I„\I¬º„ªú<Ù8‚ƒ ‹1CÍÊÃþSf Y0]‚k°­?YšðÓûºo¥]ê>Ç×}³ü0Ð×}Yóìc“èv¥Zoë>ïë~½®ûŠ¥¦ß„ðé`kb7œÓz•Ñý²îÛ³fÄ}Z¥'rÝÇ·Ö}Îë¾|Ю{¥t JÐ!)ÏqÝŸŒ{Ìò¥¦ËiÒóºÏ#íUø«T…Éq>ѵ—u?h”GÅ„šrº"‘–¹X5G=3øéÂGª5G”~=qÙ¢âåŽÏÕMÄÆ—A¤5Ç{ý>«Ä½œss|ó Uµézr¼ë{®šÊç_ú¡ÔŽšËï½Ü  .Ï.^€–…Ç0{3ñceº }C0Bg”+í föLWuÝòĺ*Áœ6Ý»úpºp£_‰›pÍJ]ÓÜÔ«L>«s\ œÑe¹&µœš#á-x ¸C™¹Ô[»– æy–(.&©úÉã÷bˆSqŸÃxst¯ûº‹8£ K %¡É0C´çypIÈK%Ø=“ ž 5dÇûR‚ÂTžKÕ{B éV§÷“‚pm”…¦dxŒ\%¨Ô‰šÝ¦(þÁèçCžÒÞ¯*GéÞæ W sê}ÜAEs»=öîý…ÆÖRÅ"‹|ÐP×su¬ {"ï¡s-ŸwX £*€ &ÅX  b”J–>×-ÍŸêebFÓ5Iaë"# ?UôXU%ÕX¹Â;í(bÙ|ˆTÑŸ"F3íÀäTUŽG©¯™†žy¡ÊŸŠŽ–ì›ÎþÒßI©ÏÚÈBS΄Ɠês@?ôAðí`NG1UÙò¶Ÿyi$5 ­c±ð¿þ×ÿú‚5TµzEqvÀüåÒYüîŸ-¨½¸]ocâ¹/ŸÛ]üþEK’ß{ª|3ÿ!RSØk¢¥—YõÅKšïíåÇ™‡Ú˼fÔ~啼?mÝH°óàIZâW'ÏÛsà¨Xùý/îW?ï‹…ïÏô¯¾nPX®aw÷òI_ŽÖߘ3ýSÚŸðÛ¡M3;uuß{æÓxséÐo>ûº†‡Ò÷´w™øë}_úÆ,¹EË?ü<‡ð·¿wåߺ°_ •`8 ÿ‹EÈúiÿâ ý•%åo´¾±ÅüõgüýMæçúZ¾}Cl«ˆëï]î¿ÿ‚ÕŠ%ñÍÕ-ÔÕ-ÄšâG–Ö »Z:ÐØU´¢0b ^>^†b`*A«zN:b®^Å:¥ÀUX¯ëVŽrůK ¸”,/%L`p?­^»¯{¹LqŸõY3–òê ´`Îâ¶Êëè8Þ “§$¸êâÎÃó 3ЊÌX÷ç¢ï°µÉáqA­&Û‚gìáçÛä½|®o eNU Ôµ==3 Fï>̦}H'dÅ$0£uÁ:»IÜÕ…\]Ëýj‘êF8øæaôŒ ÏóÖµ†‹Z§F7}%oòY\cnß‹ºÎ©eAæùƒu®&H¬z èAƒ´¡c­ÏËš1¤Ä€qC3s¡óºz_"SM›§­+ -ÄW‘ùŽm^ñLÌ¿[Úc0ÞTìdk¢§×EÖ¾b­Š‡ÜUä>`)ÈŒËú1Ý‘ük‡•!††*Ñá¬ÕÑÓn°œ{;zÚ>ã<ÁeqØÿYÓã™¶:¢cßÕèª=­+É©¯n ìV4åc\'Ëwbö>Þ‡ó|}öœÇa×ÑÓy7ñ†üc~ðÈ}ãeO:n¦XU/ó|FO§5d$êníðMLß)ócÍûv_*;z:™îbM ÖÄAO„iTG/•2¸7ŠÁÅà š[~Ê8¢ Sp@Å(T)ä(Y±9.ÖT2+)gÑev5ãÎXï'¥ˆBÆó/³©œåµÜZþ»˜˜££m$þjØYp-=µ¿SŠ+wŸŸ9þ~ÆŸ|®—åÅt7‘zþ†Â9Øèɶʌ gÿxnó<ÅH^ÀUlÅP<šÌƒ‡ïL ý„¶ÁT]Ôr§þÿ|‹6’û~Üá ‡¢†õ(•UÈX—(ÓL¨„¹¤6käýž)ìÄ#<¸Ÿ™D}Æ‚(× …eRò9šòLÕQ±#M9M?n vªés&uQ”ï)„R–}—&—ÆÙó5™bS;&RM)yÖOã‰aF»%Åy|~ßU3kx¦Œ˜)¥@}ýp…:Öi€­w©'¯eÏí¬ª–å+ Õw£eÃÕyf¨r•ì7uWäÏÆ‰±þ fèLÎëøBœAÃÁó€ýj­…|oî¬i²á9dÈ#ì²qÍv²b¨ôé³ÁUé0ïïÜ,=ñ~¤ÛÙ3 y>=2—ÏàI}y† î­i a=6ˆ"C6P]â¡åu=-Óò§„÷hÔtH‹Ü£²ß¾J‰¬«ð¬æŸRéÔÌ!ïáMaü*3)Ü€l1ªF[ȈC3›&UMTP±ý­’â&ÿl<¾ v¯…|ª¹±€øb@'K"è gsGú)ÛÂÁxhœU¹l0®YªMÃ{;Ï5Æ hs)ã‹9 #$ÅQm<Û°’? ‘ðMVÂ&=šI2?æ§Ÿçãc_žhÔK–Ö{WèîÚ¥ Ï`[îIï•™U¤7]³.ƒ7‘m‚Ž.-GßX_UUMóŽÉƒ^« Î…Šþc&ÎWª¶(TbÕ’kèÕˆ»e}1Õ7|â\‰Kx Š)žäó³¤oÙlIc´{ÃT¨Ð-ŠïKóûƒ&rtžƒ…±½©=;v ä¨1JL,ìó¬?– Ú±/è K¶È¡S%´¬N¯“o ßÛÂÛ|”ûuŽéwägõQá¶î½d ·²qS¦êjQ­t;`'YúD”¦RíÊ(  ÉÁôRw´ÖcáZr[!ÿ…ZÂ)„zêæ83°f7 ƒÂ×½žœh˜]i /eé5>0˜ÈLê=øMèÊzýùefm_Ýy/eßñºýÌWwñ TíR¢¯7\&̾¬Z?b2÷°.—+q§¥ãkÆÍÚ7tq8ÏЃ _Ü”7ð†³U×P»B6»#Ô¼Õ¡r «æR÷Kµ<ñ¯®šõ‚߆‚8´ƒêÙ X“ZÎ`huÁ_U{V%û™Š„ó¤5øTU­u ƒ.Rÿ³ð5û‹³- 诓HIµ>n2Và”ê¤R6%e긂ã›w™{MS̨ñ*¯ðqâ¦C¬›÷+}ÒÚœkjN88ßíjñE<†,(Óì; „£Ô³nxK¢\χ&½êN—âuó†6Õ1@†Ÿë\>ñ'ƒê(Œ!Ÿ——Œ8ÖÄ`âyXè¬ßÉçcÖ˜¼,î6¶Wx3¦µ,ƒ×~^èö–/óÙâÙÀ4^ÃÐÕë²Ï,Uií§†ËÏÙ3X6ífW9ž¦R;y3O4+.‡ó;ǹj/JZ/¦µóÃ[9Ñú@Ejçô¬Y¢uö]°hlQÇÐ ‚]Òª˜´5e ©RhæˆêÈì_…:Ì K¥ž#y‹OÅäÆêU²-Rj•¬wnÌêd÷DC¤¬ªòÈò\ë€FjÙ5£ D¡Lä.ᦃ”Ç<;¿úö‡C¿‚epAtaCA˜$åú™Y4© u°Ç¹ýÔqTãnÁyWxLÂ2AÛ<¶T8¯«Áܶsª6®ŸùÓ¥?.»D‹ mž„Tw‰ë´U žû¼( ša¨\ßt1öa¥mñÉø"†rO%h°žàyÇÒÛÔ’5ùSú³Æ)Ùìê8>ýaôCS„¸›wAæ,D…®©û\#éUëCÈ‘?ÆšáÎ>uÄ 5@F¥C§ˆŽnccZGÍ2¨˜¤µU .®Ÿò‡:rŠ£¹—« [ÓäžÌ%½.O‹°9nˆ zÉfHdq·ºFùqÓÓf‰V Y'À‚ºÛ»Þ|^Ð7mB¾ û-º#9"s*¶°±û¸É#@¬°m(ÙSí{å°e {Y²ï°Þ?¹Ó{íÝ=ÏËÍÙéQýq†tùùý3bÎùAÙöÚÛöÚ0äÝPã03ͽèÒж僯Á¾ÈÄCXb˜Äó«Gß# P?T¦°mž ‘²óR‹èöÌ«k šppô 6ý7.'F-Ašú{fQå Ï^„h%3æÒ«ÏÎáÙÜ”Õ!ÝÚ\t£š˜úù@’¦]íH•Q1ß=Œ­ITª¸OÛÓ]/C¶Ö8WÃKèHºó.âݹÄòƒ±¸Ãæq-AD4x»"Õ Yƶsÿ‚©4lGu]zµzSu¼å÷ ©ÒÀPŽnh•Ÿ° #1ÅBzpo›ilìÁa*s‘^Á²>1:6'=ÌkàIã$iLÇâ®U†ùHIŠÜ`8±˜žé—M^Ê]SQjVt~”ñÁzÌ óÉ"Iw…n©öª[%ÙcÃ$ýinÅÏBb-#ø«-úêä¼%̧J#E²S¤»»JºT%ô3t°ÄÁˆSR°ÄÓs8gÑŸeì`Ä8·Û½]Ü`Hÿ¼aå³ðã°æ{Ãæ¸+£,ÎÖ÷¦íßzXqzòÆ$ºM"¿Wâ<ËÁ®åÙð ½ÎØøÚ\îLçÑ·¸’ÌQ§îgž1T%l=ÞéÙŠ6Iþ0ÎÚh}7YÍ ñQ°dB×¥ÿóBþ"R DÑ¿¥cçõcÂ0cßÇF\HLàŧL¾8îî0D;z*vCØ7Xr¡|ýÉÛ†¯Ã5ñwOC¨f®Jö–ô aRˆbµŠ cŸj}º‘"xµª^NÈx´èž¾c=ôÚ8ò}©Iï7¬^Ã0šÄïÞëi¯‡¤îÓ} ǵžçл{–~~æ× 1:¶cìçÀ­ñ©ÞèÚXžQèpfÅjåPJãodÍ|#˜°&~G Óål•r~nÈÌÀÄ%Û X…Ôì^iؼEârXòƒòõ¡¿·£ÃŽ;:´f§f\~q“å+âÒþ«I%¡+s8+vÐΣª½»©„Ü‹Èw9ô«¼âH­ÔÁ…ª¨ë±tòtL‚•c¨Æ¾€Ê3z?0ÿ S‡_Ì’75ס`'o‰ ¿¼|Jïw¹hLægÖ)˼t+=DÔôgSê·L¡ö†À>‡î¯FìËâléÛCõ Ò< gã±û„=‡Ž®ÜEÌãâéÇ覞Õ^5'³àø´fš£r­/Æ|.6âýQ‰nýƒ¸ÌáßpAIûBÚ6.2:ë‹ï×bõ°¸¨Šé<èXL±ŽOET‹À¡ÌÌê}E×Ìô´m‰ GÜ16Ÿ)¼ìMP˜¦0ïd æÜè0‡0V,=+9r:Ò»Ç.qYΪVÕ ‘Œ:›Ì¾çÂÁåM çlÞõ±ÝתY4¯ë¬ÿTlRc>¶H12µŽòqŸÿ1c/©8M1éq7>Û>oZ;ñºg5hÚù¢¾> ã²ã†Dj¸çeÜ,Ñe7ÅYœdê†A@ç°Øø¿s rR©;—[µ…½_aD³ÃÆ‘´ReMΟ8åëêRe}³ ’…dî‹2¬LôE “Óï(#çl/RêU[ Œ²¢PÖ µ’úãñ±Ã8¬á9ÐëtÐwt]X»ƒ,‡wæØY_ŒçŽaSÏ´w_hÚç”β@¤j0-Ôb ¥¸ÂyyÖ—t¾óf7ÿ¯IíãâÒð¾lh›NqŠ«Œ½NðŒê[¶R>Çdºov³)enàJ%qYÓ,ø™Ã+£¤ÍÈ{%”‹ÖãjÎþA˜"yZÉÒ£åä0.2¥Nïk¨åe¯G^{&80ê›ÜæëŽL>ys®õM׋“¶ˆ ñÄ<²Ï D…Çu3èY¼¡*µ;ª€U ãphs¹Ž[¿MÝÛX]NØÓüCØ¡›áý2ÆSÆuè3Ð霱_ ·”¼ì¹'ƒ&—ëƒÆÙH„ô»sÝ+ÈgïgC˜Q£öLôWKÇc0'o ½P`_ÇÌÑ<çð€å4™p[4Ñ0ëW¢djó7R©1ÆåßBÇ(bZŒk%V.ÉäS%’·Kötšà[Ù´;÷3r<Ô¶®áË^yÁX5”\U˜‡›ÿlÈ{±>:?ˆÔ$§Ñ«‹[=r¿#û¤D± ÃÁ¥Z€›$¡Ÿëý¡rwÔ§$HÍóÂ6ŠøL¥ó³ˆì>%Pq|åP핞S»hÙŠ$+Lnï¨$Y=¼­jZ›Å–…U.’­j`§ýtäÊogbu8ÏRŸI?åzÕ<)^W QÉ7•hÔgàðMU©ÌmZ±Uh¢eQó}q¨rø!à§4ªªÙð <ò˜¤È‚m¬˜Ûfüј¦XD‘‡¥#rZÐLµ£ƒÚ1ʶåÏý‘%DÊØjy›V–ÝNÃuÙØDXÑ3º&½IÁŠVö=ôFGýÐX¦,¥l6šš‡Þ"gÞJÙ:d³"d9ª›uikFµ0ÑA RĤ‰èÊ; Ì1‘ZUIð­æ¬Yí~ ŸžõeÊs…+{Ö åO„dŽPÇp=عL«Îœ¿© 4:\á¸ò:È!ØèÊÃä­á{5uÒ}ä1·4äq)½7mŸò“]åOPÂŽ8 ¥sðшTuúÌ2{ÜBúþâAàR銲®ú|å–X§.çhKÞ~ž)ëJö±ªã Œ/Á03ðfCQE*qF業ŠHÚá¯\¢Zåè»Êž®ëgM d”v¶)©›`Œ‚(~Tƒ4‡ò6lM÷ñ=a†B‰x‘t i,*úÅÒ¾@æžšG–dû~§?‘õ’éˆÊIšì1wÀæ.à™©½×T{ì>â§w™:b§%ÔÕÝÐòƒ×3õ;BñÌ,n©ùÄáÊœãP¹ÿ:Ø£:{L-g+Œ8´LÆIC¢½Êih|íb¹Ê!ràï^2ÚÜÜÈàÿþßÿû{N虲ùæ_üãпpQ¿h»û§­1ÿv«Íÿxù«ßöûÞíÿ¬‹ÿÞ˜jæ°—]ë?ÄyúåsÿØçÿ«L¦»_ï›ñ¿Ì8þ _ú¾Þozþ~1ÌþÁWýÅ‹~ïW;þÝKÞw͘¯ÏñW.è_y½ûÖÃûWš¿ò%à‚¾ñ¯?òÍKøjžþñGûÝ-ÞŸúâ¿ü9œN ¿õáÿ!¶ŸŸ«\S饧í«I¯¡zi·FƳ¯¥¨þ{#˽í¸ðɨºªt7dkˆœdc•;“XC/9õš-©SEâvÿY9n¥…ÁÝ´³ù.^ˆA2yhn›ðT¼LäïMœ¹—X»¼0†ŠgNˆjÐ .NꓚÛ40ÑQ˜uP1yJ‹Ò †þ–¡!±ùnLß10«®¡˜åq rµR‘2ÕÀ€6ïì•_å"§?G1ý­7Ÿ¢YB·PTéÞ#\ÆŽ—]böùÌÐÌ õçBÕ/ãƒ#8ª s4¥ò&ãZGÖrpêE(ÆaÂ0¤BÊÎb&DW= v†v •)ß>JkêüYó¼ žLÞQ:FÒ™½¯Ÿ³Tèä÷4º ßž{:E]1Jq Lsh‚½f]®¦„XŽM¡Þz ïªð>6åCÚc.+ñ0½'•®aŒ ä‰gãš;K{Õ(¯ÐÐðL:’z[ëǵ`Ô æHD¸2N¼ÄTWGº=‹ù=7“¶»Lÿ¤j…i_ðö=“\ó<îZ¿ÂºÄÛÉݼ³Ì>VÇ>¨ºº6xY¦DëW´bÿQm Ò9´¦ýê­!¾íP·fë«F]<‘ÐÞib]?ªTŸB‘ŠtÞ,qi„(¹SåA$¼MXËë»Lý)MmgXÃ}¤d¾Ëlú™Òö¾]·®v–pReš§l¦&EÁïë|&ð)/¦ÚÂQQ̧BŠÆ"> [%XÙsÑÌ·Nž²»JôvÂ#ýIW"RU2uPÆvÐ ú>¨TÕ)û¢ÄÉ\äb[;†žGQoyrË. ò¹6Õ¬¸]ÒÍ(.wYn¶ÝkéÒ\QMõƒRIô†—‰møŒ‘fÂA¦*°¦ªVí¹isúVö¡kð£&¢îÑe2ÕƒŠŠfm•:ØêÜRÑÊÕy-óªä³ B-§öü 7­åþó}¬+_{†ðƒ,1ü+ácZ•xªB§aìö8{3E4Ü^{¢öPÛq¯Ì¹ªÌæï§Ê-.—"¥‚&’î„ kéØÔóý¡Ð÷y¥¢1!ÊQÆå¾ ZòF 3ý…ÎÙ:.¹F1bNƲùWĸ¬ãp-ꣂϽqÜ8w¹®ƒó0„a×0¹RÔè¨Rú´Á3îè ×± 6LDU“ÐüàT¶"¡|&Ä©Þ ü-±§3»¬vµs§â”iP|p®F¼˜Jæ™ÿ®¨X2o(«–%?σ²ˆùÖ”3uÝ,Z|:¸©¨<Ê;Óˆa²®¡©ïajLyÇ,ÁGm]øÈpS\®mƒhjögŠ|²ÊÿSãu¿Å0[,A i¦ŽlNðhÚõ&Å­JTt53W¯ª#d$²ß•}œ¿) }&!%nðj*e@ïu©ƒøëö¤Ü–âà‰²‡Õš¹¨ò¯H<쬃Šh*tðVUâ£<¨d'‡ÊHR„û1 Ö©í å˜5]sÔPü TNçñé5úq¸bï0wX¹úÞC«¬íé!yn ˺*³HL™M4^MÝ8Ïæ»ŸÖ< ù2`\[]8@ý9xðbf‘÷ÌMt‡W‰ò¦=¹ÀQÞ°´åahÒÆ%ÑŸ·ÁUCOÇàZ‹hæ ¿zæ2÷à#yz[DÖr5”ž Þš÷‹l·"×AßXçáHÏ–¡<“Œâ¶+ç°¡A•¯©Ä!"µò§ç>àÍôiLòKtC¦›Ú×6c:f(ÞÒt Ù9u#[67zÏ´s8Ä¡e·§ú9 »T˜¨ç¤¼zl¯…ý`ãéò›˜€(‘!›Ú²š´ÖSGÿ¦Ü†{ÖuÊàÚfÞ«LÇby—Þ³Ãhà÷^ɺ[u†–´ÒFO•¼Þ*OìÙþóblãÓÐÕþ§o¨Æì5¿ƒBu Vy6VºïÅ‘†÷ ‚ÎOO^DñnÒK‡’8 ÙæQQ‰îÝÙS6¨ƒÝTµÊãÿð£v¦ƒÈüê‘ ·ôÁâ*Ãé>V"v<ÞAîzÞÕ=a•÷¯RÓ)U[QÝài¨Cô^D¼b“÷Ã%‰”l–Λó§)Ù•vç]–÷<ö¤ö ÿõªG=ôfGVuõæ²zdíK£wR½4RšÍ®Á“xm”ªŒX“‡ÊÛ{ÀÛ&:íJö­ST–J2—*Þ+0~†­µÑ³h¸Í|ï2T h…Œ}Oú|ÂêH€à¥*»†%,/´¥"PɯÀÌ8Å€<9‚5+X]«?©p€ÙÞãÒsY'Íã»Æ=Ë¡½(Ê´ŸYh;­ eT;&°øw³òw·L ú«»$/ Ýû¢yö€_>õ5 ïw~è_u`\6N6œR/–ð}áV3ç×òòYg÷Ä N›5”y1¼&¬b"|ñP«n¶ºhÊ#kØt]Шº#‹“ÝïBwBVwf¼ÃCLÁeA¯ûHB7{®¡©™aÂêõ½Œ?+\å«)âL1 {5¡fd#PgÊ‹Àß™>ctׯåyøMG>oïó‹8~ÙÐ7¬d˜Ûx ,gÝj›LxÅ‘9Ä;].m Y¡À“™“5;ºc"`jÖ ;‡°BÓŸ›$ÇAo26vܹbefnYµl½[3æµ°×ìnrB“Äzu 2Q5üÏd²™5æ Ow\þ™©bHÇU·ŒÏÓ*5KIsÇtíµ2yZu~ìë úºHuŽõ{ÙæODpË2·P8™ ï礪.Ÿå‡¸Þ7pœ³Õz7¤”®§ë]¸+6}æ]æM‘„ôD¦HsB±Š§|–êTõ0µÏÄ‘A0QN5ÿÆ®c–÷È2Â]ŸÍ}U6P‚]6Õ¤fC– ”ê4›#ý)8.±á÷,Ç-y­‹ËśԮ-æ¢Ô¤{QK ü:Ú˜äÆ·²©z6ˆ•ÌKðÚÔJ¨:ÜŠ¡”A±„CšUª !ƒÌà­ 5¿+ùžf¢Sh‹UÁˆÈÞªÜò LS!-ŠÔ²zݶ2Ùy¿s/5Ø‚Æêô‚°FxŸ§*KìZ(GIš¼¹Ý¹Èg³eøŸgÏKq¦1K¯<‰“·škvºWl„4 %nësõöI™ £´³'½Ty.T Or¡ÐÞ¡'¦h‡\¨D¾…/uùF;ø¢L«)8¦QbjRÌ?1IŽ;øÜ7=¢€× z+*©Í¢rä"ÌG•ˆ]>4’Rªt%­gUŽ¿ÊÑO}þ„§i‹÷Dt7’‡Tþ*ö.™½•ë8È+Y|Á{á•8UéTwB÷ªæ÷ÄkÊÙ%ŽaÊR½ƒKiߪ%Mýž2Ù‹‘º‡€+A±¢†"ŒV…jžYo¸ç|Œ¾ TdÏŠÜwçÁŒuTÛr/çU ä²¢ì=J±æç^÷8õC ÖOŒùv›VF/(¢wE«œ'öSåÊe>þPNÒË{Ê»bs‚ª!®Lð‘—U|é¸]Î¥íLNX'Š”³ao¥«¥ך4YƒKv–†nÔM›±™8¡ë`1Œ¶!¬:å´#{w`u 5œËœUë½ VþãA.(&§Ôl”›w]vêß±¿‡Á¤6]–ð” M f4$A…[VT„‘c“ÕµüðdîÛçY+ØssyçãBëkºÇ—”ÞÏ«J§”!#k̾J[;Îq¸Yº3zâ^58i¦¢G¾·Ão Y%Gè<ÖÏPÜ£W‹þ›TŸ?-6\¯ÃÑ8^s×>ŽÆtÈÖ[]ÀU”ý¢n¿>ކ¯±#; Tú‰J 1bò‘K-CôÝçæÖ\„/^.gª~è^´å²n–¨ï,7$¤?K¦ô{…_@qÀ({vTûç6¾*†ÎQrs6Ì÷êŒm*޵XL3‡õþ¯Œçî-ó’žàóv7íÃëtúÙz0î[µñaÛ}O5ø\å‘ :4eÍÀîuL¤¥ûREZÛC8Sÿ¼kÚ;䀋êÜ(Û’)v]Ï4úFkL·`¸c#’:ÛZp!¤†™7­ûé^ÈL8Íú,ð”äªÉêÊ¡ƒcUŽÍÎRrHS™±´ù“ä2i Kª•2³¬ÁŠ@ñ:5àüFöüäTŸädªsÙçê8˜Ìj÷Ù¡§ïêÌÚAÓöÚƒ=õü”ö:"œc0c&s½’û5$[ú¼µçl÷»)N/=ß>¦Yø?ÿçÿüš ïWÕ2¾þÁêþêݦ¤þ_ù¾þ“ÿÎ|õ3¿pÁõoüê¯=ï—Ÿù¿óœ¾·_ü䯼üê@y¦¾Sü3Ÿþ;Oû93þÖ«úòÃÿÑç÷?ã_ue¹^×/^ðïÆ¤ÿh+îßýFè…ÿážÇ¯í¤Íúoúîÿ{¹&†ó‹®ä¶Þ:~½ÇL„É¿sì ¿õ+۵Ϯ–ÁÐÒ6:Fu•é-\L µ<ÝËÏh2™0´Fë_ÝÔƒ„!šd¦–«n»Ö4s‘ÏC%êøk™UIÄ®WZ™Ú÷‚—pªÕ!ÏŠ7< š¡¼7/O,t^FÇÝz}±;‰b, »²‘,Ͷϟž#éY½”|hãµf []gm€ÐŠ8Ê+TI†¬lŽ©$ZiiYKw:ö*7ºë-ãùéøRì½ÄÚªkÈù¯ŒZº¡bh3Á #ï¿\EÍJÅ¡¡:êéúÑçYа˜YhUÍ@¢¦snr±ïc«2F<š˜œŒMt®ËîR¤ k?‚Cí9ú³0ô®õŸÑl¢ÇÛÖŸñÝã½›m6EêŒãÈŒuïOe*‡WÓ[K&î?Ö¡Òúÿn#À]Ð1ÄÅÌpg²»eÀ;ÆaU:Éèæš>õÃÁ}>åêa]A“žp¹”ga¾Ö)V=÷¨8ua^gÈ1Rs×P .`’Q®YjÆÝ—»ª·0÷¯"åâíõoB*`«¨!×Û|Z±®2ñ\“æO̶?BJŽÊz‰”ãä´mÎA'¶¯K·Ž  ‹+Škq§pç¨ÄáqÙ3Ýz™s^0õªÑÑBÔJŽóKÁ&a|ħÃÇ.ÑSYZ!ƒâéË@¢’v­çÏyP¤çÙˆiÆÑ”¡ËíÕíUCÔCÛté÷ñ¼G'ĹXG9Â0A]*’*¡(œ¬(ŽÐ$^¼@<Á TñaK@£“Ò†ˆ<³kÕ–;j ‹«šUêzŸj@¿Sš¬Q×:ÆYƒ°Ê©úqÈ€H=H&Á£Ïåüœºtë)[]ØUpSï¶¡ŸâRnR×"k™‰1C8éátpBE¢-ÅyœvOãW%Þ'ÙrSò«ÇTdâÁ e ÆÆ§wãƒÞðÓEž5B>*4;¦ð¨×THd3\äUa”îÜLå¤yÎ5Þâ¹Ïrœ˜Z Å­¹du 1±^•½6o«T‡{ª’—¡Œt7n„dûžÇ*ïXÖ‘­å‘mö›’¶¸Ò&;¶ª’¨Ï31ÁI³`C©1(hOuä.Á_Š©.Z.>(ÏÔÛe—sºÎªúa“=3.ؽÈþqÊÔ¼9ÝL(&FWóGˆ”-t4È©šÍ&mBbVMš´Ìz«MTã uó…ñÄÝÄ|C ñÙe­¤yk¸çay¸}@Þ$Ë|rC=&aR~X.Y) `ð®òÈ‘¬&¢Ñ s›s±‰` #7ãJ=8e?©­š'I„𱚔Ón&Ë([Ì—]‹9EaNxvÉf»ñŽ€ T—³7º…Ó^Ä¥Â5É0ªvrx&•ž}ƒ¸‰iÅ­sœÏÔí«ü¬-ûð[ˆumØLÂ:.d­A¯T ƤýÝÃzXp©xd5þhgx¦ɣ†J]ÒHèëL#}ú;@$Œ1H£Nô”õÔÁw¡RÞ·˜ó‘éL©M ¥{˜³¹FÌ袛eÓ¡”:Éóà‚uç̪c9,"˜h Ü7m7·g`6ã.ðSˆl©zê8)Ñ©­USAÿrX©¡Æíå1 å÷öýp•„u{“":Z…É/z%ÈsÎüÎ1¿”HfùV¿æhÞƒ‡¼‰ž[¹ /zƒ?cÙ8¿¥”ÌÆên踔ƒG7·Ù3¦ñ´LVs¿…hÒî¹Qƒ1z*“¨Ê$WÚ±iP—ÊL¢p%ñXšÖMPzôÆò=Úû´ï_z?k^¥÷g®›Å Õšh£=ï›}ð´A˜ÆËlŽ›Ku‹©òF—«¦GÔÝro´]éJe2Š•åhUÑäÀÙ>²ÂØ´ˆÍq K®´*ó÷A«tóò( @]5‡ø»]†EC?×Jª@;úédˆó±ÉO>EnûUeªIÅ‹½i™Ò. `«Zl©SÕ7ž¤8Ñ@ÓáWMõ¶¶n&áꙸóS´Lï‹iv§:©ú‹¾UŽÊÊVâÀ«>NôÑt¶?[í¶ÁÈŽi9W„Všª1¿GÍîÓOÁÌdÌÙ}<†àÌg¤èåÐðŒóœÑ³Ý”$áÃ3$Ñ»‘¡Äs¸Bá6Í•9½wèó÷Äèš²Ç×#yªsŠZrú°Êi r¢H ÙHSõsî ªŒù#+ÓC´¯M’aa¸ ¢Uý÷P[u·l]t¦^«Vg-tu?4C2¾Iãòù¥’̆¡F2jÏmé7BTñ3¹×q†o å<…ó÷IYo]׬*.ó(†š *n…`cšÑG!Õ ­ðÓùª™Æ@I+YAby™œ´J®3“{ÄV‘3ú¡T1N¬Ä\Ö*Ï8ÚK¬ßã0ìÎ=jß M †V‰ã2âåî )—d…w;ŠL»b>2{F?q6áÇeœÛתÂÕ[ñQ•kó2Þ¯âͶ–"úL âd©hÓI;åGu‰Ð÷¡ÒÁ¶§x¤Þ=Ó^šD¨4&æŒ;æÕÃÂ׸Fë:ÞgYWç†cZkàjg£Ì}…|¹eµ\8$Çë3“ž«Ò~zMX]lF×cÁ}˜jÈ#ó¨îزI¤6ÑK|(>.I‚†¤æMõÖñ&cíÛýdÛsŒûÉj½¨)ÝpÓa’ÕVš]µ›¯¼A¿à!ëëý>ús§%ÿm]S|Z!AÇâÕ°O‰nè"«~Àx&øâ&Þ½¡!£J¸Z#r üÙ ?tåÚ|SñV‚ÇÁÎEô‹/[zˆCüwÛbÈFDnœ$÷ŠÚE&¢+§_øèåÅðt0r¢ó;»õæ5 Ù9Ÿ#‘Ðï³Wͬ"úþ…£ºb~U¸J7w\?øš­¸Ó/3J´ò=/€É¶Ç'\æ%F—m8Ù•}'«Â '3c«òhÚ+,W’°¦úËé*vû_?×¶* ‡Ú&‡Þ}Ƹ>ëT¸îŽånÕYÑ{$&™©»Ãú"C¹‡èªÈ>œÃÇSÐ^c­·ÂÔkXe<˼oÏw”ƒ²®¿ì·J6n›WÏõÚMŒ÷—kÝ×Ì9B÷Ãgœê˜¿«ý樄Ô03bŽ!ÃøµaÔjW®‰¸ìÐæ˜p‚¦›n†‹èBDúa¦¶/©ZZ¦:ÍéT CI¥*|qûÞœ÷¡¦ÒïªnÊIûîŒU]ÈÓ„Ó"ôÒCFxÕ$Ò…r‰jvc}dE²b_fßž)°a(J|µ¨g/tó Š˜±´iz²•1ÉE¨Q,“ªAð)—3øÃ@<ÛM#œ­álQc(í ]®Ù¬©#·KçrX¨Ø8ûÒûL1té±Sò+Û8Úá£íÚÐïn8éz©»FGô&ÑwéÅp ›Çd1Bj’& ,D2é 5Öòà¥Q2Q,4ÍÍËI!Ð=/U£fI:Ë}§æ¨bciÍ¡yz.Ëo €*…J9+ø˜9æqÕ6%*€}GHÓ”C#lgúíÀª3»™þ<ªæ†¸¹ùÓ瘫¢?¿}¨p NéßäÉ™8…¢’t lL‹t“§ùâaˆbZy™ZnÆ$,<ãE©ëlÄÎH0ï!;èéÔêî©R̽~×ÿÞ—˜ýdY{Ã,†-› 0 䆹KèTP¬Öÿm1Æ÷è´¹;ܱ3ÔÚ|è ¢ÉÎÑ×[ÿÑ Ù¨«!Ç¢úh['bœ¿ã:_ŽÇxc·ã‚Hu»¹¥#7c,—›î;†Û!‹-€Oú¾g‚ƒHñǘl¯ÅùPƒ0Ô ¼¢àSbrßkbx;xtbfÚe޽mÕ÷D º0¦Yèû4„“}‹çÕ%1Øæ>Z¯ª£ÇsÂÖ•9'Ũ4ÁÆp˜7‡ûx¦È?íPŽ,çó G@+Έf8j\¬©/'+}ió0õ&ý’ç"0ÉÍöÈ?ëÇêâ¹é€ìÒŠšÅzP!uE©D#ΉO*€*ÅZÛ9=N¼‚p5s–8,Ѩ9°p,Ý.žáZÚ0•ƒS¹Üؤ<ήûNa©îç¥ú‹**%9«§‹4ò¾§RI“{„ìfôäî™zVVKpÂ*Rîroé¦É¨@llìà\‹ºêJY5OÍ¿héFQæbÿ™*AÜ!ÚFSKŸ}0éJJi|—‚©.ʼ8¿zÙÙÇa.v^m*"&ýÇo0æ Éʨ Ðǃcç 1Ѭgl>ÈŠtX^PéÚR$GÇ7f¡<´ÇÚ<ª p“š>cl‹òŠß:· ¸Æ-=„˜D«&i¬ßë£ä&ý_[êPdi˜Tî–Nÿ ê/B(sËÆØê\*ÅhXÙîÍà &~ø¡b…rIÏRÉQí“R S¸`Uªf;|k/ Êð%f¦rK’ËÂO îÇOì8ݲÊRô Y׎ªh4¡ M?’Á‘ͦà´¶cµ&­yâ yÒµ zð ¸…©t+zW*oÉ-Â!u4?\¿»¦§œìQV<ØÎÁÎØˆ?(t_!—/ó}TfEލðô<1²û‘a7dˆñß'ÖZ_^“‹?×âñ•‘ÇÎ÷°×;Ãgeì«dj &U®.¸ÑÏ} M¢½‚DØ×«ÒÁ¥ès¼P­â\á›0ì?ý¹èL«ÀϾc›tÛ6›åãgUÇ’õÝ0DÅ5÷xxb ßèôñ`HòqªxÈÒ«¾xƒ¢"Êc• }ÛH¯•J;ƒRG2´.n5<ÙS§<¥·Ó‹¿ Âèœ ~Ô°a¸ïìÚô˜q HkÄKR¯FFµ¼wD&ÒÍñ¦¼t^ž•q0aµS¥ò‹×òpb@í„:gžÉ–£ IbNrko Ó÷esŒŸåƒ0«cò+ø&9QŃÁ\¡F©L×LŸ®';Ì•òv„Cª i/jz>ž7êj¾pçA¸ö#67c ž%âT"—‡j}H!8Ššq9õE£:ÄžO93à¸Ñ|¬±ò„}ˆØL‰×.mÚz¡Í›šõY5ðÏ@5ŽÂxñìA–wL¼ “ÌÆBŽØ¡1ùÖÔ½ãßp—ò¾¡PÚ‹£8r–E&;nçþO.“ i³÷4ŧWºÜõÙD×Ìrxg˜0àH¬Qí 7äýà•«JÃèË¥[õ…ßp:«TÖ|È!pÑ0ÃHϘ¯S(ƒ,{Ü7ßpº6 sÏÁËú¦ë„öß±g3'²õ_6X/ú¤j÷(?к~·+Þ ø“4£_ã†iNì¡òFVïÁ´qÊV•=½ëx•âŽl‰ŒUs¦d|áD¼!p1¿ºø`xUêa®)VTÒÀø@gT3xýsyÁÓХɉl`ŽHƒÆ$Fl«»N9hÝ—xŸ¯©kr™}£*U¥ÌÂ…mư>¿¥åëü‰òÒz+ßõß[MÒl]å»Åpl°ÚµY¹3?;ã·è˜@CÍn@Š_Þìe ÔP¦›¼`qßp¨Dð•ýëhÉÛÏï,·½÷õö“L¢ÞyqWS­Aórœ'÷¨rƒU¡âQÕ¹¤(ëç÷¬ªëècúëÞ £Èñ¸¨7bóæ/]€ûª+Þ§£vÕ¥/áfñÒtÿî¥é9ó–­–¸ÍÄžVͰŒÜÓªŽy\ž-ð­Háqóú²r3²®›ÞiìáÛnO)S‰¬ëõc¬!z$ꮎ]“üêω>¡î2Ÿ%Îßú%Çù3" ¸ ïDåðrp“ NøD7ïkL?˜Lnáï},½ÿá{‰1s¼ÞȺ¼.W¿îÇ›v¯{Á>o»UG:s÷¸¸ªÆ>ˆ·µÎðÎË.,ŒÇçâ½§âÄjçmOÉ Ë/ÌBÊyØÒ«_ŽPÞÂ%¦$ˆ'×ËTFÝâçÔ«Ô?f5«‚7 €ISþÚs1-_ƒg Tk:ÔÕŒ&^°ÖŸûä¹ pôFÍòò—~§ªÄÝP 8®°–¹0y®Yd8e2{Ú"·K4©·Î¹IP b8MZ¦Uøeô §7ðÃ8ÜÆà>ÏåY è¦bZž<ÙHEXDã?ÌW¦s[zRŽÙ,WkóÍeôTªD¹°URrð<æ0»ùR¤%÷MÂXG4ÆS‚Þ…8)³­šÂË÷vÏh§í9új–)µåO¶™QqaÅ+dW‚Ø×Á ÉozíÃÞ”Òbû”8³Æèjz ò.ܽ‚3n€¨4!z&0VÕRæO3{Îצ2‹$Ç¢ug“„Ÿùv+ø{‹ƒ.›“¼åV¥’R¾¢ ·½âéñ6–À´žHÕO› ]4–&ÂXÒþ:h_Í®ü"œ{Or}@¯@<÷É9 ‹ñ*›~jd€³ÿ`–˘)2‘U×ûì\P®PïC*J£8¬·ÌšVeµw"ÆöB€‰šV„Ò~6¥ºL<+”Ï({'ÓEÞúδj&xÉÃÌ r86¼?ˆ-²:êïßžiμˆK”³øŒD^Ù*¢½#±ÖAŸhXÕͺ·èŠ–&OË^™/D<ä›UÁ©y.ÑçݹÞF?Ë&²¼%¶5–îgk·¬Å´`8ÙŸÏ\;NçBEõ4ÅB8¬MÐÂ)¨² I¨ÍYd/ -:ùV¡õ^ýĉ½´d \vXûÿâF`³ &Öäf‚h‚9BYeOiè}"Ö¹3ÜØ-vB=p÷n1”áˆá–Ý—XtZ *zjcV”±0·z“%½)¬/ÆlÒŽd÷ƒH÷] €Úë€ùIÅ„¼ õŸ4ý¼°pÔÅ»,›Ù)ßý¼u—¤KÄl»kn¦ÚY}ˆk÷èBM¶MA CœêyË4õ«,µŠÌñæüU²ç:¶xãf!Œ@á÷dG¾L¬– ×wÓ}8Vú$ Kx*&Ȫ†JPt& ¡.‚)б4Mù"kzÏRïnhÒïÕ^õEÇjtà +}Ê d1ÔÝá‡d8E6#wc(Ç ý:¶d$e³%Ì3ÕY¸9ºVð¶q…ÚºÞ›1æƒhö6p8à&¹XÚ“ ï¹ÔfgPÌ‹ôv2ãä<|â¦)x5îÙ³· ÔËeE¥w#Ã_¾&•~6«,Gn¬l …ó/L+ÑÐñ>ɨ“ÍHuo˜ƒÈH†„«Ÿ‡ÝÓã9œS$‘ÊtyùçýðÜ?t1æÛÔƒ¤·æ`gl ¨×ˆ¨«®csðþ­:ýJ6^L¢Û=ot˜Zj*õý#^ ¤¨+p9NWflÖ0¨‰6Mô©P¹f‰IYÓÖZ@¼µ¹QýÎý³Ö·€†Ä<ýƒ@MN&åO]ëHY§ËúŠÎOWRŒLð-´žÍìk’N9T“’Uغ‡)GÖ*Ú¾¡s öDXLå$ŽX–y&ÙØex%Ibë$¡È°à°.¶KÈŽMJÞß¿#‰îLO‹áPT“µcŒ×ÊêÔRöTUÑG–[Tq2§¬‹²@ô{¡ï›2w¬…Í{÷çÑ÷ud ¢ˆiTeÀL:ƒ(üßÿûY¿óOW3ý‹ÿüñü÷?­ô̯Ÿð¿Ðkøæÿ‡|ÿëÿÊÏï?Áû¹ÝÂ?ôÖ¾ùevú⌷õ _úåfì¿£Õ·/æ/]Û?ñÆ1øÿkÂßtÿ æíþÖëû{oþŸýh—f˜¿æA'Õ I6uúŠLrú¸Ë¹g 㫌=Ð’Ùô„‡æTsùöÓqô„ \rÒzIÍÍÕŸ}*N”©õûtÙµÖcÒp‚²ª«µÌo3(Xo­|:–‘ÓŸRR+/v2ðưÅà12C»ÍiÍÙ˜[.ÍéÔ#ǵɫÍ|/¶ƒÌï×<»±´£\ óݳXÁÜ’²yMuxGù]£ëôw#_Œ‹ù9NŸÈ|@³Üp]ØyÔÕà·œ’Â#®æ1trgn¬õ8ßçþʌ糠£=ö¢Å¼ÖdŒáz/-NrŽuÕÕ§¾µÉÊÅæ¹ ¨9'®-DÃøžd{ñï=$’q­Ùoƒ«äf" o2Öò ÔËh™¾ð]¼Å8y#0ª¡ß¢k®Ý)ë9î80=wÙ†`¸®Ñ #Þ$¯a~X×çgÒpÑ·þÀaÅ:1ƒ„D6Ÿ×Ùú7€kܰ†ò†ÈÌã£Eïµñ·a\ ¦ÝÒ —¼¯ Ñ}]fî= ·±~}—Ñ÷›¦ÜÀuéxÛÇäß«Ìv ">¹âMóó<¢¹WåÕÓjúÜ}U¦~«~rð¾*ih(‚Þ¼i4ò°»BÉ–Ý¢H•ªôÞó}<¼Úæí½È×p!) niÖ‡òÄqG~ÊüM!Q߬Շ]ÒÌ$‡Œ›“ëtr¤(Wì2þ–y j–aûÙ!ï;5÷iÒ~û~Ò=´„€ÑwTâœ^î6m×Qt¹K³&IG‘UBΜwR§ÃïÆ-ê`„ô®¿k-…ê„2TˆRþ/ZOËÏ_ò÷ô<Ÿ†@”—Ä]ÏR®ÃäûDîSä4‰@• •Á=c^å–‡¹©‚›©\G‘æk’ñö­>Óž-åþŽ3ï)ˆ¤w™"Qø KUEUzt¸ç†¡+<²£¶¨4yAˆKö°…¨-+Qæïâ!KzÙ ïSo¡B¿‰ŽR簾† Z 7T°÷x$ª¹%g]Úµl¾”H<Ý1š~ýù|v¤N}†(‰²gmB@‘@‘òfCCÅ)™òÂõúL%–2Ægâ É| 4’"Ë ‚ØžWÈÝ7´åyæ®®ï”qÍß܆klž¼g•L=ýFlRºLÓKë‘gm°)åœqã±ÄbK9&˜Ò»G´³öÕÁÿ$!´…U!’ËjxgÎÞ\i<)ņ±z¤ÓyDj–ɿɾGb-SÍmK:³rdœ½H™óóç[Z*%æá“ ÓIO`PU¿ÒÝÆí;h-Ö.A2Ù1ºÙonÙn•s6U=Ý·ˆ$¼ì 㓘¦ã‹¨1Þº‰¾Öƒß‘…–ϧR7QŸÙ!N®j¼®¸+õÊ%§êkTãH=üxþÖK¤K‰$ÊzÍÊMÛÀ>.¤ß€–ªQú±!Äú wãäÐ#§‰ŠÁã!}mžd«fY>&d±³Aÿôp‰˜DZ<úªòÀÈÕF!œÞJ~öªS<#Ø«L ò=õ°Ÿî݈hf…f@TÊä‡9éë^˜¤b?Ù–­i×6x¤ÓõÒKÍ eª"?n™ e/ÕÜ«´úœW{àO˜\Caü¹›£$Ò`¯ç‡×­T)ŸºÞ) e®¬¡Ýš&ë¦Q j"O—G‡ËcŽF. ¾(Ì_¾‘ÁÂåz.îÅ*UÕ‡WT1‚=ÈñÏòfùþ†SLäÏB\Ëî h²“¸bY¸ ×ßÊ£_¾¡åE镲!å¸AZ7æëu’¾Ð&@_1‹<¦œá›Ãꤦg_¼ª^õæK…Wq95ÊÎ>ïyµÃ9 w©JtÜ« ™Ò3愊mÂÖ@ùb]!a»º”6ÚÏZ“h8–c˜øj4.\ÐÁඦa¶Ðý-j4Ñv𓼭?‡uÁDëò;]ÑnÕèîÂS\hPà™‡«d\åu„ª™ÍÛjº`Õå„˾eVŒ¾øY}E’¾¬5WÆ_ø¨3ú<ÜæêÂËj5¬+ÃóÕ¸q—fO´zŠ_ñ+?dÅá: ·Óì=¦—þO–ƒÛýb¢S/+Ð!Ñý(pywͦð2é1 •èïú;ƒôB%O¼ŒíË·a‚©ÐÏýùЀ4Aúøâ~†kFµ©*\÷÷ ß·oóPïãNK]×omë¶Àë)®uÌCÀ='3ÍVÆcÆåaËŸ39Qy¯¦$»Ë¹L©ë36÷l9ì²èÁy$“ÑNµ²¹‹‰Ý¸Ð'e©Õ‚HéÛ„¡Ñ^43NŸH¨4²RG:"w‡Lž f²ŸÆ‡>˜ÃÀ¥Z²zЦŸö訮¦L˜81l¢c’$&lÊÚ¶¾hö3Æ]“flØ8lH†Eù©t¡Ä~JoÖ¸9tEº×ô˜åÕâ·”Å›}<¥Þª…¿Üqᷱ̋ oÛš ›Ùä‡ÕšŠQØ$KŒÁÊÄÑSÝšt~rè±ÑÀ¬n¿î í•V“¿ŠJasøûg¾ÔÔcÖL­ÚI6Ñ Ê,™Þ=Ì윺¥\ãЊ\‚5öê gú¼šŒš’ÝÙ`æ\®Y~ëTvФ§Û9WåáÅLw’O7‰ä¨¸êƒvÐтϡ£ç3ê>Dò°1‡çlm]ÇhvéYÙÇn—Ç>•Š,}lj¢§©I±–Ë×?{Öà4LÈÚËú{<‚£Hå>mãÊžüÜEE «“ًشóÒ¿‘Ží¦'ä~Þ« ÷ÞG‹ÒÄœ÷ýT¹.Ö+p”Û§HŽ3öŒC½nØâëwD†D©z_¥ô¯l~²b}hˆÔpï-Îè@@Ò0 oJ M.v…)MY–ê¢îõÃgn–ߊa8H/¤G¤ ¾¾6ýPýçm5ǫ³¡¦lO`E}dñ|øÙî&åù8§ ¢ÎP> Þ¢8‰÷it­{b:ßR>ÿA£heoˆtßfë˜F ²YQÆTK]t ‚ϾÑ8üpF¯R‰Ý¬|9«LÂ%uGAŸ¾áㇷ—R~óYÀ¹C&ª¹AW~™“Z´ÃÁy—´1"xD²å;ׇ%¦”s«ŒÇ¥Êw*ÞÄ@w6¾ ˆ ºô´ïe~)&‚(¸£%E ÏÛ½$gŒ¶¸N¿‹Îaj±™^¶ ¦l­‚%æý²û%T–ðÁÚt~ˆ´°`a†UÂûjλ 'ߨ¸‘š¡„á’ ¥J9HŽÆ”u”!¥|;9 jÈ—ŒÓÍ ˆo*µ—ÎÎA{ìªd§òôŠù=Òûãê, »±WûbôEQ¾ÞKä`)ëÉâ@ÀîaÇ0ǹºá•I3Ÿ cýMn[dSqÞ*GsÁþ9Çhã°¤/Äñ‚-m¸Å#Æ‘/æxÄÁ2¼M}‘$&åË0e½å‰ò.–-hXЃj k^Ÿþ/0_ Ä¥ÒÆ‚k]Äe NlõŠ Ò§XÖÇSÒ¯‘vÖ1öH+SñfW°Ikíç¤Å%ݱ"–—÷PzÂWÿí fcCs§zÍ$ðz’JcçAͼñ•¶—Þ=ð¼·»¿®lÝþè$9äD¯(VÂÚ\.í¡ýùg?̸¸b1- Fþ΀fE%9Ô‰Û«Q_ÔV]‘›l·^‹ì…ˆÔ°¥C°R²QqNr°ÀedåY£×TØÒÅ}#¡ÐP±1b¹§F›Ä`{7e†cÌ$Ç #ƒjÌ.ãIUc>§w‹ÌÊ …5:÷çWþl’FösèÄxaé$ŒaÒ‹ÙW5þݬ(§¡Cк•·[ ³ >—i‰àÜ«¢Á…^n=‹}x…TuÓEñ@˜Æ/u>Ü7œÜ}…a%:¿Û›85~±V¼qóÚ>’Àîâ›ÑIHŸ'Â!ñ0Nê)èH[«–C éãÃòx–ÄW@Nöˆ1<˜ÎB†–T`‡ü5¾1½f9`Uј+ýmì$þ2xݰ´Øpqö¶ç=<“Øw¦‘aeÜžÐX« W¾„ám™S kÕpˆ>I;,å3Õàt/ "lkè©ö²­Ý¶ibTÒ¨žh†zsÕ­FŲÓFÀ” l{ÿ,–OiÁÌ=‡Çqâ¥_%qA+!# öÞoyÃeÒ¸Óæƒ4YÕˆ“XÖ¾N¶…·û]tkR“b`l¸îÔ•U„8Äãt•‰m_ÃxY³ªUëduRÂ=’zÕkzùâá}š‘¡õèTKžL{«Z`µaU:so z¥yÝäåj~Ö{¬+¥_¼ù!6ŒuåÓqy¤ç‘D,œÍ¼á¯n`*‘OeD}në²ñ~rÏ:©^¹Ë¼œÁ¹5Êkh½^ª\m“¥%ý„ópqÇžQ«=ð–|ÔRD ‚—çŽ %Ms„Ö22:~ «‹kÃJ\¾6gîw^íš2wk^ÔõçWeIôÂA ÿË­¾JiºÔçÄfEòõvj {&‰T\›*Û….{Ø#Ú‰‰»Íø2 Y¯ñsé>û»†è×Úƒæe¦½‰U½çµê"zù³«R¦ ^Ë&ûª/¨q›ø-á²êz-ùiK˜‡ƒ ­`‡ê;дå3f|7u™ãƒôíÓGˆ¸æê\æán Ÿ¨Ö+ÒæJ̯;?Ÿ3wÀ€0*C¹ô¸¼œ—÷‹ë«»I¤âòN ]× ï$[ /áÚ/Ð{GÖÀ¬úž©ÇLIá=í>.aÖh€×÷€¶^öN¢lè”ìÔôß{YpÅš<Ö ëb‡nÿêõ óõ[z÷vÿcÝû21Ô2›ñ!Ñ5õÂÄwgà^U×µ¼Fô2Æ.ß³éñdÀª¯;‚ñº/ûN¾úL}> µŽÞY|v¯Å0å(ˆ ³ÙT™TˆÚ ÔÒžÎEwYpÚw@iè1!S§4¾Ëð7e”\0¦V–^?$ Ø *}/ÿ›0•‰×ž€yÐZ¦Öœ-5èŠÔ° °eï½`yM7þÚ¬NŽêÄ-cizAr½jXÖï”<L;}kXæ¨j¼!]ªq«órZì jÂäÖì‹ïã`Œ`ª7U¶›ôr¥+“#: ˜Š/¨»D.n»mÐzo¦†ÈÄ¥‰ìæZò7}hµ#|Üãà‚¾F91o$hyÑÉß§7‚'yý¼z4ïÄ@ÔÝÁÏgµO¶Í¢Kµè‰§l íÝ‹ÇzBò ?Ú,¤/–Œ²ò”a<’WŒfÊ#ö¡<7T-\Ò­Wï²¶ì¬ý§ï ÌÅœvPО”혭U–•"©5&{íqF{ß6ãÎp½fÏZ88kë†c¶ï8ŽÆŒMk“†dÈ¥ï£"¹aªP iì^.O@õ¾7˜3uôüd‘ÓáOûBNÕvbö9lÜ’O§V™x*Œç^}þ“é9ƒr‹ •>EF,,kteŒ7m¨Á„ÿn S¶ J²èÍ»V”¤TTf0TÂß§‡ÛrA›7Æ‚Š´þ‘Û×Ä‘.m°WEQû-‰©JT ¿ ð[ì!ÏÖÇ–P$£J‚2tžhωñh•6BcK Ó›÷bz$uÁ”ÇÙ£hµIc.ó²b}~öÆš(Çàk%{|Œ¥]w—Wäª5"¹þrq–Ví±sÀÏ?ûa ¶!úáÕˆ0é×È —zóå¾2ÊÜZ¡š×ºq Pi²—»,);Ë(÷öA—…s« ïýhÛV“³?«m4[ùº”q„È—IY&<á!{aU~^1yîÚdšý‰„b,Ø… | éåbjŸG/¨WŒiìKðæáVýW)[féÕ%ï Ñ1;¥w¾[ebe YÍРçG¾¡ö¾Q1ß ùð´…ÑÙfMÄ ìƒ½—ª‡Ùò2¹j®«ü&Ûci=3DìÇØ3°4¾[µ_édzˆE9g*^7:7™²Ò[ÄÀö°‘gv8èÔè:ØL ›‘>§I̪ûö7€4âjN¿×þ;ΚšS<Ì6›GÆù¹Ö̘÷’mÄ „ðó,¹ùq5”<â9¤,e­àéA¡b¶¶È¤½GÄŽ­ ÞôhãÓb­yT[}¼˜ÓbúѺDºD4$+´ ÅXƒìyx+¡%vÒï:tö˜¨r?,¦t¬û1‘1WëröA•eS5 f í¬êý,Ÿ1ÇHî˜\p"!aNAžúÐ,KbÒbÄ++{SŠ»Ì«ä` W병1¯f?¢%åênê ÙDi•–Ío¡ÖDê&‘¶^R‘°¿ÍC NM©Êó˜ZQîÔsŒi‚tKò²ß³Þƒ·ß5Ï>•½$°,õ¡ šØ!cÏǾ×KLŠêŸ¡vôu‚²?Öþ³ã‰ó¨ÓmÊ\»-ŽH+!à \|’ –¯õPä!¤#O‰½kÒÑõð¦Òsñ2Ê›¿ÄEk`é‘YžëĚʮ¥Ë¿Ãµ¤W¬ …™Àš™ˆ–}mLéTtzC[^¥ö¦*gèOc†„Rd–ŒL5ˆ£tÛ°}´©‡®Ì’ˆS5QõɃLŸ͚e Ûé°s¢W Ã3?”d¯¥J|£˜‰Ñ\AL74½ã«ìo]4N{Å —gÝúoF´hrè­yŒ…ÉáÕ~˜îÅùÝ^¿A>0³õŒ¦Å®Aw¯ú8ftÓz­öf¡®VãØšè Ð(Gð‹ÿEôíÀ9+%N±-3ôRåf¤yM3ήÀ—!ãI"¼(NK—Îz/U%¸éŽ^ƒÓв:0ß}~ x漢æ4£ŠxAWÆø6÷­æT8*¬Ä,·|õ>Š„SküJšt¸Ÿ\×qùÞºmôg.ÖeQ¶É~5O¿ùØaäÖúÀ×Å Õ›Q¯«îŸšÅ ;Ž®ñ<Χ[€¾œÖÃoa ²¡^Jo©±&¬ï%Ž¡%s”yç$f5ޱk .\0ºl÷°áÇ»•œÇðË x¬nâÒÔ‡/"®!äºIyÞÕS7=ù¹-aÂ^–á£ÌïZ±$Üs ñ×Þ¬ÞcX!y÷êyåÀŒi —äÜû K9n´,€Y’sûƹjxŸõÀékwW“p*^’\˜2ï­‹55¹ í'0vÐ÷&Œoôñ¼ÔUú¿bž­ —ž£Äðçƒ8¦=Þâä˜ÅÏŽcó°]Ó3¼†æcÜdˆõºpJ¿íYrýb^æCß?x‚Ù-¼ìï.ëK8҉іP¸QêÕí7Ö©1øÆé²†™¢ lÞΑØH5³ŽtnÕR'¬ÿƒŒl¢°‚úÀUùÖ(®›|Qí'yNû¨2= >%_+oQ¸ÍPí‰`‡šD.—»ì·d×jºÔ:žL9ó#éž®Ea_Ëä0²k8“—ê• µ,W.ƒµÃxBåÜ nÏÂeÊ3ìΰìÁÂWÓkße^ÊæÑ¼QäçxðŸ%GnnSå’Áx~‡êÄ;6Wpuí³²^¥b~Ø;”qʤ³§ž÷èÔ36ꇶsnVntˆë³ëì'þÂw 'ys›Æö ¢°ËÏVLÔzŨq"2T‚Û)Ãb’¥ÖËæŠi§ÜžÚý"¬Í÷:âá¾ô'ÓËT…q)iã9Š(qQç©*“t%úÂÏjUX/BgŽKB*Ü™7 ñ Ž Œ÷Pr¹Ç3.L¨ƒ*ã˾“:¿¬!²úÉõšoÆGõé'Öö3k^*u†&L†B¸°÷µ¿»Ìr(~%¢IEtšoÞ52ŸŽìj• B‚"Osã¼so˜Ö—–h:}0uPI«œÓüv(hšÙ|Þ¹Ž_„‚§ÿ +§ú§ w¤ëq–&s½{àezÊð<]í;ý¾7³–Áòƒ­5&c±9˜~ü6#¶ØæcPCÌ<*# od;kh™‚æéa€ÅÝÈ#¥'F ½ÜÇÍ÷T)«-cfØ¿Lk-ĵýŒ÷¦Q¹a],)žcÞëx6T:®}^%;=uGêYŸ‘T¯Û£m 覂aÌYbð™çpw%Û»´w…úá  4±>œe;0è«ä¬(‚4[aG/pSµyzJ8°Á;ÿHcS½ü„`íº‡ i×›®&{é’~̾t?¡G©²Êt«–½4SM÷î= ݿ̡ƒQÖ×w‰à˜ÍJs&Ý4šÇoø•sm»÷‚³äãYHųBÍ!1IþþÇʥџyR$›ñÏ‚ç N!ÂX¡}ÈiÜp¼?ó¡pÆFüžQïõÄY6?HÃßn¦oè½`Ç>žµB¢Sð8F/ÍdJ沨!qkίÔÏ#Çw^—2àûï8gÖšÍXCƒž±Àlø'×AúÆ%7•²¹Â;Ó™kÈ»¬Þº¥ºÃùØ^EÃûOÑ ªÆ|ÊqC ÂÃdž£éÙc«÷4Q¹e‹YêýðÙœ¨WÓÃ$Ó}¶w‘%,b¼Šô«^?ÓÔÑL?!>4™Œ*‘“= Ä„;‹¿C¹Ú!&|¡ÔŸ W¿ ÞÖÝÄ¢}éž]†Ÿ sÕ.§.Cïý¬Ž?Úœ¥lDÂÏGsªOb+Ì^)§pîŒýDü>˜9Ô†¨ð49¨•ÞŸûÇðñé)_æJîãwó¾s'‰§(ý…é¹6´Tú¤THÔêüo¾bM/öIZõ±ˆ­#>YŸ—x–`’áŽ=ñÊ»ãqâ»SÒ4nÛècÎÇEd£jÀ¸Ê½RõÊ}JdaK]O}l™¯2N\‚ŒµL¢@›ÊXf¼¥3Y^±±ùþ3ÞýÀ(%9T?x—xã‡VßA£ª^ëé¯ÀAGJ8膿–”_ªc³™'néË-àý™\xÇU™Y÷;J„‘ýº3ç÷6xÄà}0D³.ü/ó޹ÀÜŸ^yij½ðŽŒ{Äì’wÂ}fàå?¾’½{½÷ÿEÓÊ­ÿ£.¸Å«·«¼!;Ýdxv7uÓ˜ÆÞõ^pŸ6À;;¤K^Üy[,ÕšÔè ŒË\#®ÓÙîï|pÎÝ7úûWÍžÅ7'6cà;2qAT0J,%S\cŸÞ 3Éúß$¢¯ãµÞqJ\zð­Õò‹EÿÖ€zmxý®[›.a«Æ‹·9‹Wj,±I8cÞW|kY½ñ2ƒñ…•p}Nã“omxŶÇäÉWohê-’Œóg”¦ïý7$So웬rô7¿rè_.MôºKèg?‹«&Þ„ûà¸ô5á›qÛ¥Þ8Ã14Eúý«¾ëÂvE¤½Ö€ÈÁpŽ+78¡A˜£ &M¿xá¸pìÀ¥)kü@\ãºÖûp`X¯Áfجàu*¶ 7©ù÷ï½B‰}à\÷[ôÌdÛä¢Þ¼^Æ8sÕOOm÷/€G_x9HL›Œk@Kr:#1ô)µ9UOõ-x{Ô3ìì8Ý[ë Y\}3žH&cªá}ÃD¯½Dcxiø…c‘×NûýŸ«uaÜ4â>ð¶žÙü7ሷ˜bÈ".›¥•Ÿ±ì`Ðß¿ùï¬)ƾ4Õuþ¡/¬ê‚ÇÌÉ—;eŽyÈiÓréðzý|ã²lÎÖu¡ýzC߬›Í.‡“zS1ºÊpÙ(à¾Y1ŒvÞ„ æ¾¾ÞŒ/‡Mó‹@½¯ió“54L?Šª‹æå]Ǿ÷xv Ëê+¯ ½À±§_%ίˮ·³ÖËÙÇ8b|ë)ÍhzuõÁàiõâ³i5Êõ÷ÑÜFðä5¾r›åÉëÞ“” ïìZ.+Àxཷ[Ãð××LÜ=ùð’ø´ö…·›ÄÅ‚Àæ™ö¼&t~¨¬ÀOé=V€ !_Z‚ò¨Ä!¢ ‘®ê@\§Ì¤òŸ/ 9I;CIS›<½ }<{f‹ÏŸÃKl¬ËÁi$v šö¹ß]¦æa6¡rÂÏÃ%UΑ»º'8ŠH…²¦ò³Ü¿Õù¸µÏ­†H)ƒ•hâ ÒúµX©•Âö‚æm` =?¥H†Q‚aá“FÙh ‰‹2VHe6Ñò éØƒÓò¨º¬3åp?Ï(sŸ’¦jè‘ÂBRd¹Ê].‡£OisËL·GËÀSã\eM-¦gà7^c*¬‚ÖQ¡p°¹£ +=‰N>?ÿ<œøA‘_-‘¿ý9…>cúé'CòW¯TéÌQ#o=±Ì”QÅW@Æ"Ä-—)âéÞi¯c2¿‰•i•ÛJýt•(ùl‹ÃâHKÒ•“ç‘WãsõÞ®¹´V‚7©ô¤—ê+šÄ\rUñ€¾™82”T,XÞõ û-je’ÅtÖ€_#7:êòÅg4AQ#qzÈÝ’* {üWvG½·Ù¡ZGéƒÙNÆap­U–-µ’ž|‘gü‹|©öû˜€Ó‘L¥ªê5°£Í9¼o–¨ïDê®ÿ n*Å«ˆžqHYQôù´ñ}':kd¢›†¶uÌåà:UjÖåkƒ®a²FH_Ëé9JÉâ#ÒÌ8-ÅÇ‹åÇ üôW„œ8Ïâÿ¬Q úÖ=”Æ<*NHÇ}SÂ._e°B ²‡Ó&êèI|ŠŒ¸¡­åûY:ÚÜ¢Èüúž¯xö™¶¤àhŠÞÓÔ×÷\Õ}D•KÊÓ– Ý¡ë^T¸¾ßÓýT³Xxö€Šo1ÐÖ*C¢É ÛÝ ÔF‘7Wú¡›î²~ÎhÁM.Ìü6rÐcÐ?ïš'ÐíÀ)ã,òÚÌÚ-æï…Lü³röÆØ'ò#å=á2a·~ä¯ö™m㾋CŠshúµìt6YP4ëósR+[|óaŒ$ÓÀ‡NO„—ˆ@Ï`Gõû&înÒ0™P´¶·7 ÷æèžuaèz’:×<úÔnXÁv€jÙÈðb€ÝsG;ô}u1f¬oKÛ¼¸60$Ê&ÿökpŽ›ÚèW©Ãœ/hh”îl.å ® Aî¦g† ­rò°éÀfræ‡+ݸiÚDç°ŽÎ[3Äsc÷P–›œoŘ$ý@n>&S/Zéç&‚&‹6ÙÆ”yŸD²êˆ,@dÚy|ET+^VwÂ!jöÆ YÚ‚‘´BÆÕÌçdì©¿HUó‹d•c6™©d=@O8£ž.4çêü±¦¶š½-úK¨¶Û‡Eé¹PõÒÜ0ÑÇ>X&Ô¡¦»æ÷Qî?ÐÖ_íÐyÇ4 •~ºŽ¤Ø/—[7żSãºQ%î7¥Íò¶)Ó>ŠiÉ~ `÷<1¹7ÊàÏðã(؆†SɦUzš€û>‰‰‰E’X6ï =õ{ŠýêÉÞÛìa½’Þç`þ;å^Nû>ÅRÚ<ÁwI<ŸØß@ùjØwz޼ò'épŸÛܲÆjLD›óSb>Üåä¹<gS¼—ôJ«¹‘~@Òg§¦µˆ¹Z²¢)Ú¡­=Ö«[sxbVø}Ñ’=u±iøùo?¾ÖÝÃ[!±f2_£:—ªÎzÔdáõêøZwº¶áï> ÇÔJ‡’/oüŠÜ|ÉÍ.Èf¶0ÙUÎ(Æ„Ç|‡5}'Ò'†=o›/¼îŒ\Kõ/¯Ý¯˜Ú(å¨JÕÓ|záCžÊ®TÁí}½uAÌ*G¸Ö˜1 K\›¤"Òð­˜ÒÚ&F‚k>¼vSŸY&#êä ÂL‘j-^ß@fßKÿ—zGfÂã¢&ËŒ½ À<•IÇ0ÖÞ`·ºáVü¿£Ìè˜P>O|õù¸P}_u"öÃíý¿3ÇfB:ŽöA˜ãÊáãm=~_¬Üøb=¾ýþwcâk¤ïûnL¼zeýј8A9}Íê#ü !{Äð °³zTCÛ®\Ç…³™¼,¾+0¬Û;û­˜È߉‰Ã=_p­·˜ÈQeôçþÙ˜ØC!+å¡9&²7®ÿ•˜Xbú˜XÿöþuË’7Fa¡zªæ{4=yØù‘ᤙ¤ï¨niitÔZê®ÊŒØÛíòALüúäð¿'Ñ}zgò¡©ë7\í{ã/4›ç›¾ª†ÏîàPŒ+xÁýáûL¦Iß|©{ êš;çbÀ)X~õÍó!“ÃŽN‚÷pX5fl:eP4;¹ŽŸO´êÝ”+¦·{±ËFDÅ:¸Æ¿d–UåMƒ2”ÁTù¹ºOŽÂâ8?˜fî9Q¾+¤-å±… R‹ ¤P*®5bq«\‡¾;MÙ?p2n/¡Ágžárh)khsÐÃýìvx•¶%Ææ;ª­c©»d/è'Ú-žswL&pø»öE3 .šÄŸÅÝxÖ ÷™¦1 ž)-¾ðÐù]Ò>Þî>PÙ“î ™P}ö^GƒxìqP\8D¾s'îܼYï ÊÚ:öŒu‰¤òÁ(Òä _¼ ~ÎÙFÐ0 vGºÔ»b o«12Ÿ­ïlÎ݉*s|Racôßm4DêŸd ,XJÊ>ë>xÖ:‡h>(ÆáQøŸ@`£S{ïæY›‡áÃ÷¨ä¨jj$œÀéZ3¥¡©\9åzÂcæŸös¯zþaÙœÁƒX®€ïŒÒv›DçëQåî©X«ä—ùÍÂ>žhc°Î÷/Ϩ‘Ve>ÏËlóÉ).W›c¶àR4rã“ÑsOLœBƒàÏÿ¸Ù K¤Õ{t^Å‚CÈV{òà•¶p'Èè¸zßÈ1Žá¬Àêí ’؇Ý€¿ |c`;•ù E½©yX•iu—%¸’¨ƒQR8¦¡_e÷`­p`)éjè)ˆ©ØE7@³D$0®J@S=æÌ  E;8TŠb"+4¼þ$7beD;=Šæ?bauútn•ýè[KQ݈t˜0ÿ š"ÆU¼zglb§ JØÕ"Zý^~ÛÔ5ók~>ÛLÒx*zHëÆˆ¨¤¢êó =:lón €þ“À¥ô¬¤9êÙ@ÊåðŽ4ƒ<>]!D! ç[åM%/6Q‡êÒÍ­È)ñùØB!Ô%u]2Ô[~]“üôÄ}='Ù]Zñ];An ¼e„4îSQ;¯ƒ¯€4îZY#†&ëÉ9Üœ›èÂ^?;¹Bk‚X‹NéÑÅAx°ñÜþƒÇ‘ll/`¼'-8‰ `*ßh¼ -ü Éç“=·òvdëZÇ ¡`Bt×vu‘IX%EÜÇ<›dx»˜2A:9ö¦É.´ ˜MYæìIºœ«ØT‘áŽÐ:Ú Òr"=)"'Á\¹î}¾ç«I óa\Cy²KcSK§Ü[r6ú°g›§+øÄÒ|œ|X´©3ܘ-þ#a9¡æ ífó‰fü³þDœ cÇÚ Õ ŽâNUv¼ëÏ È„c¿]-žÔøpÑÆ€3µŽÃ‘}üç£æú:„ Û‰ú0áB•˜7^Êb0 ºHªâ ˆžXR¦læíµ_¾w2¾¹A3:§³ˆN@¦ƒ .j÷#ddê;hªbÔЖJæ ¾_ƒ×eL›¿À®pЮ?a&1­ŠC’>þl½iwãŠ½Ä ÏÂy½â@l€ß›¦Z¼j¬·Ï¦ð2˜cÑ ¶r j¸ÿïñ™†Ú¸ búæ±Ða,‰®C\kÿ‹Ûz?Ãd¦2ŽÐˆáðÎK@s—Åßà \c(¨k’Üä>qÒð|š†àËçÍOxÌIçÔÑ hó`œóWCÙñ¹pþþ—mvZ?gPÏ|Nñ¶³3Ÿ˜bßqAs>qþ>“ŸÖšx?®®€¼ÉGkb Ÿ¯Eüȶ½së´éÄ„hFo \>;r;ÖÁÓjÕ‰5ˆ8S¯¬èzKºp MoÒÂúøž0íAàÀOÃ%Ÿ;šþç8B(û e`BÍð_‚Úp0ZC]Óç¬í€ë‡·dþÂqNË7.¤ð ˜7bŸwaÜk¾Ök‡ô5™Z$cÆ<ýÞàþæóˆÛÏJ";î—Dá †©xÕFƒ¸åic½ðH,±Ç‹ ã-áz9Tp,pßÙØV÷€8U'Lý¨Ÿ©»N¡i}ÎW›\0ñÛú×õ׎ ‡1:{$àZ€¢íó½Ö1¯éÉ<ï ,îq¤dÍëGãühÅ2ÄšC,þª’Ëp.ǨÏ\sB TÃ̧_ ÙÛ@}eÚ *áX}Ø´x£$ôõ8& wfô”h…íigõsÄŸáëlȘªVÀÀ•ÀÀ¿¼›…áR<ãÖÈ3Sã ‡ïÅ=:ã‡wбŽI*&O Ô©ü;î÷SÏÆÝ`€¡ÜHBwêúàÆ¯aåž.Јu OÉžù#ÙÚO{ƱÒ$VõòéY«B$¦}iYßc§Ü°áû£ÓGèØnµø„lºä "á†{tsù‡>ãŠps¯PC÷í!T³:¯c­/OøVôµ}+I2” JœÆþ‰É ÏÍæ0Q†˜Ñ³ÛìPâ‹¢È#z±º¸hâÏe…_Š;p.õˆºä #Ü'Úžûù".(ˆ-`¹Ü9±¨PðÏçÿ•ÆH* ¦?Pì¤l2V—?cI€§`yS™`›·)¡Åp³ÔéQK€9]o’å œNÛÅS)†=Q‚»Q-òÜŒO /=HžÉ``Á„¡Ð°ó%ä]¢÷ß–ÊȘƛAèÉ6?+ùTÃFä(À4Þ­ò5l…E:æ&c¢Äs¦Oæy_Fp­ AH2s¤‹Ü´u­úé½Ê‰Ð釺½T'%ébùƒ³žœ)hBDçA*›¢Ž$"ÕÄÚ8UÂá;‘q‹L…> ‰Ïù’µ.±íE-A‘dÊÈš“qk­Â4²yÝ\,ý,â ‘0#kyõ¨\5ÓT¢ÿæ2-¢Ò˜ÍåpA!I¦±â2dU“WwG2Žr@5q ÌÄÑ@?gâ ê#¤uDád®»0­¯Ÿmôø{­4J¹}µ×‡ùx…}.ì_B¦}°Ü‰)ÏÂ|sœX=/µq¦§V|»¹Œt€Æó„™Šz’HDqÁ ¡&킉ÃX£•gÍøÍÈÉüût;/¹îçLB×ÒÉ…ÝcíÅñö4l‰ù6ˆÚcQÞC¹êÃ4ßLƒœµýì~øÔFQùY]ö^Œ\ÌÏ)Jñ,7†7ÜšíH1#Nú-‡Íó±À:È!ÃrÏCÓ•j‚}=BHúºŽ©†¶4¨”2]6wÚלzÈ,®#Ý ’Í1Ð{Æ*‰ùð™ â,.Í eüó½uy,×6è¦F 3jÀAîI€AÊ'Œ™\ aáÎ0™¸b׫µé,ݰ1pX2·èY’];;.W9AD7(»Åòã æa¾X½V/hDxq=:¤(ü™.œ®¼Ó3ŠKêxƒé@”XûÃ姪ZíyÇîÎxÖË? fònÖ5Â5rÞ0f“5cJÑî8Óùê¸àloØôéf9‹SÈyíÏF—e]1 ˜{6émú­KyÌ‹u¾2çÎz¾úžð¾w¨Šqíkì÷õ…ÓâÂ8®Ÿƒp¿ÊlE”þ9^pà ¨ÅÀqûÀ7d2af8OH« ϽÑM¸ìÏM»&‚ãYy†FÌpã«ð°"ÐŒÙC&~l"à§Akj$ܵùYpÞ;¬;1šËZ ’¨íLeÞb“ˆ« BTž,Ä=ö±Féäª;Õ: #„|hÈ 4g8ß”?8g¤pA†s‚E„żޙüä=… ïôߊ‘z:ñŸÔ±3ßy8ШÂAÓöûã³1¡ù<5íCàxÞ8¡ÅŽ?€OØ}?±â /€Õ‰£#P]õØë ÙŒ«³‰8ñBp4ŸÂ‡ÂAÖ>Ñ«[Î 0óX]9¨´fGu³rAÓþ¯7lrÍdµ>ø¦ñsrØó¶uÀÚbZV'q환^ÓÆJï {¯¯9@9Z²_Û^<2ò»nØÕö—_E͆ŒH<ï‚=Í&nâ 8/ñq¸qg|4·+‡ÇBfòó8–쎱<ϧ¬ù¯Íl§¡›ÎÿÅ”txƯXcˆ=1åÌ6¼_/ÉÁû¾&4û×Ü©Á6iÚB˜ÍÝNDf{ý¯:ðx!t½›¬>ÿöu#ž ë‹Û%†®ê„õF%¥3GꞘ—¯× x•èÀ‹OÈ€¹À‹ç‘gÆÇ…Jê|®AbÛ˜K\Í 9ÄáÝqán>1jSO 9­™òÕÂ䟘üuÉ…0’ú®ÄóSA0þrw.”ÜÏ_ðBÛ4ãmÆnÿŸðuþYÌsŠ(²_y¡õ™k1®ÿòuø¦'f}]¾óLþ>·ëQ³ÈËg<`æw}–&N¼P|<»§óâ‹F®Ñë”R³à÷6j–²¤ëp#f)F;»?ôÇ€‚uÖC“¡jaЗÀÇ- dø3Lfñ+¹‹¤­S/˜biwîë1 õU'¥ègÀT¢ë€©MYa6 ».ðébj]êsêt9îzmœpÃË.Jž£ÿ¼ÀE7&ÔŸ¿û5¡a<Ë®U›ªØдÇC×>£[¶Žé¼´r[tšôú²ÝÔÑ¿›*—kðnÙS¢#N R®ïzÇTˆîAWeÝïk²¹‡+îx³·-ø^2^p±ß0P1ËàQadf]s2úD(Çð¼¬>(÷ÃÔ¬ÀÄŠ¶ýŸù£åQ =qXÈ›k1Ñ_£\Ò»îž=á½<²¢Ë_ã¤2ÆèãÐö&ع4?Ì-QØ „Ý&cz]9;[[CÝS%“aÅE¯. ´=3öŽ;VÉ^4ˆŸß°)rl3˜ž™ò=ßÓˆ”„û”ÚÕñÙ>[Þ¤ þ§ñ<ËàzÌR¨'ún1)k†™! ‚±z‰¤X’å7J WC9Eæ³0ªîù€"…ߨ‘ØJw¸4ûó9Í⛓’M8…ô=2³æM!RÉíThuåíbœXD<’Êç0!aÛc΀ïY†€p¯”o @ ƒ2îçYÓ>2CesKXý³ÔXÅ0Bճ߄!º\?¦e…Á”[ΞhX·c†¡1ê(æ#yËys¡ô‡Q-VünàßE(WdhGÊfpúçÿZ›Pxj¸²Œ¿(Ü;«¨AÜ! ÕÉ× :‡°ÄXeÝr&,‚ŽG=Ý_U?K7eI ËòÙËëày(µø`ùXbóZØÿÄkãÄ”D4½pIw »©,ŽLø(úÑÊá â­w(×TWš˜ ßgµ]L ÊŒ)Adï ùõ+`®@An½ò53b~IY ËDSý: | 1aƒûj䵬òúÑÆ›*·Ê»à0ÐÏÚO,ó¥yÞe™¾‡ƒ‡R‚sÍÞÄZë>*r“&kL|LÔ4sïÁDp#Ã0!¤ð-ÂwÏía†•Ð5l³•gÆ ÛCÂ|J˜Rí †ˆÝ5]]!Ü2ªy`͆b‹¦¨û{8XQxMÍ¿ˆ!9LვãëmŒšÃNïfò釼j5*w%x-öɄKùF$^Ê}Pý.]qÕ„'£›_§þ5ÎûáážØ?åòä·,XÉŸ™(4tÉÃ¥ÙXqCb2áþk²÷×Úf˜ææ2¥eç°Ãxöš‡{Nrp‹Rãʺ";Å#‚éMDå—0LbáÆ¤Ã­vó‹`˜%S}~ý£ˆ‘°ïõ±sƒà·€#¼ÍMPQLjÅ5Z".JòU26ç*…ï£P?1t&œkž.%‚6Ð<#{§Éé­0Ï‹Ôt•oÒ\SÕÀQ|± ɸñPL´`›^Ö2.…p‡¼`®ÌC–)©qŸˆlòÜb‚©®¹ óûè< ®s¹c¹DJ4†Àrqõ€e]êa¦·W¤Ÿ/ Èâ >kLÎ9ãc3<·è3DYc¼ <Ô¼ùO Ç[쨸‡Ž6ËÍ”á']51X­Ð»Ý<܃µP± ÇÿAÛÈrH ·@òD8+MÕT(À ³ì@<€6ÙÕ¸ìŸÃ”p6ð ²":«PÑ5FutMÀcXüM]€qó4áÐëê=aô‡šÉ¥ÎãW>6i¼ãFŽíªÉîáÕ—I —²iCãœÑm8@îálÒõΧ%çhÿ~Ee"Lh7ËZŠb5ŠyrxëX Y!÷bëú´c>‹~d¥â.ÈÞ…bܺ­£¸µã gNÏYÞ̯ˆ.gIþ™Plʲ (Øz²”Ý>xá:\Å{áÎåz>,ÓÀ}³¤YàL°%C¤Lg¨¯ ù&“PmÆí`?'G à$“μpìÖ1•Ûܬåv·xºmÆ+L¯¤åàÁ –ì q„Í.1›Ô ,¶ERÃj`f‚'(Ÿ©&VÑ-p¹`ê_'õÕÎ1äün†À)KIŽ$ã6pà‰¸&?Ê)ªÀ›º6¶ÁÛbþsÊÓ"R*F\¯øÄ`2ŸÈï-ç`4›Cà^wUMH$• óÜö!a#›¡‚è-”Òâ?oÍå¶×QeÓÖ©ç IÍDetNóvŠÊ9u`˜G†Ýàp¢ì8îÀ(Ì„p@ð’óúϨŽíïÐ` ŠÄ´á„çƒÃŠ-h|]"ïñÐ8OÀ6I9ùZUøºp.¾¢ ŽOÝò‹¿|„E†õ–ÄO,ö_Xh½ag«©$§dÞÆH^€å#éü WµÖ|7nDXà¨Áõ†™>ò«Á¨‡_ƒ9ãÑ÷fÚ&gç©Ùܱº¶;Þ™YÞœ„Ðs|¾Þ± ¨ª/ô1Á9aFÍ…™=Ï×ü×ýsQ'ÓªSPÁ¸ÚfØ„éÒûlrZ/å¯ó™XãN?àrç¯ß{åëêPÃÕÿšúr8<Ët+¨žìЉ´}âW;UY*á²üÆéÃ}?áäùñbØøgNœƒÓ6þÞÀ¹;µú+þNÝ-ìÌѺÐŒ]ÕO¢¯Czpã÷¡ÇtÙ<øÂ5Ú}f]»{ý7îCĤ¯¹n\?òU‰ûªûZÀìg”a×laÌ ‡54.„:y²¼ïµvNámœ–/˜Ïá™§yºÍúùŒ¯¯ù5®n‚¿ó,ôr8ïÜu³êÍäqý¼Òtž…È»JõŸCZÄ}.ùšD=ü©aÝÔ­c‹“c%¨r»PL/¼2gNÈ‚)Ü«šÆ1¦¼ X΢3Ç>Š­¹=YUÁa&Äz»3¹@óH nA€ÍßãÁn#=.8  u ²ûÜÉL>H sºÒ'ÙoFH¸˜«™,™P…ƒ]“îÑlI <§¶n² ºÖzåoý†šs` ®×¬:4|ªñ~~²aè±%¹7˜ÒIؼ•ùŽpØÂM3Ó6}·.¸bvÉC²?z(õõ5Óº¶JT„0V¦i¯J<’ÿ÷Û>‡°©4%³£Ù”C¢`n|Ý@¬þ°â«ËÖDŒƒ-ù¯ðƒ¨…ÑÖ¢>qéˆ+JäͶøñXxdá. víãŒW8ö-@£Í_6 ’W´ä7ÙãwWSs*M ²Æ¦Ã¬Ž5Ë‚rËƦ˜$Ó„Vê £Ga’ð{]EŸ8‰SªŠVôS™@~ùõ‡QéTc 51ò„Fú£øž¸–À=‹ðf›·ÆÏâ(qoj¢_n³ª0ٜɠÝ(ZRˆ~–F†ÝpSPï̓ær§Vž³ ̤ËIÄm,Êy"Cá4þ>9‘%çdhŠîçÓû×0.“߸„Ê+óÝ;^91=“JÅ69¯1ÈM4.“s½3aÈ›‹©®uÚ-£úbõ‚rÇ•/äöóH±9 ‰q^)›‘bp§Øù,»±pqÏÅ PÿO¸³i 2™4#¦•¼b°=‚û’<ÿ–‹d÷˜ê°úÕ½ü¿ÂNRºP¯¹¼â¢1w’¶=9‹daˆƒyÛ˸9dµºKeS' y<9“`À`àª-y'Ž žwƒ?M™…bx¦·”€É±ƒ¢`×TN$ÝGw’Æ’vfX&^ž 6t§zjí‚ÿ!ÛÝRóŠ> ;4 ›,¬Æt Je°¨§hHÇÏØíoXÖÓ1Y æTC0ÖG4¸‰Aîò‹C ´#¶w€­+ã唓´ÍÔHÉØˆ¤õ‰Ÿ”¹V‚0ý¾Bfh¸ˆM0žÁâ>qB$‡„ŠbX›\IÁ7ý‡iØö •Ú•y“Q[ËÞâÖgfýû­ÉÉæfPá6‹ã‘øÁ“'~›€j‚¬®¹‡Ž¯®o™õ”ʬm¶jNí±̬¶I.¥@ÌР½B]îÑ™‡ä¦I[á僃£KÙÙ:Ú4â'FÔ:£Ê X¯„›°*;t%OÊV ÃËò¤ØÏo SÁWé=‰QC8†Ï|™@ÂsN…ùp°ŽEeˆFt_^+÷?´'Áæ»0 6K0í3j;?haaÍýˆZj]õŽWåDïdž0‹¢«à¨ šE Šð¼²(+ 7lEzðBËãt)2oq§6á}sàæC§s˜”ëùÛ8Ú,“l…njìy8{kMöŽÌb¨Ii6¬¥iþìÍ$)Aì³sB²Bü½6ÏËÑ- “]3j÷ðyë³ þ¯©‚^åhAa_îS¹ÁÍ<ŠÉìŸÀcN~ÃäV(A×tAQÃUô“¥Ë„Ö[šLðJ°ÔÌO:Q‹ÿa: GM›d(¦$4¶ ûÐ:w·A1óæ,ZÕ6”éô?)¨ášªÁ[b"¹ÔVÌ4±ÖZ¢à¾“ ®3¡Ý£ƒaàF'-¾h ›~ø. 5Ùsy$5tS鎶•¥k˜ËjÄê}Õ¹ô9ÛëŠ NÆê¾*:çÌn‰ • ­ã¾’µäÏ´›¹'ÉTÃ"ìj=ñ¸‚ßöd!Õ ¬¾Ÿoü¥<–?ÿbª6Y„ Ê4Üjðæ•ÞxÆí§}'€mHËá&D ïv¡—Ym '±çM5ÎÔ[ ωڴL®b^sE.)×=HŸ4ðD M!Í2L-]}mðÌHâ|K3Ùçºf¡À|k²ößàÊZ nÃjæFÇ®–G±?Dã£ùCÌ™ÞvuØæú(±ÛLféûZHW j óRÄÜT5Æ·É<4³ó—ð\°”>þÙoÌ6ãä:Þx,ãþÄÿÉîöfÜ2ωsòGëŒ5žq»ãIsÄsa ætÊe51ùð‚ ®W‰'<Ýí³Æ_=]ŸåÍ$Ýsà¼äÜÆBí@$?²\Fnºš+14(DçĘ=]и‡kÚ·¯èÔãŒÌÅI“æ!z'wÖ—C®¦Ëìõ a<')UW‹–Áx®š;ì‰%€Ëú.£†‘ϸà¹zöhIdƒ-Öï +_ÕÔ0Î|™‰c1Ã& íôésê U<ÇŸ“aë ÇœñŽo2ð8™óùá„Ö½º`WÐù®ÝóÞ‰kç£!æ÷dþuq‘Ƕ™ÛN[xH0¶ÿn{óàÂq¨_×O>ûÝꮪ.>`£ëøð7_ϸ’7S·y£NëkŠég‹Æ/+Æ.+ 0Ø5ï`åÕ«yó´jœ¦iN?ðrš¿ cÁ|̧Žs„AýîÎÒ<ѧóÜç =ÎdŽ^*g“Òy §ñÆm‰ÖͧYÕ‡0ÁËYœ“R4“$ÇãºðaŸ¹ ý×ÉØD¯[¦ƒàº8²Íì‘x˜­…w–øßäàCã´i›OHÎ:2Ú09r¿͵p ·IÊ%6’Gb¼9¯_ÓéBŽ3,J`40ÆKÁ§˜FäW²N“9ÜC‰1-‡MƒQ#a kªwà 8¯Åq?8± 78ÿ§ý5.ŽPn“‹“±ç´—p™¿ôvA&6CÊÓ=ˆX¤ŸÈ)þ_ÈÈ9gGó(àppå?óÒã@·…=)ÊT÷ð9„hïrû#ŸÚ*ÁB‡§ÄÔ/:éÒ^’Á—‹Xt4ÍDP8ñ ŠýNêÇxt­HF÷A…òqÛÞ~!àqÞ;G‘f£äÅÆo¸­Ì¸Õ’{ŒmÉC³¯®b3Ÿ °Ô±ÔoìpnhÊH´—Ÿ†°ïAŽÕDÇæ\»c8‰ÔÝšese€[ÍEh©òÝöRÇoQÏôC¼ö|q:¢Æq<(]Ê*F\.çÍ[ÒšAäWÇ}“PG#ïk¤è/ÊŸoÑÕåÝROƉƒ?c*6ÛQêfp‡.ÞI ‰qià »?[ÍFµŠ¥õNÅŽªÜ«ÈeŠßŒhˆçaàZë'±Íš”(¤„O² ó‰~dFÂêØC"»ú.…(—¢V¼m€ÔW® MPÜ¥^wj·eá>÷¸Tôk[7Œ°+8à%uïn8"ïíãÛ¸*ëáØƒÙ”Všâ”L¦O¹¡¹Œ*·~_ä Ï-R.JFMM±V6o5S¬Ã!*cN†k>ŸA˜Ù=мÿO#Þ ì¯àŠ}J|à„÷†¼«ssJázÌ›«¸ŠÍ«MÔ‡o^ò8Š‘¢A²¹kZ^H•ChëÏcËs…ø8¨Ñ 0*ï*2D„r.Òͪ:lU~š¥2çP>¢ÄåUøg#ªˆ0gSBz¯p\޵Là€æÂ¹ j ~«Å9×nDÓÍASÊûÄ+H™÷Y¾Ÿ¡±AI´„ímƒ)ëž`ò‹¢¨CìG¡@–4?ßßT¶VíÜ‘%ÒÂ<;ÂðôywÐñʶA8°,¨cr!p6ahsR`<<ú’ê¦ß®¼T×”šä-˜ 碇fcÊÿ.ë$ð#'.ÔhU/rá{q§Ø^_?ÂÔóO|­tg™‚úæ@©pŒI;3ºÞ…Â|cBp˜VüÔµ`æ*´Í9t$ÇSïøHóRÖ2ìÖƒ‚bvnCá°¤@ÝŸo¢‹áA"b$s=CÖùâÏè0)ÏÃÐD,º±.jRÅ-«ô`þëÁï9i<_ã4Ђ«W‡Žï%Ñ&ªTÅ'ùߊ9['›+Á º+÷¢6‘•ˆ-4#±k½"Çàx&üÈ36M3¥M¨O•EJ+MŒ‰D?ðžÌ2Žs•ŠD ¹rОÐ+o@ÅÖ?§çD9žR7¬'’>.{) ²i&inë ò@ÁaªŽþ³¾(Žªb<ûL2ŸšÖ&*ª½Òã4» ž œ" b«¢Q¾‹./,N‚˜z-’ü:de3Ñ!-{Mˆ‘_Â-Xa¸Ò…ôM7Wbó~ÀÈÎR<Ý‚»ò[%†Ø×šbÓ±±–µ—2žK|Þ*„Ÿ¢Œóç6T¹÷‚øŠôæ_ .µó‘”Œèûac€ÙùcPÓ®—vùNùlôÛI%tjQU­°Í.åÏ>Ҍ՘éð ªN>SuN¸«‡ìkY;jFGy/j|– š¡­áÀ%ib£[áJù<&§g€ôÉì°fpp.Ôÿ‡lÞšú³U7õ £ÀVE™³ë6oõfŒ“’'³Ú_B Õ½5_ÿpA˜0K/´—)š3š »øQŠ:qGÕmë' ‚“'9‡|åó”›G–ûn-œ2!Ÿs:·Ý ˜Bpm³”SO/]ov®r ¢pðH«àAcæäü]pÓKm-®Mð¨/û™8)°U÷cúÕdާÄpU×ÒõÎ-QåÜ4XBé{“l懤‘Iw޼JáÉ2 ~‡;íZ‡]âßx×¢h‡-×™–ž@ª…*_;ÌqKR%®?±¿¶ùõsöÑ´læ¸ZN þ*NŸébEZ¿J¨ª€5ŒÿÚÍèAd!z 4&ÌÀÜ‘ËI^:i$f·Õœ¯¤²b… â­Oíò”gü8^KÎÝ¢N.)ÏÈÄt `‡ëöª£,NÚ)L¢__£§7Cb„pAÝQ¦°Eк¬&e‚ ÍÒºˆÓ:t£,Ê:D˜r¶}"óJÛDŒÑVâúsw’Â!S”¦²`ô9š­p×û¼2Á¡ß(5ân{¾Ãµ¯d<æÈ|²üü½Þ‰üÁYè{Ò §z-ÐÒ +œ\³fø2tL—áLµÿr½²9aÚ7‡ÆÕÅšãï¡Ç¬:~Ì>~úQ ¡þÀ'‡FVîu âðÞoÉù{ϤýÝ }?bÆåœœ8CŒíð£µ_œM¿~ÁÁ)ÿ©´@#Cô‰:@޾Ggá,Æp1­S<9û›Lk9a„¨.ÖÓìF^·ô9'B38:ä|8ûªIð·œóèí…9c1OáÚ‡ˆ&³³T–)Á$j!@Á@£E=­ÈàXdÀqÛdˆóBjÔ×¾Bõê¶\wìpó]›º%ºyî¢Í¹£{=4Í»êWÁÓ|*P¦0˜+ÚºÃÑŒ»w/Øào ½‚8’ñl…[itóYÒÆhyúÝÆ¤l¢fŽËoäè°L/16“ÝmNÿÉÁp -îÁdu·,€í ‡ 3uNLÂ1|8¤yx¶Ve¥ܼÏÉì{Q; ^äø‰~y*=33:?͗놈P|ÒËa*7KÅìÖcèÊפâ®4ÈÜÁ[1¶´ë×=p¢&mŒ.ë\aL¥2˜îÓ5 +ƒ ' 8x+Ûz¬æO“Vº vziž5ANÝéj1ÔLÙ@Û»·²Þ…Ä\âQÀp(2YÓqïžcüá¶@xj‰H5²–‹±9.w>Ohž’Øœ]FR Tãéõš —wLÑèሱzs”À€ A6eJOÆú ‚M+Ô`W›OEËÃÎMV ùC)œ3ù *·oǴܤèÉQ(õɽZ£ Ä^ŠÃó |?Cis]Ëføœ/ì”LómÜQ"9Ö åˆn?ÁSs¥áÒÍ—e^ˆš 3â\ë°¼áè–‚yåÉaÓ¥+V{ï/Oª„¿M´Ëÿ`  œv \^m-f$8Ü1ø¶.).JŽ×XfJa£—ÆÜ“@Áü1“™çé ˜U†-ñ4ð»8?ø”Xø\eS‰µþŠò¶ g§‰# ’›láÑe‚dÍàªÞÁð@Ydn_õ„ Èp&/g[!<|¿â5ÇfÒˆg µZºí +ÜÑÐÌÜÖµ·|7*8ǵS‡E,̆Ӭž p<¹Á±²F~’¢ßƒ}OÃÜs'=„“ëúÄà¡ìbjsO¼gy?î½·þV÷RãYmþ®•?s' b©uAÆH“'unþdL¥ ÄÇ-”ÀmÚGéfŠËªj±ï:&¼dìH!ûÉo›ßU#„v!¼6ª9'©ž$›6‡ŽpsðÌ'@c·m£íûC)\bqĽì ½Ý¸qư ²®7¼:0Îâ’¸×í¦A¢X4ü/ ÎǨË`ÓŒ??g@5pÁ žµ­ÿYÚ(`øo„@E›“]YØó$zE»kù\"`ó³qs` $Fư§Ô¶O '> ‹$7Wfù'Øú¤í5Ý£ëw$éØg³ð'ì Ù/êã‡E;•÷šWèx1ø4â½´Î…€­9’qÝüŠ’9*›ÙE²=ooTºŸ†›hØÙ¬YÞÊ îý<ƒŸ#ðØíB‡Åqhð /r^ï=±MnkñOð#5o]<@1GõØ"iH±)ÁÚì.î„Ô›C›B=ê{r½rÔïòìÀŽ#ëä¡ó´žq}—=g®$ÍÝØ ›OþȸXÎÐÞ½ùc¹‹œ—þ…Däþñ{°ðÜX0”\è6ãÚ嚋Վ},4£5“æ4ˆMµa=—I:O)iØîñbI ˆ‘Oå-JémÈN`w·ÐY[ÕÇ]Ó²Û8áE£m¤éèW`¾¥â_XhëË}”¤Å}w%LÉPqã%U€òè}¾*UäÖ2úlÚá/q¨†‚–êé³ÄK³×0Tê7ZU }ïdPãçáZÆ£6Z˜ÙÈϸ ¹=ÑjzÇš'X̬±¿fYÎyK¡·Ó¤ºwWÑÔ¥´0¶ç¥ùùåÂÄ¡‘˜UG0˜À€'ae‹$^™ #šr4£¶Í³£R5B E‰¶:ç‰$ˆÏÕ™åZ› ÅŽ‹ôÔ|öy5Hìûí´Ûý18Mh …½žÙ?›F;Úåêê6¤ß¤Crnœ§¹ÅVzÜaȡ󦟪 _§Y‡+v=…ÁjÔp[ÁM²ÖœËöeð4©¦£‘C–‘Ÿ˜ÞP®­~ÊxŸñ|݉»W¬0ÓUîæO³%zêÊ…´fïjþ jn[µÃ„#¶ º:˜ß"0>KßùTLKYµç”ͳŒr;ŸqŠ5YCô½QÎ…Ô]C¹½ Sê¿& ó„àb4÷–øpÙ]¨N}9¾Í˜;—l;zpØ M -ë ö3hDç†ê†[¶ÎÃ<† 8K?Šy[œHë¸6ûAÜ‹™V×à¨z°µàt¥Í®2‡âuºÏžÆ¤03Áü è¹/æd‡…£—.Vu0ÇàŠxgë€ ×þm«tâÞ„æP%¡PAÇ£ê‚鞯ó]ÈGÍñ¶f1]oö}ì°¹3¿çSú„X/õè- /1ÇÃÛõû%0 žÃJ;9eŸñä¬Q3^⡹¾ã ªŽ½ŸÂNòFmlȬ(¼ÄÜóÄÙ³SüsY ñN^4›7ðóXÝ<^qXßí| P…Ò$[¹Xu*ôÎ;ˆÃ1¾ßô9c‘;ñ§Î††5ˆo$RÂR#ÃËE£í#Vƒ¢VÀÊYÝï««Sü¬™˜Óáü\éS`­$ǵ ¯K0¯ íÊ}Ú¦¸›GNGÑ|Ã2Ç-¿0 óTSÕ¬ª1ÉNº©éù3Ü9žà<†D#Š :x¨Îš'!£¹ç€7e ¢¸Ì¿Õ™ÇÊ?ÂçÆ"ï¹@ÕË"Í<ëX8Äð¡œþÍ£\¾‡‰úùç#ogí£ V¢¾ÎèÏŸþ2›C‚\oÉæ™€ždKÇÕ_Îf¼à5ëR[¼:6âPŒâ|Ú^öþÙüqPï8|Ø›K-:xý06C1vyûÙhÓƒ êÅ©têà¦ï'ØÜãÆå30¶¸×?¿9ˆ?þ“5/Þr¨ÓX»Ýßu?'±ôl¼6ˆ.´À{)4>s¤œÉ5åÆ!ÆŸÄ{påÈÄKl½}‰lGW7ï!Û ì¦Çýk¿¯SûjÁ|n>}í¼oM*¼ä<¿Ìgç’øtj~ºæÃâÅa}½Äá£6ÄdJ}ycÜ Ëï}ÍI?Sp-¾vUªÒŸzEÉÙ¹9Œ†ÐÈ`lrµBýÜ^ͱÍmšRBmÜ¡ú1(ðcT}Rv1¨’Dǰ+ìªN~µgÞ‡ ˆî„»‹á¡à”hç€lb2£ã뮇iκ1òçQ©º~ú)~_¯‘Ó½;ÆpH“,®ì©ru;ñކªÐ277ú¡€c†8Â$ ©$çA ¡%áÀ@ØÚ?Àrc¨ìbÕàQîfœÛ<ˆÓ !}ÇퟟSŠSѥܣgÝSÌï^µªØK%Ï›9¥¹éÚÞ÷Ç|ÓîÆÐÒg¸„*s6Üæ™¨D…ü-ÄÔO"”ŒNqÔ[Y¹.wEIÙ·i@*F~¤@^ׇ»Ñ–Â,÷UùT9hNR¶ßÆg£±V»Ìèn•úgüáÅU׋U˜ Xå ¡v»f÷wñ]`•yÄ€=iRÂ2»)?ÿåó9ìeÂã¼ÄÊÙ×MÛd®Ü¥­ÜÂL®¨¬ÃêôÇ^å`¾!Öè©Ó3³­Fºmì‰ 7ÀÍR«œ?´ìþ°e’bL•ïÔµ)ëÑLù’螺Wb!N !ž qóù²x 2[g’paá÷þÝc¥ŽÇƒw¢%¼ŸŠxàâ z*/Åãèt ÉÖDXÏçîCÓg€ÈŠÛä¡'¦ƒEÆSˆ¦É샚ÑÖà­f•ënXæ¨jȪ‚$*Á½¸<èòµ!Í¿`Átõ=3½¤CzᇈlÐ1ÌzæY[1ŸdWJ®æÎ=¨üMõLgÍics :9.cCöÿR·e@Çà(Xçûr…‹p’ûÂÝ‘z•¸I–†f­†Þz D»çÊnã(“B!UïÜPw®ÅÌÁÐ1ä%¤t12²®pE„ µþ½ÜȈª©ö™-Š»(i–m¾8èëDÇ Æœ®©/I*c‰Nö„ ¦O9-Ì=–a,i0ºrSíõHÅæ}²×ÐŽõj ÃglX–è“Zˆ(˪/“\)˜^Óƒ'F%6+áY×plö¶d9 ‡K·üÑ#0B=é L$ÃÐRÞÏä…hÉ?é| *nûá} ™Pák¿š#orH„l#öàù³ßÉæu»ñÝ"²¡Dr/êz%U Õsx‚7ÓHÌfn‰•lÁtðà R‚8»Åëi$lrõžOc9`cÀK ®|b[k‘¥ž8”ˆ/Î_Oœ]ꆉóq ·ã¼ÌürGd{ÊxÓŒÃTYŒ*`ÂhQ Ì#¹çu0R$$]qAF’ ³LJΩë\8PLƒ_}׿/"psEªifE›NH·ð­ûºpRMbÊzvód%Bð!åJnã:!ôÒl–jh¢%!¸Â0þY¡/“‹ s¦vM¶©dÜšÏ×°5ÜA" ƒXãv¦ gsÓ¤A+ç©‹ˆ™¯~hœé0þ]8&„~H- UxDEY(k}O3%9l;calÐõAÙã‰õbhªWD4o%3”š‹9ï…‹äÿðH("•ñ…C*Üdšb -t6XjkÀÓÌ‘•sCÆ #Á'çÔ3†¢ŽY®3¡¼^§HÂr7SmU£ËRa-¬é¦É?¿÷W’}Šl$gª BâñÄër×`sˆl2´Œ›'$Û±¬F4Ë †+–)ê”W”ÖýÄ|óù“Úæ¶ò¦á4-ðdÆÖrU|àŽT5º¶žèˆî¡ö7ᇺãšÏT%iÁàP¾mìc„ôëq\Ÿ­OÎÉkèNÞµ…ɽGÒæ<ý'þe+ú:¾8Â7ï‡nÁj†¼ð^ ¦„©œD§£ûp]’gß™ÁÔC›õw{<¨QˆÇ8\ǃ÷hjom&ræ#ޱ¤Ëâ§HLÉíÍDòÅí鼫óÃÁÜ4¦§½Ç—Œ‰Å‘3Ãs³uŠÑu*Z?ÉÕò1àϸö‡Ÿù& EBŸ[¸³ü|7 à1·}ËAïe\ÒaZŒ1‘ÃXï²uüÝØ7øàDých¹ŠUuþß—!Co _ùKYÊÇÄâ¼MÚ&ïæº'å¬îÒØ¾TÐ+¼ƒ2—ÓÃ&׿[2±øp8x?+4ndÿ¾Ø¦"gCªª™‘¨$9ë,½,ê)YÜàÆ h39úl# LÉ¥?Ù«{ïWOœôpsÄ}M”ܬ UîÂ|oN£­ÜO3«ƒY&c@ÔÉ}Í}¬Wq®0P¿Ô[E¼íŸ iàuqPBï7L*9Àå ÅGE%>x§¯ŸÖ\ À“xJ_ ì‹K:¦B·ÓoúÝãç¢b08›'¾ùUÔ%„¾÷ä¶*ðr^öêp:Ãâ)>s3Š/Ôäp>5¢píªO‰2êE¸¦¦säÔõrãàÛ¾Â%‡Øæ²þ_'Kñ£ÕøäÄ—˜Ö©Ã@wyŧ±·âð¿Få3|ûÏ,Æ·Bè%ñl{àþØ·bèäºÞøV¨*|®' æjÍb먃ÈÇp‚NÍ6Œ‹s#f¼(èr·ó)o7qxÿ¯?D#ZÓÜÇž?T‡a%XUÝœu3ëv͘Þ.ÂåüK1:1™µà1Á°gå2¬Se7)ԲЬ®èš(Ø'ÒÍ´&#}®EБë|¨©›Bw BÖ•b–iM©#šçZíã$8¢ßxÚOÚd¯)ø9¨;G7ùDÄœ¥d7FØ×ÿas òn6¢S±‹¨ ø±Si rè nFÚ&q†M§\a@?ÏŽpB6.`ÝÃÝÅP(ˆÐ8å–•²žž Ë€:u†2bý\<¡7_Wãɾî?S‹H­­®LYJDí0»ðšntvÖœ oâ.ÃKæØ¼‡öÞÄåš4(ÂZ7Ô ûèuVËœp£™ :ô*Ú@6BðzGã(” ®ÞEr‰=•Dô¤á®Üg½Ìñ¢›=:+N H¨%1FHüfÜrÐ@1³xÉO†p}tÌY݉z¿+»õ|“Ã|zsLj9´8ˆÛïjµG,ÀÇÍ/Ü_?ƒÎͶóQ¼ñõPƒÐ‡£ 7¯k„qÓc§‘ÁÌ"êB'z¬œº5bÖ©ö§ ƒ„6Õ8a–Ç3ã F„~Æžä‘´qÙBC»[ëw¡yPµ<Œ²Ÿô\€ò)òL@5—ÌúVå1—aMR„mâç6Ìl’¾@2°ù¥vû•´^!SŠÅ2¨<§‹„0ÑòØ“¼y¸!±kÜ ³XcW0ü˜á^v9?ä *:‰/¤ùbÌEæñr~½ð„”eD¨¾¥aO1yTy¸Ý(«ß’`I*’⺭=ǹP‰D`µp–|U¤YxVn¼j9––`ã¦@ظjÔ¢|UpXØQ5"ÔÑ’VÁˆ‹o‰=ÅQt®0Ä[n¥¢AÅ•¦ë<ãXœÌQ‹Øº]X1vw”´Ls®VC0-l{”ܸ\6=0)Yu+Ë(öp$çÚ„)š žFá„¥7ÚÞTŠäï䕸‹ð Ò°Ãꀚ¤ÐÇi—^gq%ªÕ90Š…'«[V0œ?‡ÊZƒH ‚˜IÄŠÍu}îÑܱµ˜åØÒ¼ åΨ SMlxHÒŸR? @„JLÛÆnµcA â ïN¸~ ù¯ä€òìÁõ)åš,’%IvÑ ?é>sùtc9á€ÿ3ÐÈþP#²'NбâBâB¨ – 6@«šÑ©° û2<±@Ń7bôSÆžj§<¦!¢%[r€Íþ=ƒqÚ<97ù^%é g[bP4þG×ÀVƒ‡Rœ(¹…r–tÿr‚:9˜Çø[=#ºÂÁñ ó*özö«‹ºÑå´-£¤X1¾T¾Ùn6TuY¬ á–’šw\Pc_šÉ®ðeÊàm¸kV eˆnXz˜œ8 €9q«Ë¸®%¯Ÿ<§,VÖè#µ 95¦Ñrw{÷cÅJX©:TšÁ¢AE×ÌÌ™ÝDÙ î£nàòÞΦX®ñ§æNp^•Ä;g$¨Ñ2~ù3Óy¸ŸÜëBí#|P©Ýáf7.`>RÙ0ؾ_úÕòi§‡îõ–ãÅA0CÏwÕ=’æ ÉŸ+En4—þË_{]£)¡M.F‚|WÝd |ˆvÆtxì’!ƒe¢'%AB&cOç°ÚÕ—¤­#Æ]H5Â’bQ³B¥’…’x[ÌŒ L'øoy$,n0„°Y °ÑÄ៎3ÈK!pe.£$5Ô1¡»ÕµóéúD©àŽœ*𠱿ŽðõW»vïwt^iV“6w`†¯ßnÅD‚„»g0i,1”qº1ÆnÀŒÁŸx*p¸Xæ ÷†> ¨:ÓaÖA…nü»^(rÀî¢fRúä{ƒ)7Ä {Z°GãÌž<ÍØëIÊVÛf‹\ÓFœVæ ›éfÛ~ãØBƒ`1ó²ƒGòæaÜÑÔ瘘*ë–¬cjœ‘騬Ô~(œý}^í@Çóƒcs¹Ø¸4L¨íôNRÿfˆÖ˜ ÿø ‘Wä µ5êl®:êäp>CxRgñ±Ï-zYqë?ñ:ëdì^EíPâiáÀc@ Pö÷Õ4 Èè9©Íɶ&xxâ¢g…ÆEË¢«ŸÙ@ë]Lf$o¸/“¯×5O:äR,0=~¦ì~‹TCà_Ð?ÿûõUŸ“Žn¤Ø [õìj:†ŠÓ&€-ð+S*‚ðQ >“¸‚Æÿ‘óøq\†Ã'e œ7OþÄ×ü"øä3Ÿ©T°¹õ¾Zœë¢×w—á$Ïê„}½%uÚêõ*¢t`yᆒ¹îéÐij1%¨U/õlÝGzVÁî^¿“EB:0¸ÿ^í «n.÷£yðAÉ뜵Þ÷ôaŒSŒuÛ–÷÷œÜ¥_¢‡÷Ã%V>ïüõ>à‡bb˜‡¯·ßÂ0YzÈ~íÏ~ó4}®[lÄ[ö4:Tê ?ÇÓ 8ç‰ÇùO•©7—êÖ”ÃIÜ'bÛ¹(>†Gqœ7 >Œ¹÷l³‚¦äçqUC‡z’êóûôæÅð¶˜qJ&Q/ËÀçç+Ⱦ¨0áž…F~£bدMп¾ò/¾ºbfù»ÆèÄ©ä¹OÔ'J¡=èãx¼ Ô-™ìKç KñMÃ"Ä“êMÇÝ×aB ç¼ýØJ+5-½å¹_Ù-wœ9…þÀZhÄLº£vjÛ‡³íæúyPØT¿…uâùTQ:9²_aA âJ‰9è÷¨þ0ɦ>P4zÈXÝœÒèµóœðeΰ®BÕ…EŽäQÆÇ¶?;S§«@Á¥šÛ)0°ò2Ïù å˜ÞÔÀ¶ Å KÔ§]>CƒÄ=Hü@{ ˜&ư?¯ š¡i‘3]³+×67qÌ®÷³é÷CÆu»q«sj9Ž7J.J6i<Ç\Ò¥DûØ 2÷óY SÐC‹I§~VXZ2MY3prv99^Zâ*®z\x`Åf“›+@uš6±q†WøMh¥ÒP”Ã&[n2õ'Àœc•<—ädcÂÊ2Û …Á¥•¢Zñt%áƒ:ÂÉçüD,7¶!?%!°~½¾M=Óa&v½O«ÍÓ¡ýYÅ=â .øZiêNë»éõn4"‚Š–Œóæ)HS\l³9èêg–› Ò|"h\”° ¶4¨…pª£Bx– ˆ¸‡'Ýγ0+ßjËbSõ#ßw˘S+'(¯æÖ&k“E¡®9# û:ß&€”Øísa$M1Jd`¡ö9©*˜Áµ’wqQJñ´]¼þ£¥Za Ú’íÆþ>ÆgÝ/*ª°^?¸µó‰f0oŽä4ÕHˆ‰´uSèùM­’F®ßÆ–TˆZXšÍÒZ‰ÕZݧf¨;ÿ¬[Gy‹¨èI¬!¡òwëÛáe;¸+·îš¡ÂȨÊrrÎÓ=e(€¸5Ž rJeÙ¨á]ÃJ‘£L8&OÂRÞU¨¦ÂžÕQiv(g‚žÉÏÕD£öx0‘ê/í"pUDˆµKc%ÕÝ›ŸÄ݇ÛË4ÄÈlpE×\eKÝ”Ë:Î b™*=¥ìaÚ7…ØfHU‡U,ýXP;„4µ™M°ÕÉLø© jCêxiÒ¸ÒyTù–5‡¬¦@qÈL¥‹Ú‡Kv–êËShül@B?s_„’B¥X"¡‘±ÄÁ<ƒ²Þ$¹[:­óNSU¸ÑâµD-ªC+…Žú™oñ… lé sZx48¢uÜ’0Šlæ fà †òuÂóz%/+h2‘Ÿ"IÌγ2¤ö[F“ÈTt‘^6D.Xó÷$:šZ¸†%:ä $¦ˆ‚lKez"FyÇ'.: ”ö}yùH¦Ë³+îšd(~@²ç‡ž×ÂÏa€p†¹§W5Z+Pv!Ü0ÆF0Ô|,&Œ¡I­p¶vqË­(Dø¢7˜ò€\ ~t ¡cÀÐäQ"­  ñ°æT‘ÈQêý’-A1–·uäi7Ç\ ¾Ô±U K” YìÐ"½ýÕ"Dc (-B˜°•ãÃ#yÑõjäøÚJ9ì訸• lõÆÊj°v/n©÷ü1UÝwHú­ƒ5¹Ï¼§øEo"ºÐ€ÜŠFCМ¸éJDŒÄ|Å;û¹X#¥ª‹p%2½‘b¿€ èœ”$Ï Ãb®mÊRó/˜Â¢QŠ š’šÃÐe5áŒMÖy̰[ÖMzw™q+´$7³3¢êYè~?ÅfS·Š”Å! ~ô°¨Â<ÜDmm‚–4kÃð½¶ÒÖ£ Æg„Ý~sàeLÛM¨ð‘9™Qk ï¼ †:IE9€õ&E¥¬*=DWÅ“elB;*¤Ùìe·¦¡Ñ”}üz_»¯¦¦2«øµ*'ÿY2ȦÑߤ1‘¬¢-:ö”^.=DüÂŨ–"âª]-&HeI²EòU1!o}_ËÙ+ÂÜ}õP(F…©ð¤Á}56MkºwŒ² 1Y}YI8´|ï͈:…í ™¸­LßèΞh Ž˜m“F$™awKë!‚ŸÍ‘Pë‰6'ò5úžBh“¯9¦j+, óŸë9¥½ãþCFÀÊäödÉ„>^Ø*®ÔôE¶œf¿{£ bp-æ$:À'MŠ¢«Âý\¥§­rÈü]Ý GwkðF©ßP€sŒÈ£¹+éøþ°/Oùp"0Ï/Iœ‘<€Ó™”P¢ÒHs8‡çØ`tV–gQWòit\뾺}3L ’-DS×ìK€ª7øàî ¥«NDLcNŽxk†Å¸ a/Ð ªR‡×0CNá¦&ò.ºè1ûë•L*âÀur®î ^KQîæFwø“¡ó¤¢Óù¹4 pWX›rؾïšP«öš Aƒ$\ÞfÊÞ&cj¤-˜ËÇkXÖ‚ã’u‹¼ÐJþ%Ç@SdäW˜sÂn³€>¨Îj nZäE_gÆË|(¾º *•F­Çߟ}ŒßaíÎjF+îE@͉ٸ1F ¢9dLiçìX=ù;Wô´yë%˜åw¼<õȆžX€âúáfGöÃüÙ¾ê )r®wɨ¼¸™cÜô_Àabñ™33ðѬwm¯ª· ~ÐÄË>Æ {þt”_3&…ô„ÇT0†ÓëEß§k^ÜÖ·sÛÔà ·Á¶ _–g¨DัçLŸ^냵!QĬÕ2Æn9+PuOH²ƒ÷&€ºïù¡P½:*£Žœ­ª€Ãvÿ³>¾>Ö°Rd/|ýv½T½Æ¿vœ´@>¢ººúÀ×x¦Ö¡°ÇáÜ›U~N$ìjÏ‹DÎ1Ÿ)1T³Ã=}0$¤³{öï¤iŽ0ìÄ£¢L3_uONßw<¢¸À§or8>ÍŒ0«ü2æâ%ÔÜDZl¼ñòÅ'!ˆã±‘üvþXj”Íæ¶Ø8¤_ŸeŸBùlÙ|Ž•Ó"øê#Bªc’†dJ艗>Æ ïJ fÙ^dA°”±ã‚-«ÇõÂ6ù€Œ¸«VöŽ~8Þ¦™o‰¤tÀߊš¾‡Cý½ ‘C9Ñ8îaÞS`8Ãr2Tú¨…¯þìòúýJ‚êX»7E”±Î=êÄ §™á¶ŽæNŽsg¹:4‰× Ä9Á°?ËC÷›áÔŒ:–˜‚š·1Z³%ëÛü2 «hëÓyÖ*<ïê'/Þןªhñ]JφÃE7yXMȘkV½µ€vk9õM&}ŽcFÉS CÁsZ/­1_hÍ ¶³ž§Ó=ÃÁÔ (÷ëëã^ ÿv•Cà1+F[xÒû߯Ú?ìît5_Ü/åÈðÔÜÍ8ÀcA¨9ºkÒÜb0寗E1¬–êÎë L¥)Yw3›r˜¿Î–Ñ`WÂ!í~†ÃBæ(¥rXJ' áV¾6û³}1Fu‹\2¬5»æ|ØÉN¢î* ~û#‹SÂ&ÜØ!M¬Ä@a °ÔVh·"ËúÙœ©t"î¨!°‘êîÒéWí 3Z˜N`mtT^¹l‹ý AÃk³%L–wv¿žòALÝ '›ŒÀòÏsCDòPîPe†»ú® —à㘾®dcJ*'×®½!×’€(79Õ«z/"(ʵ!^?M[?Û¹‡¥+Ã¥[xhiB »2ÔRÊÝÑ×Z]¼u²WîU„róg•ÒL…œ¾Tuáèž}¢ûM`GFy°È’ꤪàagIÐdÜV[Üå3ÓJ`Ý¢XœšŒ]PÅ)3þ|xb}a¤ÝÀþ4b"¥à®nLY›ˆ™9ûCÖÜbBZ´Ã¡t&¼¡„[8ÌÆæ¢w,¡*Š _&G4ùwl1Ÿ±!Å4MÒo(ª©î0‘­|…ÍQpë&º“9u¾‹¡L(¹ŠbIÙ‰Õ<1R:'!|‡FDÅ/Ÿ—Oƒ‘ ÿë·a.ÎùÐLÏ•ÙhpÜ¥¶%NÑ›øëêˆ,QKUÎ¥à7 ¯çð°zâÍ D5ã]»åI…€µž¢Y*É,” w›Ÿcù€Á‡ž9¬ˆ~ÏÅë}Cæ4•B:Áàáî((gN…Úè0<:/t.èüüÙ1fî©g45G2Jy è ëý“¢ahŒk^ºâ-hÍa-›ržp,•#% m.zÕš h,n¢ò;m>óPmÒZ~Êù¦ Þ`¼`ÛœjQ©-§<8Q•OQ™ê’’'¡  JH:Å ˆ²É‚,åˆp¥ ºvè„|iÇ6\U)Yú¦¦S¢BRÚ Ñæ8-YQëÑ’*U'bÃØ–,Õê²°`ÓGP·d?(œˆFKâ=ù†Wç@{Hu*Bõœ‚x/Ø?˜±6pê[èÂýÒßõ‡°HxÃ6ñŒ#RR”¹R ¦Þ¥.òÊú0òòÏ3¯Wê@ S‹åK2ÊT#J¿½kŲ«¡Jr*B\aêOÚϱ—®tb8šøj+åá«¡É&ŒÚÙµ9ÏKðõ?€hb’r¸ª€ºº %çÁÉ—¥BN\ïÅ(þK×ãp‘ aäÄàßðG5ªÒa['Þ¶³Àµ¯çkóàÍ÷C9Ï¥Ò/n÷Ù“K¼d­Z•(ÇÒB±ó`ŪG!-Ò%ðª£ùÚ[Jš,Y#">°•µD%Î"’eUx9žqµy”øƒ(úk+ÑÞeë4µ«w ©ðă)—Èñ*"#1ØÔ’V¼.Q$ÛŠSª$g»¢3¡Û²Ü’SGüp‘'O|ŒP_2ÏÚ'X¢YëR œ}Ó³„a íR·’ê%2÷[uª«ô•™%r«wÖìNB Iõ'F¨ €sJd;"b‹:¸¯¼•[عÜRd„ÙêgÎ&ã«”o‰8Œü·,_o ¨¤ü¼ˆ¨‚½I®%ĘF;Cî7ç¬\ô¢¶jáæˆÂö&®QÑÝÊ UŸtµ¾­ÂÖo–Ý =n’e±ï3¥$¾ìÅI‰_*ŠâbL4n4­ùÇviš*dDB8~ìÊè,·T/Óg-=?öMÍŠ&—be%þÀa©Ñ là×ùÉeaßî]é%³% M¿ºŒàÊH:÷DPd!òalW¿0¨Ä•9ãI ’w²Â|Þ’„Pg.09 ïj«0°•.=ØnÄ2ÔJ:e^G²-ÃÅ¢‘òá·³ðD¤2 Û&Ðù­ð芷ۓTí’"*“fÒ›sIÆF× $¸FârU‰üUZ—A‰¼z#AMܳO$?K—öJ.¤×ZD“øƒÞÞÀóñ2yÓ2ZÖD8ÓCá!˜â ÃÄ€CA¢„ NFòU…½Ÿ}'‰ØR[B‚º\™ÉëáP‘ª„aÁd"U¹Ädˆ ²¹åk¯q +ì03‰ðÓ„·1lo‰æñAh‚¡‹–Ò¸yº¦ ÔÈÛ)»m _"í•:2@‚4iöÅ5ÛMŒ­OKð¤ø#íxâäéÃ`“Ѷ™S ›V!½TÁ‚­J¿F'ÇïÝdXRä`«–«ë»Çï¾ÏHªHÖoÅždͺës H EÉ¢–7C/—¤š"Ä÷Aǂز©RÐdÜŸ¤ÕWŽD5ÉÉu-üi{£(€ùì‚5´y¶ã:úU¢dg‚ ªì&Ýò}VÓÝÊ¥x\ ¦÷‘+±X/0\ (Eeƒ®3‹À™®ŒX&"'"Òˆ£Ýv¸ÊœÝLdÂßnDÙt©"BîªÕ©C³P‹#ûkáÆ0]R½ÜT–UyaHž@‡dBo1ťȴ Ê+#DcŠèpÀçܬ¸VXÞ¶@`ýåóêOOj¼Ÿ´xpp5mØôæîtX,¿Ò<@@qÁýv‘£Q0ñê늑ÙLj¡¨1;Aã|U•»ndÞɉ~r}Á,¢&qIœñ¨GüàAœ÷Ñq¢»: fSÎk°5Œ®NQÛjÿ|UD8a(Ï?w];g£}+7äƒÉMH~EtïÞðƒª©÷Äë0ÍIxR–©´ùM× ºDÍàÇy!ê=WvÖü 6©{µH¯$&ûê)Ø ŸyÞ ®H‚—%Õ7‹ËŠ¢ ­áÈuc+ñBºÍ-€|åñ‘ya2v‰‰àŒ±ÀFÜ~@æI‹àÆ%#Zh²Î§Øêe¸*¢á¼NÿÛ6XŒo$UIÒ‡˜{X®œQõ®zv kÕ¥ÒM™r1Ûþ '%¶—çÓÊ¿·ãô'žÅ x×$‰1 »ÚÛÈ­l®è¡¼xÜa³ÙñwÀ:‰n”Âï[®1ÃÂN’ñ®ö4s«J.GÛk¼õ\¹7?çî´>]ï–MLámMWð‹YGWzÖ…ßçó(tƒSzË¥W÷¸Í–ÅNÀ´C„È¥²¶;ýékº¢-clC`?Œ×6”M>Ñüc¨l:Ñyž©™c"ùÀZÃÊ“I8Ë”(×XD/så?Æ?ó–€)\Bó\%‚Ká& !$$.Ö"üㆪ$:%¼gÙ°ù´ä Q4“ ÛŠdŒ¢Pxb¥±ÿYF‘LQörìÊŠX›*9>«ê/¹höötM,¬O ,šó´:ÅÒ•i9b*ƒÞºØp+ST•ÓÕóÊçÁûîÄ–Ãóڤ܇·‘ó=g$>e*©“ª0"’£ª†…H.¸»è¬\˜OžàªSžh%ù3ÎC¸"„ãÅP]XÅ’ TeK[%JöNÍxÂe7A˜ÓôV’PåW zEM)!ìªì_¶Eu¡Tqˆ;©7¥Sûaéoe£ô=r+ê–TpYâÈvÑ!Ís>§ë¦oÒ$Dj/YctGT‡†®ÙSÈ(v2ÞP©þ;æâŽWjb0¡Ñ,«¥«IípªzOu×úr©À$uï&ÌV»1iP¸Ùd ábºpϘìðþÜzœb㸼;…§'ÏÜe£ì6pïk6~#¡zãm%Ïdøb‡2År'WªTvèݸPD l*¾$[~Í:C¦³Ôù<Ô$Æ© öÚ ò5TDrAD‡{vŸ&MaGåî]±n)8Q”e·tt©|U¦Û\‚*Á Šï¸ "D©ˆÑøYMÄU˜f–;«Wqýät¡€©à6¥¯¥„èñÛÖQŒ‹®/ÍT™®í¦ÑDQ}Ê›,yô5WÎ;êÙ½¥Už*+£a”[ÔFÜAø–“œ² ¶¤Û8µ0¹µ¤©Fr°œ3íΙ¡‡–×asŸd]˜x­Ñ[úœϤÁmEcMöÖÅ]¿ÄÆŠ‡œ3*î°Õ¹ŽG¨*äà‘!±‘a­VÀä6:rÀAÏMUˆJŠ,‘¡¨Õ´¬)o·g‘ë°ˆÿ³Ç˜=W%ÉÿùÞ¿LFmU‡¡ Ã.Èà#ˆØ¥Ég2/Bi‡ÈKeÆÄ#$eEÚN¥3mQ¸¬`i•OtE¥P éæiâu"ãj… 67?’àªjZ»Ë€R W«b%w(¶„J5È!e︮xUh«©Ò#`–E‘‚Lc*•v3yÓPèè»w¶}üE¼8%d£k´×­{Ÿ*"&7‹TÀÚuâ`»j Ú¥¾&AÅ„ƒMÆž¢“C[2üªYp±¢£‚Mj–q/õᡨpUt†Ò¨ú¨®¦å¦’jzWщiFí®™Ä"Ur£Á{Bæj%{[·|_™@œÐ¨?wAÓ§B4Fâm¨Ç•—¦ Dç· (0QϳÂXUëÑÄ€&‹Õœœ½‰€¤ì²$ä︅x=õ@`vM‚«Qä> ¡q‹l<ˆÌÚ³g…3zPŸ÷)šTQ,|Ÿ\fV|‚²DM9V-ÜÚ½h(‰ÒÙ*âéûÈšsÄ cG:h5 ½¤Ù8Slµ¦%ã‰Y$ÅêÉÕ r bUÜ2e-íÙPžœ…_Ê¡ŽùŽÖ±·KX³tt§#0Mqz">ªÌ`¤6ÌÍ Ž0I ª=Í8÷°¦Ñ&ý,dá]ÚÏœÔ ç/ÇqÎvRÇà˜xz6ݢݹ•8 €XØUáüŒv&¦oØGHÿð<Ϋ¸ ,`Þç<Ÿ© 7šT£ ñ”Â"'JÐ¥iÛa†¡©ù»f•D1‘ýh0æøD=¡Ý¡Î*’þ®Æ®õ|–%dÓôû*F§¸Íqmó}çŸÃïÍ)³®U”ÓFƒ|uB°ªRÏf¦;=Ë(Ú„QpÊjŠX•MŸ¥Î:HxËÏFåljÈÃÙpØËâäË Ã4bŽž…­èö†{Õ)ð&“÷ÐwÌ¢a%ú£ªðÕ×éAá$‘ ¼Eã·xzùú:œð[D࢘4‰:¼ dô8ˆ‘ƒÎUY庭æ5OcÆ\Ÿà“dñ£8ž1c Áa,G•—£ZbÏ)NQcj²àö¹Ã@àr >êkL ðÁDã3…2Ô/å•>ü3Ü×<>ÚðxÛ.¾?GÙV|#à1è)ÉØŽ| V¨`aNC‹C¬Á%ÝÁÑ—±?6T?z÷OUø†¿Í+>ÈWÞ †ô§ŒLå¼~‘è½ý¨7¤^~¥Þ ;bû­Õµ×÷nyp=ùñS•#ý²¡¾¦éß¼§ôÍ´ ß­IŠ2Þ§WRžjVvx*$àÐ…o*?™ü;éì®ìЉ¥T&"³õoíÊ-o¤×2(D¬Ž}ÂÚOm} ì0hû¿Ø ìݺÑ%1Uôî\¹¼}2β;ú´¦Å`¾{ã±”Ýõ@àgîÅÆB»‰:úpA·ê‹‘r%eÁîNØ•ÜÐ÷¦‹“l" ûÐÔÐÉáA•ÃÆIIœçýE3âWØpáØå”nȦÖ6®}N­m^ªc|ŸÔÓìU"Î]9EÖå©!ÁI(*bpÖƒÂiÏ×{P&9ˆ!ðNçÑHááAx-‘1¦ÅŨ0e“N"éþ«YÆvºEz©5¼0[FfÚvõÁ¤Q˜B6t9k›sˆŠø’ìCxyõCq_ž)ñ¯oÞÅorÐÞÌqûêV¯2y7š«ì$õŠOôÖX–¼5NÒЗÆ°"<àìí]ÙoU ¼±Ãý@h)ú¹‡íìÃ¥hê{Õ`Ï]qnJægÍ43M–%]Þz‹C)À…»Ñm°!ìîž:?:¢ƒÂ› EC{Ÿ­´IïqXÏ7Œç ¢ëƒñ åÔ"NA>Ý,ÅÍÔŽÍ~B}”IXÏ&ÃW ×öp¡Úúð£û:‰ƒââTú4”ÖC=ÎÙ†’Ÿ6ŽmhS³ÖðѤK}nÔ $z‰8 ¨¶{mKx¶RšùžL.„Ÿ`˜ÎU%Š,aЄÀ¹Ó\ŽÑµˆï E N"WyœBÔLµæ¥¨5-Œä£†ÀϺ8ò5¡ôtŠbˆÂ>ÒŠR4‰\nW‘iÛ‡ŸÈÆbb–ûÒû>€Œ+ìa‘„Û¬¡Du‹ž„ ÅE {“?@åûÉ¡Cï=IùV@ÛHZt#9óA_”nšŒw•)æÕ*”Ò‚p¿6*:w‡¢æóš…0D±ÍÏ[x"­’Ú¬Q’áAaR$ª­æ÷ðWv9©Û` 4zÓBÕ„ÚŒ©èöì}‚Rå<Šð£­Éð£ô‡ÈX]óÄ?ÎÅP/ü0È<ïõElŽl­üðŽˆ^}‰‚]ª!M£Álpâxí8Ù®¯™² qkC-¨*`ÄiçÇ~%%n×Ý Ø¤`ûÜ,†ÐV’ÅHKé­µI,¦Âò F´„†Cbä]UPLìä lóÖ'D ©bq?{ ù–Ú¸´ŽH à=c M7#(C:+VU¨c庉&ðÚ!ÄS×wÁUÛÕº œÐl<1áTѤâõp€¨zÖS„ñO75KU)/2íÏÈ;boF!ö(Ä;m)w|Gë z5¢®ép=pÙ– Pž²ÈÁ¾L$ÀšX2Ã\ç_ƃÍ£òKõ3÷ÙíÍqw…oF™pe¬õß`Õd!¡;<ðÚIНƒ7ªþÚêLC·*-•€ãRu2eE0ÞÕµ„„¢Ê-Ô$B%¾~[Š2v‰ˆ¸±QX¹ ˆ*Q,™;s®u5‘µÒŠ šíqsf¨˜¦à³7FN•w’K!aa)Q¤ó‚¬%~SC2•šÜHCŠ­¶*ÕóTü/i½É% P&ÌâR{PU x.[HQ23¥”2Ü wá›C]‰ðõäÇk[>äÆjŠ5OfÄü4‚HXokØèN¯%ZJ#E½L¨ž¹Œá'@= à¤ÛêT•ŸÒc¯¿®愱ªþ–žÀU¿ŸqážsЮlJ$D^}—ûT…¢XWZ€Ò·ÜÏ¡=È;jÔâ5$è!’t—d»rRŽMFÚäÊ“üÐ`*ÐÉ\ìê¶Œ¤éG1 !qÙžYI¾’druådîìM-¨T/M€A{lDÿ_•hT¶ ×OQ”¤p9…8KçÉ-¥@ ”š´Z÷OßkTú¶J$NܪQì±H9K žå²îúyÜêVÐ=,Eˆ®ËUëø§$©Ä Š,1EÍ/+Ý%:€°Šr_×[ÕÌb,]¦w“×YgJÕ®– ¯)<ÊçZ#¢«ë…këϺQÜ>M¢ÝeߥY£5)"-nå&7¼Š!ÊáB˜0á½ÉH¤ 8¥F|»±ƒl07õYÝkE÷§4vT1T b°(D´88ÉâÓ›¦Ñ0ÖcÅ•_.¿Ëû†%ëüV5ñݹ\ Án—*Ð$-”õÚõûÖ´ÔáÚmÞ*pÓd?åg‰ÆGÎ÷î!îPþ…j·Ñäóy²µâGåÎá*™ q7Ú²ˆrybmðpûÒIóòQ´sH•å&Ze–›WˆIE«¼°*@îþ ³4SKvU^©”(€H´›R,rjDLIå@Ñ ‰î€Ê™h;òJ"IhJNJ°öÖ¥“ äÊ ²Ÿ›mÝÛVäYõÃYhy §1)vy5]ŠôM°DÖqÇÄthœ"¸ûù"¡ZK—Ú-Ÿš® ûMEʾAšÔ.; &‰œRØ#®ýS5i¿)A­0Q…wÑ Ð@™»U4ÅZÀˆe(½Q´Ä½;nk1•u2l™aÉýÆ%Äüâô[²e¬'òÄft(rˆ.N‚#Ó’¢L'0 zùWö©Ü%~3¢ðé´e/‰ÃÿjP.ŸÞ©˜ Kƒâ[ ìó]Tã)„‡Gsq§—íBé’‰ž” „;wõ‹ûcíüg(¯ùH’3ˆ±ªâSÊ&’= Ñqvigõ±Ø$‡E—Ë’»D-t ‰7ºP7Õžá&Ú$ùi…W’{û}ø$JÇG­‰à“ JAÚ„éõЂ•æúó å‹5):<ÐÕ˾jÖŽÛœ„›ûÚ]HàNM·s!e4…JrG/l䞪弈 ž1z†`͸Xoú½$¬¦êš®2‡}Prò! 'íXêMÚEG@Cµ¼ÉÄV fC"·’Æ_ƒålSÖ?ß[xc‡“æ@{L´ê_ïìÿ 8K•µÅ[§¨õú}•AìªÐrÖ¶xeüc&Mß‹+iR˜TinŠx},S¢ç,ô@žÃ/Æü>r¨Oÿú¦3þÕ«Î'ÎDùWÒãéË>T¶úd™Î²Ÿ}Ò}¹~ñœ—CÝ$z/ëÑ‚>šlÜ6nûú“¹ï|˜ÏCÈ :*ò`ÞïøÝr‹~Üßçu™¾ì;‰ÜýcŽzrxÙ?Ÿlœã®1æ¶ßk–œ|ßR÷zSÐú¨êÇ]¸ çÓ³)Õ=©¿M·±Ãe¼qýÜËzÅo"ÒçákÚ‹x渜`§ƒð“¸Œ×i*f¸Ÿz$//[±¼_ñ8þÅiÙ¿Qï|ŸÙó\½¯µ[|Ák— ŠCŒÃ‡ï|º¾Ë/ævzGo~<Ÿ†91þn,ë#½ýsúŽÿh¦ñÏh¿vz$Öå;¹›òÙüàUƇ;½ õ9ó¹Ù Ùñ™þ½ñøÓò:Ê6–ŒÎ)âðAÌ1ÿà»®/™cÅQKdþõÓ籆‘æëwó4w|ùÒÓ€óu`^·Ññ£¦Áài ÑþšG~0…ÓïOûv[¾l'ÆÎ`îªé÷ns?¬.¾¬áá#˜y‹]ÔN›rßFõ´¿¯“3ŒÓK(÷¸Ê–+/ñŸ,³¶<Ú𾆗âyXç±ç²~±QÙãÇß´xtÞm¬Ïö?yYÁ—³I‰ÿÙ+ÿ³Wþg¯|ºWüÀ“¯ºO,ßò¤>X/YBŸUæ³½&eûÉCþú› f5snÆd<¿úµœú0¬èJ9x˜}4#¢¨ˆìku’¡—BQšð„ëšþàÜÖU.*6¤¾ŽWEŒ„,xªÃ(|éÊ´$|‘ëB` ¹ò2®n•ÌO-`b,²³^ƒá"Úi°¯«éÏÝ ©\{OÄÆz:„ì ݧ`lþ©Á…s€;]¢¦6¢ü…)+<ƒ5©y/ð‡—4‰HkWá^«<¤T7Y'7¬ °Z &ƒ?š(²>KÈ‘sÅŠ®ʹkD²ºF6=„Û+EˆB!slî@:ùMÏnbûBêט…™J…F 'Š{xÛßþ£¾—Ì, Q]bFâÀÍ¢pMD!‹}xìãöÃo,2‹Û”žËÄU¾»ä¼`ì=R`˜e’¿¤™´II‰Ä'µ½p1⃧®Ì§NM*U÷X(µ&‹;C§~áêŸgàAkÒ•âgî£X;ûù´qÛêv{<¯+©ïzüSÿšãEµžUê€|õáÌg«Ì)âáTÝyV!Ð÷òqxÖØ“nÏ-QiŸÁò³ ‡ƒh‡§ä9/Ib±ó.V2ç|@™0OãD†"$1å™°Ä»ÅcåIBÃE(vš¨I7x¤åŽˆ€Íunõf.ÆÄ{}æ:s_,Þ¬Ö4qÅ¿ — Q§8«b~žÉó̸––ž 4%Ñr¢ú¼[kçú!#ìZ³œÏª'Æ0l”¿ÏwËkäÓ¿6&BpùQ¡Âf¶ÓËÄ­µÔ{÷_›Â¦tëæ=4,§i íI£üUÍFhôdR‹œ(žgÄ&·g¦A+„¹%EÇYD´L%ÆoLœ:Eʳíq+(ý<;•ÀÉH¾¸'ZÀÊcáö’¤x)•4Ó/JŒ%ÑÌŲÌcý.=•V ~¶6—£©ÉŠÁ;™Ò„$” ¶ ñH¤ ÅE$[¤K [®Ô¼¿G„D zKÄJÐÙ7[¾x”³ a¼#"™-e”àH«È°Þó €ìWeòî[gðjKûBIózh¨×¾ÚŬ'¢T}b™Cóî©Lœks0ÖþçN ©{Fè³Ò®ú3ŒKmˆ­!ó¬Õõ^ÂÓM0!«3ÓktÿÂ:c–Önðgî@åš©lñN–È„IErPU£È”áÿ.ÉXùrWUÆrÈ61ȨÑ×!FRö#ÎÞÌ y~x·3›Oq¤2¨žÄÈYG‰iÌÕÄlj–ˆÂVpÓB”÷F×ößçn ù4l±o³„Ñcl%${ÜwÑÏÞ£ª¬íq_ÊÕz‘½õ.œ JÂáºlµ(Êy)Ê^“dý’lŠ2¸…°´!IWåÚïì‚kÝHóÊüyV²÷+P|FD¬ÀÁ¡b4žÍ¥¾ %Lèx•«*&ñ̹ͱsÅõ¾òîV6µÛýN_O^ªÈºS!Ek·Œ‘/0a0„«m•*‘Âö>óº)9MŸŸõˆ aà”妩ªŒ!‘m*ù˜°ì~Wy$W²5?QÚÛ‹bÏì"F7d–#›ÃÃÓ.: h!OÓ¬¿æ›Š¼†Å"Ìšb µ"–Áfët¼Ç;ÝúZwi©Ï LEêžÙMú éIX9Q¨RPÚ]’µB“<0nF@]9+·¼¬©\¥Ë½Áû$C[}%¦*‘œÒ‡«ãFÑëÇ’ÁÝÍŸh Š)ÚÕéZ¨¯°$O· Z ®Ñ•NÎ&ÚI@ÐÊ_:ýZØlÂŒÀûxÔ¨jX-u4?’h4F‘ЄÈ2? é>!­Ó% KÇßiоŽEÈZ‹ªþS4?šç ƒv ¤¨3åß`^ÎËþb[[Š]ÝÒ¤föh2Xù»šˆ»œ'r{ŒBwmÏ·* 1nµDß*Fä¶ŠšP9• û›Ðoš²pÚ}Ø^ƒÜÚB{ÄÝó6äÖÊ$A‚^Å•ˆq,YÎuªíµÉ8»a…q™ö=dÝzጕ˜¯ý´ÌE5V—I7W¹°Âþ1º­ÁmÒ¶K%g)¯ñ熎KïŸ I|Æž`@2 Y” ÓÖŠ½\ÛsBïI¨bÖKþ>b¹º.Em‚`qæ¨Ü±ªh­DH%A¥x‡(él1ˆîî7m-ÑÄÀ–ä*ÊŠ ó¿’ó¥–m–‘®U¦»ÉyŒ‚ 2¶jœ+pn‰R‘!–"sû˜pŸ"rñt’—ɯ¨Þ!Γ§£Ä<——•ç¥ûymsÏå±Ü@Ï{#…ïŠTLœz¹sâ~~!²FÂo `*n *sgF e eªß£R£ŒÏÔ„›„gÈ›…/©r%M|ºS µ©.Í¢•[Sm&0ìpê’µ&…ÕÊ Àƒ¦(zm›0ïaiÏÛõFhßûœE±å–HDþò‹åÛlwFµà`ëL˜o¸†WJ7Oè!¨šð&¸‡Bœ ^Iï—ÆŒ%ÄR„ß`Û³¡Dò7vM\Ù1ÿÙencèHGNh6è÷Ë-qöÏ6Íï¨i–AZâ7¡W´LáïtÐfxT¿6ÞÕ=M%åRz'åZ¯ì8S3m eHGv°Üü´-Þ!*¢…n‹j¡“qã±™ &U Dw-hc{ΈgŒu“2ZUY’û¬÷®¢.R™˜Š ¼…ï.»P¸‡ K~tȦ…|\°µØÚñknL#QŠ[Y·dÞÚI“@lÅ[aPš8txÀ.Ä]V)ñÚ`¿ŠŸö¹Â?TÞ³ï qì§mR!E‡Ý ‰éªÝ¦È­Âîû¥ì[,Ñe¶)qû SŒÓ“Ä5¿NÙ9&tžx(ÔAã³µí¶Ä¼Ž¤J‰CÎÆhŽÙœ0v•Ç M.g_žh””¿I= ÓáÏ—s¿a{c£HàCö´Q•Fq‰oÇjtœ-ÍÖ4î9Ó=¢RîšÜ[–#…JépàKì1F9*€ílFì‹=/µ.E9 •ÓxLYZâÅ3œŠ¨Êvo/â|'SV’ÃO?eüLÜy "Ö? QƒÁ›‘jl&èà%½½‘6mËÍn}¸ªnplŠ¢vò*ß]-jhhjOî•%gýš*Ö^‡F®&HtiÍ]MôÕ#”î £´9âÐùânn[¾®ÞkòL”ßKZ-Fþåÿû¿ÿß¿ ÌªîE=B*ÆÜà•¼IM„`*ÐpÍ¿Ò/úP]áø‰¨AûýüÍøÅGgÔÀË #ŒuNõÑwþsµ×Ë>i:Ûøç? ¦Üuðø™þZåvóù0¼¯ëÿ¼”þÞ;ß”OnÚ7ï’ãßý³V‰úÏœ°µ×}‹V»üj@Qw¥_—Nž¡Ç¿› ¨O >ÜÈJ¨©”ê/¢–«Xá÷+¡ j¾Ëõ_@nâxJñÙÿ$^Qà–uÖ.YûùNùö×UYíÓ‰Àû4½=+Þ—<þæ^À‡êúÝ¡\†ÏM_‡ø›ó†¿5±|Ø?‰ãn¥Ñ=Âüjù7^‘ÃñᨌsƒÍãâ÷æSæoõÉ/Þâ'þ‘eVgûÞn°?ì«÷ õß³Ó=u¢™M%é`ÈÇP}Ÿô/jàBÐðËõ‰ªU^.Ü#.ÿq²ÕIÑ sýßT2ŒL6ëwµÎVþ#/ßyS³ª›òÓEØìá§ìY²NBRùó)1ñþäéws:Œ¯i¾‹Uõ}TŠàMNŒge§I婽ij¿ë6ª¯ìOÿnV,áqŒËë´HO œ'œ¬çy-}ŸGkú…ïÓÊ~þŽï›í%^­¿ø"cbà§ñ{@Žq&ɵ“Ã~$£Í×ï´‘æøýÁÛí*¯;âó8î{¼zæ•ÇÛÖÓfýÝ]ÑÆÉ÷Ó–û…²Ò‡ÑûºŸâÊ)EPNªLÖ >™—-ÿ›ÅTXdj½½óü€|™[¾òß÷ó‰÷U.â|Þüj 0µøf¾œ¥/¹Òg‰Ù0ï*r?èù²³×øþd¯½œ3¼ýί´']ðä›—$‡£”ä=âÿÇ~ÝTËÞ6ï§QÈÏ·¯äEú’sºH,7½v¦@%Ž£òl¥O„%jò¬·äŽæïÄ~Ì8až5\×M´Ï‰„Z¬[Ö|£e$HŠ-¯) 6‚Xæñá »OãœÂ ´ÄŒ$-#×=é´i±ÇE4=%u ?< tD*”VN€ž¦*qþP€Wªe‡¯ŠãMÛB¥pÁP³‚¸+x.¤ŽéZ.•‰«ç!í ‘2%…1¯)Þó>š¾o…BÎ6ÅcÝÇ3`býf>Líü-…A eM8$¥\B÷ãã€ãzPÒÉH–t‚}Û)Æê´AuJ8#ú,ûGyè.E\ÒßaÆ r€ ž’;Š~6@Mì ÿ{D­É€…–Åÿ—†ÌM´Åkε>\¾¾ û‘ó8;ëÊyÝ×I!Å*Øãç³®ÉÃØêÄ osTîÔ†˜«>>ÿÂ¥–%ÏÖ”¿xOd³€ïoD1·à(LÃÒÈT.M-`Îèy¨[Q ~óH2˜Kù!§ÏnmæÓTòªÁ¡y(ˆ8ÀÑuÞÿ]Xk† k›×Û^»M›Ê&ŠS]ýÊbhoø“‡3õÒ†d+ÆçsõV¶ôMEMêpöKmÆÇG¨M<„á}ÆŠÒ”í-n5¾­wFt¾•(÷X´T²š¡z° ¼«¤ ·”=³ W U•ÀŽužo°ˆÅÒD2¹ãGñQÏ=MØLT&jBÉ7¶ô· µŸåg©æ)KÍNÅEá„l`ËWS„BÝCÝ’áýµÔ·7q‘¸Î¬¢Š8mÕÈ5öø!G»,W^¨É¼Ý´¬\f7RÁ­ê 9hÍYæÉãH³lPGrS×dìIäõ'v~jb J'«¿0ø ‰*-ü(â9Ly÷Ê5ž= )B,¥úµ ‹ÿU$cD¨éè!¤AÁ$Þü§jšdÉöYÉ5û­A»®ZvȘÒt¡«ÚS ü"‡­ßþL%Ÿäƒ©‚“;A %pµ‘Í<(½À±§I~îªÞ¥UÔ÷¤«–¨6¼+näš½J˜G¯kÿ»”&C ˉÜÕÈ’ Gi2#†V‹‚HP«¯½Tiñ[´­Y‰¡70ß´º “)ê™ï:&¸LŒOUÌ(Iºôèó™i ÔÐ Råµ1@DÏO6IÖ5¾¨ÏK»£u‡u½Û!Ä6ÐÇÔ®àió§ èž[º<ïjg*]å%ð²<ð²äѱÿ/Kþ&ý5¯©»zÇÇËó¨ö¾z^ôµ”kLD‹/?ÿìû—šB’o#/ðÛ#Žóïµw?j´|4²Ó-ÛIj"þFüï³Qø~ÛåÃù»=ö¡·µÁ—s騈t—íë”TÎLržc^vϧE{ç=ü}^=ñÐãñÎÃÇË^Vãáž gÿNLþ$бA¿­öµ)Öñ†üu1ó®“ÆãèŸóûíÌ—x¯ßäh§=ähœÏO~DäÏ¿3/øDŠ0n^_Tùû¥ú}H-ÛY4Šìñ]5rŒwÓø].ñÛ—æxVv飯$‹Ìƒþ©˜•È)Éïòo¶0„ðÛ»xì¡°‘Þú¿,ÉÕCô>‹«0’SÄî'“ÇÓ¡ ãš{2j3Ó'º€ñ—hºâOÏÌg"Ñ)`Xðqãp|S¡ð€k 3cÀžÓi-¥zE›8Þ:ÐÂÏथ¢ p‘S£<É[lYG<Œ5‹¤².EÎYPO@é›*itÿã\§1‹¿‡©áø9ÓT݃Éèär(p|ïÅšã$šÁKqP›,XU$#!ï‰ãr˜™ ÔËq>]yfJ)(0N6ø†nœÈÑ¡Cˆ¹id±ŸYÚôgVÓWœö†0Cù–|L{’·¸ÕguŠi|橹Vݨƒͳî†Öù»`9A5wúxÜF)s›—ÛG?úÍ‘&ùÖ〣L½JÔô b"qíÃ5ï‚Èv7ŽÅ>LÆW­e.|(QN¼IR“ù"vkÔ:¹8Çf+m:YØTùž3` $åzO妄ˆó%x ÅJ둦@ÖjhT˜ºsÛ*(QÇEeŸ—å·&¢UL'›=Ö‹„W¢œO¤3ÎDEŠ‘ý9OØXÉ{¿éÛ+ãv).§:v“ÔÓ4¡”P>2<:`ÚÄCøeù8¢þZvš`…Ž2é·°Í¿/¡~©_þr0Tqvÿd…Š–ð®¢&Ÿü¾ »óReÛŒ«ë)oi6Q8€hóK`íw¢"µÖ¤zåÀÀ¾KÞ±ØR­®RÛÀ©EQ 3(Õ½¥È †—cª„ä 5 ð5—FéÒÎì¾0ºpUUÒÍ’D§9ÙšÍä&,Ë $½•~맺كn•S/j§m#®4ذ Õ­:ë®evÙ´Q³´.}‰f9Ù=OŽÉ•5‘2â¥1õPÊÜ5µ[´¨ôľZÌbÎéÀ‚vMpKRîÃWoývƒšUŽ™ý¥–‚ cŒŽ…†wß9ÅÄòäAª²[ ]Âþ¢¹°¥NóÖ“vk›"²Í''\Aܪ½¸èmyë²n¼í)†Šc$Æ–dL´¤%¨ð Ø#hžAþh]ÅЛv¾8‹Ôb'Õ˜l’nxµ2éⳬÝ3«iK' âYœ5Øa 59”×(“oM£Häõ8e¨‚ & œºZÊH7 êY¥ùÊåj`¦ê({Šð ¯„»—Ð*è[œ£I#›É$Î>¹õŒÕ öùCEÕŽq6ÝÎu»cŠŠ¬¨UBÕ›Æ"“ks"²¸e¶¤±] ›ij" ‘:Ôµ&#FŠ’U@¿ã¸åèY+ûZa(ÆR$®W‘rç»™ ÕHÊíîãïi‚Ñ1)éžJÔo/ωŸùø—û·®‚õŸßÿÿñ¿‰_þ^ûù“Î þÞsþG)|ò ÙAÆgÓ7N3þñiÿÍò9þ웂ÎXÞÔ¹ðÁ3}®¦—7ÅQ'.Ù.?…¿±Gºr þéëÿ”MŒ>Þ³ˆÖù+>•5ú›o6*þÖ²ÁßÛß+ºá?>Ä|ü›øM Ä?0[¿” ÂßxüSÆä?ìèœÏ‚iÏð6*ÞÍùþ¹Cüg&þ' ÿԑ´p?£ÿƶ©O¿æõuñ7¾ÿ¬}ÏæãšœðÃü ~¯îö«Ÿ;ø[}ø‘xy¯Fžû5k\ð»Z£jênõV~Ë,)2(µ½I¨°Þu(XõÝ9&ó7òýÝkÎú¾h»¼ˆ+|ªPuSûÒa!ë£OäÄîÿ¾/¦+ kæÛ_ß™—)ž~m qô!8Q²ççIRüØÜ~w–÷úóÛß½£¦Éíh{/Î눟Îå9ì‹kH¨Ûü ŠN‡ç»= §gy>ñ{ž“ãÈO€Ù·uot†Ó"“5£-¨ƒR g&ö/&%ÖqlÇò°ßb|ƒÂ¤Üôá/·ÿo±ˆ÷8É[âE1ïõ¡}¿O^Œ L £.«ŸnÌñw>l~sÈŽ[ÞÎDó¡kâûí¤}•ZãåŒl[ãûÓqžDXx>Æõñ}ÉiN1ç@ÈÓA–±ï“ UƒrÏß·_rß'ÕžøªßÅIªt¸˜fëÏ÷pŒ³ü k:ä9÷ƒa½ ÇøûýšÅ¨ðÊùÖwR™mfÿ“·R[Ê<¬—¾¯çæa­d2+f ±ã׿@•˜`nÅe×Ñ*A1œ’ã ò!b&¹±‚;ñ2¶K&Ãài󂽿T'{Pü«Å \ lef2œh“¹Ögpjü‚Yc7 ,¥+D•úÀ©Ò™WfÚr(g# ¢»ÿ†rŽ:s’CAèK$¾ž¤$hÓF†f(G¹Qp›‰ÝÏ €T^b—4¢Þƒ1V÷`:Vu¿îàÒWŠqöj©A^ž†`†­Rx“’pUÅK× g1,DBM„ÈÆ Ÿ¹ Çš“ 'óð\¼Áa–ž†ìíaÑh„ÈÆè‹nŽÑƒ‹ðÕcñêJQѮȡŠ^F\”±:yæØzä¬Dqïmò±½v#.˜ÂTª©™R_ÌeÓø­…†çE¹Þ“«6vóÄÒ} U-c““£ãæU>!¬#!rèÆûés WûY½êyg´ä„ÎÈŸóÃÔdsÝ[£ƒlÆô&Ê¡»ŽEo{NâÄÞf«™“q,–PÁ†ïæ8õ¦ÒâRÙvˆãƒ©°¼dÚB»gí®AøˆD?_{\ÙF¶+æôÍ›±ÛÌïÚäŒF,«ç.¦¶„>J®5@1øC—2S‰…¶_…óJðPU@ß J8”ÎØ$–)Â3M`B÷…õ•rW:)\P-¡å Ê›ÛpÈ.A…aWÈRÎ;䃢¬jßTä³é$uMÐa±¶5Þé±ÎÌ¥-Çò|ëk¿ŸàV¸©#ÑÆ¦}c(µÛAéO]!îã5ãÑUFh“‘+¨ó²žCéb‹2‚aËÖÕ…¢@B%;íM?&*Í’M¾’Ô5 }øjWb»?‰é^ÝÑ“B˜VršÈQýLÄ1›ª,AO(Ÿ õàüÀ d~A\A¥Ù~¡?,„¬¶ØÏëVë 8z‹Šâ, %ž>ê<ÜDNÂ,¼‚Š3ò‡œWô"r|oR£kU,9hS­⢺s,Õ™%ΖÚ ¬Lã°áEZ !)2E Vò, õ¥çZ³“Vt#¥›ˆ¸é[bè@BcH,Â.•¸½Hã2¯q›Ž¸qÞ¸ÝOõ< ûÕ¸;b9£y¤ë˜;ñ/Q Q¾­hpAj"g®ðhü¥Õü[Ïïbš§?<ÕTNİS„a(*‘Kkå*{¡Ý@Ö9…+ÄÕ¢:‹kMCöÕ’õg‰¢½1h癓²Uuo5M­ ®¼èyiKô^À¥u«ôWDNy>ÊK°*š…l\,XƒÎ$}¡gô 00)µÉ»€ƒ¸i¿š¸· ƒG8¤(Ï+Ñ;Hî—RÀƒÅ‚öƒ½P ò2A ÈíÉn øƒ¡£—Æ”w—³ƒBŒ‚JõË•ç£Qˆ…@ ãNk¨>¨š] %Èe¨$÷Cn3èRò „B4ýfYe˜]üáiü 7›:$ÇoËJTpÉú—û·ûw»þ~%Åü†iòNÞÁ˯á#¢åü¡ÎEƤt~VÌÏW7{¼~n¿J4é6/a0φi:0 a#‹{{;Lœ¦ú3ú|bJžð%10ú5˜ÖF'š#æ /Óy"Ÿ¹h°Â/È_½õ|X;ÇÍÃוù+þÜ'k÷º ÎqÚýe¡PÇ¿?®Û·ïüI=¦Áüüê+ⲎùÁÿdŠ8.1òöþ@ÍÚµæ/j>8äz«ø–ÿþ†ËnïŽòéO&|–eØÏ}5à c‡o,Ç·¿›9Ç_ûˆ,ù8³ïj˜w¾±ßîL«ƒêô éY­B<~†pNÚ÷V÷ª}%¯žˆ±6"œ[‘·wäô5­›ÉEtD©klâ‰M®«ÈT³Kø=ëŸã:uc¯îø>#?_ÇÓ÷ÇÛŸ§–ÇÎÕaë}´]Û~¼3ت»í^GiÓVO äïöìñÏx… u}x'>ÿÀW®â~îï“ìç3óa¼½ü(ù²¿s’óªëû8{u%r&Aò,ñqz,3çã5V—7J5#¯Ž|áSì·¨|YKÓÑQ·ær˜µßûžF?lÁy"öWˆÇ—ó|]oä%.š ßÓ®ï²Ã×50Í ?‹Q§Sð¢Ý0éGð$4Á!6“/¹§©¬Yœƒ!ók8àáLùîÆ1Cx9‡ùý®À[Œû,ß8®ÃïÏb(FÇ=;peì“ød¼ˆõp°8­ËãžnyùKHáa,¦Í2ˆ&}´£øÑYFùį9aÐDSý)âò=¢ôQÈÁA\þž›NæÏí•gž– õgÇ$X•û”l¤áù¼g“P˜ ·Nôå˜ÈmˆŒù„%Ä5Å[Òé8.hy £Ði\ÇóêÉsÇS³éåì³Åé§pWI$z̯ä¢Tä­5vË—H“›ûtÀz“®•9E’¤Ø |)ºN~Seœå·"×FLÏ,Húøó‰_%ÊX`†-\<{g5þÂp5MWKÀš`˜1”ÄRª@¡Øi7ã+Q½Áˆ„VL<Ãì á¾CWÏÁ>¨˜>¢yÃ~î•JQ ÀPx]©©™{ÅЫoÀ­„€mÒWNÁØÃ@!§F etΆ[˜eÚ³HÛ4!Õ rAS`B Æg¥$ö“Kÿ))NW}?|%–.]„RJuGêµ6Y“D—ÞÉ+lÔÌœEAK :{1}è²AX÷dÁmnC ¡… ¹ ËQ~“dí»©¯Ë~¸CÈÒšð@ ïªL`ÃB5 q Q­zž©ä%ñD’ "àÉ?ÌÌNSéHøM©†à×{ªA¡*ÖÔˆ¡DŸ„T®füjŽÁJÆ&ÍB÷UÂý*Ãh\U÷ÝÅ –ãCHݘx l‡¹¯Mð±'œì\²ßV±üXBN3ÓûC¨Œ& ,¿uá á1²5ôè±Já^¬ÞD£¦q> ¬9âÞ¦ÈÂCä7öÙ¢qi=+Œ'ç£Wˆ*. g×SÜ>nêã=ÊÈâ¥\Ózaœ¹ªx "×n:áTÚ`±cO-Ù åk¨Ä—ÇpŽè¥{+J€æUh±MyÊÏ“BcÅDåaÂÇ ò¦Ûì´–©Üα°iÁ0TÆÖ8=9O4!yÌVU{òɶy4y„¼ ïÀÐ’ç8U¢k”“®¬©dzÛ‘ Ã>ð,_jp¨ã¡¤¸UË=·HI‘½J=Û{#Qç˜MV¢µ8T3SäæÃ˜ DL£S^öù(’Üù1”9”ñ§Ñru\’ËùÜ()|̺¼’xoDß«e¤%ní»¿·¶¢O:*Frº Íaí¹Hl]b“vb»j‡›%Æ­ø•0y&„%'þr«jÿGºËÈ­ÊT RÅ:¡(ìOÖ¸@Qƒª5Éwü2Y¸p9J„Lpù ”t’vrvæt^Ñ]§%B^ì®iÍn‹’žU‹*I碰!F¢â°š$:MN¸ÚLhjëXo“0ºIû+È CÕ³T/~ŠçlB®‹P* ¢hAx¡:ä†k¬$™+QYÅ5ÿà^öû³,n5„ûÑo[“K¹{y0½hm¤$ˆBŽ)þ2:PT¡€}£œLØ„d}ur¿`y)Ä]Q¯++B¶rXM €ùOïtÍÜw!ù,ŠØ–êŒâ»0…©¶XMØ!kF Irè¡eÓá§à13Tý,DÞ|À…¬º&Ö€ €Cà"À:yÆÔåÔ!ÊH²/ä ,Ð=9?°ƒÞR­\­q2È••î?g"vÛM’(ûlµ°ÎS¶F$¼á…܋ЦÊÏç‹{¹ƒ.hªuµò–l`°%”~VŠ+z›W§¥ ÆTÈ GŒ[ª‹'éÍ@â`y¬B¹~eôŠ"› ¥š«úåzÞ½¿¡´!{SBÎ;¡}¿*žnÅ@IåµaŠ«KhǾL $) *ɘ²„ oyâýØ‚5"舂gæÕ²-ÏÚE¬‰‚I\#ºÓ\â칉¨hóèR*™'în+½38ÞÚØM‹,*k<(ED©Ú¹&u½ò>‡{îþåßþíÿüûp$ÌT?cí„ÔI—ýš&‰C¨ÓE½?\lÁâÏ8ÂzçÝ‚Bl>Ož1z°¿'^È?ol}ªVüàCÜÞ û€‰I’0czçìèaú¶?†|þΆ;òZ‘ë Îo ö ÈÁñ[å'‡‡D~ ³2òW1. CwÝ×zúq¼ 'àC¢øëwmÁ§O‹ˆ/lùWÒ?ÎÑáS²›ë¹ Ä:¼Œ¿­ ÆÃÑo{ãQ‡5 ôäNÌæxòÁðc¾?œþ( ™}\ KÉwF ûù™ˆ·¬óž6úKøñm}v)Æ:B@NP ’‰ÀËë‡ñúø˜œZT â¶b1óÞ9’ìá·p9—¼éAèÇi¿~]×þ®($ûððN>øàÌÖ3ÃïK·¦Ë±n·Jí»"ƒ‚G5Äk³ºÖ >àqÛ­a4®Q„êhW;‚íg æ&NçøiÑöCñ ¤CAPD/gÞˆþ¨–+L9¹~ðÁ©³|—P—è‚1 Ý•fb_TVSýUq8mó9³™§Óò­›õŸï“›æ€¶nׄãlðop½øÄV ½ãô?ñâj9Â:~Öplßéní~¹T>˜VU3Ž:;òÞÈ\Ï”¿z"ßñô¿¬˜³Žåt|3™Ä»£}í<`­ëÉþ89°r&GØÔL´g‘ßóhqb[ÜÓÛüœ[?å žöåá']+¼>â“BrÜu7¤i>t‡b¾õBäæ‘ ™ò}yÉÙ7¶éåJ>cÖ÷Ìt¼oo†lá·Çv}çmøgŒÞçïÞä HŽ´¸6Vœ×áñ{osü€)L|ßÙÃó/uhz¥eåaŒZhÔÍö= Gó™îûÙy7;ŠOÏñh>¬É}âSήQbxç)>]ˆhÆ%ä4!uTsá@f³>ˆ¯pûùtJÃaQÚEÕ÷aO¦Ÿlç§A†rϹy Šš»ÔA{<ëçøü÷'úæ1Ûàåêògq–¦Œöñ¿k”GövË|?Lês™ßöÝ8Buɱýè~: G"Ó!Þ²õ‡³ mµï9 ñøßs.ÈU€€M¡c@œ´øk6ü=»\ƒÙóè„“?„ÝŽ«'eNFv¬ôú ÈNqSxâE é yQ¶0Âey ÂŒýꬦu”ãàP@åNÛC¿ <ÏõѸ¡^Á<"M «“øRjPÐ8ÎÓ¾>=çÊn‰È¹þ¸)Ùܲ²„^Š#!é=|“Thá\"ðVä»”úQݨnIáÔ±j6B8§¢TÖÏ|Éi+½R*¼@†`?Õ/~ÉYæ..|D„£T³¨[´bÒžª3ÄN‡XÌ›wz/î‘ †)¹ÁH°?ž|)ü§†‹uTS 2~èG-Ï{7ŚīóÐ!\ƒƒaäÀi(ÁÉ#ª'ßB—â(šq:³ÇBL:]¯…G9g®8)9L ]¹Ím~½Y€c„aŠ*˜‡Tì÷P1cU5É Àb*Ù˜sëtb &ó¦¼Rì'ña—,c®R$†<ŒìIâ©C:$°Ž<¦Îóì¼ðÜüZ iPÕäJr}r8ªƒü è±…&„4>4™\ çÐò+´ÛV†0E4ñMà†b¬:*vòƒÎâÏÿ~m~‡Í .¯XœMpQàc#ùÛʧMš‚%Ò„*lÚµ7³iC¶"a™¡ÇûÃ^œà'&Ôî. !TËÕT ylúzsÈ+øØ<,Ç@6ˆ¡B0 gI#€6Ù7u˜Vl§%òš[\ΘÞ]ˆN¶–… g ·æJn³‹ôê¢ËkÊ<²‰ ®ž¶KÜ`²”LJQ'ÃÂz²ãîÖP‡T ¨2ÇH2»:Ñz'ŽÀvYϽÂò}VqˆoÃë‘P0Rå¤pÅZ®Ê*2޶›” # +3—–àÔ¿¾q¢p9†‡mõIž”ðXœ+à…0XtdÎÞ"åŠz øð'¢0¢f‰ ñ:ÔÐxII×"–Z7\‰öpéÑgÿv,¦Èh#­¯ÜAp¿'QÇe8‘ŽˆŠÆ_Õ$¬‚ThNæ’Üu*eBÝ9¾dnTš‡î¨­b&€‹$ÐLÍíº†q \UÊ®­ÅœŠê— ²h¶ÇcÄu&`·:ÐnB¨œ}¬FÄZ*" [«ˆT.X¸ëf¯"áhà€œÞ0ÚûC 3—Áº#Ï/ÄõU¼–ÅâÿŽã M)²EiléŠ w‰,%†Î¼²M0@Žp P&Åë»vÅr_‡¾’9…Ì#e‘P;öØ$öXúBˆÕ¹á"Ë' œ‹×Éuæ!ºñ ¯AÿßÝH!BçGHêˆ[U’Únêrî"´þCF2~åâF"< 8v¡¦¯3åç4.%öðís‘—¦Ø›˜zæËYk7.yÙŠ=Î*|ãç˜DáŠ0¥4Ÿ}ú4éÐoR!Ê›wû;vR¿_Ô”àŒèš•wÚj|ÞœY…Cˆ(´~¾œõ=¬9Ùœ¡’Ç])²7^á4PQÍeÏ­¿—½ÿç}÷>eÒÖ‘nì{~T‡e7ý$5Mv;ƒEä£BÂt ²†\SÓªþåÿüŸ?Nè'R^\•½Ã$‰Z#(Nκ~1d6"|ú[º¬A7>3|¢ÄÍòìvé”AÜùáþ»œÉâ¼]oÎâÙÁ¸ÌEüùßñVž)ù5’ 'Ú!ÚëâÕè¶Íë@¤¼q¬&Žú<ÊIá‚XÔ°¦NôÞƒ•ì`ªÝ”ÏÚZÂU‘{ÞoyÕÊëÀTa*Ö4°»ÌxŠß|û PÀO~k|ùOŒ¤QG÷„ ¼öxÍJ)1»>P…FÃâŽé·Ï; 7Á†“¼>àÿÖ»PÀÛß®ÉMÎ6¶^DMÈÄë´¬p £„z\ƒÃñÿ{Ž25DÄr)é¡ßÌC$íoÄú.¥ÏËÔ¿ž/G¡´õúwΩÚùsk8Ÿ3¯&ïÐÆ>Q¨³¨Å+ûä,ÞVfúÁ »æ”¯]Ç9ç—/k '|:ìùzÎOßtŸ£(»ë<ë\œ«¡¥Ć!_=JTÄÉFë ÏãwŒDÔˆçˆåS¾œÐ@¶“¤£`(߉…øòçÕÚ8°V¾G â÷GN¨ëº›ÕáMb­½ÏŸ0¯ïŸã@®eÿ¡&þÅø‘óT½ÿ‡ï3bƒ"ú}|Úè’ÝnG'òÑ3è@=ùúͼÎÕ!«-jžf§Ñ=˜IîŸü6p×wÀ†¾/³Ù`–÷•ÛþˆtZåä´ÊËøúlŸ×݉|;šÆ|¶ˆy÷zöì‡Ë¿ºÁݶ¾ßwoDËÃ~;qlñàÄÃåg1†Å£æä‡øQÀ1ìÊìØ;áëÏ^œ³QÞ÷´ù¿oZ˜å/¾y‰&ÍWž¬¯ÐÓ”DUNë0äonÏ%g$?: Ž$óYÊÀ–ÿëî ê“(ÈçӸܸãëÍìöh 6j”ð#qœÏ'ÇJŸd4>â›åëðí?ðï8åXÝ©ýèº}âó2º-å )—“Kû]Òá2<ŽÏ9­b…uÍáLùÅ ¥ú]yì8ó|yÈW_Þg"L ¯ä«ëSÜãŬq3¾,ဌ*5ôå\·a¸â“gÃßòÌÃ!8&º]÷iP1@.¦_É4ôxO»Ô¨âˆ]Ét™Ž중ÓãôŽýé§?†ftM÷Œ„ø×\š#‘—ƒ™—êAG}àv|’WXZ¡Þ·¦ÿ´QaŠ)·ýmxk5ü .²Ó-ûä.*5KÎÙ»G.Z3_É…Ïa¯{"{2N—°@ÿY¯Š-Ö@0ȲZxŽc#²ž]AÌvzhçÇÇ©GûdD0ÿ·† xPhªîÏÙk ,»<”M͘Iš. ýç§(‡n@_Ä3átðÆÉ·tXd'cprsØ\§‡J‡Ê±:÷µUÁâ&&6¹žY“ŠÔTÊcîdJUíÈÆp`Vš”º’=øÉzU÷îY]©ŸÃK§˜Ÿ®êf¾wɦ9}ö 6CJcÖ,úÒòC\<ΜÚ_sx{BLsȪËYgÄØ±àø†C¾cL 5ÈðÒt¥xlh`ÁXœùYÌ!82øGtŒãÊÃ9—Ü]â/ .¿ÎtdÔ˜kˆ/“ûqM;L’­éĹc4ijCßèÐ8äiÈZwíùû/#éPP*08Qg¹è†ú ÃF^lYŽr]¤ÊætjƒG'#-·FWñ!'í¬Ÿ}°´ +‚Æ¡N­Bò+ƒù`ÿD1Œ;c`ãÿ`B÷,%8‚–³Û³;XPñ‹A<.}ߥ°Á0ë)#L'ÉŒŠHl¨“˳¶ cßÅ$O7ªzEÍž™ž¡¡zø[è±äΤIZ¥ÝN*WÒ8EÌE‚J ´ ÜÄeM4•)0º…«~ø'ðõ¾¹NN¬¡(sÓMnßZ„£«üC´&Ú>àÔµRgmôöѵ¨0”·Th!_“T7á°J¢öÂnƒâMsמ#y›AV!~…Š{ åýu^cª¸äMl×gX/!Ͼ]|'!6¹Aú3 Ö$&­µŒ8”{DfQèž¼¤?OsUGÍ×3Ëpò€9J{µG1ËN'ÖçuÌj‘?uC€ŸØ"¸%²uÊÄÑYHÔÜϽɣ0CUugö¤Å¥|0jî ÅÎ@7[Ï£kq»),r7ïuq &Ê!ÇVæ–NÒñÖò}*óÏ}Vnx$®·8rO|YM<´uº~I´]ßÝ«UÐeM#@c¿J¬D\Ìœ$ÌUÉ~“ËÈô÷vn"M—ÇlRÆÖ”Ã4n?±ÇÂéÏg>æ„&3Žæì­fÑ›»Mk4­üEÏQÈçþËXv*<«,²ºÿž:¾û˜. áuBETƒ]¬Q ­®•\Mn®‚öÃG™ÚølªŒxøQœû°ÜBÄn!o*cSßXów¨<=®:š v.é (ùP¶ýiBTk-ÒU©Ü$yÆ¿ªªY‘ÒˆžÞACv‡Y0‹×ÃËCA6@Õ"f2å"ƒ$swE5YÕPă©g™ôN¿ÇPÙÔRâLAϪ¥ˆñÇ!Dg„zvb•€Æm´9ÉîÀ éðaÆ]0ˆéZêäe dž k°wïÒ­¾Â=”Þ)Þ‹ß‘ƒÌ™(@µÚ‹F´¤’îí ’ŸÜGÃÁy¹·?E¦ijô’he®ÇðÂO׃5û¹U%´°.÷Å”ïa‹ 5ÔÈÒPõ!qj…Ù²îg€Œ Õ øÞ…>³ÐÝTEˆ‹œÞÙ=‹drBhZ²­Í5vû”`-ÆÉ.‹ªdܦH×ÿ—X¤.Í•n­¦\¶O…0ÞÞÝVò'!rÉÇU6BÔ‚=®*)"2°G’œÉ§;.»I"µ[(뱄ïJTJ$ölX ž&¤ðìkmŒìÜŠJÐ/Q³&èYÜ(£¶âžùÔUv£p\r¬F šXËÓ œ@™f~ ÆÍL÷2‘ë‹WDÔÜ2¥Ë]PfÇ‚2§éZÒšX1¹·¤~÷†P[ˆPÈ·r_²•üöÙ€pu_ ô›n+úU@À[g{[i®²ÎaÏð 2öô^à!ÔÒR¶|5V¹×¦6ÔôìÔÓÑý.j¢"ÐâAÁ븑$í)! e’H¯3"TcÄí}5LØÇ^IJÅv­¬ë4ÿ¹ôŒöý¤¸…Màfïr!pÊD…Ò}}D˜§ÆJE`‰â¨Ìüv¾¶D¥„ŵZ5WNq‘üiÞ!s9_ЕCÝa>Dp ·¹è­ÕTµa椻F$ŒÃ6îM%ßÿOþå_ÿÏÿù÷FÆ9þgУyc&û7¬Oÿø•/7û·Ü|}{2P£0°&ñ‹§|áìâò\DZÅ#eëâwÄa¼ÌðÙì§Ë*në2^8Öêazœ`¼8ÕO¿•cÿ™å9>Y U–ÔŸ~¦;~¶ðáÎ{Y7ø|I[¬²­1Ó[‡þu̲?¶œýdÓ¿û]üíp¡o?ŽúûÌÞOæx¸I†Æo>?WÛgß÷-ÈÄž½ê"àws§ðÛpÚºi6à¯ûþ3ƒñéÄúÅç\âà›é5ä6¢8­«O÷ßï‚Æð³wY |ºA?ýþløEص‚ì{M—Üû—⣓ÿü³¸ž=“…›:ȧûö›$.ó«¢L'¢øáŸçãêu´‚ߦÑûüæøîÿ9:¡;€,;Lþû;ÁiHX«Ž«Fbi—èù{þ®á çç8ëÆŸ ô4z1Ÿð=9×ò6ÎÓφ—Ç™ä.öá®zt±?ŒÛ {ä·p¦5ïh浿j‡0Œ·X '˜ü8eþ¬]v¢ac°ßm–ß³“IwáÕjo¸ž=®vÎ|„Ï<—«®*·½5þ_ÿúÆ“c¢UÓ©–Õ×ùa|5^œŒ9ÉGŠíbxþ¶ÿêÈ—!oãÆOxƒó>Tz8çð÷ß>\g骃0ån‘ÿR~óM'õO2mýµYಠ)Ì‹ú¡ü72¡ƒˆqÀ¤•ºeqƒ»oTÊß1.*õÇ«õÅé›~ivO ðçÊ æÖ©O!£ŽIňÃAGÅS¯e7ßñRh éâ,?ˆ~¨N¹:q÷+4Ä,Ã`YŽK¥©HTZœ.ƒ ÊUFþj"‹Üךt±l/äÌIzV9éÜM:EMâézÝ ßÏ®^ÔÕKhJ†‰©e0W–É<)¼1Ê™Åè¹è>)! M¤åZ{Χ}ú¬ôܘ]f‘4o ãú¤EKŘtùõˆ1¥Y’pùî˜Î^¯?Cnµ+Ö7Ìx°L„¥ºA-ûÙnûíÒlÑøÐ‹<Ç«°6§Îˆ…áça¼ÎÓe‰Áv¤`I¹žàùÊ.õ|í„s;æÄèºÁð/%•ÂÃ4-áǬa_º7×2õUÞ¨ ÖwÁ†ŽïxøòwþKé…T F”áé¢ô߇kŸ5ᣠÍBÜxPˆ«%éå<€w—&.„ó5ÒdŒÛpÍ º\x9szgã8Ã~Ü6u!mÂð*Öóm<*ÅœÑ êÊŒgŠ0Ç]7óó“b(ÁÐ/Dmâ)ÄPF‚†Bàï}žáv5;Srµî£ly0™Æá؇µÐÖêéìL…AYCœ4¨ ŒŸÔŒÁJž‡a²©‰•åÅhÆŒ•Ƈ:G°ÙݘJ!¤²`|'í¦—Š³ ÷!ùôm Wb6ÝXµŠí¯…¹‡]›»i É0`ãW!EgúU­ÿ¾ LHüBʸPž˜ÎCƒÌ­Îsš«î1݆y /ΈEÜ¢ µåÆÄÔTðïȪD ­ †zRP/¦c¸þ>1HxRÍ!¸a¼•ð­õ‚[†šhE f~•8¨• S¸ì¼pñ|rÑjxbì8± Ðçtž!ì±.Ü‚7MÖ ©0”ÝÛcãé¡fBBÇÚÅ_ï.á†ï&,Á[F„閮܀ŸMnp1û¾}β}~ìæäqh²Òù%±‰õ~€˜±–p$ijÁöºœ‹JZ·q€ݱxë]šuêÏÂ8;0·pˆÃ½ì)O†wœ×sü6…ÿÚMú`f£ÝˆN™^q6¯õC1šÄÉO©07Î=çÏZlO½+z±hDç]íƒA ¨æqæ‡p2ŸŽ¥žÆ©l¦“U§…› ãÍ u½O²¿5#ÖÖD  ¾'œb +ÃXã@ª‹œ-+vaŸç°X’MLqÛ”stVŸ FìÌV¬¥ÙÌxÝÄ"’ (4½ø«èÏÕ 2CçKI:UtâŽ3ùñ…vÙ༭ԡ7'•„Ct˜AÊÌ)‡à9% ù ‰jËòסa…|½ƒ{§»û jâ^ž|0HöL2¤I6‘ޕؤ_!R·"Âmÿ$ÊNdv#…í¤ÁßHe¬áVBTÈìÆ!ÈÁn],‡!MT@ÆÈjºZT(Ẃì8JºÂ‹Áô¶§* ¬Û H÷¹V“:ÛS”ÊÉÐ’¶þÍ•~JÛ{)Åá Ïg"¯V"{tŠ©‚8×Ö,Ä€”Ul]sØ «SÅ=ôbOA#1ÂU™2aÒ1wè}®SÙËûÖ5År²öú±©?H²PNàV×_Í`t-ªêJÀ2Á'èGr?EU½G•úÐä½\Én¿5‘g¿ „Ä<‡1SšR¤{G×÷qùÍ }¿*¯®ß¬`+ZóA! çí›z¥!Ø}ݯdÕH®£9@qZ Œ^Ø))×MÅm: ¶0R/&íM®/-,Ôå›Ã»HìA’Öi/…ƒU MJyÃ¥HLÞB5Šëè-ô6d•ýלž»UÁ~Ì·©PNŒÀÈ•7ÐɵXç+v±±Wö €³ÎF•g… àŠ†‡Ú ‘.H4ÁÛáŽç:_«Àn‡NµÆ‡ïg´óÓ¿yFÿÚ-µfÏè¬'°= Aarȃ3FMp¨U‡²ŸjC²î;tšz€1?‹p÷[Ø÷Ër6Ä!ª»«»ýŸ5ö/ÿú¯ÿúïõßê?¨ÿùϯñù°Àÿ«¯û½ãßø.üÿùà±/ÅÑqúÕSâŸûm¿ù@ü§ ,þ{­Éÿˆ÷ûŸã÷¿Æâ¿äêøo¾„ð_êóÎ1å¿Îµ¢q‚ÏýJérsè89>°uò_­¬³jc7BÓ.™ŠÝh&±Þý}<¿u`Ò`åFÚö?hž}×ßáL–íŸzlûÌN›b9º1óìÈΩOSÍuê8ætì§Ÿ¹œßû‡ÇÙ¿|^¸Ó¿掓Ï0þ×3£x4Àœ¬eùBjݫܦNû*Œ8òöÉØðèF;Sà8­×š[=iôyZÁÝëŽÍ,,o·FDq3›9“kOîíò{s¥½`©ÝC)粿?áM×èÁ~ÿ…qŽy6«ŒlŽÖlkAâÞrû?ßÕ ä’ô>›cñB¦æ÷o ä†=Íîľ×óÝ@.Vÿ1&°8üñÙ´Ù6ó÷róZÿ®‰d~dövçÈY]Õ BO&Äþ»‡°ÂÁt\r€ô÷8ÆPŠIôàä?Ï‘Wûð ê”65îJ˜vÇÏ:Îäœ7µu}²ôæ5†µCp0“û>™ ¿‰©,SÁäü½ylÏ Å(Ôh|¬‘ÿL¶³–}yÔm”‹²f ?ø¸fȘëñåÁyšãÉ|òå=9 œÎÃ×ÜÈönذ˜ç鹪u4!»oƒÐ+½.w¯ZêjÕ³HA›e¬…ý3À2åQDÊÂ5¶kªÀ×Cèr³±} 3sÈL.$¿Eu«imà†§>¸Ý&žÖlÍ â„9sV’"Ò|Š¢J1 ÛPÇ·z°ÖkÞÛE;~C»ô»£# Ë”Èç Jž„ú„ôƒQ)ëìE©×ßq€†÷Üæm•!´o@`±´vMXb‘ï~Æ XUrµ¾M'aWåËH©ÂñdÓ£úâ4‡Z345‘J ‘”g/´ÃYh»Ù¦I‘š7 ÜÄ0ïÜÆŸP³Ææ²Ëm”GÏ(i¾xnØ6¯$…˜ Ãs—t+¹î¬Láá@ h›o² eFg·¨£u"bUÌ£ÜHÍÉwÝÎ1ÿ9p°[aO¢h0¦’X«IC©däÏ5'bܨ8xd|Ú>AÍÛé!]?&Œ`5‰T£·²8õÞ¡òlÖ%¸Ê9G=3Ñx<m|½ÀÚ°8aTwo5nÄ©5’PèÞÃò2RÒ,MÖ½:¦ZvïA‡Ì `Îè3"B‚Èöþ_3;xÆq6@Œî /Þ6É+„åiiZ•øD¥±¸½àXÊØÉá¬*û{Mãd.PBv¦ŸmT‘˜ƒ?ÃU²L*ÈÎe±¥C@ &~G™÷˜@Ä‚õ Ѱ9&»°ùµ Ñ€5/\´곤†ªˆtQÌ“MtF!O’ˆ~#Í;©)!ªXƒ ›æˆR:„KBkи4<2ÅÎèDó½& ïUnôFZÆþ'–p‚Ѻ›â_OÐ…8»a ¬«ŽªÀ m"íó>!p É‘SW25,Øc’&1\1«°\ß ªúÌà(Á©¦€šTWÍ:®Î¢é½«[€8ÆNHôµ“õ %vŒ³•ý–ßÝ@g›Y•,ÁœÐAÈïÕvg†lêÒ¹¸"‚³}æ~ÏŸÑ'Ë|™%̯J¼æpÀØîƒ.°æL#¼Õ·¿~0Ïâ:G9¾Ò@gaæ1cáK~f¯Õ$l3×RD¦’Mmƒ:†?‹â--Ñ7¼°t|M@G¿ÆÎ’)X$¹ÙnÄÁ}‰;Àe¦(&sŒÂ³wÑàøéÈ\”„q|™P•,• µ#÷3îtF ÃJœöDÂ…ì*œÙXdLs:‡N1؉®˜%§éÛPJ#QOà÷)]ˆ¹U®Øâ 9C“0J«2§fÚº´½žSåK$ŸÌ À*D¨æ±Umt'µ}da7ç¢xq؃ì낈s')Kv«-` x<5¼5h”û&ä@Þ!ƒW¦]v¨Ùœ/UÐÕ%õ½TƒBIÓÐwk'¾ŒUÑHí´½Z–ìjL/ PÃÌ=¥Üj’+vuÑ+¦@1+U³˜H±5*Þ9¿’C™›Sà Õ5}‹•5Ì [V3ôì²u¼9wÁ&ô–ˆŒÎ›œ'PõPmÊ0r‰5Ï[þË¿þëÿþ÷ #öf ÷ɯ}ð}ã¼<\~Ãß49Ão´&¦ÿ0ê1[› èð`Ñr‘OÍmà·5in…WK½ûÓcþƒîI„_¿ïô'ïXJÄ÷}øE—‹¿³?ù軓ÖßÛ/¶zO_‰¾Yß6óëÄÿfG Šû¢Ç›÷”É'ŠJ#7þ“ú£8ÊσܸÑùá€6Ǽúp`ßç U7s\üv# 9õi¯¡>3óD}ðÊŸ¬Î7¯·öÜ=vú.¿Ý¶$þà“/ž |¸Öøá×៲¡jòÿÔ¯oþÄm||:™ÙêߎkÝoöñÏX‡ß?ÛdSîÀûу1ÕÓÄߟïO×ûõïðùÐã—“ƒ÷‘Å'–¥ƒYtñÀ!à´óuü£Éxg„Û~°:¿CÝdÀè~'ïøhw@^ü¿üŸ¿jQe¥¦ñmhb1Vû®2 ÏwµžåŒÿ›ÑïŸEÎniçe0)¦ufD¿O¨äëŸt¿ _ßí§¿×ʨaj0 ëöaœ—-¿<æHQßu\Y"»x¾=O3u•?,òɸŠÇç`°¨ßz<’kF@u@òu ö›É:>÷`yîïý—ã²ŸÌ ¿ÅQLËæñ¾˜{)ôàÓh{5 ¼ Ö÷`œ÷]o¾.çAá5žóf„ÉAµ‡þ[¼ðÔ~ޏ{ãÔñç 9ÆÏø³ï'&¾WÎ ñZâ%¦Nü´ãàgóa6lèüJ¼/+—ƒZÙ-X1`|;Êøqš2¯ÊïõXß<Ÿ³'ÿe’çÚäåXÉ1ÓÓðuèJw6/±çêcƈuæ½üÑëøü„¢§Væª&~Æøð;&9æk-ºq°ß£Ÿ~—eŸñÆËû¾œÓ'|ó\Ëg/ïƒÙ÷õ÷}Ù÷LÆáûlýR²ö‚]™„°Br|FœtÕ±ãÏUy4Uu„­ºP ¤HÙacÄg ¦{Ým"”P€p·’„õƒû%çšy]pË<ƒ„⬹² 5À]†+ÅŒ!Lù®ÆA‰÷ÎkFQä¸9m=°;1¯+GÂ:wÆɘ7†ùŒ±A°›­ìÖƒAAí†}þZ¯‚åÊ0üFÒ$®KþóÖz ùè`“¸ÿœøwÈÚbKœIý{¾ÒЮÜR!ª£Û!gFfÔëgõÖ‰ c£”é–˺PYæñ°,´ÁÙ›Æcy&"Ä7׈66 !Üët t†ah P<~Öf&SÎÎ55ž:Þ˜nž)‘G–Á¥Ûå–Ae†[!BÑŒôj›±êÁ·áÎL“ŒšUHájÐúa:pjH©HiÈÂF<+i`µj¬º1ØhÜ…p(\¤¡ò2y!/S‹:lÌ:φ‡Ë4I(»É¬rQ¦ ›.RCó—èÃÍ6]‚ìâ ì±4– ùÚã[º‚§¹m py9#1 ÇûîÙ±ñEžKÆ$9çÌ™*;T6ÈýÈœ[òÐüHŸÛ±§{f¸ý`$óLÿ‰¡ˆCˆÅÀl~éŠsrGgK,]œÛ|íž— :“;—x,«0€Å \A*,I·,-®À³¹+F0[“!y·ð‘h¹_w2¥B+ãU,av©‘I€`ä×e0R>.èg¡p=õüüKS²¹—†`€¡W§üÔ NÍk4 V­px=àºÓýÍ1¹]‹Q¢8Äô®e¬˜KqU]˜Vª½Å&v¡¼é]‹m‡Å P¼ªë¨&3b2ÓÖÏÜÜK–‡DË:^«ˆƒ n‡[Ñ—ë3Ç+Cæ;úòÙ°£MtòãLØLs%}5˼aÄèJ?Ë]aB%ò{Šá_E¯Œá’˜t*ŸÇ ’Í"ûÎj&Øtű þ†™®[odç²ƒÑÆ,p²{J¢_áò+äàÅ9zŒ“ÔïçÔü´ÂQ£^ç †˜ÁãqoÅÔÂââÆ_‹ÉÝ*êÙ!jÚ¥E2œŸ@¼Y‚£¢ÞÞÜñe5>‚Û}øXê±øÓÿì!+†e Ø~ÐÍVO@'Ç?&~ñÌœÌ oj˜¡æ–ÍV)׿ù½Í;àö”$¦‰±çšcX—v=7‚L G׺Q,7œ'ªï…8#Ub‡R‰ÒåZù°¾! Îìz#Ÿõ‰ƒK<«°MÞŒ;ñµQáH^¶Ñל=1”8>>ikM?çÉØç‹o„}mZðâ£!='&ÿxÃϘr}/eùÃù¦ó(>ä|̪ó¢GÞüòô‡‰€ð÷˜÷о`@Õሿü€EÁÖ/!NÑtp|ý{fÏž÷Z.5雯÷y˜Ú\ ^€fù:ö(™¹p²yÖð{úÿ=†ÆgG° ÎÅòÏßu^£<­×¼ åˆL•uð}@‰Þã}¯÷ønÏ6B¼®/È—µÃóÆ8®±‘]ôBÉkëôbéÏ4Ƹ òÊOöîä5P1× JÊËó†G/çeeÌààrñ=Pôø8‰ë4Çbž÷rÛ/^÷û ©ÅËŒÍþ,‡MÇó 6Ù}´1ÊX3NT<#ÏHnžÖ×Gü:¬ú0ßõ]Ø~SÇoðz°Q:óÕÈa®8ïÎÎ fu8IüuÏ+Zd;®…ižüÙïñpò„¹.ÅaM<‰.¶G5óï‚·õ}^U Ÿ•yïÔ%^^ýÍNAL=1Øý;¦%QŸ¤~ß'¿´OL˜òw>³8ÿ/Û·Œï÷-f¥Ÿ …Ÿ»cîQN—!Ûvû Ë/÷’.¿¯q ðp4Ÿ˜ƒ†zâŠÃ,¿f¬:¨Šq‘qÁ®¡õèb€ì³Pp†´ aMIT'r;<ªª)gW WsT?Áìʹ8'ùR=ùœÉäzb—¼|I«DÍ8l+ξ'æ½mØy}Î;¡QŸ*°¦?]B]“ŠcÇ\C UjÊv°·u¢(êóÐÈîŽA¯VTs†Þµë]3¢:ÞŠ LÊ\7CÂÿFB €ž=Y|y$9É‹ œ½v Ü„8d¦¸&y#y–Çó¿58 ¾=”†EÝæÍô pê» ¦ŸÓ‰"þAêãÔ»A–½ª™0ƹ“¨›&ŸÈƒšÂ!a~&óÆ!¢5s\²ŠœDØ8‰0XB?ŽÉS(½À4¬¸ tî$bedîàÍ<üAÚ¥[áŽÅ"ëè9G¢Ì+ÛYÓŠN–ÇS㽡77÷0шä/ŒY…FÐü`›GŽÏ»yr°F]¸só Æû(7…54OÙË8õ›;Ÿ‘m}«‡ÖPH"š£ÉU¨ž¹ÁÓ\µâ˜o-lF,š÷³Jö–p=9äñ)ßæ½ªqC¶Lû!}ÉX§Æ[L'’ª»‘,ï fT¿-ÆTÃíîJäÀm\ƒÐâ³5»¼.l¾Šžýˆ}6 öLÎyŸ9þk›…¹Xúoh “øûà ÛEH¥Î…ÛÞPÞxdÁ£í‰åçzY=J5ÐêºÊ ¯Ϫ±Í‚± àþÞ±¹²D`X>ï©~2HÈ“ 6 μú„kdS8$U®Ómšû»8H‚qéÈ-¯—Ø0ác€¿¯»pÌ) ¯|«§ c¿¾GжֺŸ275ác)Xgî÷@ý3WHß!¡›¦~$à k®:øð”â­³¼†èDG…¬"8î§TŽ÷†Š_Êñ(÷†ç{.$©J´í568.\Á¹ËÈøn; Øqhc¬5ÉÅj6¤ù©$ê?D«¾ßí8Uü:_`1šÉaR_=ØÛ¾U3>yB%}.? åcÕjFú÷¾—ïEÀ+” 3¨ƒŨbÆd}Oi ‹Ì‹äÊ=^¶‡$»_%¦¦pa5/áùä4‚?\¤µwKLPa’öÈâ‘£ç†úI¬õ®`¹=¡zí°Ÿ¡ &eoG¹¼(ôDl@ù Ï@@IdwSÚôÛ ªž» ÃÒ9s©®¡ûû{À/,ièùþØÀã!G;¡ksöyì¾dZDÀýo´†V@—Æ×PÿxB v’åÜ3ål,¾+Ør›n¯E(}Îȡųˆ–7ÐÇÏ‹ð—[üŽxÆlê2Ìl«<.ë™SÎ;Ù{àÉ)ÔÇNýe`ÍćsÊàO6B¾•Ÿ?/ÿ‡RŽ´žÃ€cuýÃf éKYiðhÉ='@eGuñÅs jž-ÀÂJç'À<.NÈÁ¥pƒÇ5Ü+f Þá÷úé ÚùÉcþ¥Mã„OöœK²îDªœò»@9šÇBEÐG‡õ:Ž´›Y33‡ém.µÈ­ƒ¶>¦—Vò/tè…P+$jN{]|]TnÉÇåð[§98z«¸Â;ä6ø1ûòä<ÂnÙ˜‹‘clkxÕä¯y”N)H°ûlF£Ê ”\ÐÙì† m¸n¼/Ø<Íû£Ó‘#*!¸ ûE>˜S„Ôè‰UŠ$[ -ä(©Ÿ®­þ®…?¬ì‹Éø[1h8‘äª'¢¿ø–º›ÓÌñ»aÁô& {Áã° ' šY¤%¼±'†‰j®¹ø’<‚âfÁŽcM ŽD‡ñ~μ׫uR˜ÂZÌÇÅ‹H±Ò­ì´¶ 'ã èX ˆ5çc PÐÏ­Ulâzjpˆ­X^ųnöáÜ =?aÏÖb™å€]4 “ :¹Þ‡5íyiɦ IihöOÓ¨©±þéí`$ø"­ù_ÿûÿûoÜÿ £¿ÿJßóŸùÖß%Ëÿ7})þçŽNƒñáå‡'É3ÔÿüçöÎÌ;ýæ%ùÿâÛþWxþ—[Ì×ùpLþ+î™ÿÙÇÿ¯Èß|àÿ´}Œÿ–ûø¿ë&ýÚ ]80ØëŠï¤u-¯äÈ#nô©™’—1IñwÔ\©ÊÞ˜¬ëôΉç…E“¨SBžý»‰k¼¤sÍ–Ž”ÁA9qüµdsR²{WâDÄ;ŒE+×Õã2¿wJu¾ «ˆÌ¸½Mªówà8ÙíYQι ¯˜ïüÅ7øsž˜RBÿ@pc³Ljã¹ñ°<Zq|æ:K¬wÕÀaéN}_ÆÆ·ÚÙ`”™¸ßâHUo †#ußñÈ<ah¹ÉaÙ!Æ”ˆç<:,¹øšÌ¶n<ÿÀ^7žZì …z©WA8·4Ì÷Dð`ï0ó´™™AU#g\c÷™c?ßOŒ†áŸ…QÜûcÚì¼Æ´™´ÜOFÆ£o/Çô§÷L›ÏS\þO(rðtïÃTQâ ^§‘rûã°y9©T$C¥UEZáb% Rž_%^³9郊”z–pŸX|9‡ÎTxR­¼Ã(œÊOµ¦³¥~7?ó¯^AK£zá€6VjLg-åè®gÜûs§-ÊËE+Z`üP°ƒVÇÞŠ>„!X¯ÿL=G€ºf(¸MíÞvŸå`8´L§Tð~Knƒ0K\í¦­[¤EP™Q¡ÿk:Ä"º_'Λ©"M‘+øCôdQÿr%rT…•mj©ó§$Kèžòÿ×ÞÙm¹qÃ0XÈéû¿2zK@jv{Ꞻi.³±Ç3#‰ÔÀï[7ý+9U~Ú[xÇ+á¯Ô\ÿAñ9/2ü[/™oü½ßcöS†ã;.Ìw5ç§w‹ÌFð†'¿C}ÛCþÝ;þÔ¦þî}}äýóf?ä™~ŒÀšQ48ÕØ¿T:Žz©ø¬¸ŸºK—¤àºÇqÐAr(U’âB<\1/+Êß>uâá}FýäÔ»6Ö>9ðD¼f8óÚz=ð^¢Ô'_qÅYoÎ\ý^€²€ôêÞ¼ò Ú Ä œÉ<…éÓüF´ºiË1× oýsuÙwá­+·qòÅœhx]7fÕ0Œ­èÊ]µ¶ç3ÜšV¦s|žX^†xœFúÆ3Ïi`´Žpù/ {wÜÑOðÌÞ‡ñ7Xc#?÷ù™(€·'˜ëÔÖœFU\y‚=ޱO‡úàP`3:»½#®áôi­Fm)#ÔÎ.E5ÑožÂ(óK“<~`$YìÅ¥Ÿ=uÐ+`¸ŸTüÕUí¹{µ<uÁÌÄšÚ˜¯Úgñ),Ц¿IàGˆâìÅH>×”R¹ñ« ȇ ØýwËOo/÷0ù‘Æ¿M<ü–vå~Szü"žLþ¹õ€Ïåpºs=–s2öï ß$Ÿƒ`Ÿ†ð)â ^r;Ü”‰›cÏ}=»¤soÊÙÚs ¾—Ï.?µ¹ÁÓ͘6{næ Tr퉱 (”ÔÁ7ŸˆÖRfÁLÆžzP‘iÈ#(³Ù¾'Ί¬CÉE±PÚz˃€üÿd,]AÎI•€÷ì§a¢-¨9­ô%ý‚ð4àÚ*;U¥‘sÑꚟ.¬ˆ3QåØÎÉ3P‹ÈTG{U"cËu¥¢Hx2~Ìiúb5¬Sàl–1ÐÂk¥íû`i­©¬Ê¢GŒ®ä°PfLªéþå­«X8zs²4ø&vÁë·8ËÌízT.K ‰‡šæY’â†ÍðK£ÌW þudŒ¯#_3£Âý!ò,e>—÷ h’#bëÐYëàÖŽ”Má¢"•°+ž$s<˜Q1s¹˜^—Ä!¯u_ïä´ÝKK]ÌתÿSV¡FZO‚>—Ý PØÒQãh±…QaÃ]¿?•o`ÌãÄ/%õüÍè‰%²IÝh›i¢µ¿‚Ù¤Þ¼«›hëHŠwkÁ7·J"IÆ•ü£dlP š´#èºuóg’¬*š´Nc«*%¨«x—G?/òÞ˜°9ó´P“Ì˘0Ëd 8ë1a-ïÓ$æ¨ñŠÐû“rR(Ò%Ÿ·¼¾Ž+j¨ 4‘¤ì£q—Î,0.kü™LOçL’§!–í’—çxÚf¶²½ûzDLI¬Äæ”-!£ëôÁ¥rò^¸@9 ŠýÉT™ÛÙ&KGïã³â§¯dìý\Ù”Þ7*C~‹Ãâk…Zæ*6ävN¤=·ÍKwç³ å¾úHH ÚÉâÍœMJ@tÅ™ØÐ#‡MÔ}œ™¤òUæ @”ùt2x œ¸Ü$™5Ú†:lSuûeËêQó®?æ—îWNp9™Ü–÷mN!<*h±)Tq*ŸÍZò¨«›Ì,wp*$-ä”Þ4*¹àñ„²›$!+:n‹1Hk^Þú\Ã<ªÿ€°ôÙL3.í¤¦[Y„èH÷·Ý™N ·“LZé/»Þ‘iQ§›å0 pÖCë÷4ÉrªD÷Ûf?[+Ø2ììŸ:‘Ïj’ ó=H‚\Ý„EÑÄtÃZ#­Ò½<¹›qÀKBùƒï©A‚0U¯‹y± GT|Œ1,ún‹ŽËHÞô6Õ²¾[ë m’=vÑã0¹¾o™pOG³ç¸w~?L«:zæ¾1©†ö´õà)CV·r£þÑøDºécq›f@×8å>§Ô6÷À_ñlÙøÐv¹íÔÃÒ FÕ¹ñ'zQÛ.3ï6tfåÛÑKƒ¨Äzz;’ó¹V­eR×N5=ƒbOtDñc ÞUÞHêŠÉ¼0l»»:¶Z Shö‘Éw#ùQ‹8Ð3I?@ËafD†û¼ÊF ‹ÉÈÙÓlPÞ»ÎAŒÒ2ñEœ"¨ïӘ䨴K9¡G¼«ÍuZ‘ ^vÆÚë‹AØX®ð;9a¢‹¿åt²Ìá´rZP/ÝðRîGô·vz‘Õž%›¶ºHN.ÅcÓ!Æán["&Á„笥646µ@î4kN´;âÓ‰Œz_¢0…ögr<%‚ñubžú°Ë2#·×F…†y¶|£ ¼úiQ;E—˜Ÿü½øÏÖ”“¨™oIEND®B`‚openlayer-2.1.orig/demos/gamedemo/Gfx/Blocks/0000700000175000017500000000000012262355751021333 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/gamedemo/Gfx/Blocks/Block03.png0000644000175000017500000000637310377212142023250 0ustar georgeskgeorgesk‰PNG  IHDR(p$èì pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚÄ–]n1 „?*zv ÷éÕzØÄÍór¦ú±v×ÒA† ¥(þ ‡ëøõóÿã©¥p½VC€ˆqî½z,’³NœŒœ7Ün[—(…o—‹}/F¯‡ÀV×땃©õ¹ýÞÊKÔ”Qø~©ÓÛ%Y°î+`À* h q9m^#¨ˆÂõòòu Þß3 ÍqPˆ@D|ãfº»‹¨¶1’Û‘ù‡8-#dWƒ„µk(Ö}î›Y;{速:´] 5w¦J8zÂÞÓïûHži·¹ÇØ'F¸Ðëj,cªe¥-2gXÆÍ±&î¦Û•Ê<ܰIYBé*¡DFÂ^êæñ+K"ÆÏ*¯œ›¾µ'b«Gba#Q-$+ûÊÌÉcoLÇ)<:‘3±(wÉaæDÇ>e m¶¨™¶PÚ£·y>%?Ù³òŒÌ&³#[ï^ÓÖƒ9'Ž|0"âCas¡Íµ¡im¤zóc"îõr·ÂFc|D44͸·v?t¿ë(;£2]Á2Îæ ŒÃ£¥€‚XätÍÝð ,¯¡ë4Òjòx´øëÛ¶b5›eä:;vCmz7‰¥%ª†×·Û6ƒnÚëz–?í¯AågÉÕÆâí¶5Ì:„kVf~?&–,£%ˆäçSb0ZÍ«Íëmû$sþ;ø$µ¯áïù-CÜdbIEND®B`‚openlayer-2.1.orig/demos/gamedemo/Gfx/Blocks/Block02.png0000644000175000017500000000647310377212142023250 0ustar georgeskgeorgesk‰PNG  IHDR(p$èì pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFXIDATxÚ„–mrÜ0†d mšƒöT=XÓÌfÒ ¬þÉÈN6žµ//ÈòûB^"¸ç? ’ ÎqUýÔñÜ›æÆÿ48M…ñÞ:ßŸ× WÃ5¬Ïœ¯åav{¥ËÆÖùöT,~bâÃÀ–¼O‘]c ¯7Z§o¶Ñ:OÏ#¢áá„9R$†´På2@žð;ﯴNÛèÒh‚4~ü,0^³~pÀýHÙáß ÙŽ7¤!’I,¶äRÑ/Ý¢, ‚²!BwÇSÜq[3®$½³Âƒ" ®˜Ñãæ`Š ˆgÁ£À†WOžöâIì.LyC oà˜åÏ®Šï¸bŠY‰r4@ð%ó+$_&¡æ&?¶›#1 ÛñHÏèn¨fºº¯ÕYG‡OöÈÀ{”Ã×ÖIªÏ¥R5L±7S4Â!q–‰gƒ©8ÖO“CÎx>jd¸œûÞîY`3ºí˜¡÷ôJ-a—YKÑ(%w<üµd¥0$µ¶!Œ4Z»c;]÷Ì8RO{Á» /º¹*}i)ŒÜ4¡žŽ÷Ìr'ɹŽ0ù¼¡ç; ‡ÙôuGïôð¯wìžä :,¸•ö=d9šŽ‘åÇê<¦N «Š*=üŻǑ,Ì40¤ܶº44s2ײLW²{5¾ýYÊ3“žgFò\Fw^ LÉ;”ŠptPOZ)o//äRÚ«ü¿`Q8I‚Û=Ò}û»pgÁª~

¶“äüŲ®"ËQgJ7ãör>?¾~èß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF;IDATxÚ„–Û•Û0 DïH¬`t–&SZ¼q*0€|€o)["A`0xI?BA^!HDH¹A,òRM¦ýV…@=ZwÊQx<êÉ]„öÊ«¯\dr7º.ÜÔö£¯ßœ…¡g}ña1:›žlªæëõâ8)§8Ž“ïbµ³CÓJÔDÒ®i½A5ô¼>9NŽ“¢‰CèàÛc¢ñêõ—Vïî„Cüy¡ ixºw]ºDô¿æÿ!,ªU‰AîD¾z5¿¯™<7ÿTó&Ò^:²äÕ6ª‡áNu,Mç6Åöt»HÌ Ý]«–ïÖPÆÊ›–>:J…æPOÄ©–Æ)¢QN—´_“+KY5Ÿ›{—ét·r|{¯ìeÖIJ”K6êÏç”;®ª7±~PÇèþÅÒŒfËH%²Žç³®nÌýXãûfiÔw3ªçé<Ëûõw°Øå¡äjæIEND®B`‚openlayer-2.1.orig/demos/gamedemo/Gfx/Blocks/Block04.png0000644000175000017500000000620010377212142023236 0ustar georgeskgeorgesk‰PNG  IHDR(p$èì pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚÄU;vÃ0 T½×¦ÉÁ:÷½ÿ\'n‡(ËŠl'Y’jГHÊÁùõùÿX™ä~ÿöd¯ÇãOf"÷ûÜhxÚ»+àÂk*w^G&f’)%‡Ãî6Ô-«@×^czI$s¶,iø>Ý3Úp—ã°óÚYÖîÍš¦É0ŒÏù+¨‡a¬ã-x+Éžnå3|Á.åK-ˆø`}žm§;;çÜáW2Õ^ÿó hüŠ—IEND®B`‚openlayer-2.1.orig/demos/textdemo/0000700000175000017500000000000012262355751017445 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/textdemo/Makefile0000644000175000017500000000065510377212142021114 0ustar georgeskgeorgesk#demos/textdemo/Makefile EXE_SOURCES=Main.cpp EXE=textdemo ifeq "$(ENVIRONMENT)" "WINDOWS" EXE :=$(EXE).exe endif ifeq "$(ENVIRONMENT)" "MSYS" EXE :=$(EXE).exe endif all: $(EXE) .PHONY: all clean clean: @echo "Making clean..." $(RM) *.o $(RM) $(EXE) @echo "Demo is cleaned" $(EXE): $(EXE_SOURCES) $(CC) $(CFLAGS) $(LDFLAGS) $(EXE_SOURCES) ../../lib/$(LIB) $(LIBFLAGS) -o $@ openlayer-2.1.orig/demos/textdemo/Fonts/0000700000175000017500000000000012262355751020536 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/textdemo/Fonts/Neuropol.ttf0000644000175000017500000014503010377212142023064 0ustar georgeskgeorgesk LTSH›Zœ $ OS/2g³¨VVDMXhEoØÄ8àcmap6ð;hüºcvt # hfpgm2Jsc¸bgasp Ä(glyfå¤Âs €xhdmxùQ{G4ÈheadáëQ,6hheaÑ ¢d$hmtx9¬<]$kernß ç-° loca¼µX­ømaxpˆ nameNMuº postžž_pÀ ˆprep~5»ò J33 ­¶_<õ»n´™»n¹§ÿpþF Xþw ¨ÿpÿy   ]X bcšqþ‹šq$f €§ LARA@ öÂãþ‹ãS €FF¸*½,ž(ª)>3?/>CH!ƒ:·Dt0kkR~Pn,¬JüF€'©-j-‡L‡Mv14$/£:#g/2ì†Qô0†L³+­+1+‹N{N0¢+×+žN‡RZL@+mE`?¶(nQñ $(ò¦#:<k16 *ß ü³G¯:ª'àO‚*Æ@·EÀ_Ž>´ÒGrP¤G¯I¦E´C»GÇ,+9ÖMOÞ$~ÆP‡(v.}Pƒ4;Lˆ3 9rBiZ5IØa)ÿ¤x7ù ù ù ù ù ù Õ,Ç5Ç5Ç5Ç5Šÿë„Iÿ¿ïÿèrRECECECECECrRjAjAjAjA–sî>î>î>î>î>î>HWú0•&•&•&•&yÿÆy ÿ·²ÿÆ™I77A7-JÂ9Â9Â9Â9²@yjðM~L ¤ëƒ©rÉt/Wsy¦M¤êÛÿÿ÷ ¬5Ç<jšXSMA;±e€-Ò¢ž4 xAvZrÉè%7$-ƒ:Ã:§>“@`ÏÿÜÏ·@àO@*´C<j a‘ /‘ ¨-™9Ä5Gì‚*³+¯I‡R¶(+¦#‡(×ÿprÿ{ª'ô0¶(+ô0ª'¦#‡(n¦#‡(¶(+`?Ç,ìG×+rÿñ³+‚*†LàO¯I‡RÏÿÜZL¦EÖMQn9ÿÉ`?Ç ÖMQ×+9UP                                                                                                                                                                                                                                                                                                                                                                                                                                 "               "     #              #   %                 %   &                &  p& ÇÆ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_noqsz„‡†ˆŠ‰‹Ž‘“’”•–˜—™›šžŸ °ea´¶­g…d³Áfcp€b»¾Œœi`º¹²jm~£¤¼½«¬©ª¡¥µÂñÄÅltkurwxyv|}{‚ƒ¢¦¨À·¿§h¸®¯J\@"~«°¶¸¾ÏÐÖÜÞïðöüÿ1:>DHUY[eq~ÇÉÝ~¼    " & : ¬!"öÂÿÿ # ­²¸»¿ÐÑØÝßðñøý 19=AGPXZ^nxÆÉØ~¼    & 9 ¬!"öÁÿÿÿáÿ°ÿªÿ©ÿ¨ÿ¦ÿ¥ÿ¤ÿqÿ¹ÿ©ÿý÷üžüÿà©àŒà‰à#ߟ +\^tz€„€€|€Š”–˜ž ¦´ºÆÆÊÎÒÇÆ`a´µbȶc³¾ºdÀeÓÔf»g¹ÐÑÒÉÊÍÌËΡðñÖÕåæâáö÷úØ×ôõßàÚÙùøûü£¤îïìíãäÿéþý¥ÝÞêëç覯·¿§®¨¸©ªÄ«¬Å°±­J\@"~«°¶¸¾ÏÐÖÜÞïðöüÿ1:>DHUY[eq~ÇÉÝ~¼    " & : ¬!"öÂÿÿ # ­²¸»¿ÐÑØÝßðñøý 19=AGPXZ^nxÆÉØ~¼    & 9 ¬!"öÁÿÿÿáÿ°ÿªÿ©ÿ¨ÿ¦ÿ¥ÿ¤ÿqÿ¹ÿ©ÿý÷üžüÿà©àŒà‰à#ߟ +\^tz€„€€|€Š”–˜ž ¦´ºÆÆÊÎÒÇÆ`a´µbȶc³¾ºdÀeÓÔf»g¹ÐÑÒÉÊÍÌËΡðñÖÕåæâáö÷úØ×ôõßàÚÙùøûü£¤îïìíãäÿéþý¥ÝÞêëç覯·¿§®¨¸©ªÄ«¬Å°±­¸,K¸PX±ŽY¸ÿ…¸D¹_^-¸, EiD°`-¸,¸*!-¸, F°%FRX#Y Š ŠIdŠ F had°%F hadRX#eŠY/ °SXi °TX!°@Yi °TX!°@eYY:-¸, F°%FRX#ŠY F jad°%F jadRX#ŠY/ý-¸,K °&PXQX°€D°@DY!! E°ÀPX°ÀD!YY-¸, EiD°` E}iD°`-¸,¸*-¸,K °&SX°€°@YŠŠ °&SX#!°ÀŠŠŠ#Y °&SX#!¸ŠŠŠ#Y °&SX#!¸@ŠŠŠ#Y ¸&SX°%E¸€PX#!¸€#!°%E#!#!Y!YD-¸ ,KSXED!!Y-¸+º+º+¾3*%+¾>3%+º+¸ E}iD*·Þ þﻺ€€X\¸/¸ /¸¸Ð¸/¸ ¸ܸ¹ü¸¹ü¸EX¸/¹>Y»+¸¸¹ü013!%!!€ý€þXù¨€X*›LP¸/¸/¸/¸/¸7/¸9/¸B/¸E/» +¸»K+¸K¸ ¸и ¸#и¸*и¸,иK¸3иK¸>и¸Mи¸OÐ01#!32+#"54?##"54?#"5476;7#"54763!67632367>3232#3&ÿ1ÄR%ÿf+BQR¯e+BR QÃU&þ1ÄR&e*AR Q­f+(#QRÄRýÁ±0¯ (!$†H'"&þì' ?"Þþì' ?ÞD(%&†H*%' ?Þ( ? "Þ¶†,ÿŽ’#4?»;+¸;» +¸»$+¸¸¸и/¸ ¸и ¸и¸ и¸)и ¸5и/¸/¸/¸/¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y»!)+¸!¸¹ü¸и)¸и¸*и+и,и0и0/¸1и1/¸2и2/¸3и3/¸!¸5и5/01!#"'&5"&'&543! '&5!47632 54'&#;2; "’ýÃ#N4 þ}0?HRùþF ?( ZO=Ü'«  ýÁOj'$þ×N ;GURß4GMýðþÙpiV þ®NYZT (ÿÜw½,>IÞ»F$+¸F»?+¸»9+¸9».+¸¸F¸и/¸¸KܸEX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»=+¸=»(D+¸(» 7+¸ »H!+¸H¸7¸0и0/¸7¸2и2/¸7¸4и4/01%# =47632#"547632! =4763254+"'.#"324'.#"32w¼1–gþY¨NËÌT°å$û® ŒR#W‹Vý'þ$þK¨f³³m°µƒ ·?3NÚüCOJ3¸µæ°Ž/ ÎŒ//Œ5$"ûßC$!%þ†ØÒŠ00Šý^aNõV`x)ÿøºDQ\8»V+¸V»$F+¸$»4-+¸4¸8и8/º89¸$¸'и'/¸4¸:и:/¸4¸<иY¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº 9º, 9º- 9º5 9º? 9º@ 9¸¹Hü¸ ¹Rü¸Zи[Ð01%+"'&'#!"'&=4767&'&5467676!32747632>7'54+"%63!2[/ q‡ôþW½‡Áe7˜£ e&ë¢q‘ £îN¬¸/¸/¸/¸/01#"546767632N1-QP/ -RPg þÞ2 E !2 ?ÿøóºU»+¸¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y01#"'&547632ó7h7ž7ZHûþXNw-%F3Pýüee"-G hïø`>ÿøñºQ» +¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01#"54?654'&5432ñJElHX7f7£2LYýXnb\+ F,%H4MZs#,Ba÷Htüò<Y¸/¸/¸//¸2/º29º 29º29º29º!29º+29º62901#"/5#"'&547#"'&54?'&547632&547>327632üHtpG02ÔQSBÑ 21GllH01"ÔD3.QÙ /011#./`‹F 0wb/0!22!21aj%. Cga33!=öj!o»+¸¸и¸ и /¸¸ и /¸¸и/¸¸и/¸/¸/¸/» +¸ ¸¸и ¸Ð01+#"'&=476=#"54;543232öR°ON#¬SS©Om °RXYsO A  YYlM!‡:ÿdI$¸/¸ /¸/¸/01%#"546767>32I0/ ,!O./ ,#Pß þÞ1 E #/D¡rJ » +¸ 01#!"'&543!2rOýp: O8 ïN:N 0ÿùDѸ /¸EX¸/¹>Y01%#"'&547632D-'68&,,)45)-f354ÿøVº %¸EX¸ /¹ >Y¸EX¸/¹>Y01#"547632V"û¶bY#IgXy$!ûÛB"#%Rÿøº …¸!/¸"/¸Ü¸!¸ и /¸и/¸ ¸и/¸ ¸ и /¸¹ü¸ ¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y¸ ¹ü¸¹ü01) &54765) 4)")276ýÍþ¦ýÞ3Z3Þþ¯þŸC€Saž3€?þ¹(.lI’‘JJþ·ýÕ%š#fýÚ•!Pÿø.º Q»+¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01%#"5432./LOOL/G;O%N:,ÿøBº,¶¸-/¸./¸Ü¸-¸и/¹ü¸¸ и /¸¹ü¸EX¸&/¹& >Y¸EX¸)/¹) >Y¸EX¸ /¹ >Y»+¸¸ ¹ü¸)¹üA‰™]A 8HXhx]¸ Ð01) !2#!"54%>3!276=4'&#"'&5432B*gþ„þþÌçQQú‹N7{FìSg}ßQÒ1 N©È*ƒWk¦F¬sÖ[\O<ÍE FhT 5NBQJÿøb½6½» +¸ ¸и¸/к3 9¸EX¸"/¹" >Y¸EX¸$/¹$ >Y¸EX¸&/¹& >Y¸EX¸(/¹( >Y¸EX¸+/¹+ >Y¸EX¸/¹>Y»+¸¸¹ ü¸+¹ü¸к3901#!"543! =4)"543! =4'.+"54;27>32b³Åü;NNÅ'þâü2NNÏxX@ÉQQ)"1Ï· KK 9µQ;OhsfiNmsH[Z,D´‚'S48OFÿö¶¼£¸/¸/¸Ü¹ü¸¸ и /¹ü¸¸иEX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸01%#"'&=!"547632!47632¶eP2úúp2Pe|2PeGQ<ç¾<Qý•k<Q'ÿøYº#w¸$/¸%/¸Ü¸$¸и/¸и¹ ü¸¹ü¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¹ü¸¹ü01)"543! =4'&#!"543!2#!!2YýÜü@NN°ViVWüNN×N 1ý¶^Á…³*þÎOh|²M$N¶NN5èCV¦-ÿø|¼#3ª¸4/¸5/¸Ü¸4¸ и /¹+ü¸и¹$ü¸EX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y»)+¸¸¹ü¸и¹/ü01#! '&5!;2+ !254'&#!3!276|°„½ý³þÀs^_/ -37 .úþÊTÝ~ÂÜ|Vjü§{NnI[Nl*¦Pº/¸EX¸/¹ >Y¸EX¸/¹>Y¸¹ ü01#"547!"543!2>*ü²aQûlNN8‹_-1üJ‹OfLÿø<º*>ø?/¸@/¸Ü¹,üº,9¸¸и/¸?¸и/¸и/¸¹5üº59¸,¸и/¸5¸#и#/¸EX¸/¹ >Y¸EX¸ /¹ >Y»'0+¸'º0'9º0'9¸¹ ü¸ ¹:ü01#!"'&54767&'&5) 54) )27654'&#!"3!276<Y ¹~Ïþ%¶–º VW)£$Üþ¸þ]þµ6ÍbS~…]]þKtFLËÛeQt(uOD@’©S=>R¨„,P4+L-{7þÊYY‚XkþFh;>j `#Mÿø:º"2µ¸3/¸4/¸Ü¹ü¸3¸и/¸¸#и¹.ü¸EX¸/¹ >Y¸EX¸/¹>Y»#+¸#¸¹ üA 7 G W g w ]A† – ]¸ и /¸ииии¹(ü01!"'&5432; =! 54763!24'&#!"3:þí—þÛ1 N %  ]ý ýã±{ÄðÅ‘·Ü{Viþk?l|^b1ÕD 6O–R7À¡Q=>TµþÖ*P' G¹M"1Dª T»+AŠš]A 9IYiy]¸и¸и /¸EX¸/¹>Y01#"'&547632#"'&547632D‰8&,-&64)-,&77&-,)48&,?m54ýú4644ÿdi§%¸ /¸/¸/01#"'&547632#"546767>32i+&75),,%88%,&0/ +#O./ ,"P<655þn þÞ1 E #//ÏöÛ¸/¸/¸/¸/º901#"'&547>?6$7632 öD,üÓ)"¾‚”*& ýFº :S P6m< ( þãþã :0i »+¸» +¸ 01#!"'&543!2#!"'&543!2iOýo9 O‘8 Oýo9O‘8 §O и>/¸EX¸-/¹- >Y¸EX¸//¹/ >Y¸EX¸8/¹8>Y»+¸¸и/¸¸и/¸¸!и!/¸-¹)üA‰)™)]A 8)H)X)h)x)]01+"#"5467>54!2;276=4!"547632#"'&5476327¸“¦ë6(>S` $ \Ptþ³O) LÄ©ý ,&77&-,&78&,ê•L8A<rÆ<ˆ“b8@R®üò4642gäóFR³»+<+¸+» +¸»"+¸¸ ¸Gл07+¸0»B'+¸B»G+¸G»+¸» H+¸ ¸¸и/¸¸и/¸G¸ и /¸0¸-и0¸2и2/01#!"'&=476;&#"#"#"54323254'&#!"!;2?2+"'&54763!25#"3äÄþZx[ysU½ ‡ :J¥M{5?LE+þ/Þ +<<“‚rŒˆc“ÔŒ[yþNÁ&>CF15·.9f.o7+JI:0Œþú55ö+\ý6[CC,;xË~:*.<{ýÜÆ&-(ÿßÒÈ*¸/¸ /¸EX¸/¹ >Y»+¸01%#"'!#"'&547632 Ò>.@(ÅüXÅ %%"&¾+iNèýåþ¯þ­K.><þâ/# 1B, ûãñþQÿø5º(2ݸ3/¸4/¸ܸи3¸и/¸¸и/¸¸и/¸¹"üAŠ"š"]A 9"I"Y"i"y"]¸ и /¸¹&ü¸"¸)и&¸,и,/¸"¸0и0/¸EX¸ /¹ >Y¸EX¸/¹>Y»'++¸'¸ ¹$ü¸¹-ü01#!"543!24'&)! 4)! 7>5¦€ÂüRNN¡}goMU%%Ù þêüþ þíüì <¯TAO%NHQkh. * @:( E­!EþªþË~þ·s,0ÿø“º m»+¸¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸¹ü¸¹ü¸ Ð01#! )2#!"'&'&'&54767>3!2“Nüéþà?óQQý ™CIOZ$+iX~ \?NTOsý¥ˆ[\ (/3:]^sQCLÿø:º e¸/¸/¸Ü¸¸и/¸¹ü¸¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y¸ ¹ü¸¹ü01#!"543! 4'&#!!276:­†ÁüTNN±ïÜlM`üågKkA¬YDO%NþÊý¾AG#üª&+ÿø‰º'y»%+¸%¸и/¸EX¸/¹ >Y¸EX¸ /¹ >Y»&+¸&¸ ¹ü¸¹ü¸и/¸и/¸и/¸"Ð01#!)2#!"'&5476!32+"'.# !2‰SûÓNNü殑²;€IÙMM  $ þ“0RYaÈOh>Q¡\WG˜fO„Õ+ÿøƒº†» +¸¸иEX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹üA‰™]A 8HXhx]01#!#"'&5476;2# !2ƒSûÙNS 0¼¬¦OOþ@'ST\þOO9W’NY¸EX¸/¹>Y¸¹ü¸и/¸и/¸и/¸и¹ ü01#!"'&5476;2+"'.# )276547632¥€¸þƇº¾–µÈQQ $ þš,õHQf0DN.¦Q?9N«b¤O;Z[|ýŸ|":;7NNÿø<º!ɸ"/¸#/¸Ü¹ü¸"¸и/¹ ü¸и¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y»+¸01%#"'&5!#"&'&547>32!47632Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01%#"&'&547>32,N"00/ 0&NGO;%;N0ÿøÖºl» +¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¹üA 7GWgw]A†–]01!"5432765432ÖÏ„þüOO¨ANL1UÛO3hO#qN ;+ÿøxº»» +¸¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º9º901%#"'#"'&547632632 xZcüYOP --KO„_Y5ü¢|5AI íþXO9%:NþgßH.þ=þ)+ÿø‘ºJ»+¸¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¹ü01%#!"'&54323!2‘Ný8ô‰ÓNK0š1³¼NGO,IÌ3N:üÍ_ NÿóO·˜¸ /¸!/¸Ü¹ü¸ ¸и/¹ü¸/¸/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Yº 9º 901%#"5#"'#"'&5432 632O0LNýq4YZ4ýeNM0|Q1 ú0NG:OüØ@@,üèO:þq:üeœ:{Rÿð6Ã~¸/¸/¸Ü¸¸ и /¹ü¸¹ü¸/¸/¸ /¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Yº9º901%#"'#"543247>326z8Gûó00"NrHLÿ00"O{‹;qü«;Oø„@ü™P:NLÿøºe¸/¸/¸Ü¸¸и/¸¹ü¸¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y¸ ¹ü¸¹ü01)"'&5) 4) ) ýËþ¦å„Ê3ZlÂßþ¯þ þ¬TaP?þ¹:Rº2J.KÑýÔ'ššýÙ•+ÿøº~¸/¸/¸Ü¸¸ и /¹ü¸¹ü¸¸иEX¸/¹ >Y¸EX¸/¹>Y¸EX¸ /¹ >Y»+¸¸¹ü01#!#"543!254)! ¶Çüý0 SNN¼ƒÁÜþÞüñ!î·Q;þœ9O%N4H“¶¦jþ\Eÿa)º+‚¸,/¸-/¸Ü¹üº9¸,¸и/¹%ü¸ /¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¹)üº)9¸¹ü01#"/! 4763!24)"3! )È#&2&#- ùþUý½Ê÷dþzÆßþ™þ¥:Ž…0€U=ÄJ# ,‰B>ÐF)&DÔý»G‡ _ý»] ?ÿ÷ º$´¸%/¸&/¸Ü¸%¸и/º9¹ü¸¹ü¸¸!иEX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»#+¸#º 9¸¹ ü01#!#"'#"'&543!254)!  ®Š´þ’æ;ƒ4ü NS 0N~І¿ÞþÈýó¥L8þÅ3K±þ—O9%N6M±•šzþz(ÿøŽº1µ¸2/¸3/¸Ü¸2¸и/¸и/¸¹ü¸¹'ü¸и/¸EX¸/¹ >Y¸EX¸/¹>Y»,+¸,¸¹ ü¸¸и/¸¹$üA‰$™$]A 8$H$X$h$x$]01)"54763! =4-.'&'&=476!2# 3!2ŽSþ]üÿM 07þÓþ_ExV^ìq-N/Xþ”ˆcH)Õ{Â&b7•O6sip AHu\ÕDf;€UO7P¦ÿø_ºV» +¸¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸¹ü¸ и Ð01#!#"'&5!"54763!2_NþMN/þO 3³NTOüBO;¾O6Qÿô/º%¬¸&/¸'/¸Ü¸&¸ и /¹ü¸¹ü¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸!/¹! >Y¸EX¸#/¹# >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¹ü¸Ð01!"&'.# '&54323!276547632/ýg=((<þ,_!NK1*sN2¯Y¸EX¸/¹ >Y¸EX¸/¹>Yº 901#"'&5432 632æý05PR3ý.mS”‘Tn|#üJI#A$üR®$ÿø Æ%v¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸"/¹" >Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º9º901#"' #"'&547632 632 632  þ,^\'þ€þs$^e$þ! )#+Hš†*\ )(Œ”Q)!(qüZT5üÉINü(2ü™EZü³f2ÿóº#i¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y01%#"' #"547 &547632 632 00"6ýÖýÐBv(;ýØ':T^Z'ýÛ8*?&Ôþ,F$"áÍ!%6 þ;ÄC%!þ3þ$ÿøäºU» +¸¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01#"5&5432 632ä$ý©- ROý§"YeeZy#"ýÁþR; N¯?!#Bþÿ#ÿø„©¸ /¸EX¸/¹>Y¹ü01%#!"'&547632!2„Qû§H1>#k18%-üÄQT\!A*Á+ !/%ü´<ÿøÿºG» +¸¸EX¸/¹ >Y¸EX¸ /¹ >Y¸¹ü¸ ¹ü01+32#!"543!2ÿN—’OOþÞNN'NTOüªOhO%NÿøVº %¸EX¸ /¹ >Y¸EX¸/¹>Y01%#"'&5432VXcû·#YfJ":B%#"AûÛ!6ÿøúº?»+¸EX¸/¹ >Y¸EX¸/¹>Y¹ü¸¹ ü01%#!"54;#"54763!2úNþÙOO—’O 2"NGOOhVO7N*3㸸/¸/¸/01#"'.'.'#"547632ãE#" L?Fp*I %% m: H:Hh#: þõ þ¾Öÿ‘ » +¸ 01#!"'&543!2ÖNúÏ: N18ôN* MO+ ³ÒHQ¸/¸/¸/¸/01#"'&'.'&54632HC?D /  8?G " þìGÿø½·4ª¸5/¸6/¸Ü¸5¸и/¸¹ ü¸ и /¸ ¸#и#/¸ ¸&и&/¸¹,ü¸EX¸/¹>Y»+¸» &+¸ ¸¸и/¸¸и/¸¸и/¸¹0ü01)"'&=4763!&!"+"54324&'.5!"3!276½þPýü¦y£›s­êþó  NNý†æÏýBF[^Y¸EX¸ /¹ >Y¸EX¸/¹>Y»+¸¸¹ü01)"'&547632! 4)3!2676uþ þ¼±”¿* NNuóÒþãý‡ˆ1`1-EYj&þÒ?Q™I:O»þ×þ§U|þ$A! 'ÿø„·:»+¸¸EX¸/¹>Y» +¸ ¸¹ü01%#!"'&5)2#!")2„büóácªÂDRRüËþ!OGO+D³z#YYkþ‰zOÿø‘¹!’¸"/¸#/¸"¸ и /¸и/¸ ¸ и /¸#¸ܹü¸и ¹ü¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¹ü01#! &547)5432! 3! ‘¿‡¾þ¾þávN8"+Óý…þåk.‡0FšP=0Nc*»O8ü¹Û}þ¬] *ÿøX¸'¡¸(/¸)/¸Ü¸(¸и/¹'ü¸и/¸¹ü¸EX¸ /¹ >Y¸EX¸/¹>Y»"+¸»+¸¸ ¹ üA 7 G W g w ]A† – ]01#!32#"&'&'&54763!254!"X;ûç #…gNNj‡#®Ru´{ËЦm—ÎþSý^…ÇWˆ' bO@[{a¦P:7F‡vlIn@ÿø£»£» +¸¸и/¸EX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹üA‰™]A 8HXhx]¸и/01#!#"'&5!2#"!2£Nþ¾NN *ÙQ%NŽ+†?NabýHO9Y GNBEþïrº"0Ó¸1/¸2/¸Ü¹#ü¸и/¸#¸и/¸1¸и/¸#¸ и /¸¹.ü¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸¹ ü¸¹#ü¸¹(ü¸)Ð01%+"54;2767!"'&5!2;24'&#!"!rΉÒXOO™(nrý½Í„ÀT. '½™ÇÕu_Rþ³v3i:¥M7cN!"3I¬d.8N§þ&ÑG$ Pþ›{_ÿøŒº Ÿ¸!/¸"/¸Ü¹ü¸!¸и/¹ ü¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y» +¸01%#"54'&#!#"'&547632!2Œ* NNjFký”NN **KN:ýf½G9O5YýHO9%:N½(DÄ>ÿøP¦;»+¸¸ܸ /¸EX¸/¹>Y¸EX¸/¹>Y01#"'&547632#"'&5432P,&77&,,&77&,OM )OL *:444ûÙO9%N8ÿ/¤ª!I»+¸¸#ܸ /¸EX¸/¹>Y¸EX¸/¹>Y»+¸01#"'&547632!"543 5432¤,&85),,)58&,¿TþìNNTOM *>555ûßÊ>cO`,N8Gÿø¨º™» +¸¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º9º901%#"'#"54323632 ¨YTý/* LNNI)ÇEY6ýz•6BJ iþÝ8O%N:ý×dI0þ¾þµPÿø#º Q»+¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y01%#"'&5432#NM +NI*GO8%N:Gÿø]·<»(.+¸(»+¸»+¸¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸*/¹*>Y¸EX¸,/¹,>Y»: +¸:¸ ¸ и ¸ и /¸ ¸и/¸ ¸и/¸ ¸"и"/¸ ¸%и:¸1и:¸4и4/¸:¸8и8/01%#"'&54!+"#"54'&+"'.# #"5!26763 ]NN +þó *^+ NO=*_  þð* NNÌ[sweZ„F¥»GO9Or ^ýÌ9O6Utý³9O79<8 þÇIÿøe·y¸ /¸!/¸Ü¹ü¸ ¸и/¹ü¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y» +¸01%#"'&54'.#!"#"'&5) eON +lO<þ”7KfNN *äYßGO9bAAýŸO9_þñEÿøa·#X¸$/¸%/¸Ü¸$¸ и /¸¹ü¸ ¹ü¸EX¸/¹>Y»+¸¸¹ü01#!"'&54763! 4)"3!276a¢s¿þ¡®®­¼`ÔÖþüþ©`LlnIbWSJf"¤L:;N¡a¡S@þÎþqr#GþŸD !Cþïp·~¸/¸ /¸Ü¸¸ и /¹ü¸¹ü¸¸иEX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹ü01)#"54763! 4'&#! !2pþ8ýn+ MN¦`ÜPûÕu/€þ·þè’ó)þ×Ã8N]¯C+þæþ‰tL qþGþït·~¸/¸/¸Ü¹ü¸¸ и /¸¸и ¹ü¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¹ü01#"=! ) 4) 3t, NNýqþ7úSàÕþêþ·þÚòÃ8NÃ)sþäþæplþŒv,ÿø›·M»+¸¸EX¸ /¹ >Y¸EX¸ /¹ >Y»+¸¸¸и/01#"&#"#"547632›^ 1 ó,JKÁvéOSOyý¹:PF¼C*+ÿøê·%z¸&/¸'/¸Ü¸&¸и/¸и/¸¹ ü¸¹ ü¸EX¸/¹>Y»+¸»# +¸#¸¹ü¸¸и/01)"543!2=4#! 547>32+") êþ^ý6NNËÆ´þ©þ'î0¹ŒOO˜wi^‡ þîOba$W4¯1 dN32Vþýÿø#ºƒ» +¸¸ ¸и¸иEX¸/¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸¸¸ и¸Ð01#!#"'&5"&'&547>35432!2#Oþ²NM +*5 22 5*NM +NOMNýHO8¸BB½N8½Mÿõ‰·!š¸"/¸#/¸Ü¸"¸ и /¹ü¸¹ü¸/¸/¸/¸/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Y¸EX¸ /¹ >Y¹ü¸Ð01!"&'&+ 432) 547632‰ýœ6$ -ýþNN */;)+ OOþßRO9ý®mjU9Oÿâ5»)¸/¸EX¸ /¹ >Y¸EX¸/¹>Y01#"'&5432 6325ý`#--!ý\sE=:Erv#üÔ)'.#E!ýFº!$»»K¸/¸ /¸EX¸/¹>Y¸EX¸/¹>Yº 9º 9º 901#"' #"'&5432 632 632»þy"^Z#þÉþÄ$]a"þcVD<%UR&<CWdwý CAGý·BEø' D/ýŽGFEý¸r/ÿøb·#V¸/¸/¸/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸ /¹ >Yº9º!901%#"' #"547 &547632 632 b7Zþ(þ$ZZ-Öþ/+9 WÕË[Z+þ:Ð,>6 Xþ¨F) PQ*7 þ¨WE*þ±þ­ Pþïv·)¢¸*/¸+/¸Ü¹ü¸*¸и/¹ü¸¸"и/¸/¸%/¸'/¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y¸¹ ü¸ и /¸ и /¸и/¸и¹!ü01%!"'&54;23 5! 47632)432vìWþÔ1 O  ýŠþ$* NN vON *Ã<7O^J9Oý¶n¸O9(ÿø`—¸ /¸EX¸/¹>Y¹ü01%#!"'&5476322`Rû«5,08;)%*5üqqRQY"33$¼7*&ý®.ÿZHZ!9» +¸ ¸и¸л +¸ » +¸ 01+32#"'&54'&5476547632HYj11jHH˜7ƒ8778‚6šYRþ@-+Bþ QM `&%"#cPþî.#7»+¸ /¸ /¸EX¸/¹>Y¸EX¸/¹>Y01#"&'&547632.N"000MNÃO;˜:N4ÿZNZ!A»+¸¸¸и/¸¸л  +¸ »+¸01#"54;47&5#"5432N87‚?‘IIj22jYYš6‚78X% ýûbMQõA,-@îRScýþ"#Lï07W¸8/¸9/¸8¸и/¹ü¸и/¸9¸7ܹ1ü¸,и,/»(+¸(»  +¸ 01#"'&54'&#"#"'&=4763 327654.5432ïŠKØ´[€;­D"6ON *ŠKØD8 /¬G 5ON *²:%.A UV_9u±;%¤~AU`93þ’F[ !»+¸¸ܸ /¸/¸/01#"'&5432#"5432F-)46&-‰8&,/LOOL/î33mû¾;O9N:ÿÿ9ˆ–J'D0MlBÿøº<µ»8+¸8¸и/¸¸ и¸и8¸.и./¸EX¸#/¹# >Y¸EX¸)/¹) >Y¸EX¸/¹>Y¸EX¸/¹>Y»9+¸9»+¸¸¸ и9¸и¸/и¸6Ð01%+#"=#".54;5#"'&54;5&5432 63232+32M:y/KO› ;››) ;›ý§"YeeZ$ý©w( :xx) ¼7>:N? 8Y )7'?!#BþÿA#"ýÁ' *8Y ZiŒ"!» +¸ ¸¸и ¸Ð01#"'&547632#"'&547632Œ') ""*'þ¤!** ""*'Ã! ** !(** !´Î:/?#º(8+¸(º+¸º+¸º0 +¸0¸¸к 809¸¸и/A  qA9 I Y i y ‰ ™ © ¹ É Ù é ù ]A6(F(V(f(v(†(–(¦(¶(Æ(Ö(æ(ö( ]A((q¸0¸AÜ»,4+¸,»<$+¸<º+¸º +¸º 9014+!253##"'#"543!24'&#"32767#"'&547632Qlü _YÁ]þƒ1-4ÒÆ‡†¾À………ˆ½½‡‡^¢¤ãã¡   ä㣣£<Â8‹¶Ó11“«Ä’‹ËÌ‹ŽŽŽÉ𬧧¬ð¬¦I°jï¸ /¸!/¸Ü¸ÜA qA9IYiy‰™©¹ÉÙéù ]¸и/¸ ¸и/¸ÜA6FVfv†–¦¶ÆÖæö ]Aq¸и/¸¸ и /¸¸и/º+¸º +¸ 01#"'&5476324'&#"3276°YXƒƒXXXY‚‚YYU@@__@@@@__@@6‚YXXXƒƒXYYY_@@@@__@@@@ØÒmQ¸ /¸/¸/01#"547632m’BHC /’BG8 ")ÿøŒ¹²»+» +¸ »+¸A 6FVfv]A…•]¸¸ и¸ܸEX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y» +¸¸¹ü¸ ¸Ð013!!""5!#"5# )2Ù£ZýšX[þû\Z‡þ•aÆ<¬ŠûÐLMý³IIM <ûÇLÿ¤þ¡eº+¸¸¹ü01+"54;27>7632e¿´NNd/ Ufkô\Y1,0N7þš?T3C͸D/¸E/¸D¸Ð¸/¸E¸ܹ üAŠ š ]A 9 I Y i y ]¸и/¸¸и/¸¸и/¸¹&ü¸¸:и:/¸¸>и>/¸8/»)/+¸)»+¸¸¸и¸и/¸¸"и"/017476;254.547632!+"'.#"!2#"'&547632#"'&7¸Š¯ë6(>Sþ  $ [QtMO) LÄ©õ,&75),,&77&-j”L9A<rÆ<ˆ“b8@R®454ÿÿ ÿßÂr&"ðA|!ÿÿ ÿßÂt&"ðfÉ#ÿÿ ÿßÂt&"ð¦%ÿÿ ÿßÂ"&"ð¨íDÿÿ ÿßÂr&"ðcñTÿÿ ÿßÂ{&"ð§ûÿìÉ36Õ»14+¸1¸и/¸4¸и/º419¸ /¸/¸EX¸/¹ >Y¸EX¸!/¹! >Y¸EX¸ /¹ >Y¸EX¸/¹>Y»4+¸4¸и/¸ ¹ü¸!¹&üº!&9¸(и(/¸)и)/¸+и+/¸.и¹2ü01#!!32+"'&5!#"'&5476326!32+"'.# !2SþÌNNÖÏy©þ*Å %%"&¾+kr…»MM  þ“ìRüåþ­YaÈOh=Q³þâ/# 1Cj[fO„Õ¾ñþÿÿ,þɺ&$ühE(ÿÿ5ÿø“m&& A&ÿÿ5ÿø“y&& fÊ(ÿÿ5ÿø“x&& ¦?)ÿÿ5ÿø“|&& c^ÿÿÿëÿø€n&*Aÿ8ÿÿÿøœz&*fÿ/)ÿÿÿ¿ÿøx~&*Q¦þÔ/ÿÿÿèÿø}&*3cþŽ_ÿÿRÿð61&/¨+SÿÿCÿør&0÷AJ!ÿÿCÿø}&0÷fx,ÿÿCÿøt&0÷¦ç%ÿÿCÿø0&0÷¨ÍRÿÿCÿø&0÷c¸aRÄ ƒ¸!/¸"/¸!¸и/¹ü¸Ð¸/¸"¸ܺ 9¹ü¸EX¸/¹ >Y¸EX¸/¹>Y¸¹ü¸ии¹ ü¸ иÐ01 &#!  3! 54) ) 8)-þ þ¬æüâE(aPßýËþ¦ýÍ3Z {±$èšýÙ ‚üý•'0+ýÏþ¹F2J3KÿÿAÿôy&6ðA•(ÿÿAÿôt&6ðfš#ÿÿAÿôs&6ð¦æ$ÿÿAÿôy&6ðcÀ[sÿíV½:¯¸;/¸Y¸EX¸/¹>Y»+¸¸¹ ü¸.¹üº7901#!"543! =4)"543! =4'.#!"#"54763!2V³Åþ“NNm'þâþŠNNwxVBý§D.=, ONd[“ŠÏ· KM 9µQ;OhsfiNmsH<ü«9PTQL,D´‚'S48O'ÿÿ>ÿø´g&B÷Ajÿÿ>ÿø´i&B÷fïÿÿ>ÿø´f&B÷¦ÿÿ>ÿø´ &B÷¨•,ÿÿ>ÿø´P&B÷c=2ÿÿ>ÿø´V&B÷§,ÿëWÿøê¸7>S»K+¸K»>?+¸>»8+¸¸>¸и/¸?¸BиB/¸?¸EиE/¸,/¸0/¸3/¸EX¸ /¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y»8+¸8»E+¸¸ ¹ üA 7 G W g w ]A† – ]¸,¹;ü¸ и /¸;¸#и#/¸;¸%и%/¸;¸'и'/¸ ¸OиPÐ01#!32# '+"'&=4763!&!"+"543 67>3254! 4&'.5!";276ê;ü럆mN9^þµpjðÄ’£›s­ªþó  Nepƒaž(‡dŸt—ÎþéþŽÕþSBF[^LŒz–K:ecObF6FއvltnÝ**2y5!ÿÿ0þ«·&D hj ÿÿ&ÿøTb&FüA ÿÿ&ÿøTb&Füfƒÿÿ&ÿøTa&Fü¦„ÿÿ&ÿøTV&Füch8ÿÿÿÆÿø[k&¢úAÿÿÿ ÿø¡R&¢þfÿ4ÿÿÿ·ÿøp[&¢:¦þÌ ÿÿÿÆÿøø[&¢cþl=ÿÿIÿøe&O¨*ÿÿ7ÿøSb&PòAäÿÿ7ÿøSX&PòfNÿÿAÿø]_&Pü¦¡ÿÿ7ÿøS &Pò¨{,ÿÿ-ÿøIU&Pècj7Jÿøf· 't¸(/¸)/¸(¸и/¸)¸ܺ9¹üº 9¸¹ü¸и/¸EX¸/¹>Y»$ +¸$¸¹ü01%3!27654/!"#!"'&54763!2Ã4?WRKfÛþ•`LlH¢s¿þ¡ýn~­¼`àa“² Bq ;#GþŸ oþ¤L:;C¬a¡S@&Aÿÿ9ÿõub&VìA:ÿÿ9ÿõug&Vìf[ÿÿ9ÿõue&V즓ÿÿ9ÿõuU&Vìct7ÿÿ@þïfV&Zðc…8jÿø<j 7»+¸ /¸ /¸EX¸/¹>Y¸EX¸/¹>Y01%#"'&5432/¸0ܸи/¸=¸и/¸0¹4ü¸¹9ü¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸"/¹" >Y¸EX¸/¹>Y¸EX¸/¹>Y»1+¸1¸¹ü¸и/¸ и и"¹(üA‰(™(]A 8(H(X(h(x(]¸-и-/¸6и ¸;Ð01#!!;2732+"'!"'&5! 67>32#"'7&# !24! ! ¯Sþq0< NN|ü‹‹þ²å„ÊCYz^–&ƒ^0 Mþ“’Rý7þ™þ¬kPYaÈ‚Ohgg:Rº2JcF4O„Õþ•'ššýÙ•Lÿø/¸$.<Ç»7+¸7».0+¸.»%+¸¸.¸и/¸/¸ /¸EX¸ /¹ >Y¸EX¸/¹>Y»%+¸%¸ ¹ üA 7 G W g w ]A† – ]¸ ¸и/¸ ¹2ü¸(и(/¸ ¸9Ð01#!32+ '!"'&5476; 6!254!"4!"!276/;ýEŸ‡jNN_þµq}þå®®­¼*t‹&Ÿt—Îþó0U*sÖþÛ`Ll:SJfÇW‹'bO__;N¡a¡S@]^6Fއvl Bnþûqr#GþŸy!ÿÿ ÿøßs&:ûc—UëʤO¸/¸/¸/01#"'.'.'#"547632¤E#" L?Fp*I %% : H:Hh#: þõ© (k ¸ /¸/01#"'&5476324'&#"3276(97PN7:96PN8:F$&00&$$&00&$»O1113MN2003M1 12 ÉI÷Þ» +¸ 01#!"'&543!2÷/ýp: O7 0  7D /‚?@¸/¸/¸ /¸/01#"'&'.5432?PR./PP/1ÇE 4! E 1þÞ ÿÿˆ(FÿÚš†GD)#¸/¸/¸/¸/¸ /¸/¸"/¸$/01#"&'&'.5432#"&'&'.5432-P#, //PQ-1P#, //PQ-1ËE 1! E 2þÞ E 1! E 2þÞ ‚F@'#¸/¸/¸/¸/¸/¸/¸$/¸&/01#"546767632#"546767632F1-QP/ -RPþæ1-QP/ -RPû þÞ2 E !2 E þÞ2 E !2 ©‹ ¸/¸/01#!"'&54763! ‹fJSþ©bInlL`W"@! DaG#rMþ¡º+¸¸¹ ü01432;2+"5MfU /dNN´¿>N0,1Y\ôêÉ£N¸/¸/¸/01432>7632#"'&êE#" L?Fp*Iþö%%þõ: H:Hh#:þõ ÿÿÿ÷¨Áe» +¸¸Ð¸/¸ ¸и/¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¸и¸ Ð01#"5#"54;543232#¾PRžII’zx˜DDý0JJÐFDÂddÂEE ÿĶÁ'†»!+¸¸!¸и/¸!¸и/¸¸ и /¸/¸EX¸ /¹ >Y»+¸»+¸¸¸Ð¸¸и¸и¸"Ð017'#"54;543232+32+#"=#"543ù¢HH’{w˜EE¦¢II’{w˜DDtÑÌFDÂddÂEEÌÑFEÁddÁFEܵ»+¸»+¸» +¸AŠš]A 9IYiy]AŠ š ]A 9 I Y i y ]A 6FVfv]A…•]¸ܸEX¸/¹>Y¸EX¸ /¹ >Y¸EX¸/¹>Y¸¹üA 7GWgw]A†–]¸иÐ01%#"5432#"5432#"54327uttu¥uttuúªuttu]\\XX\\XX\\X´Î:%5ïº.+¸º +¸º&+¸&A qA9IYiy‰™©¹ÉÙéù ]A6FVfv†–¦¶ÆÖæö ]Aq¸7Ü»"*+¸"»2+¸2» +¸»+¸01";2+"=4;2#4'&#"32767#"'&547632]bcÜ((æ®°å((5‡‡½½ˆ……ˆ½½‡‡^¢¤ãã¡   ä䣢§QÐR-0­Öª-0°Ã’ŽŽ‹ÊÌ‹ŽŽŽÉ𬧧¬ð¬ªÿÿª¹Y» +¸¸иEX¸ /¹ >Y¸EX¸/¹>Y»+¸¸¹ü¸ ¹ü01!2#%"5!32+ !2#FEEûˆ]Ù¢GG‘þÌžEEþFKR8/ELœîEJjÿ¹1Ÿ»+¸¸Ð¸¸и¸ и¸+иEX¸#/¹# >Y¸EX¸/¹>Y»+¸»,+¸,¸¹ ü¸¸и¸и¸и,¸и#¹(ü01!2#!)2#! 5#"54;5#"54;5)2#! !2#ŽW>>ý©KãCCýþ1@@11@@1ÛÐAAý6þÒEE¨¬D@E¢HI/ICA¬F?oHIŒoDAX/¸ 3Ѹ4/¸5/¸4¸и/¹ü¸5¸ ܹüº 9¸ ¸и¸и/¸¸к"9¸¸$и¸.иEX¸&/¹& >Y¸EX¸/¹>Y»+¸»0+¸0º9¸¹üº"09¸&¹+ü01"3!2=4#)"543!254+ =47&54!32+"3 ¯¦Ã—ªYxxþýÕIIH—¥òþ{wws)LLQ¦½ûnçWA`X=c o4;kþDFtdëDh69nâHDVbïMJ΀H¸/¸/¸EX¸ /¹ >Y¹üA‰™]A 8HXhx]01&5476323267>32#"&] |_3e=  V’LI•©SU  hle;Øž ¸/¸/¸ /¸/01#"547632#"547632ž7ÿ998,97þï97e°I{7'¸/¸//¸/¸/º 9º&901%#".547-.54>32#".547-.54>32Ä $þè   c"$üÀ #þæ   d#$Â&ÓÐ $ þë((þî&ÓÐ $ þë'(-®z7'¸/¸/¸/¸//º 9º&901632 #"&'&547632 #"&'&547´ #þæ   þœ#$A $þç   þ##g$ÓÎ$ %)%ÓÎ$ %)¢þùjªV¸/¸/¸¸Ð¸/¹ü¸¸ܹü¸¸и/¸ /¸/¸EX¸/¹>Y¹ü01432!25432)#"5¢TS‰ðTTþIý–TSbHHý(WHHý©þõ¸OOž¶K8 »+¸01"543!2#âDD+>>¶?C@B ¶a8 »+¸01"543!2#ãCC@>>¶?C@BA=¯¹ j¸/¸/¸ܹü¸¸и/¹ü¸¸и/¸EX¸/¹ >Y» +¸»+¸¸¹ü01!"3!25) =4)6+"54; þmqrm’þîþÂþâÀo‚<Y¸EX¸3/¹3 >Yº +9º +9¸+¹ü¸$и%Ð01+"=#"/#"&'&5##"&'.5#"547632 >32 3D´44¹D0® #“D +70 %Wå2D¼Ý%%âÁD1Eþ»#!EC$þÅ<U$®+z¸/¸/º 901632 #"&'&547ª $þç   þ##g%ÓÎ$ %)-®4z¸/¸/º 9017#".547-.54>32® $þç   c##Á$ÓÎ$ þì%)ÿÿ:ÿdI$ :ÿdu$+#¸/¸ /¸/¸/¸/¸/¸'/¸*/01%#"546767>32#"546767>32u0/ ,!O./ ,#PþÔ0/ ,!O./ ,#Pß þÞ1 E #/E þÞ1 E #/>îh¬'#¸/¸/¸/¸/¸/¸/¸$/¸&/01#"546767632#"546767632h1-QP/ -RPþæ1-QP/ -RPg þÞ2 E !2 E þÞ2 E !2 @ÿùS @»+¸EX¸ /¹ >Y¸EX¸ /¹ >Y¸EX¸/¹>Y01#"5432#"5476329/LOOL/,&8‰,)44)-::N9O;ûó5m4`þF³Žº+¸и¸и/¸/01#3#3³SSSS¨æø¸æÿÜÿøŠº+“¸,/¸-/¸,¸Ð¸/¸-¸ܸ¸и¹'ü¸и¹ ü¸EX¸/¹ >Y¸EX¸ /¹ >Y»+¸¸¸и ¹ü¸¹%ü¸¸'Ð0143! #!"5#"'&543+!27654'&#!32œN±ï­†ÁüTNˆ, 8 8meMkmM_üåm, °¼NþÊý½¬YDOÁ 8N[Mþ§&RAH"þ«ÿÿÿøÕ{&:ñf†*ÿÿ@þïf]&Zðf Oÿø‘½#‹¸$/¸%/¸$¸ и /¸и/¸ ¸ и /¸%¸ܹü¸и ¹ü¸EX¸/¹ >Y¸EX¸/¹>Y»+¸¸¹ü¸¹!ü01#! &547)5#"543!2! 3! ‘¿‡¾þ¾þáv´OO„Óý…þåk.‡0FšP=0Nc*e[NSü¹Û}þ¬] *ÿøº Џ!/¸"/¸Ü¸!¸ и /¹ü¸и/¸¹ü¸¸иEX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y»+¸»+¸01#!#"'47>32!254)! ¶Çüýql/ 0&N¼ƒÁÜþÞüñ!:·Q;°OO%;Nf4H“¶¦jþ\Cþïpº#¼¸$/¸%/¸Ü¸$¸ и /¹!ü¸и/¸!¸к 9¸¹ü¸EX¸ /¹ >Y¸EX¸/¹ >Y¸EX¸/¹>Y¸EX¸/¹>Y¸EX¸/¹>Y»+¸º9¸¹!ü01)#"543263! 4'&#! !2pþ8ýn+ MNNI*]±PûÕu/€þ·þù‘ó)þ×Ã8N/N:Ñþæþ‰tL dþjÿ¹1Ÿ»+¸¸Ð¸¸и¸ и¸+иEX¸#/¹# >Y¸EX¸/¹>Y»+¸»,+¸,¸¹ ü¸¸и¸и¸и,¸и#¹(ü01!2#!)2#! 5#"54;5#"54;5)2#! !2#ŽW>>ý©KãCCýþ1@@11@@1ÛÐAAý6þÒEE¨¬D@E¢HI/ICA¬F?oHIŒoDA‘ÿç ÌÎ -»+»'!+¸'»+¸¸¸и/¸¸(и¸/ܸ/¸ /¸/¸EX¸/¹ >Y¸EX¸/¹ >Y»(+¸(01#"5432#"547632#"=!"&5432!432BYXYXO %WÌYXý0*VW›XY„MMìMMûR!BP!ûýMM•,3øMMþU«MM‘ÿç¼Î 7§»+»&+¸»,+¸¸!и¸9ܸ/¸ /¸EX¸/¹ >Y¸EX¸/¹ >Y¸EX¸ /¹ >Y¸EX¸#/¹#>Y»*+¸*»5/+¸5¸#¹ü01#"5432#"547632)"!2#!"=4)2=4+"54; BYXYXuN 'XÖþ¹þç®ÆHHüÍCv‡|ÔMMÄ>„MMìMMûR!BP!þìGLLDâáDWCMJë-ÿç Î #Pû)3+¸)»+¸»+¸¸¸и)¸$к&3)9¸3¸Eи¸Rܸ /¸/¸/¸EX¸/¹ >Y¸EX¸M/¹M >Y»+¸»1++¸1»?9+¸?º&9?9¸M¹Hü01#"547632#"=!"&5432!432%)"543!2=4'&#!"543!267#6=4+"54; N 'XÉYXý0+WVœXY÷òiiþ”ýñPP%¥&D7ýÕPP+82¢¡PP€tR!BP"üOO•+3øMMþU«MM€k78t0ðJMSRMO Q>LLÝ9=÷¹j¸ /¸!/¸Ü¸ ¸и/¹ü¸¸ и¹ü¸EX¸/¹ >Y» +¸»+¸¸¹ü01)"!2#!"=4)2=4+"54; ÷þ¹þè¯ÇGGüÍDw…|ÔMMÄ>—îEMJBãàDXCLLë5=¹,p»+¸¸Ðº9¸¸!и¸.ܸEX¸)/¹) >Y» +¸ »+¸º9¸)¹$ü01)"543!2=4'&#!"543!267#6=4+"54; vvþ”ýñPP$¦&D9ý×PP) 72£ QQ~v«l67u0ðJMSRMO Q>LLÝÿÿGþ¡½·&B®Ôÿÿþ¡ÒÈ&"®Hÿÿ*þ¡X¸&F®¹ÿÿ+þ¡‰º&&®¬ÿÿIÿøeQ&Of5ÿÿRÿð6P&/f¡ÿÿÿ(ÿøŽP&4f›ÿÿÿ+ÿøê/&Tf_Þÿÿ#ÿø„P&;f0ÿÿÿ(ÿø`Q&[f!ÿÿÿpÿø‘º&-GÿgQÖÙÿÿÿ{ÿøùº&MGÿrC\_ÿÿ'ÿø„N&D¯Žÿÿ0ÿø“M&$¯³ÿÿÿ(ÿøŽM&4¯”ÿÿÿ+ÿøêN&T¯Cÿÿ0ÿø“P&$fWÿÿÿ'ÿø„Q&Df2ÿÿ#ÿø„M&;¯|ÿÿÿ(ÿø`N&[¯Gÿÿÿø_M&5¯pÿÿÿ#ÿø„&;¿ÿÿÿ(ÿø`&[¿þÿÿ(þ¡Žº&4hVÿÿ+þ¡ê·&Thÿÿ?ÿ÷ P&3fÿÿÿ,ÿø›Q&SfÃÿÿÿßÒ&"·èÿÿÿGÿø½€&B·tÿÿ+ÿø‘P&-fIÿÿÿÿñÿø†Q&Mfÿÿÿ+ÿø‰M&&¯“ÿÿÿ*ÿøXN&F¯zÿÿLÿø:M&%¯üÿÿÿOÿø‘N&E¯©ÿÿIÿøeN&O¯‘ÿÿRÿð6M&/¯ýÿÿÜÿøŠº+“¸,/¸-/¸,¸Ð¸/¸-¸ܸ¸и¹'ü¸и¹ ü¸EX¸/¹ >Y¸EX¸ /¹ >Y»+¸¸¸и ¹ü¸¹%ü¸¸'Ð0143! #!"5#"'&543+!27654'&#!32œN±ï­†ÁüTNˆ, 8 8meMkmM_üåm, °¼NþÊý½¬YDOÁ 8N[Mþ§&RAH"þ«ÿÿLÿø&0¸£ÿÿÿEÿøaž&P¸IÿÿMÿõ‰ž&V¸aÿÿQÿô/&6¸¶ÿÿÿþ¡_º&5hÀÿÿÿÉþ¡#º&Uh%ÿÿ?ÿ÷ M&3¯éÿÿÿ ÿøÂN&S¯ÿÿÿMÿõ‰k&V§‚ÿÿQÿô/j&6§×ÿÿÿ+ÿø‘ &- Hçÿÿÿø#Œ&U ³hÿÿPÿøl;&M #BBBBòÒ¬ÎüLœ „´Öþ,¦è†.¨  º ò ² V ° ô 4 p ° šb®nØ8¬”,pÈX  Œð^äzlüBÀ4ŠÀ.l¢Äð’LÎZÔ„R¬ , n!D!²""Š"ö#>#²$$$¤$Þ%>%¨&6&j&º&ð'D'¾'ü( (¸(þ)ê*”*¼+B+l,0,<,H,T,`,l,x-0-<-H-T-`-l-x-„--œ-¨-´-À-Ì-Ø-ä.b.n.z.†.’/7Pÿ7SÿK7Vÿƒ7Zÿ{8 ÿo8ÿÇ8"þx80ÿÒ8Bþâ8FÿŒ8J8Pÿn8Sÿ•8Vÿ´8Wÿ®8Zÿ¬: ÿ):ÿ^:ÿ):ÿ‡:ÿ…:"ýç:0ÿª:BýÈ:Dÿ:Fþê:HþË:PþÊ:Qþí:RþØ:VÿP:WÿJ:[ý©:†þŽ:‡þœ:ˆþc:‰þq:ŠþU:‹þq:Œþ:ÿ9:Žÿc:ÿc:ÿG:‘ÿG:’€:“ÿò:”U:•€?üä?üÃ?;ü¡?Bü×?Eüs?Füó?HüØ?NüÖ?OüÔ?PüØ?QüÚ?RüÖ?Tüó?VüÐ?ZüÍ@ùß@ùþ@ùà@ùä@ú@ùý@ùý@ùÞ@ùÝ@"ú@#ùÙ@$úd@%ùÞ@&ún@'út@(ùÿ@)ùÜ@,ú@-úf@.ùÜ@/ùØ@0ùé@1ùÿ@2û§@3ùë@4úi@5ú˜@6ùÙ@7ú@8ú@9ú@:ú@;ús@Bú:@Cú‚@Dús@Eúf@FúŸ@Iú–@Lûk@Nùã@Oú’@Pú–@Rûù@Tû @UüÔ@Vún@Wú@Xú@Yú•@[ú—BWÿÆBXÿÞBZÿºC ÿÙCÿÙCWÿÎCZÿÃD FWÿ³FXÿÊFYÿÊFZÿÝG ÿ×Gÿ×GFÿÜGPÿ¾IZÿÇLFÿÚLPÿÃNZÿËOWÿÒOZÿÏP ÿÇPÿÇPWÿÈPXÿßPYÿàPZÿ¼Q ÿÉQÿÉQZÿ²S ÿZSÿ²SÿZSüÚSHSHSDÿêSEÿ¯SFÿÝSG9SHÿ½SI!SNÿÉSOÿÏSPÿ¿SRÿÄSSÿçSUSVÿãSWÿÜSXSY7SZÿÛS[þfU[þ{W ÿWÿWü1WFÿÛWPÿ¼W[ýûX ÿ‘Xÿ‘XüìXFÿÑXPÿÖYFÿºZ ÿqZÿqZFZPÿÅcüœcüzc"ü·c;üXcBüªcDüÊcEü+cFüÇcHü¬cNüªcOü¨cPü¬cQü®cRüªcSüÅcTüÆcVü¤cWüØcXüÍcYüÔcZü¡c[üÉeüºeü˜e;üÖeBüÜe[üµfüªfü…f"üðf;ü”fEüj“”+”CG”G€”I9”L+”MG”•«¦ûܦû¸¦;ûÓ¦Bûø¦[ü§ü•§üp§"ü̧+üà§;üq§Büß§Eü9§Hüá§Nüß§OüݧPüá§Qüã§Rüß§VüÙ§ZüÖ¨üä¨;ûð¨Bü¨Dü0¨EûƨFü-¨Hü¨Nü¨Oü¨Pü¨Qü¨Rü¨Süê¨Tü,¨Vü ¨Wü>¨Xü3¨Yü:¨Zü¨[ü/©"þB©$ÿ€©(ÿq©0ÿQ©2ÿw©4ÿ–©5S©Bþt©Dþ”©Eý½©Fþ‘©GÿŸ©Hþv©Kþ‰©Nþt©Oþr©Pþv©Qþx©Rþt©TþªTþ•ªUÿ}«"ýi«$ÿ‡«(ÿx«0ÿW«2ÿ}«4ÿ«5[«Býc«Dýƒ«Eüä«Fý€«Gÿ¦«Hýe«Kþ¿«Nýc«Oýa«Pýe«Qýg«Rýc«Tý¬;üô¬EüÒ­[üïÆüÝz»ËÓÚôü A V a l … ¨¯ v· - = 4K  " ± ‚Á C Y 2o 6¡ × ç õNeuropolFreeware version. Copyright (c) Ray Larabie, 1997. All rights reserved. Freeware. Revised 2003 www.larabiefonts.com Check www.typodermic.com for new variations and extended font families.NeuropolRegularRayLarabie: Neuropol: 2003NeuropolVersion 2.02 2003NeuropolNeuropol is a trademark of the Typodermic foundry and Ray LarabieRay LarabieRay Larabiehttp://www.typodermic.comhttp://www.larabiefonts.comNeuropolRegularNeuropolFreeware version. Copyright (c) Ray Larabie, 1997. All rights reserved. Freeware. Revised 2003 www.larabiefonts.com Check www.typodermic.com for new variations and extended font families.NeuropolRegularRayLarabie: Neuropol: 2003NeuropolVersion 2.02 2003NeuropolNeuropol is a trademark of the Typodermic foundry and Ray LarabieRay LarabieRay Larabiehttp://www.typodermic.comhttp://www.larabiefonts.comNeuropolRegularNeuropolÿ…   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„–ŽŠƒˆÞ¢­ÉÇ®bcdËeÈÊÏÌÍÎfÓÐѯg‘ÖÔÕh‰jikmln oqprsutvwxzy{}|¡~€º×°±»ØÝÙ¶·´µ‡àá‚«‹…½†Ûߪ©—²³ÜŒ¾¿ÄÅèéëìêíîõôöòó     âãÿäåýþæçûü !"#$%&'()*+,.nullmacronEuroaogonekAogonekeogonekEogoneknacuteNacuteSacutesacuteZacutezacuteTcaron Zdotaccent zdotaccentRacuteracuteAbreveabreveLacutelacuteEcaronecaronDcarondcaronncaronNcaronuni0110 Ohungarumlaut ohungarumlaut uhungarumlaut Uhungarumlautuni0162uni0163RcaronrcaronuringUringLcaronuni0111tcaronlcaronÿÿ øÿÿþ ÿþ ÿþ ÿþ ÿý ÿý ÿý ÿýÿýÿüÿüÿüÿüÿûÿûÿûÿûÿûÿúÿúÿúÿúÿúÿù ÿù!ÿù"ÿù#ÿø$ÿø%ÿø& ÿø' ÿø(!ÿ÷)!ÿ÷*"ÿ÷+#ÿ÷,$ÿö-%ÿö.&ÿö/&ÿö0'ÿö1(ÿõ2)ÿõ3*ÿõ4+ÿõ5+ÿõ6,ÿô7-ÿô8.ÿô9/ÿô:/ÿó;0ÿó<1ÿó=2ÿó>3ÿó?4ÿò@4ÿòA5ÿòB6ÿòC7ÿòD7ÿñE8ÿñF9ÿñG:ÿñH;ÿðI<ÿðJ=ÿðK=ÿðL>ÿðM>ÿïN@ÿïOAÿïPAÿïQBÿïRCÿîSCÿîTDÿîUFÿîVFÿíWGÿíXHÿíYHÿíZJÿí[Jÿì\Kÿì]Lÿì^Lÿì_Mÿë`OÿëaOÿëbPÿëcQÿëdQÿêeRÿêfSÿêgTÿêhTÿêiVÿéjVÿékWÿélXÿémYÿènZÿèoZÿèp[ÿèq\ÿèr]ÿçs]ÿçt^ÿçu_ÿçv`ÿçwaÿæxbÿæycÿæzcÿæ{dÿå|dÿå}fÿå~gÿågÿå€hÿäiÿä‚iÿäƒkÿä„lÿä…lÿã†mÿã‡nÿãˆnÿã‰pÿâŠpÿâ‹qÿâŒrÿâsÿâŽsÿáuÿáuÿá‘vÿá’wÿà“xÿà”yÿà•yÿà–zÿà—zÿߘ|ÿß™}ÿßš~ÿß›~ÿßœÿÞÿÞž€ÿÞŸ‚ÿÞ ‚ÿÝ¡ƒÿÝ¢„ÿÝ£…ÿݤ…ÿÝ¥†ÿܦ‡ÿܧˆÿܨ‰ÿÜ©‰ÿܪŠÿÛ«‹ÿÛ¬ŒÿÛ­ÿÛ®ŽÿÚ¯ŽÿÚ°ÿÚ±ÿÚ²‘ÿÚ³’ÿÙ´’ÿÙµ“ÿÙ¶”ÿÙ·•ÿظ–ÿع—ÿغ—ÿØ»˜ÿؼ™ÿ×½šÿ×¾›ÿ׿›ÿ×Àœÿ×ÁÿÖžÿÖßÿÖÄ ÿÖÅ ÿÕÆ¡ÿÕÇ¢ÿÕÈ£ÿÕɤÿÕʤÿÔË¥ÿÔ̦ÿÔͦÿÔΨÿÔϨÿÓЩÿÓѪÿÓÒ«ÿÓÓ«ÿÒÔ­ÿÒÕ­ÿÒÖ®ÿÒׯÿÒØ°ÿÑÙ°ÿÑÚ±ÿÑÛ²ÿÑܳÿÑÝ´ÿÐÞµÿÐßµÿÐà¶ÿÐá·ÿÏâ¸ÿÏã¹ÿÏä¹ÿÏåºÿÏæ»ÿÎç¼ÿÎè½ÿÎé½ÿÎê¾ÿÍë¿ÿÍìÀÿÍíÁÿÍîÁÿÍïÂÿÌðÃÿÌñÅÿÌòÅÿÌóÆÿÌôÆÿËõÇÿËöÈÿË÷ÉÿËøÊÿÊùÊÿÊúËÿÊûÌÿÊüÍÿÊýÎÿÉþÏÿÉÿÏÿÉopenlayer-2.1.orig/demos/textdemo/Main.cpp0000644000175000017500000000240010560043510021025 0ustar georgeskgeorgesk// TEXT RENDERING DEMO // #include #include #include #include using namespace ol; using namespace std; int main() { // SETUP // // Set up the program with all possible drivers // Setup::SetupProgram(); // Set up the screen in windowed mode with the window size of 800 x 600 // Setup::SetupScreen( 800, 600, WINDOWED ); Canvas::Fill( Rgba::BLACK ); // Load the font with the size 30 x 24 and a white color // TextRenderer neuropol; neuropol.Load( "Fonts/Neuropol.ttf", 30, 24, Rgba::WHITE ); // Test if the font was really loaded (maybe it didn't exist) // if( !neuropol ) { allegro_message( "Couldn't load Fonts/Neuropol.ttf!" ); exit( -1 ); } // RENDERING // // This is the text we wish to print to the screen // string text = "Hello World!"; // Print the text to the screen such that the text starts at x = 200 // // and the baseline of the text is positioned at y = 100 // neuropol.Print( text, 200, 100 ); // Refresh the screen contents to show the rendered image // Canvas::Refresh(); // Wait for a keypress // readkey(); return 0; } END_OF_MAIN() openlayer-2.1.orig/demos/CMakeLists.txt0000644000175000017500000000757610567607610020405 0ustar georgeskgeorgesk# ------------------------------------------------------- # OpenLayer cmake build script to create demos called from # main build # Written by: juvinious # ------------------------------------------------------- if(NOT ${CREATE_STATIC_LIB}) set(OL_LIB_BUILD 0) if(MSVC) remove_definitions(/DOL_LIB_BUILD) else(MSVC) remove_definitions(-DOL_LIB_BUILD) endif(MSVC) endif(NOT ${CREATE_STATIC_LIB}) # ------------------------------------------------------- # Create the examples # ------------------------------------------------------- add_executable(collisiondemo ${CMAKE_SOURCE_DIR}/demos/collisiondemo/main.cpp) target_link_libraries(collisiondemo openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) add_dependencies(collisiondemo openlayer) add_executable(gamedemo ${CMAKE_SOURCE_DIR}/demos/gamedemo/Demo.cpp) target_link_libraries(gamedemo openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) add_dependencies(gamedemo openlayer) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Fonts/Neuropol.ttf ${CMAKE_BINARY_DIR}/bin/Fonts/Neuropol.ttf COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Gfx/Background.png ${CMAKE_BINARY_DIR}/bin/Gfx/Background.png COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Gfx/Ball.png ${CMAKE_BINARY_DIR}/bin/Gfx/Ball.png COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Gfx/Blocks/Block01.png ${CMAKE_BINARY_DIR}/bin/Gfx/Blocks/Block01.png COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Gfx/Blocks/Block02.png ${CMAKE_BINARY_DIR}/bin/Gfx/Blocks/Block02.png COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Gfx/Blocks/Block03.png ${CMAKE_BINARY_DIR}/bin/Gfx/Blocks/Block03.png COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Gfx/Blocks/Block04.png ${CMAKE_BINARY_DIR}/bin/Gfx/Blocks/Block04.png COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/gamedemo/Gfx/Paddle.png ${CMAKE_BINARY_DIR}/bin/Gfx/Paddle.png COPYONLY) add_executable(gameloop ${CMAKE_SOURCE_DIR}/demos/gameloop/Main.cpp) target_link_libraries(gameloop openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) add_dependencies(gameloop openlayer) configure_file(${CMAKE_SOURCE_DIR}/demos/gameloop/Gfx/Bitmap.png ${CMAKE_BINARY_DIR}/bin/Gfx/Bitmap.png COPYONLY) add_executable(linestripdemo ${CMAKE_SOURCE_DIR}/demos/linestripdemo/Main.cpp) target_link_libraries(linestripdemo openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) add_dependencies(linestripdemo openlayer) add_executable(renderbitmap ${CMAKE_SOURCE_DIR}/demos/renderbitmap/Main.cpp) target_link_libraries(renderbitmap openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) add_dependencies(renderbitmap openlayer) add_executable(shapedemo ${CMAKE_SOURCE_DIR}/demos/shapedemo/Main.cpp) target_link_libraries(shapedemo openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) add_dependencies(shapedemo openlayer) configure_file(${CMAKE_SOURCE_DIR}/demos/shapedemo/Gfx/PointerAlpha.bmp ${CMAKE_BINARY_DIR}/bin/Gfx/PointerAlpha.bmp COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/demos/shapedemo/Gfx/PointerAlpha.png ${CMAKE_BINARY_DIR}/bin/Gfx/PointerAlpha.png COPYONLY) add_executable(textdemo ${CMAKE_SOURCE_DIR}/demos/textdemo/Main.cpp) target_link_libraries(textdemo openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) add_dependencies(textdemo openlayer)openlayer-2.1.orig/demos/collisiondemo/0000700000175000017500000000000012262355751020454 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/collisiondemo/main.cpp0000644000175000017500000001510110377573006022114 0ustar georgeskgeorgesk/*** OpenLayer Collision Demo --- Purpose: This demo demonstrates polygon collision detection in OpenLayer Created: 2006/02/16 Author: Brady Eidson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ***/ #include // A helper function to return a random number between min and max // float FRand( float min, float max ) { return min + float( rand() )/float( RAND_MAX ) * ( max - min ); } using namespace ol; class MotionPoly : public Poly { public: MotionPoly( ) {} void UpdatePosition( float deltaTime ) { position += velocity * deltaTime; } void Draw() { Transforms::SetPosition( position ); Poly::Draw( Rgba::WHITE ); } Placement GetPlacement() { return Placement( position ); } float mass; Vec2D velocity; Vec2D position; }; class BoundingRectangle : public Poly { public: BoundingRectangle( const Vec2D& topleft, const Vec2D& _size ) : tl( topleft ), br( topleft + _size ) { Add( tl ); Add( Vec2D( br.x, tl.y )); Add( br ); Add( Vec2D( tl.x, br.y )); } bool Contains( MotionPoly& p ) { unsigned int i; const std::vector< Vec2D > v = p.GetVertices(); Vec2D test_tl = tl - p.position; Vec2D test_br = br - p.position; for( i = 0; i < v.size(); i++ ) { if( v[i].x > test_br.x || v[i].x < test_tl.x || v[i].y > test_br.y || v[i].y < test_tl.y ) return false; } return true; } private: Vec2D tl; Vec2D br; }; int main() { // SETUP // // Set up the program with all possible drivers // Setup::SetupProgram(); printf( "Setup\n" ); // Set up the screen in windowed mode with the window size of 800 x 600 // Setup::SetupScreen( 800, 600, WINDOWED ); printf( "SetupScreen\n" ); MotionPoly player; player.Add( Vec2D( 0, 0 )); player.Add( Vec2D( 30, 0 )); player.Add( Vec2D( 30, 30 )); player.Add( Vec2D( 0, 30 )); player.position.x = 20.0; player.position.y = 20.0; player.velocity.x = 0.0; player.velocity.y = 0.0; player.mass = 25.0; MotionPoly wall; wall.Add( Vec2D( 0.0, 0.0 )); wall.Add( Vec2D( SCREEN_W, 0.0 )); wall.Add( Vec2D( SCREEN_W, SCREEN_H )); wall.Add( Vec2D( 0.0, SCREEN_H )); MotionPoly enemy; enemy.Add( Vec2D( 15, 0 )); enemy.Add( Vec2D( 30, 15 )); enemy.Add( Vec2D( 15, 30 )); enemy.Add( Vec2D( 0, 15 )); enemy.mass = 10.0; enemy.position = Vec2D( 700,0 ); BoundingRectangle goal( Vec2D( 300,200 ), Vec2D( 80.0, 80.0 )); // Set up the delta time routines with the default fps of 100.0 // const float FRAMERATE = 100.0; FpsCounter::Start( FRAMERATE ); bool collisionzoom = false; Collision collision; const float THRUST = 5.0; const float GRAVITY = .098; bool bExit = false; // Run the game loop until esc is pressed // while( !key[KEY_ESC] && !bExit ) { // LOGIC // while( keypressed()) { if( readkey() >> 8 == KEY_SPACE ) { FpsCounter::Pause(); bool pause = true; while( pause ) { while( keypressed()) { if( readkey() >> 8 == KEY_SPACE ) pause = false; } rest(1); } FpsCounter::Resume(); } } //printf( "Starting a frame\n" ); // Inform the fps counter that a new frame has started // FpsCounter::NewFrameStarted(); // Get the delta time // float deltaTime = FpsCounter::GetDeltaTime(); //printf( "Currentfps - %f\n", FpsCounter::GetFps()); // Move the bitmap with the arrow keys // Vec2D force; if( key[KEY_LEFT] ) force.x -= 1; if( key[KEY_RIGHT] ) force.x += 1; if( key[KEY_UP] ) force.y -= 1; if( key[KEY_DOWN] ) force.y += 1; if( force.x && force.y ) force *= .7071; force *= THRUST; Vec2D accel = force / player.mass; accel.y += GRAVITY; //printf( "Force is %f,%f\n", force.x, force.y ); //printf( "Accel is %f,%f\n", accel.x, accel.y ); //printf( "DT is %f\n", deltaTime ); //printf( "PreVelocity is %+07.3f,%+07.3f\n", player.velocity.x, player.velocity.y ); player.velocity += accel*deltaTime; //printf( "Velocity is %+07.3f,%+07.3f\n", player.velocity.x, player.velocity.y ); player.UpdatePosition( deltaTime ); //accel.x = FRand( -.1, .1 ); //accel.y = FRand( -.1, .1 ); accel.x = 0.0; accel.y = GRAVITY; enemy.velocity += accel * deltaTime; enemy.UpdatePosition( deltaTime ); collision = player.GetCollision( wall, player.GetPlacement(), wall.GetPlacement()); if( collision.IsCollision()) { Vec2D surfaceNormal = collision.GetSegment( OBJ_B ).GetNormal(); float speedAgainstSurface = -player.velocity * surfaceNormal; player.velocity += 2 * speedAgainstSurface * surfaceNormal; } collision = enemy.GetCollision( wall, enemy.GetPlacement(), wall.GetPlacement()); if( collision.IsCollision()) { Vec2D surfaceNormal = collision.GetSegment( OBJ_B ).GetNormal(); float speedAgainstSurface = -enemy.velocity * surfaceNormal; enemy.velocity += 2 * speedAgainstSurface * surfaceNormal; } collision = player.GetCollision( enemy, player.GetPlacement(), enemy.GetPlacement()); if( collision.IsCollision()) { Vec2D pp = player.velocity * player.mass; Vec2D ep = enemy.velocity * enemy.mass; Vec2D vcm = (pp + ep) / (player.mass + enemy.mass ); Vec2D pvf = -( player.velocity - vcm ) + vcm; Vec2D evf = -( enemy.velocity - vcm ) + vcm; player.velocity = pvf; enemy.velocity = evf; } if( goal.Contains( player )) { allegro_message( "You went into the firey goal of death! You lose!" ); bExit = true; } if( goal.Contains( enemy )) { allegro_message( "You got the enemy into the firey goal of death! Congrats, you win!" ); bExit = true; } // RENDERING // // Clear the screen to white // Canvas::Fill( Rgba::BLACK ); // Draw the bitmap to the screen with the top-left coordinates // player.Draw(); enemy.Draw(); Transforms::SetPosition( 0,0 ); goal.DrawOutline( Rgba::RED ); // Refresh the screen contents to show this frame // Canvas::Refresh(); rest(0); } return 0; } END_OF_MAIN() openlayer-2.1.orig/demos/shapedemo/0000700000175000017500000000000012262355751017561 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/shapedemo/Makefile0000644000175000017500000000066710377212142021233 0ustar georgeskgeorgesk#demos/linestripdemo/Makefile EXE_SOURCES=Main.cpp EXE=linestripdemo ifeq "$(ENVIRONMENT)" "WINDOWS" EXE :=$(EXE).exe endif ifeq "$(ENVIRONMENT)" "MSYS" EXE :=$(EXE).exe endif all: $(EXE) .PHONY: all clean clean: @echo "Making clean..." $(RM) *.o $(RM) $(EXE) @echo "Demo is cleaned" $(EXE): $(EXE_SOURCES) $(CC) $(CFLAGS) $(LDFLAGS) $(EXE_SOURCES) ../../lib/$(LIB) $(LIBFLAGS) -o $@ openlayer-2.1.orig/demos/shapedemo/Main.cpp0000644000175000017500000000705710517133454021167 0ustar georgeskgeorgesk/*** OpenLayer Shape Demo --- Purpose: This demo demonstrates usage of the ol::Shape class and its derivitives Author: Brady Eidson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ***/ #include #include using namespace ol; /* int main() { Setup::SetupProgram(); Setup::SetupScreen( 800,600,WINDOWED ); Bitmap bmp( 296, 83, Rgba( 0.0,0.0,0.0,.3)); bmp.Save( "Gfx/AlphaBitmap.png" ); return 0; } END_OF_MAIN() */ void mousePointerLoop( Shape& mouseShape ) { while( !keypressed() && !mouse_b ) { Canvas::Fill( Rgba::BLACK ); Transforms::SetPosition( mouse_x, mouse_y ); mouseShape.Draw( Rgba::WHITE ); Transforms::ResetTransforms(); Canvas::Refresh(); rest(1); } while(mouse_b){} } bool global_pressed; bool global_released; void mouse_function( int flags ) { if( flags & MOUSE_FLAG_LEFT_DOWN ) global_pressed = true; else if( flags & MOUSE_FLAG_LEFT_UP ) global_released = true; } END_OF_FUNCTION(mouse_function) void polygonLoop( Bitmap& pointer ) { LineStrip polygon; Line line( 0,0,0,0 ); global_pressed = false; global_released = false; bool drawing = false; while( !keypressed()) { Canvas::Fill( Rgba::BLACK ); polygon.Draw( Rgba::WHITE ); if( drawing ) { line.end = Vec2D( mouse_x, mouse_y ); line.Draw( Rgba::WHITE ); } pointer.Blit( mouse_x, mouse_y ); Canvas::Refresh(); if( global_pressed ) { if( !polygon.GetNumOfVertices()) polygon.AddToEnd( Vec2D( mouse_x, mouse_y )); line.start = polygon.GetVertex( polygon.GetNumOfVertices() - 1 ); global_pressed = false; drawing = true; } if( global_released ) { polygon.AddToEnd( Vec2D( mouse_x, mouse_y )); global_released = false; drawing = false; } rest(1); } } int main() { // SETUP // // Set up the program with all possible drivers // Setup::SetupProgram(); LOCK_VARIABLE( global_pressed ); LOCK_VARIABLE( global_released ); LOCK_FUNCTION( mouse_function ); mouse_callback = mouse_function; // Set up the screen in windowed mode with the window size of 800 x 600 // Setup::SetupScreen( 800, 600, WINDOWED ); // Load a bitmap // Bitmap pointer; pointer.Load( "Gfx/PointerAlpha.png", "Gfx/PointerAlpha.bmp" ); // Test if the bitmap was really loaded (maybe it didn't exist) // if( !pointer ) { allegro_message( "Couldn't load the bitmap!" ); exit( -1 ); } // RENDERING // // Draw the bitmap to the screen with the top-left coordinates of x = 200.0, y = 100.0 // Circle cPointer( Vec2D( 10,10 ), 10 ); mousePointerLoop( cPointer ); while( keypressed()) readkey(); Rect rPointer( 0.0, 0.0, 20.0, 15.0 ); mousePointerLoop( rPointer ); while( keypressed()) readkey(); ol::Ellipse ePointer( 20.0, 10.0, 20.0, 10.0 ); mousePointerLoop( ePointer ); while( keypressed()) readkey(); polygonLoop( pointer ); return 0; } END_OF_MAIN() openlayer-2.1.orig/demos/shapedemo/Gfx/0000700000175000017500000000000012262355751020305 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/shapedemo/Gfx/PointerAlpha.bmp0000644000175000017500000000316610407765130023406 0ustar georgeskgeorgeskBMv6(@ÄÄ€€€€€€€€€ÀÀÀÀÜÀðʦ @ ` €   À à@@ @@@`@€@ @À@à`` `@```€` `À`à€€ €@€`€€€ €À€à    @ ` €   À àÀÀ À@À`À€À ÀÀÀààà à@à`à€à àÀàà@@ @@@`@€@ @À@à@ @ @ @@ `@ €@  @ À@ à@@@@ @@@@@`@@€@@ @@À@@à@`@` @`@@``@`€@` @`À@`à@€@€ @€@@€`@€€@€ @€À@€à@ @  @ @@ `@ €@  @ À@ à@À@À @À@@À`@À€@À @ÀÀ@Àà@à@à @à@@à`@à€@à @àÀ@àà€€ €@€`€€€ €À€à€ € € @€ `€ €€  € À€ à€@€@ €@@€@`€@€€@ €@À€@à€`€` €`@€``€`€€` €`À€`à€€€€ €€@€€`€€€€€ €€À€€à€ €  € @€ `€ €€  € À€ à€À€À €À@€À`€À€€À €ÀÀ€Àà€à€à €à@€à`€à€€à €àÀ€ààÀÀ À@À`À€À ÀÀÀàÀ À À @À `À €À  À ÀÀ àÀ@À@ À@@À@`À@€À@ À@ÀÀ@àÀ`À` À`@À``À`€À` À`ÀÀ`àÀ€À€ À€@À€`À€€À€ À€ÀÀ€àÀ À  À @À `À €À  À ÀÀ àÀÀÀÀ ÀÀ@ÀÀ`ÀÀ€ÀÀ ðûÿ¤  €€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿopenlayer-2.1.orig/demos/shapedemo/Gfx/PointerAlpha.png0000644000175000017500000000033410407765130023406 0ustar georgeskgeorgesk‰PNG  IHDRqÜšgAMA± üa“IDAT8OÅ“ÛÀ Cõÿ?Ú±9 *—²,1ñ…Z‹µµVzÕûN_„Pª=ÔhF)ç4¿"€èlŒ°)"ôÂN5-I„¦Cðð‡(ä9‚Dv„ 5(ã-d(²Un]Œ`ÊÒQ„ á%âÆ6ý¡ÍάÂÉ϶ó%bùGB/¬â„±;ËÊ/¿ ¶ <t»›Ÿ19=QIEND®B`‚openlayer-2.1.orig/demos/gameloop/0000700000175000017500000000000012262355751017417 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/gameloop/Makefile0000644000175000017500000000065510377212142021066 0ustar georgeskgeorgesk#demos/gameloop/Makefile EXE_SOURCES=Main.cpp EXE=gameloop ifeq "$(ENVIRONMENT)" "WINDOWS" EXE :=$(EXE).exe endif ifeq "$(ENVIRONMENT)" "MSYS" EXE :=$(EXE).exe endif all: $(EXE) .PHONY: all clean clean: @echo "Making clean..." $(RM) *.o $(RM) $(EXE) @echo "Demo is cleaned" $(EXE): $(EXE_SOURCES) $(CC) $(CFLAGS) $(LDFLAGS) $(EXE_SOURCES) ../../lib/$(LIB) $(LIBFLAGS) -o $@ openlayer-2.1.orig/demos/gameloop/Main.cpp0000644000175000017500000000332410560043510021005 0ustar georgeskgeorgesk// GAME LOOP DEMO // // Note that due to the extremely high fps (possibly over 2000) the movement may not feel smooth! // #include using namespace ol; int main() { // SETUP // // Set up the program with all possible drivers // Setup::SetupProgram(); // Set up the screen in windowed mode with the window size of 800 x 600 // Setup::SetupScreen( 800, 600, WINDOWED ); // Load a bitmap // Bitmap bmp( "Gfx/Bitmap.png" ); // Test if the bitmap was really loaded (maybe it didn't exist) // if( !bmp ) { allegro_message( "Couldn't load the bitmap!" ); exit( -1 ); } // Set up the delta time routines with the default fps of 100.0 // FpsCounter::Start( 100.0 ); // The top-left coordinates of the bitmap // float x = 200.0, y = 100.0; // The speed of the bitmap movement // float speed = 2.0; // Run the game loop until esc is pressed // while( !key[KEY_ESC] ) { // LOGIC // // Inform the fps counter that a new frame has started // FpsCounter::NewFrameStarted(); // Get the delta time // float deltaTime = FpsCounter::GetDeltaTime(); // Move the bitmap with the arrow keys // if( key[KEY_LEFT] ) x -= deltaTime * speed; if( key[KEY_RIGHT] ) x += deltaTime * speed; if( key[KEY_UP] ) y -= deltaTime * speed; if( key[KEY_DOWN] ) y += deltaTime * speed; printf( "%f, %f\n", x, y ); // RENDERING // // Clear the screen to white // Canvas::Fill( Rgba::WHITE ); // Draw the bitmap to the screen with the top-left coordinates // bmp.Blit( x, y ); // Refresh the screen contents to show this frame // Canvas::Refresh(); } return 0; } END_OF_MAIN() openlayer-2.1.orig/demos/gameloop/Gfx/0000700000175000017500000000000012262355751020143 5ustar georgeskgeorgeskopenlayer-2.1.orig/demos/gameloop/Gfx/Bitmap.png0000644000175000017500000006753010377212142022101 0ustar georgeskgeorgesk‰PNG  IHDR(S£÷ ø pHYs  šœ MiCCPPhotoshop ICC profilexÚSwX“÷>ß÷eVBØð±—l"#¬ÈY¢’a„@Å…ˆ VœHUÄ‚Õ Hˆâ (¸gAŠˆZ‹U\8îܧµ}zïííû×û¼çœçüÎyÏ€&‘æ¢j9R…<:ØOHÄɽ€Hà æËÂgÅðyx~t°?ü¯opÕ.$ÇáÿƒºP&W ‘à"ç RÈ.TÈȰS³d ”ly|B"ª ìôI>Ø©“ÜØ¢©™(G$@»`UR,À ¬@".À®€Y¶2G€½vŽX@`€™B,Ì 8CÍ L 0Ò¿à©_p…¸HÀ˕͗KÒ3¸•Ðwòðàâ!âÂl±Ba)f ä"œ—›#HçLÎ ùÑÁþ8?çæäáæfçlïôÅ¢þkðo">!ñßþ¼ŒNÏïÚ_ååÖpǰu¿k©[ÚVhßù]3Û  Z Ðzù‹y8ü@ž¡PÈ< í%b¡½0ã‹>ÿ3áoà‹~öü@þÛzðqš@™­À£ƒýqanv®RŽçËB1n÷ç#þÇ…ýŽ)Ñâ4±\,ŠñX‰¸P"MÇy¹R‘D!É•âé2ñ–ý “w ¬†OÀN¶µËlÀ~î‹XÒv@~ó-Œ ‘g42y÷“¿ù@+Í—¤ã¼è\¨”LÆD *°A Á¬ÀœÁ¼ÀaD@ $À<Bä€ ¡–ATÀ:ص° šá´Á18 çà\ëp`žÂ¼† AÈa!:ˆbŽØ"ΙŽ"aH4’€¤ éˆQ"ÅÈr¤©Bj‘]H#ò-r9\@úÛÈ 2ŠüмG1”²QÔu@¹¨ŠÆ sÑt4]€–¢kÑ´=€¶¢§ÑKèut}ŠŽc€Ñ1fŒÙa\Œ‡E`‰X&ÇcåX5V5cX7vÀžaï$‹€ì^„Âl‚GXLXC¨%ì#´ºW ƒ„1Â'"“¨O´%zùÄxb:±XF¬&î!!ž%^'_“H$É’äN !%2I IkHÛH-¤S¤>ÒiœL&ëmÉÞä²€¬ —‘·O’ûÉÃä·:ňâL ¢$R¤”J5e?奟2B™ ªQÍ©žÔªˆ:ŸZIm vP/S‡©4uš%Í›Cˤ-£ÕКigi÷h/étº ݃E—ЗÒkèéçéƒôw † ƒÇHb(k{§·/™L¦Ó—™ÈT0×2™g˜˜oUX*ö*|‘Ê•:•V•~•çªTUsU?Õyª T«U«^V}¦FU³Pã© Ô«Õ©U»©6®ÎRwRPÏQ_£¾_ý‚úc ²†…F †H£Tc·Æ!Æ2eñXBÖrVë,k˜Mb[²ùìLvûv/{LSCsªf¬f‘fæqÍƱàð9ÙœJÎ!Î Î{--?-±Öj­f­~­7ÚzÚ¾ÚbírííëÚïup@,õ:m:÷u º6ºQº…ºÛuÏê>Ócëyé õÊõéÝÑGõmô£õêïÖïÑ7046l18cðÌcèk˜i¸Ñð„á¨Ëhº‘Äh£ÑI£'¸&î‡gã5x>f¬ob¬4ÞeÜkVyVõV׬IÖ\ë,ëmÖWlPW› ›:›Ë¶¨­›­Äv›mßâ)Ò)õSnÚ1ìüì ìšìí9öaö%ömöÏÌÖ;t;|rtuÌvlp¼ë¤á4éĩÃéWgg¡só5¦KË—v—Sm§Š§nŸzË•åîºÒµÓõ£›»›Ü­ÙmÔÝÌ=Å}«ûM.›É]Ã=ïAôð÷XâqÌã§›§Âóç/^v^Y^û½O³œ&žÖ0mÈÛÄ[à½Ë{`:>=eúÎé>Æ>ŸzŸ‡¾¦¾"ß=¾#~Ö~™~üžû;úËýø¿áyòñN`Áå½³k™¥5»/ >B Yr“oÀòùc3Üg,šÑÊZú0Ì&LÖކÏß~o¦ùLé̶ˆàGlˆ¸i™ù})*2ª.êQ´Stqt÷,Ö¬äYûg½Žñ©Œ¹;Ûj¶rvg¬jlRlc웸€¸ª¸x‡øEñ—t$ í‰äÄØÄ=‰ãsçlš3œäšT–tc®åÜ¢¹æéÎËžwç|þü/÷„óû%ÒŸ3gAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFduIDATxÚìýÇ“d×¹'~G]á2<ÜCkZk Š$’à#¨ÉWU¯«…õLmºg1‹ù f5‹1ëYÔØŒÕTWñ5‹âQCk ‘:#eh•¡<ÜÃÃõUGôâDÜt$$ØEB°°HëWœs~çÓ¿Àgû@aŒ€RJ)BƒRŠ1–RRJBJ)„|yümJ©”Ò0 PJaŒ•Rá_ ÃPJ5~„>ùò¸¿°?³`S;¥TŽ1FiŒ)¥!ús)¥þ«l8¾œò¿âAÑ[ža®ëÆãñ 0ÆzÌëõºR*RJ}ß×çø¾1B|9zŸàQJ9çz¿ ·R)e(Öô¡!þ$„è™B(¥„~_"ð/ÚòÂá2MÓ0 BH©T"„˜¦&!DJÉó›þçç~/ûì<ŠaBÓ4Cõ2n!J©Öp½ñ÷–”RÛ¶1ÆŒ1}/µÐ³¸B¦irÎc‘HDò}¢Ñh(»ôìhFáœ;ŽnŽRJ˲8çÿ5²No¬zBZ¿µ, !Ä{`Þ¿Þ-êô~É9×"„„’MOj¨ö4*œú¯á áïZ/Ò?À/àŸP4 Ã0M3DišZŸçœkOïkA(¥8çÑh´R©hH„âÈqÀÿJ[#‰è»k“^ßsn¦_ïÿøø€ÞÕôXëM´Ñ„Ó3­G?ÄU(CÙ¨%aˆ:­j†¹a–e1ÆB³ðËCŽáX,fš¦+BcÌq­·kƒM+#zék˜qÎ#‘H¹\ŽÇãŽãX–eÛ¶çyœóÆ]ò/]!øµf«!§oýØ>ïB}Ѝ A¥çXcIÏn¨%† 5F­ü4ºOÂ3õd4z8Ch[Kª¹¹ cH·$Ó©¤JJ RJËm­®çsÙ­ÜæÖßüLÓ •Cºz½Fƒ „(%:;[ãѨP¢¹)ÑÒ’²M“Kêü¡g !²¹Yº|õÖÆFá/B…^ ÚMF¥”Z¬iÝGJ©¬¾K¨æh„ ¼5¾Ú$h”u?ZÊi…0ük-ýÅð—PÉBèÑ×zQ8…!z[[›ÛZR­™ææLbgw'¤ú"zRòp:ײ›k+¹ÉéÅ/¶ ³, <Ï#„ض-¥ô}_)eY¥”1ÔÛÝÙÚÞ”ij"Œø¾OSJ(…Aã RrƘVAƒ Ðj ÷y ‚?¼ð^¹\ý‹PÇ-ËÒpõú»ZúÐ3¤±Š„ðQ „|F$FÐÙïloO§RÑd`i¹ÍUB‹+…Å{›<ÛÁ½Ý‰„5:ØšŒ›J©­Íë7ï”* $pœìü"$|NÕ-U¤”¦i 0‚"$7†lomîééH§S€˜ Áw'׋U¸€÷®.º.ÿ¨ë?ûÄè}K3—oM×”üÀ „€€og ¶A×××Õ’Nõö¶75Å@r™ÛÚÚڬܜ¯×ÝP… ÆlŸ÷ˆÑ' )Á˜2™²m RjCN_ª¿¿·££-ëÍðÚÍ™™¹Õ|¾¼{¬'·î$D)„pƒ‹’@)¤R‚H +k…×§víêïïíÈå6_{í].¾€4…„Ïø¶‹`…x 5%" }!mË%M£££V$‚)VBåóååÕÜõs®Ï‰Èž]Ý&3F‡;c¡/Cu¶uÎ¥ç …!4ÄÆFþâå;¥R0‚ (ƒB@)4ÅÐÈî½--m±XŒ1æ8ÞµñÙ­RõÖ%ýÀ­™Ä¡Cmp黫ë5ƒ€^ R’P÷Á÷A*ðøœŠ=ô‰‰»Fç‡Îó •I °ÐyÕ"¥išÊ$Àض0ÔþO„Ðè®á––Û4Bù|ùÎÔâÄÄR"Ù»»ïБP'AZÒ‚€À 66 ¾ïB9žä"†G‰ˆµBçÏߨ=6N7]¼|sii•s”ꡬü¬b# Œ¡³5*AD‚ 0MÓŽÚ™æf½œ¯ß˜žÏæóÅ¡Žt:yôð°RÛÛ!Hréú~½îbŒ•PU×-•\)©DlnnZ–µ±±Q«Õ‚ PJ`ŒF€°ÞR·Ÿ$fÁž½»ÚÛ;“É8!djfõÆ­ÙÅ{¹ÓÇÇlÛØ5Ú­”B­¬m^¿5ßÝÙ|poÿôôô; „€ $øH¹½fý@¯ ½3þÝOï‹B˲B×h­iju£»%T8Ãè€dDÙ&"HÈí˜R&#¦‰ú{;»{;ãÑ8Bbi¹póöòäl¶¯'½o÷Ø@`ð‡z[‘X•JEÇqÇ÷]‚P÷×”†œ}ýýÝÃÃÉD̶ÍùÅ·ß¾OF÷ŒööõµH,D ”Þ…•”òÝ w=µ?—;wþª€RX¨û¡Âfáó¨rþM€§³O<ÏÓÉ¡jÞè;–RjR»ÅÂй†AÈ4ß4±bÇ'©, ZÒéþÁÁH,¦Êç«ç/LÜ[Ùlk‰Ÿ==ÚÕ‘Âgs•K׿î­l?<ØšIôvgt´ïæíÅñÛËûöôíÙÕëyÞìô¬žB¡ˆÏAJåA2ZXZ‹G£©tÓëo^®Õí âœkï¶Î‡ ç[©ÏŠÐCB@w*n™¶©UƒZ­ÖÖÒ¶wÿˆmÛ áöäÂåËé–äþþt©–ëõº_,¹TJ(Ïsc¢PÝu1¸¾Ôjd{{»ïû¹\NaÛvµZæ~ƒ¯}Q!ê(‚!‹îÛ·«µµ5‰är[oŸ¿¡”8}|_gg†û¾BÈ­»ÅbµR«W«ÏóÚZÒ=}] «ét*‰üîo–Ëõ0+mÛ¡ýA÷y”xô¯nÄcŒuàEÏ·6Ïs,µ½§]Ɔa踜Ýh*áÙ&6„®À`Q0 µþþá–Ž6¥ë.LÜšX¶ úØÙ}vu#¤ê¾xã­ñ{+›gNŒ}ý+G¥”œËááþÁáþß½p!‹õô´DbM…BÕXBrß÷EÎ-Œ@k&½–ͧR “ ÕRE?¿Öo1Æ–q!)?3sŽÐ¶M¥!g›ÈaT©mÛ‘‘‘‘‘¥D6W|÷ÝqŸósè”’s.+•ºRÏÇJ„ªÕªØxòdYªV«éu?77;éDW#$ 8;Þ-è(BðààÀÐP_4E¿pãÚøôWž<12Ô)%8ŽW*U …¢ã¸˜RÙŽ1)Uê=Ô`3 È `Œ0ÖFˆR~’þÊÀÓÖ—Öã!ötÈH's…ѼÐÛaÔ4#ƒž Œ‘e“)FP{gOWOiÚRµ›sç/LÀð`û¹G÷[U ¦ç³/¼rmïîžÿ៾†´õïóÀó\ß/Ýææf+AH}ýk§ßyo¼­--±UácÓ4™I%!·î ­‡)Å¥THÝw'ì8Ö !­&tK‚ïK.%`Y–ïKŒÉÈÈPGGc|m|æâå;»võž=}!Å9ßÜ,—JÇó,ÃØØØ Ô*pj!¤^w]Ž9)eµZÿPèL2"’+©¶õ=-è(A¦iî?¸§½µÕ²Œ•µü+¯]îèhùïþ雌‘ 6ÖóÙ\AžÇó«5LI’ Û¶„@®+i ]ZZ –í¤%}¢©ô¯(ëBŸÇ–ТÕNBˆ–r–e¹®‹1¦”‚”˜“!†$Ac$%ËÄQ›P ã»Ò--J©¥åüû'7òeÓdOœÝ7Ü߀áý‹“—¯Ï=ó•û†Û%(©d¥Xò}ßó”ëƒP$‹läË-é8B*‹H 5ÊÕ*#¤^¯3Æc‚HOW›eùüV,#U«u¢_M«ÁZ;WJrŽ”"‰O{ÿ%(üA£Á4("ÄqË2FG‡ººZð˯^œ[X}ꉣý½¡ÍÍr¡XᜋE·^BpÉ…(+!„A€ê>ј¥ÚÞÛ7 $Á,:J€RÒÒ’Ù»w,bLß~÷Ö‰¹¯<~bl¬Û­×ó…ÒÒÂj¥RÑu$zðpE sxxPò‚cœË•óu…_˜LÛ¿ðtP[g04ÚryÉŒ±`g–´èó§PüëÏu]˲töIˆ«xZ¦i)§ëëBsŠRiH)#eŒs‰1¦S ¶‰ºzúÚ;»Rùò‹¯^/—ëpúøØ‘C ¹Dýêï»>ÿö·N'bVà››¹jµÊ}p9Ô]Ž1ŠFMÛ6s›[ñd\)¢ ƒB8Ž ãñh¦9‘hJ´µ5K ·nÏtt¦äw„H µ#ðTæÀ( àÓ™|½ÜÑC¢¦J¥’ƒƒ½¡7ß¾º²–{þ¹ÇZ[Sž'¦§—Šår¡7M³\,Šíc[c p¡´ú()zàC ÅÔ0F‡ûz(¥S3+o½s=Jþ›ŸNb@¯¿y¹V©ám¿¥õO úû”xÚù¡ÿB­òq§?Ô…­zzC¾É}ÛÆK‚Š0"¹Ä„ Ûdñ(ëínÎ4¨«×çÎ_šË O?u¤§+­@!…Ãkoßt]þío7sœÚʽEÏ ê.÷#D QÊA¾Ïmfnä‹Éd!D).Šßxöܶ£RÊõ‚÷/ÞìjK·¤š¶¶Jù¼A±Ï裡pŒnï²J)ŸBøS³ë>(vô‡ƒd2ÅL3‰´ud¤”7nÍNL-=õÔÑL&U«yKKk•J%·±Aµ\æ\j¼i•YÊu—®À®C䣔‡íI§ÓŒ±wÞ»ywr1•J>ÿü9%DµZŸŸßÚ*ù¾/D‚‹û6¡ïrf'Ž9HD ÅR-[¥Jµ^×¹´œË‡:à?;ÎäOxÚ¹§Í¶ÐqÒ¯kÌôiLÑ%„‚3#€¥O –K) JB†AÓ©èÀЈº>ñÕëËËyhÍ$žyòp‡rU*D…P”RfKKY.WTG‹ãTZZâ’ÔÒ’ÒvRjvzis³’Û,9³¿%—RÞ¾yÛd ” â;ʤÁ¤¡p > Û?yq‡>¤h! †a)„,ËjiI%ãñj½>>>}èÀðÐ@/÷ù©YÏ rÙ5ß÷…øä´á‘@Èv â«gu¦i8°«¹¹^yíÚüâJWWË׿vß*–'''ëõºÏ}:.Õvˆ#lG’ÇNŠDì­­rµZïëëôýàÂ…›AÜG|¡P÷x”RÏótÑÔD ¸Utð Ì‚e#Ò0AB"¤ñŠ1ƘZmoÏ B²›•—^¹¦ÕËîÎÌ·¿~\b$çÌ$åª{m|ö‡ÏŸ‰´Z¯ÎÌL¹.¯Ô8UHD,d`Žhëˆ5%"ùüf2nt½Ú&R-©¸ÁˆÈm–~öËwõ£îÙÕÝÓÓòØÙ=P­VnݺƒT%G~ ¤RZæ </@\âÐþùTRu1ŒT´0LP<žTJaLS©$ÆøÚµ Ã2N? ¤ZZÊV‹Õb¹èx^¨X> ðÐ`´6êÈ,%`0`ŒÚvtïÞ±ææ&ÀèÅ/¯®ç››Ï={†s?¿Yœ™šª×ëAàù¾ Á€1`@éÖŽƒ÷†±¶–¼  +‚×ß¼â8Žïûâ#ŒçÏ;êþbà5&X6fuýÙCq€2™ (0ÆŠƒ €¶Ý¡Ì¶YWOWoo/Æ03·þâ«×õ·öŽõ<~n¿<mÛJ¡Wß¼ñíožŒ%"µZmjrÂq„˱ωçIŒçT!j26Ô4êútjnkßž¡|Ñ5ãÝU—Ô< UiXÉüñ3!¤"ª®Z_/Œßœ %eT—¨èp?|0#> 0|Zzæ‡íŠ€bÊL“ ”LÆmÓ¨»õ‰©¥g¾v ´‘Ý\]ߨÖëõjý¡ ¨ @ü¥¨3ˆÙ»w,•J*D^zñ’FÝ·¾~V‘Ï'ïÞu]×÷]/¸j½k`Œ2™ŽãÇÀâÒªi²þÁ.Ïó_óR­V‚à Œº¿xÁuZ ©à0HƒIƒ*F$‰1H „ ̳,«»»»§¯ ®ŒÏ¾qJ_äÈ¡ÁSÇÆ ^¯W*5ÓdŒ‘{÷6{ºÒ™æ„ï¹ÓÓÓõº,×…R¨îrFH “ŽŽ–HÄÊæŠŒ rii}×h_µR3(E U+õX Ty«¶²–Í®mV]×÷9D J!!uR£k[¿Ú§#î ôq§”V«ÕöÎΦ¦Æxbb±³3ÓÙÙR«Ô&&–——…â#êštªQG郆¨Û³gW*•À˜þñå‹«ëyÛ4¿ÿ+$Š…­™© Ç©<ðù6¤‘N"ˆ'⇊Ǔpkb¶«­%•NÔëÎÛo_©Vj:3ö¡ËK~!P÷—OçÈi^7]Ùõ§—v¢è@¹”’e`aR0¨$L'è!ˆB³,«¿°½=o¼sSÇ ´óðÁA(Šår¤lJ4!„fçW?·WZXXÚÜr\Wz8Ï9c¦ÁhSSld¤_‚œ˜X8y|Ÿª\®*¥|ŸG£‘Í­òâbVJBHÉu¦ëº^°ÍSæIOJ €Ãˆ0C@»Â?­9Cè!‹m—ùÒ––6É·=ùâ`7R(›-x^€1õ<ñ'Š-> uèè3XÄ´‡Gš›‘?¾xqu=ßþIŒe¡Xº{ûv½VãA Äö(„!Õœ:yò$Æt³T^[ÉØ7‚ ÅÊ›o^r]W!¥zˆ@V ¿@t9ðtF¬®(y(ä«¿‹Y9ç„(†„AÁd€é6Y# G£Ñ¾¾ÖÖf¥Ô›ïÞzu¡\6W*•”v4jÚ,›+µ¶&BóóóëëùºËL¤¤AQ ˈ` –a ö!ÆoÎôö¶†Û·æöíDIäÒòºã¸úI|îsÁyàs.Ú˰òò3GÔ‰®\h}$D<Ñ^ÜjµÞßß¡Z]ÏB8Ž÷'ÖîïG0­a~ŠÌ`+ÒÛßÛÖÖbÖ ¯\Ѩû‡o<OšÕryêÎDµZõ|îóõAkk|l÷þd2…™˜Z4 ºw÷°Rê­w¯g³9íMyè8aÝ_¼Ðe§“žõ* Ëç€\èoËꤔ¶I *âŒJà B(îsÆÆ`0F©58ØßÔ”Býæ…KË;•§OŽÚ7€1^]^-–‹ÜõBÉTJ)´¼š;qdÈ÷åV©Vs”ãH NÄŠ¸¾KJ „GGû¢ñh.[àÜïêÈTju×­Gmkum£½µ¥T) e„)wÐæº¾Ï%4Ð*…Ã$Ÿ•C=$~¥©O"¶m !‚ °Mà”V.×VW7*•êÇ—;ñ$Äè†aÒˆiëhëín'”^¼:=¿¸Ÿ;ÔÓ“ö<÷îÝ»¥JÉãÜ 0Œ¡5onnÛÙܬ.¯çû{Û±h­æ\½~w}#Ç— uù–l(qP >ÿ\~9ðôú3 C§)êD“20Wj(ëB'»AbNˆ´(` œKB°¶ë¨iÚm]©T~ýû‹Ë«ùЮ;v`H¬Ü[Éå²Û7ÝÉÁE „@KK˹\Å劖ï»`2›ëkjŠ •[wæÎž=¢”ššZسg8Ì8ššZàü>iÒ6_„vÏѱ“€n …t:MÑ â¤ïº¶mW*—ïä¦4î®ЦE,ËnÊ4÷övBffÖ®\» {võŸ<¾g3—›˜˜ÚÌå<Ÿkõ’hMÇRéôèè(Æ”™ö•kS‘ˆu`ψbemãúõ‰j½ÞÀ> Ôû|QÙéŸuH X#7^EhL (¡’FˆbDDa¬UPİX,ÖÚÞÙÙÙo½w;DÝž]ÝgNì–J­¬¬lä6ÏÛæ#ÃØ÷]Œ™L.×y­ÆS†aq)1¦Édtd¨7™Œº.¿}wöäñ}H©É饎ŽÛ¶Ö76;Z[ªÕj6» $äô‚Pt*¥#ãŸFéÑhRgrK.Aºø·X,~Lq‡²íîu–‰ Ê%ƒƒ½¦iмþö5H¥âO=vhkss}cc}uՏ޾´·Äš››GÆÆ!”Òñ› RÂþý£çÕ]çÒ¥›ù|A!…ØNN“ vÒS>Š9âïxºlÇó¼ÄzV„ÔΡæÒ1!ŠÁ ѦŸÊ4©R$‰´´µut´a ï_œ¼3±]ùßÓ•~òÜA¥Tv-»±¾žR c&9Ä"”jœK$ˆB„bIP‘H¤««­¿¿K(µ™/Þ¼=wäȘm³õõÍõõ]£Ç=/ !¤nݺ+ï>mçXîl%;Á’Ï.eªúíP!Ä¥¬9Nʲj5/Ä"… „ã×q’ŠI˜LfÆb±þÞîˆeq.ÿ˯^ÑýηcŒä7*³““BÁ@oKsssWO`ʹy{!²k´Ré»7nÜÍmnÕjŽV£táyèÝ‘_PÝòã¯1&&a6švu ZÔ®ý Å`2EŒD° TCÒ&6 ˲¬ææLGG!øÚøÌÕsú"­™Ä³_=Ê¥âúê²ä>H`”%LËØ©¾Ïp¢)a!•LÆÛÛÛR©d$bI)§§—æç×?wضY¡P¾}wöôé€a-›ïïí¨Ôj›[%LC\ä÷—Xñ8øü1O+¥|߯×ëRÆ„’VÄ ÑÝÝ>Ð×¥-±?‹:¢5̆p%ÀPô£ÑÖÖÖT*i›æߺì8}r¹Í©©¹CF±ÈÊJ¾5“Ä®]¹ŽAJÉ@,ÁB~ ³D"qüèî––TµZÏå¶.^¾ó™êz£ÔƒE@;Ê™Tš¯Ë …bwgËP_×ÌÌÒÁƒ£»Fûþð´QG?¤db Ô ¶m'b‰®Ž–XĘœ^[X€ÁþöãGG+•šS«>zX“LÂ67+“³³¦ÉíÀû¾\]]Ÿ]ÞÜ* !ta£RRKo)?ÇŒ‰}à騱¦$‚•Pè5&m<€CŠ1Âa2 À ÷ !ƒ¶iwvvš&[Ën½þöðŽÏ|íh*wÝúò BžBm€ˆXÒ6m¡$5ç.Æ02Ôùû?¾wæÔÞžŽäxÁÍÛ‹Ó³+pêØXWG­­¬,ß»×’Švwg\ŸcŒÒéx6»©·mÓõM¡`I”‚&ý³£-}êÔýHѨÚñxô¥WÞÿLO¡c aØCJɹŸÍº¥žŽLkêîô|­RomM?qîØ;ï]øGšvxøƒñFÀ2PÌ6SM‘áÁöhÔÜÚª¼ôÚe°,ãÙ§ŽÕj5Œ!•NSŠ}WÎÜÛ˜_Ìövgž8»Ïó!‚Õåü½•Üúú–Bé­AJØ[|Ám¹¿xºæ@ëíѼ†ô²ZhL1¢ Іƒ@"¤‚@`Œ"1J +ÝÑF \­º/¾zÕÛ±=NíhKÕëîÂÌT­²‰±—0€ e™ˆFÌ”ãxžÓÕ–:{rÏ»ïßþu®¤¿~æÔ®GNîêéJ€çxkk+[›¹–t|×¾}HÁäüÚÞÝ}•šs÷î$`L‘ˆ3¤ε÷U§Dƒƒ½}pwréÝó7±Èãîéjh*˺,=L,¾ŸÑ¯ àŸ(ÕŸ”FØRáÿ!uoe-–°Ïœ:ôâËçÏ>r°³»íé§ÏÞ¹33¿°ö0íJ>ð &Û‚¦%¬ŽöÖh<ÊzãÛ;ñžÝMM¡ÔúFñÞ½ÜÕ³G u¶%÷Ž´BÔëõõÕåB¡¼º^pŹЛ‚p‚ÌÆþ;9ЇLômgIØp>ÈEºÚ‰ìÃ#ŠbnPe2ňB ! „fš±D¢¹¹µ»»!õÒk׿Öõ·†Û¿òøaŒarrzcuK?„1!D)„±4BHD!¦Ù»·Ç4RxûaDÀ1ÆŽãæ Õ™™eJ1BèÔ‰=vÔžœœè2MóÂ…ñÀ«P¬AžçyŽòSÂ,ËÝ5œN§àÒ•‰ñ›³‰Xä™gN&b‘­­Ò{ï]ü¨^_JaׇJ-ø„ÕQM²>£@)eŒé¦:ÓmÿÞ¡ÖLºæø¯¿~á‘G77'=Ïñ}?—+ ÅB¡œÏ¾í´d;>¥ §ÓJ§ScjéTK$Œc“Ó¹_½ ¶mž;³·îz—®LŸ9±;“‰µ·&D $ÈZ­V.äK•­B¡èºàÊ÷Á÷E Àó€ÿýi•Kâi}ÍYßXíßX|ý€ ;ƒ)‚$!Š0…±”€@(B°Rˆ†aXñh²½½@Î,dCÔ%b‘³§÷ÀÊÊÚÆú†PAè&Ýi^#H"…0¦ <5µÞÙÙ‰X–Eõr/W¥åÍÍ’®³¤”ž>¾—™ìÞ½µöÖf‚ðÊÊJ±°N±pw^ŒÖ±¯d*9:<‰E|—¿òÆ•åÕ¼aЧž8’ŒÚ›ùü•+ã)ô!»J!äºAÝ•®ÿ),&¥€‹mý!ý¿@X)JFݽ;k ÍÍMÏ|í‘^9ßÙžÙ=Öß”HÄ"‘Þî]ŽQH)BưÃ"C0!Dç@X–E™œ^Ó¨€Ñán!àȱý»û¥äBˆR©V©T²Ùl¥T✠¡jò]åxàsàœ|¸ãÏ—À{Ð-fÆ)ÃzÔv¶waš˜A5ÀÀˆ‚ dÛ)Š1¦Ô Œ%ššÚ;[)žÏßzçfx¯=yØ0h¥TZ^^âÒ‡†þÚJ¡@ , ¤ÂB2$(ÆC¡PÏåjAàAà8ŽfRbŠññ£»›šâ…͈Çc…BáöÍ[–!”€¶ý±+ÀÈ2Xgw×À@ŸÈåʯ¼qEW!}ãéS--ÉJ©róæm„cZæë½F@ ”ïKŸcŸëÁùtÖ€$P@#enlÒÀ`‚šššîojnþÎ7OÏ.®¿þöå­­ÊÙÓû8çí­‰ÎöBÊd¥„À „P†e”*î‰5 €Ï-e§g³=]ép“íîÎ<û”®ŸÚBJ¸õÚf.[*•|Ÿ»¾ åxÊçÒó æ© xÿËã>ð¥ÙŸ P· Ñ;¥@`1¢…HÐDlÛŽÆb Û¶àý«“:ýNM·$ݺ{gj­»÷KÔ¹¤”bŠ…"¾#$p„¦¾’3FÏ£W*Bˆë»J).¶—OÜ×Üœ¬–k››¥Ñ]}Žãܸq“%¥ÜÖÌB„ L#»öìI¥SB¡»“K¹Í’aPøú3'[Z’•J寭 Ÿsšk# ‰@¹\ AênðQ•šŸ¤è 8|Ž<Em©gÙ¦ŠD¨e½87;šZ2‡vÅí;Ì¥ºqkÝ´ñ»î,-z;®Ô¡} )¥øwŸ‹F÷Õ]ôÿ¾‘ˆñÝçŽpî Ål6»¹Urvd_{{sss«‡Œ ¤ÆÇoy^ Á Æu4ÆÔ°:ºÚF†F ·Yº3±xøÀÈ˯_ÎçËçÎì씜OÞ-W«Jµmó(ˆ”çK¥ç¸êª‡Ò}ºÑóÆæ÷CŒB„PkÙÒêz1³¢Q“’HXñ¨HAC ¬Lß÷9fÚ&ØâKW¦VÖrðè™}¥Jefn©\,k _(t»BRçàñ>Ÿ cCš1!èìÙñXZZR--)øøØ Ë5?ðø])aµël,üÑ`¬Q)É•~¥Æ!ƈ‰%MMRÊÜf)LÈ)…”Ò T½.C"ÍD"ÖÚÚÔßÛ©·Æ\nk||ú£ú9·¤SŽ|Ô™‰Dlx°»¥%ÕÜœÐ'\¾|§ø±[«>`2hìÉÔ,]¸Œw„cJÇ^€fËÞÉ QFh4n`, 1þãO_Û4Ÿÿƹrµ¸±±±¶²âûNHfWêÞ=îØ’Nµu¤Û[›õ»A°‘/Þ¸>¥5:(ʹÜÖÕëŠ.¢žž=,zxǶVsšo„Xͤc©Tº³³UsÒ‹ÅééùR©Æ¡†ÑÙÙL)¾2> ëôqÜÚÚüÔSgJ¥ÒwÂn< ±4Ì%LÇr§9Loó<ïOÅñ4kèÆl¤aÿ0ä1­šL1"è¾{†bšv<ÏdZ;:º˜©|ŸÿóÏ_×n•³§÷îÚÕSÈÇÇoר$h[übÈ÷Q "(ÌÆnìà ;ýÝÛÒÒä9þ­;3'ŽíVݺq·Ïb¼ÔEîííícc#°¼š¿·’?¼X!¤QwèÀà‰c»Ü  Zwßyçbà€Q P¥!étr÷H_K[)%á>Rè•7.nn–ÂÆÑãžž¶®®¶öLÓg¾þö•­­ ¥ôèÁ±îÞv©RjûÕ‚ xùÕKZ›ÓM`>~¨PßWoä‡þÜ0À$Ê0”N—kŒâ2ÓŒGã­­™D"bÛö/~õÖZv¾ùÌéîîL>_¸zõºãÔ\ï!ÙÌ¢¡Û+ÆØdìС]z+iÜþ aRÊjµ‰X.½õ›ï^Ó8)å®ÑÞîîöXÄ µ}m(¼õÖåÍ­J#ùH:|ì‘à ©F©Ím½ýöµFŽœŽ¶äþ½ƒmmé0ËJÊíðÉõëw}Ÿ›¶ÙßÛ‘HÄ^}ýêüâÚØHÏ#§„W(Ëï¿I304æ*E\Ž¥Ä Ÿ(]ÿª&€nYVØcrÁÂúWØIà J±IcŠÒÅf<žljjjmïhkipçç×^}ó:tu¤Ÿ}ú„RêâÅ«[[[VˆuwrÎ —8œÚP×M’FOÛ“L%jµúäôâ‰#»•RwïNnnf)ðm}€ŠiWWÛÐÈÆpõêŒBèøÑ!Ï ~þ/²¹Ò=½_yr?Þ¡ª½tevi9·°”7MöÝçŽ õ¥K¥µù›>×.)c¤g`W¢)£×Ñ[ËÙ\Q÷U<{z׉cÃËKs¹ì=F˜”FÓm]©TŠbYª9믿;ÞuâÄhµ˜¯×«é¶.F˜BèÚøü;‹Ùl þáÙc##]+‹÷ÆoOr.]×w1¸þÎذÐÕGô^½ßôv‡Žc̲¨d Â2ªav4ÚšimëHY–uáÒÄÕëSðÔGì*WËçß½T,Oq€Âæ$ÀÈ6 À¶ “²GÆ:Ú:˜iK)«urzmñ^~v>«sÍþí?>ÞÑ–œ_û?}:ÛßîH*Y™~7^$ÖkÄFTJ˜¿·95µ2~û<ùèî“ÇG*¥ÒÌÔøŽtÀ‘DSÿ¨BèÒ•é·Þ›€TÒþÁwN'ãÑ»7/:NMó×u÷4gZ‰R˜Âøí{ÙléÊø<þèîÓLJŠù5Ï«ÙÑx$’$ÌÜ*9?ûåù­’ɤmYÆShmN¬olLܹuŸ¼K÷Þð9öâs(B(ݪà£B)´Ñ‡B>ØiI¥? [Ø…· {Mb¬$HR˜Éa” L¡Ô°Í(!( ·YÖ7Ú·oP)´²²Z*U"AàëK…J3ÆX)PÛ^SÆ ý®Œ±T2~äØÛ¶¶J嵕Üñ£{@©;·&J•͈Awbn$™´÷ìÛµm…Ô+¯ÝéìÍ8Ž÷óß\ÈæJý½™¯=yPçX_¾<ýæù‰“G‡ÏœùW?8])9?ûÍ¥®®GÒ-ÅÕZ¡L-³µ¹-ÓÞI©Å9¿xuþòÕÏ ŽúwÿýÓ¦i¾÷þ]Ši"‘¨–ã”â–¶®––!„ç/¿7¹°œ?¸»ÿÿú?}üó/ß=|%Ó]MÄ9Ÿ]̾üúõÑáÎ'ÏlKÇ%àŸþâ­®®l%Êåz¥®lƒø@ìàM€”ÛŽŒÞºQ‰;­ÎA4{/ˆ’°3ÂLÓŒE"m)Ã0nß]Ò¨;t`xïî~ÇsîÜ™(—‹^ ”J€ÑR]±*ˆÅp__×Áƒ{a©Å{›®ÌÌ/æL“=½çÇß}Ô°hvmóÖÄ’ï·jÔ¥SÑŸ|ïd"ayµ¢ æö#ñT«RhuµðÚ{·Ë]£ßxúÙùÅ­Ÿþâý“'wÇ“iðÀ4ͦæÖæL'"jüæ¢F]S"òÃïžN%íR©èû¾iÛétkº¥‹ÆpáÒôùK3žœ<:ò?ÿŸ¾aXôwnûÊ ”Ši˜àpgbõë_;ÚÖ’ ­­•~ýÇ÷~÷•ï?ÿx*ÕˆY­ƒxA !͹BˆH)Á„¥Ø ¶N˲4v´Yô ð ÃÀkž]€G)¥”ŠŽºŸV¡p×AvιÂŒ‚‘P‚ `R@J l0ÛŒ–!%WJ­®æ ÓœèêÈ8Ž3ywžû<ÉLMq‹)©B’K!„s° þ W?p_OÇ޽ÔâÕõÜæféÀ¾!PèÖ­»N½HP@)¥„ ––äðè.ÆØÚFqzvõèáád2Z­{¿øõ…l®ÔÛùî?œ¥îN¯½õÞÝÑáöÿùß=µÅ Š'£P¯úŒ²«‹utõÅ“)„Èì|îÕׯ—*Now景N$"PÚª%S…T½Z5m³¥¥+™L¸qgyüæÒÞ½ýO=q $G­çJ‹÷rµšƒ1(…^yãBè_ÿðqÆp}^¯{žl•*‰D$™J"â#„ ò…ªÎ-Ö(úK ?!B hö!ðî›è”€i(ðbM‰îÞvÃ07Þzç:Þ?òÔ“'J¥­¹™¥¥¥eŸ P:=m§BB À˜º»;û{uåZvëõwï,.æà±Göœ<:dšÌ0(ÙÞÞôæù‰7ÿãØ&û×?<‹Y•­r.·ÒÒwÂ4£€‹—gîLÝ{üÌîÁÞ&íÀ¸vsÉ4™ØÆ–iÊdRéüÂ¥¹kã ÐÔùñwO¥â‘Jykqv2‰´v$Í`ñ^î…WÆ‹åzoæé¯iJDBÅb9•Œ0¢0ö[[[)¥žç__<´¯—™¦”P®Ö_|õ¢çž,/o w67E666R1 û>  Œìs$ò<¡Fè.aŒ…Ì)ÛÀkìÝ£›Š0ÆBª¢PiÌ÷ ÉŽ(¥)(A®§À2¥ŒRð,ÆL!ê/”`l¬!T(ën] 4¡ÞÑSý `Œ!×—†¡Ép±R‚1ÝGÖ€¾¾®}ûF0À[Ó†aØ7ß¹uË­‘⌌‘e¨¶¶Ö¾¡ŒñääJv³øè©½R‚ëú¿üÍûÙ\©­-ù­¯õ]ÿ¥×Æÿ{ª9Áâ” ue|±X¬§SQ×ç†aõô ˜¦­zéµñ›·à±³{N RB©T¿»ôÄÙ] >:ºKJìyÞ¯ÿx½·»å¿0FHPe³…þÅ{Éd4™´³¹ÒÛïÞ:y|Woc껾B„sþ‡—.xNК‰`™&qj3™.Ð& e; àcÚ}ÛÍFèà lšv&Ó<4ÐgÛV¹ì¾ðÊE8rhôì#jµÚÄÄÌÂÂ’à`zŸcS³YƒFq2•>tèePŒá/_½~k Ú[›¾úÄÎÎ&Û¶ R&#u7Èæ¶nÝYÓdÿôã3‰˜U«T …|Wß! P®8¿øõû‡÷÷ÿ7?zƒDÆ~ÿ≩ÕS'FB^­bšfG÷€eH©_»‰ËuÛd?ùÞé–T´RÙZ[™K&“m]ý¦/¾zãÚÍE­Xž<>¦—t©T»~céñGw!¤šDH6Wš_Ì<>"”/øÃ —JŽhó<¯TÚÎËçR …AX(P #âŠKÌ%"‡b¨dZ–¥ Ê·±£UGÝK¤Ñi¢ñ¾p¤T[üú¢:%R€¥TŒ XHAÀ#Š1Õ ‘’•Š£/2Ð×­š]bÛS¼Á¤)¹Rp„°¢hÃ!‰EöŽ d2i%Ä»o tuud”R·nÜpëe SŒAZ–Ì´¶÷ Ž „.\šÆ9¹û¾ûËßרûÁ·N..å/^=÷è4¥ƒPH(d …Þ¹8óÊ·è߯÷ŽÄV׋¿ýãåb¹Þ”ˆ|ç›ÇÛ;›•ˆñ›s[[µ'Û‹”ÚÌÎôc€ÛSk×n/=vvOk¦¤ÄXPŠ×׋?ýÅyÏ Îœ™›[½zcñûÏŸ±mS÷öÚXÛüÍKWJ¥Ú¹3» Šëõ*Æ`2TGbs‹cô1§øÇsÜkÔ±‡¡Î`È0¬¶¶–={vY–U*9?ý/¯Àé“{îö¼àîÝÉ¥¥e¤\¤‰1ºð B4ÕÒöÈ#'MƲÙܯ~ÿ~±X€±‘Žoó$c ¤´  —«u)ùoÝÕWøÁ·Ž¶f5§VÈçÛ:†1ÆSËׯç¾óÍ㉄EPJ)?ýùùùÅÍŽ¶ä™Sc©zµ800ÂL³Tª½{aº¹9ñê›·l“ý›=Ò–ŽÖë•ÂÆZ,‘jëè#„­o”ù› zʾýÍ£í-?Æo,ËÕ'Ý@"Jé™ÕR©vòøˆä $AJýËoÎgs%èéJkf׉;·‚ÀÃ(D©PJ!Šƒ@(„•Bž'ÅvC·¯êîHx!ºB×§vrj˜iø)¥t“-­sjU“1&¥DÛ®!,Ú^=ŠDm]B)9 EB áþþvf²Í|¡T©¦!A¤Ú¶!1®`D8B¾ç…Ò•1Æ9èëÛÝo2V­×oÞœ9p`$‹¸¾;yw2ðjƒŠi›$Oö Œ(…^}}|x¸£¯§M)ä9Î/ÿ~6[J&íoýè[ïO"¥þÛõ!Šb à d)ÀXÁÏ~{ñöݵ®ŽäWß#¥´ ‹06;Ÿûç_ž€Ž¶ä÷¾uº¹9"ñÞ•ÙùÅÓÇGêÇåÂR×À(Hùâë· Ãøþ?œPŠHÎC„ÀúzáýùÏ ÚÛ›`#_þ·ÿxŽ1ç|zvå׿¿¬Å#'Ç$àå…%JHÄ „ªÔ*š±Kwð|ÄÇà&Ñý™?JÖ†58Ø?0ÐgYÆÜÂê /]€¯=yb÷îþz½:3·poñȺ”€É¾N0DMšL·Å“©Ýc#&cKË«ÿùgoëtïñ£CS‚f*Êõ=)å{gîN¯Àw¿q¤»»¹îº¹l®»Œ ôê›7•R?úÎiÎ9Æ”*U¼ŸÿæÚúF±£-õã>j›¬^.¶vvBÖÖ¶®ßZÊ4'^~ó–m³úñ£Ýí p·œoní²"1BØüböýÙyhoozþÙ#©TtþÂäÂBö̉‘£»´™Œ0úýËã»F;wB”ªŸÿê=º‘¡Ž¯>q!´°´°™Ë557Çã©b¹¸±‘%tš®á8R(¦µ72ÁN¹î”|_Œ¡L¨UrÎc: ¡‡º—]hÝi ©.ŒBHŒ!$$`0¥ „0„ˆÜ)Q€T2)¹ÌJç‚1ÜŠØÜw’m•*¡Bº7ƒöÈ öîß?*”ZZ\]YË9s)T©Ô'''ƒ †S‚0&ÁH‘x< —®Í94’LÆ ðÜ_l£.úø™±·Þ¹{pÿ@_ #JJW$†ÊgKÿù—— ÅúÐ@˾}\·4b¦1߀ºúá¹Kãó¥Rme­pøàà?~ÿ BHrWa•Lw÷î…ÙáÁööÖ&…(ß4Bh-[þO?¿àyAS"Òœˆ¤“Ñýû0ÖÓ£¤Ï_{ãÖû—§5ê~ò½G"ÙåÕ¶Ž®ž—rL©óç/‹%Ãbã¼ÇùC"f‰74ÖÚ ³F@ B,ËÞ³gO[[:_¿1ýæÛ×RÉøóÿð¸m3Ïs¦§ï--ÝÊá¾ï;Õ&A`ÇÓ==]]mŒ¡‰©¥ùÝy}·¿~|l¤Ë´M¤<¤Pà#ë\Ê·ß¼pež8;::Ú.¹,Ëm}H¡w.Lô÷fû3!‰ÁüÂÖ/wÅñ‚þÞÖï|ë¸m2¯V‰Æ“H‰‰É•;S+ûvuýo¿¾ ?ùÞñ¾Ž„RÂó ±¦vjE‘R3 Û¨ëhKþã÷N_½±T,Ï­­•ŽêûW?: ‚ÀCHQj½siæ‘“#ñxTJÍÈ­~û‡ËKËyØ;Ö÷ø¹ýJ¡•{««ËëGNœŠÅb A!táü¥r¹ˆ0â{ dz¾h4ÍÂÆX:æü4Õ~B-Á´'“RªÏƒæ$´þÑPÞvo"¤@P F.”Ò˜Ažç9ޱP4ªÝP êÕºZ­J!$(Bm7ìPº$œRÚÓÓ64ÐF…Rç/ÜèlÏœ:uON/f³kŒp‚€b®aX®/-‹Uën«"G*…R®ëýò7ç³¹R2iÜÛ;1³öÜ³Ç ƒb)¯b2…RêÖÔÚþù%Ø¿»ó‡Ï—sî#f—¶j¿øýv9ÌZ¶ôÛ—¯¶g’'D£{0€ïs§²Oe¤D³‹Ùb±~êØ0RÄçœû®+)××Kÿéïéª_;jž956Ð׆”@ ¥êu÷ûÕ{ó‹9èkùÉ÷N Š…¼‰¦[¥ÚÂÂÚáÃÃÝÝíŒ(DHkkûÑ£iËŠéê¨Î\3™™/lMM-dZ[+•ÚÂÂ2HîûeL ] :ÀíéíîïïN§ÓJ©_¾81µ°kWÿc«TjwïÎlnnˆ p ¨´X«E‰6µ·wwtµP 7nÍýñå«ú„}瑾P¢&…0í¸Ë=BÈ¿üáÊÄÔ*ΥŠ„Ð<(:`뺎P(LÃü€W³±‹iš®ë†þL}¶&ÕlL~ -–e¹¾kPŒu’ÇEÄf€KÉ%—¾ï[ŧSIÀÚ.c¡aL‚4 @s!¥Pƒ¸˜ P©T¢»³s`¨›²ºž›œ\Üp¤µ9ÁôìR.»Ž!ÀX( D Œ9¥Ô00ÆPÈMMEžïþê·ç³¹2”JN$b<ÿcˆéW¥ô#ØJJ€WÞ¼ûæ»SðãçOŒõ8žàR˜nÍÿ—®9N?|þLo&´BªUßwëÔ€D¢•s¸xyNå’òyÃ0’É8Aj}³ôÓÔut¤~øü©Ls c‰„$­Ôêÿñ§o­eKpúøðgws. ù‚OBÍÌ­OLÜû‡çNxdÌ–JB3M„ĶOTssÓÉ“•RácGÆ$÷kµÚÖV©X(OLNú(‚¡­£­£­e` Ï4Í\®ôÂ+0ÀsÏ>2:ÚW(ËåòôôB¹\R¢l3ü`P˜‰{û‡Z3­­íÍ–A/^žxí­í:¯ÿö_=ÑÕ‘Bp¿ÌˆAÍ(çRâŸýþÂRïï=wjØçàyn,Ö„úåï.Ú××ÕWAÀ˜"®Œ/ýþå[ðÄÙ}œQR*% ƒ*¤~þÛ+­É½cu?øöÑîîÖjU8^YðúZqüæRS":·€}çto+`¬û»®Ç}0¶¢­Pï_žQ :6ìs̹¡º|yR{Îöíé}ê±CJ‰üF^)58<¬š_[^Î;wÊÅbˆ@0!°RÛSÀ˜¡±ƒ1®9žBD þ€—å¾ÄÓ±ß÷5ul^T«Ú:ÔçhÈéX‚ïû¥çJq `¾Ï3]×F•ïûA êu‰°Þþöj¹Ž”Š%bA 0ÆÞá !P#©3͸éííèë֛ǻço$‘'?Wkõ[·f|·J©À0%(…¦ºy€A!ÑX"Aò|ï¿~_£.™´¿õµãíM [)1äSЉ /½qçíóS©dôß>™NÇëu_(¤„ÚÈoÞ¸³¸x/ßþTww3çœó æN­bX4†á8ÞKoÜíïm9´¯€äs›†Á’É$!juu+”uƒý­?úÎ#Q›a*¾Àø…KÓkÛó#ûvµ+É%÷ZÚ’Aà½ýî„m³ÿñ_ ‚z5?uæX?`<·´±ž¯__.ëV,èI%m„Ps“µoW‡À*ûZê8v¨¹V©9ž‡ˆLuÂ!¯¾~íöÝùs:vd·çyÅbyuuceeµZ­ˆ ÆÅ}Ôa  À6)3£ƒÃƒmQÛVJüê·ï…¦ËO~p¶½µIr^.å,Ëðá®®&g³É¸ {FÛŸ}j¿Ï±„Eë®ûÊk7OimŽù®‹SblºçŸ;±{¤KJ 0Â+ÙÒ^ºö•s{#úïÿÃ[ðÜÓ‡ÆF:\WÖªåH¬I)41³šË•ž<·ûÿñÿzA£®¯§…K)¯â9„ˆSjÔjÞ‹¯ßèím9¼@\‰)ÙÈn¾}þ޶ëž<·_r¾µµeÚfs4.%œ¿4ašìÜ£ûAÊ»wïnn•¤4~vO:wG8e;ç¿wqnG_mBbа‚+7&¦Vþñ‡ Õÿÿ?¿ßøê¡Ãûûü@ú¾4í”ðòë7ú2=²ûú%úÓÓÕT-×…ð8w#‘X4EÍ-å._>vdl '-„ª”ª‘X„K~ñê4ôtµ<ýÔ¥P©TŽÇ“ˆš¼üêÕÃû‡;;›B·oß][[ç’„"JÉÆ9ιëKX6”Ñ<$©H{µ¥±\¨’êO!:x½íüØîhG8ç”ebÎ%Æ:PD£v$3M3‘ˆE"¥Tk&–LÆnÞž ‚àØ‘1Œac}czv~kk‹ ¢J¥’­™Öx2ÞÖ֢ﻰ°6~{~°¿óÀ¾!Li½ê®¬¬on•â>cŠ!¡í\ו€…b¦ÚѾ˲¸ïÿú÷ÛŽ©áÁÎo<} ‚À«lå‚  Dm;‘È`Ãøõo/:^ðƒoŸö9x^ y^^óF29vdøòõÙr¹þä¹ýP-W…B†A-Ë`L•JÎ;ïOb€g¿zÌŽÚRòr±ˆ‹X¥Äúzñg¿9¯QwúøØWŸ8 ½ÄÕrÙ眙6ŸX®þóÏÏÿøûgRɸPËõ+ãs¾ë?ñØ‚T¥V»·¸ÂL666²²’s}1Ü߈ëg!R(5=Çf²|±z÷îÊF¾¤Í*-o{z2M‰H¹ì"„öŽu%Sq“1×õ§æûþüü9œŒÛ‘wÞŸ*Uê_y|¿”¸X¬ƒôm›ÙÑ(”Ëõ·Þ»­úê‡" ‚ R©QÊD,Çñþýÿï…–tòûÏ?Š ¼€™L(43·61±tòø®L¦©^¯ß¹3U,„PŽ#…"RN)ÀJyž§ÑJÂÆLÎmUS»RôIZ éú™¹ aúTB‰©”BoWa+À ƒä®¢XJ.9'„”JNSSôЗ^¹táÒ­3§ö¶·gÚ:Z0Æ4Ëøýò¿ñ›sSKƒýíÏ={†1†Ê®mær›A˜„ø„HxN¡¡„ @™m›ãžž.˲\ßÿíïßËåJ:ôyæÄn<'›]Ói4l eJLA‚ëú_ú˜ëKŸ ²º–½zcþèþÁ¾¾6MÛ5:Ø…1•RÆ1@HU*µ›·ïMÏ®?ynÿP­ZÞÌ®qÀ™ÖNÎy.W Q÷ÄÙ}§OyžW©”6sY’™¶Ée,KÆmÓdѨ‰1¾ywei)»¾Q÷ì±WÞÿO?}åðÁ¡áÁŽxÜÖµ‘///ç6òååÕüÑÃCÿæGOB@ÊBqkem³P(ú¾«D@GP€1¡|¾%¦“xÌ¢˜ÛQÛñ¼ßýî|n³gNì:t`ˆ U-o ¾ï+!3%Å$Gˆ–±µUÉd¥­ò•ñ9„Ô7¿v8bY€AJÑÞçý;ñ¤™JÚ©K׿s¹òÜRþ‘ãÃÿî¿ÿ*çÒój›¹l¥²ÉK$2Œ¡¥åÜoþpE£î+çvØ×S­º¹ÜZi3§B 51†”BBaƒ=ýÔ¡ÿåÿý2Œwôµ>qvŸ”œsw}u¹R)QÀ”_/sßíéHýî…KÝËYÃ2í Q¬Ë)‰Ï¹1RcbPPÊóÒ´RŠ 25·6Üßö­gö¶6'– ÙÍÒ»çgÞ|û¼ðÊ5ÛdgO÷`ËÀ÷wDK“ „ˆzݽzcF)T(×nÞ^9~¸?þè;'‘"ˆ ,}ò<§Úݽ~ã^Äß Þ»85~{ißž¾Ÿ|ﬞç„"–Á}.DpùêÌøÍ¥'Îîìo–RTËùå¥Eà&„„R‚sÿ‰³»~ú‹w´r¾k´ë™‘.)e±\ùÙÏÏËõÓLJODJ$.^]ØÚª=þè°ÉÌÀ 0ŶÉ‚Îö¦7Þ¹ÿZ45 +ã³¹\ù޽ܑCCÿæ'Q Ü/ •Jɲ"&³ JɈ…M“H„ÐäìÚÜÜZ©R;qlwOG@Þ[^[œ_ô]@*)$€Ä€FB©ˆï+.Aø´z¨ó:ºpŸ3¥Q|5rBkY§q ÃFj£Æ8;çÜ4M)¹eP ~4JcÆIܶ C±H„&”H&SMMÍ¡¥ÕB6WzïýÉPëmmM ´·¥ã]i]“S)m•¶6K¥Mßç^ ¤¶‘¥ô9;]È !ˆ ƒ©Tj`h :A¢îñG÷Ü߃”ªUJùüºç9"€Ò¨i›v4™L&šH¡õâ¿üáZ©âôt¥OèëIïdý jP|óöâKol“I;4ÐÚÚ4Ð׆Ó¥"¹ìšïûˆÛŒFb±L¦Y(ås\ µt>5³¾¸¸¢=U‘H¤©©©³³3‘HØf DÀ%çœ#%K%D¥RZ»7OPÀLe*°£,‘°ZÛ{M; ×o­xNpwvc-[yhàζٹS!õ䣔bɹÔÕ¼B|Ÿ¦¯¿=§³/½1ýÐë˜&{äh/"cyæXÆ8"Dr¨×«€HlÛq_r¸peþíóSpöôžCú1† J ¦2—«üê÷=/8~täøÁABˆ|ãÖÄÆúzssÄ2Œ¦¦æh4ÚœiÆXbÀR`ª!T,Vþ/o–Jµý{ž~â@ ‚kãó['¶µ%¤ïºžW3™I©ØPˆ\¿³üêë7v¦l0“IŽ´a¡Ji3»¶Ä¹³£±h<§2`bnãåW¯@wgfh¨cl¤W‹œÕÕõlvsîyžJ×H \!˜ËAˆm9dš¦nßFÝvº²’B(,ÄÒk¤…«B«Q§n…æŸösZ–Ë…´œcÓ4c±XŒRjš¦†n2i·¤£¥ÛÅ—TCŸþz©ä,-oT*N:´ˆÁ'DÄ)¾ï Òf†aDãñ‘‘¡x<êy®¯€çž=ÕÙ™Á¯®nlll(¡ên•bª;7D";§†i2ªÖHI Q« ŸcƘ”<ÓL¥”’o˜Rzß"õº¿²¶¹µUÑê·~’D"ÑÔ”HÆÆ@BOÌL-ç6·jµB(‰¤R©T*‰D0ÆH‰HL“(¥*5/—ÛZ]Í×jNh]†Çu>CWW*І´í\© ÛÅi:KQBaŒ©A…@œc¡¥ÆR c¦Sl×(DÑËÅq=¼¶iûÜWBaŠ9çØç2›ÝªÕ<Îe,“RÚ¶­TÐÑUB–A)EˆxžW*ÕÊU!F)M%cJ?5(Æxmmszv¥VÙbLÙ6³ –injiIël fŠ1€”€)ÆœË_þîÝâ}ýÉx4›ÛJ$"CÝ--q¤ã8Åb±\,ÛѨ°(Ēɨ”ù¼ÓÒªe÷ÞZ.—Ûª×ë:=#‹%‰xÿÍ ôNzôðHSSìàþaɹÊqœÍ­­µµ¬ ÝÊ›™&b&çD)ÔܜЄqP­Öײ[Åb=^-ô¨F"‘D"aB*g†… Ró …òÆF!ÜX}ߥ–^a;nÝ_$Líz d÷Qµ°a’fŒi‹®1¶ª§a'“0#&LB ».5’iÈé5¤YwÂô´0´¦J=ð!AÆÜ  íÔe‡Å¸–eYVdll(žŒû>Q÷Ü7Îôtµ(!ïe7·rn½îû~è‰eŒĨa#UŠaJ)¥¾ï;Žã8ŽTêÔ]5ź5ç\CÎu]=ú„=…úÐ3亮ã8õz]325º‚MÓÔ×§0h8Âd½H$B)µ,˶mýÎÑO¨ŸM說ý Ÿ§qMèwÑ©T*íííÔ—Ëåz½®• Ji2™¬T*z xžç8ŽÖkô\ …T*U­V5öLÓ YÆõ ëÝÄ0 í$·m[R¸¹ „Q‰ 7𠪵µ5žŒƒ„¨‰'£QÛ& iUèW¿~+_(ïëyäô¤¦!´µUqg}}£^w”’ˆ`¢Ƙ˜6¦ηž~#ιVzÖ• ç+F"‘X,¶ã“ ‚ Ð3«__Ÿ¯]„öq¢U¶±è.$ú(àÑÓÔ†ôí^†š!0êõzcWÇÆ(áC™ÈBg©ÎmtІ¼ zûןèÁ2¨ÄXTa°#-B˜RŠ©iÚccC‰DÌsýß½´½/~ëë§;;Ò¾Ïççóù¼ëºœû¡½*„À@=€O8—hGs‚ QÚhGK§PëÖ{^Cú+úiõ ê…¥”Ò˜Ñ{d£ išÂùkùõ?Ã%Ö,ë[„¬•@Mêܘ^«ÓúÂ-Yk a%˜^"zËÓ+Òq=þŒ±L&³¾¾®ß®µµµ\.{ž·¾¾ÞÓÓ³ºº*¥ŒÅbµZMCQOúúúº½FC‚=2:>‹é§ÅbzÕrÎ}ߥ+Q)jÁL–HDLÓD8é¥RÉööV=û«ë¹|¾ôþÅ mn{t?€òÝ ´YÚ*Uªõ*÷}…”Rž”À}IA$"y€P]W†Ù’zTÇá;‡¾…~Z½³8Ž£w}‚Lß÷u…jØ­6D”¶ÜÂ…¥ý¡®§o¡Û ,ê‡FÌèe.—F¶•´Õ?Ëü¡¥œF]ÈüÑÜÐÛˆ:¥#‚RɈÔv](ë¶ ìèÐÐ@ssÂó‚u_ædwg†s>7³´¹µé9ç¾BJ ¥T!¾\¼aLõ³ítØá!´<ÑG<}N¿0Тªß«ñüðäpÚ‰BU¼‘’(¼fCSBÑÚ>Sgð…£qŸ†`gÇ ÓõŽFڕЉ­ÁÞQ+ü^G?Xx„ï«ÇGÏf˜VêAz¿Öbƒ$p8„pŠ%$ Œq<ïlJ$R åµ›sÚpu]ÿÚÍÙ–tò{ß~D)T®Ö³kÙz½êy^ és¥T ”HPˆø>æ‡Ï"Äó¼prÞm“rçhLhÖ¯¼ãDùX„¼ál6js Ÿia£hUÍÐÞ#„¸®kš¦~ÛmÜ0¤ÉØô×3#‘HoKK !ôËß¼¢®«#b~þÞæfN÷ˆj´k ^AjŽÀzM<°ôÃÅÚÈÔ>y¡öjŠþ‡ù6Bì5&4<пúO ]èv~  }x…FÀ4>Ü•·‘°£/…zGã£>p…ÜæÃ!UæÝ'P ;Ît‰¥G©’ ’M1“™c»w777a ¥’3·°ö À[³ï_œÈdšž{ö„aÕjýÞÊŠã8~Ý ÏçRåû;RˆÕ:ßéO5êÂçùð”…¾E¸}ƒÅÜ0n Ô‹cF†ú4‘Ûï_¼¨%¾ñÕÝ™ ssK…|Þq<(ÿ€5,Q±ì:žÀbé?ð´áƒ=HŸ$×j8t^¨´?ðë졳ð—^磶FïPø ‚T8ÑH J€2D£ñT*uèÈŒ¡X¬Ï/®†±{¬)…º}{á­÷n%‘ï>÷¨1ªåúÂÂR½^DàûÜóDðPöJ >Ç媉D4[¸ÉþÙ){à-ÓJ>þ*Ÿyh÷7†"”RŒ(F„iì…j•a–ìÍ´6ƒ„ß¿|u]]->çu®ë |`¸1pŽŠe×ç8>C½]¿‡®ÓƒmÇ~)ÅU„©D,’hjÚ»{,‰H€ë7fm“ííѦ `|gbñíwo&‘¯íd"©Tj s u·Î}¿êrà÷KÝRœ+/@^€Beäs4JôS»1¥a¬#4Ð5ê C°Cø‹6í¨Ö0[[›%ÀwPwî̾îîŒïó K…¦xJq x»­BÈw¡Tqêž&ÅûòøÛm¦Û HºY´¦â'Tš¶A1ŽÄb‡Ä”Þ[Éæ ¥C†whcAheyãíwof2‰§ž8’LD+gzr¾V«¸>—R .9Ƙ Ž1V¸ÄBø^®ÏÍöô©@NÓži?AHDA±4¨4 Åú{†…¨Óæòê4éúìüâææ¦çxRrÝö-T$Uj¾/©R_6gû$PþS) E,l¤lÎdNœ8ß\PÜ? €76ŠœÆxy5ÿû/fšÏ={*‹•Ëõ»w§«õj½îû~ ûÃ¥"r<å¨V«aŒ?Ãõ)H<=‚aýÑ6º€T2¦(¾ŸÅ²W4mÛèÛ–u/Þ—uuSs…bÁó>€:ãúÒqd݇?ÁéûåñWQ/}  —`8•ÔmOh<=~ü°ä|üöìÀ@gS,â»þêz¡¯¯ææV^}óÚ`û“Å 噹·^w=M–¯»”J„—\ ås¤ëqþMú—Àƒ0j»;Dƒ§Q)eP`Dš&è„°ðO”RJ Û¶‡û[Ò)øãެkh02»¹¹éyžRB‚THI.9çT¾ßÿ;moÿ‰¢ì›D P,9÷‹$£ñ#Çö !nÜž;¸X)UªÔêu¿··])¥ÛÍÜ?tüè.„P~£0=»àÖ@Hßç:ÁµÁõJœ@`)ùÇŒi} ¼mBhÔýiKƒ*]ó:{4D5êúZÒ)…Ð^¸¢îÐ!¤Ôôì=:¡#àB„]‘¥€@ç_¢îo®a>Š ˜€‚KÙÙ݉š˜ZÜ5Ú'¥œ›[noomkK)¥nÜš½teò©ÇŽ ´À½{Ù••õz½^w}8GyA°íc”ØåHJ„1|NÝ' ¼0×a‡ø};ˆe2 TÒ0Ïm·&·,+”u ¦f²kkõºëŽëoði}‰ºOòx`Œ)F€À¡––”çÍÍMÚ¾î€r¹þÎû7}×ÿþwOÄbœ‹¥¥µµl®V«¡¨àNº,‘\ E\ÁRòFfØ/÷§4̰hÚž$ ª 0¤¶ÿCaŒ1#‘ÈØØP2o”u»võÜ?(¥œš˜Y__wœšãI °pç¸î.ð%êþöâ.”xmS jÆNJÁ`„R#“I"$6ò[’ ”I¨••üZ6ýÆÜñ£c÷@½^[\\+–‹¾ë‚ô— ˜ipΑRŸÓ@lçÐ…y_J¼?ïÆÔJ¦w:jLj2 ň$H!@R Œ0 …1ÂL›Åb±d*îyÁ+¯]Ó¨Û=Òóȉݜó¥¥åÕÕU×­»¾z@¬‰ÏpcÄ/ ¬S@v`Fð}¯¦ÁÀ2€`0M¤„‡A¶gâ¿ùò˯ëj·æ®®–ÿñß>ƒ1– ¶¶¶–––Üz]y>ÅÂB1¥œ»>aø\RŠõÞzã>ïØûÛеÿײ¬Æœ‰ÆB˜1÷{áÃ0t‰ÍÈP‡eáò'¦fVçæ–uþøÇÌ£ûòødÅàýª]Á°gWo:GD0ÅRJÔjÁ½{¹|!LRש'Y¬¡º&úbŒù›N€.Ê é$àƒÕîái˜Üq«PÓ4…$ŒRÀÛžêzÝ_\ÌÎ~‰ºÏ<ðÂ,s ¿JÕ£Œ`‚ ƒ‚„ºçå Õìzyfn¹T®è+¾ÝÕYêòë°v[oÓ:ó ƒº¿­ªê–º@;ÜÃSKÂÚx=ôzÿÛ*mw<¯T*år¹R©|‰ºÏ#WV¶*Âu€®Ž ëntdH‚v˜]]×ý‚ ý[ ´VÂB²F˜Aü©ôᇺ®¾^¯€®Ýö<¯^¯ë¢Ò/Q÷™7ü¶9È5åqXö¥KäJí´Ô²®±Ì´ÑÑ¿!“èßbÜu-s#ODˆ·°ôKk~8 \û‘à ÓñŽ/Q÷¹À^XÛÛ=1·sÿµ4k¤^møI¤±¨ïó¯û„œ+z¼B"Àí¢ïzö°:îOWjh>,‡{hQé—Çgß¿¢-½ªv kšµj õ_z«mìáñ%ðþ¤ô¤T›ga¦e#Ø>&f>\ ÷QE¥_Ÿ}ÓîêÁ ˆõöªA¨ë¾õ6ý÷0Ñýp‚æðù´*G¿<>_RQ3MiøéFá_€ݧ0”Ð'øòøòø8 æïóøßÀ9JNÖUÇIEND®B`‚openlayer-2.1.orig/CMakeLists.txt0000644000175000017500000002737210647144172017270 0ustar georgeskgeorgesk# ------------------------------------------------------- # OpenLayer cmake build script. Creates makefiles for unix # based systems and/or # project files for a given environment like MSVC. # # TODO: # * Create CYGWIN TARGET # * Fix MSVC # * Seperate into modules? # # Written by: juvinious # ------------------------------------------------------- # ------------------------------------------------------- # Ensure that we are doing an out of source build # Prevents any mishaps # ------------------------------------------------------- if(EXISTS ${CMAKE_SOURCE_DIR}/CMakeCache.txt) file(REMOVE ${CMAKE_SOURCE_DIR}/CMakeCache.txt) file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/CMakeFiles) endif(EXISTS ${CMAKE_SOURCE_DIR}/CMakeCache.txt) if(EXISTS ${CMAKE_BINARY_DIR}/Makefile) file(REMOVE ${CMAKE_BINARY_DIR}/Makefile) endif(EXISTS ${CMAKE_BINARY_DIR}/Makefile) if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) if(UNIX AND NOT CYGWIN) message(FATAL_ERROR "Oops. Don't do an in-source build. Create an extra directory change into it and run cmake pointing to the base directory. IE: \nmkdir mybuild && cd mybuild && cmake ../ && make\nYou may need to remove CMakeCache.txt and the CMakeFiles directory in ${CMAKE_SOURCE_DIR} if you can't get rid of this error.") else(UNIX AND NOT CYGWIN) message(FATAL_ERROR "Oops. Don't do an in-source build. Create an extra directory change into it and run cmake pointing to the base directory. IE: \nmkdir mybuild; cd mybuild; cmakesetup ../\nYou may need to remove CMakeCache.txt and the CMakeFiles directory in ${CMAKE_SOURCE_DIR} if you can't get rid of this error.") endif(UNIX AND NOT CYGWIN) endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) # ------------------------------------------------------- # Set working directories # ------------------------------------------------------- set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) # ------------------------------------------------------- # Directory in which extra macros can be found # ------------------------------------------------------- list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/build) # ------------------------------------------------------- # Add in uninstall target # ------------------------------------------------------- configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") # ------------------------------------------------------- # project name # ------------------------------------------------------- project (OpenLayer) # ------------------------------------------------------- # Including needed macros # ------------------------------------------------------- include(CMakeMacros) find_package(ZLIB) find_package(FREETYPE) find_package(PNG) find_package(ALLEGRO REQUIRED) find_package(OpenGL REQUIRED) find_package(ALLEGROGL REQUIRED) MARK_AS_ADVANCED( CLEAR ZLIB_LIBRARY ZLIB_INCLUDE_DIR PNG_LIBRARY PNG_INCLUDE_DIR OPENGL_glu_LIBRARY OPENGL_gl_LIBRARY OPENGL_INCLUDE_DIR ) # ------------------------------------------------------- # User setable options # ------------------------------------------------------- option(CREATE_STATIC_LIB "Make the library static?" on) dependent_option(DISABLE_TTF "Disable TTF Support" off "FREETYPE_FOUND" on) if(NOT DISABLE_TTF) set(TTF_OK 1) endif(NOT DISABLE_TTF) dependent_option(ENABLE_INTERNAL_FONT "Use internal font renderer" on "TTF_OK" on) # dependent_option(DISABLE_PNG "Disable PNG support" on "PNG_FOUND" on) option(DISABLE_PNG "Disable PNG support" off) option(DISABLE_OLD_API "Disable backwards compatibility with 2.0 and below" off) option(DISABLE_STATE_CHANGES "Disable state changes" off) if(NOT MSVC) set(CXXFLAGS "-O2 -Wall -fexpensive-optimizations") else(NOT MSVC) set(CXXFLAGS "-O2") endif(NOT MSVC) add_definitions(${CXXFLAGS}) # ------------------------------------------------------- # Check whether to create a shared or static library # ------------------------------------------------------- if(CREATE_STATIC_LIB) set(CREATE_STATIC_LIB STATIC) else(CREATE_STATIC_LIB) set(CREATE_STATIC_LIB SHARED) set(OL_SHARED 1) set(OL_LIB_BUILD 1) if(MSVC) add_definitions(/DOL_SHARED) add_definitions(/DOL_LIB_BUILD) else(MSVC) add_definitions(-DOL_SHARED) add_definitions(-DOL_LIB_BUILD) endif(MSVC) endif(CREATE_STATIC_LIB) # ------------------------------------------------------- # Paths and system setup # ------------------------------------------------------- # ------------------------------------------------------- # UNIX BASED SYSTEMS # ------------------------------------------------------- if(UNIX AND NOT CYGWIN) # ------------------------------------------------------- # Take those user options and set the necessary compile time preprocessors # ------------------------------------------------------- if(NOT DISABLE_TTF) if(ENABLE_INTERNAL_FONT) add_definitions(-DUSE_NEW_TTF) set(USE_NEW_TTF 1) endif(ENABLE_INTERNAL_FONT) else(NOT DISABLE_TTF) add_definitions(-DOL_NO_TTF) set(OL_NO_TTF 1) endif(NOT DISABLE_TTF) if(DISABLE_PNG) add_definitions(-DOL_NO_PNG) set(OL_NO_PNG 1) endif(DISABLE_PNG) if(DISABLE_OLD_API) add_definitions(-DOL_NO_OLD_API) set(OL_NO_OLD_API 1) endif(DISABLE_OLD_API) if(DISABLE_STATE_CHANGES) add_definitions(-DOL_NO_STATE_CHANGE) set(OL_NO_STATE_CHANGE 1) endif(DISABLE_STATE_CHANGES) if(NOT ENABLE_INTERNAL_FONT) add_subdirectory(utils/glyphkeeper) set(GLYPHKEEPER_LIB glyph-agl) endif(NOT ENABLE_INTERNAL_FONT) endif(UNIX AND NOT CYGWIN) # ------------------------------------------------------- # MINGW # ------------------------------------------------------- if(MINGW) # ------------------------------------------------------- # Take those user options and set the necessary compile time preprocessors # ------------------------------------------------------- if(NOT DISABLE_TTF) if(ENABLE_INTERNAL_FONT) add_definitions(-DUSE_NEW_TTF) set(USE_NEW_TTF 1) endif(ENABLE_INTERNAL_FONT) else(NOT DISABLE_TTF) add_definitions(-DOL_NO_TTF) set(OL_NO_TTF 1) endif(NOT DISABLE_TTF) if(DISABLE_PNG) add_definitions(-DOL_NO_PNG) set(OL_NO_PNG 1) endif(DISABLE_PNG) if(DISABLE_OLD_API) add_definitions(-DOL_NO_OLD_API) set(OL_NO_OLD_API 1) endif(DISABLE_OLD_API) if(DISABLE_STATE_CHANGES) add_definitions(-DOL_NO_STATE_CHANGE) set(OL_NO_STATE_CHANGE 1) endif(DISABLE_STATE_CHANGES) if(NOT ENABLE_INTERNAL_FONT) add_subdirectory(utils/glyphkeeper) set(GLYPHKEEPER_LIB glyph-agl) endif(NOT ENABLE_INTERNAL_FONT) set(WIN_LIBS -luser32 -lgdi32) endif(MINGW) # ------------------------------------------------------- # MSVC # ------------------------------------------------------- if(MSVC) # ------------------------------------------------------- # Take those user options and set the necessary compile time preprocessors # ------------------------------------------------------- SET(CMAKE_CXX_FLAGS "/nologo /W3 /Gy") SET(CMAKE_CXX_FLAGS_DEBUG "/MTd /Z7 /Od") SET(CMAKE_CXX_FLAGS_RELEASE "/MT /O2") SET(CMAKE_CXX_FLAGS_MINSIZEREL "/MT /O2") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MTd /Z7 /Od") set(CMAKE_CONFIGURATION_TYPES Release) add_definitions("/link SUBSYSTEM:WINDOWS") if(NOT DISABLE_TTF) if(ENABLE_INTERNAL_FONT) add_definitions(/DUSE_NEW_TTF) set(USE_NEW_TTF 1) endif(ENABLE_INTERNAL_FONT) else(NOT DISABLE_TTF) add_definitions(/DOL_NO_TTF) set(OL_NO_TTF 1) endif(NOT DISABLE_TTF) if(DISABLE_PNG) add_definitions(/DOL_NO_PNG) set(OL_NO_PNG 1) endif(DISABLE_PNG) if(DISABLE_OLD_API) add_definitions(/DOL_NO_OLD_API) set(OL_NO_OLD_API 1) endif(DISABLE_OLD_API) if(DISABLE_STATE_CHANGES) add_definitions(/DOL_NO_STATE_CHANGE) set(OL_NO_STATE_CHANGE 1) endif(DISABLE_STATE_CHANGES) if(NOT ENABLE_INTERNAL_FONT) add_subdirectory(utils/glyphkeeper) set(GLYPHKEEPER_LIB glyph-agl) endif(NOT ENABLE_INTERNAL_FONT) set(WIN_LIBS /user32 /gdi32) endif(MSVC) # ------------------------------------------------------- # Added stuff for osx # ------------------------------------------------------- if(APPLE) set(WIN_LIBS "-framework Carbon") endif(APPLE) # ------------------------------------------------------- # Setup some vars that might cause dep issues # ------------------------------------------------------- if(DISABLE_PNG) set(PNG_LIB "") else(DISABLE_PNG) set(PNG_LIB ${PNG_LIBRARY}) endif(DISABLE_PNG) if(DISABLE_TTF) set(FREETYPE_LIB "") set(FREETYPE_INCLUDE "") set(ZLIB_LIB "") else(DISABLE_TTF) set(FREETYPE_LIB ${FREETYPE_LIBRARY}) set(FREETYPE_INCLUDE ${FREETYPE_INCLUDE_DIR}) set(ZLIB_LIB ${ZLIB_LIBRARY}) endif(DISABLE_TTF) # ------------------------------------------------------- # Create the necessary header file for the library # ------------------------------------------------------- configure_file(build/OpenLayer.hpp.in ${CMAKE_BINARY_DIR}/include/OpenLayer.hpp) # ------------------------------------------------------- # openlayer-config for *nix based systems # ------------------------------------------------------- if(UNIX AND NOT CYGWIN) if(NOT DISABLE_TTF) if(NOT ENABLE_INTERNAL_FONT) set(R_GK -lglyph-agl) endif(NOT ENABLE_INTERNAL_FONT) set(R_FT -lfreetype) endif(NOT DISABLE_TTF) if(NOT DISABLE_PNG) set(R_PNG -lpng) endif(NOT DISABLE_PNG) set(REQUIRED_LIBS "-lagl ${R_PNG} ${R_GK} ${R_FT} -lz `allegro-config --libs` -lGL -lGLU") configure_file(build/openlayer-config.in ${CMAKE_BINARY_DIR}/bin/openlayer-config ESCAPE_QUOTES) endif(UNIX AND NOT CYGWIN) # ------------------------------------------------------- # Source directory containing all the necessary .cpp files # ------------------------------------------------------- aux_source_directory(src SOURCES) # ------------------------------------------------------- # Include directory # ------------------------------------------------------- include_directories(include ${CMAKE_BINARY_DIR}/include include/OpenLayer ${FREETYPE_INCLUDE}) # ------------------------------------------------------- # OpenLayer Library # ------------------------------------------------------- add_library (openlayer ${CREATE_STATIC_LIB} ${SOURCES}) # ------------------------------------------------------- # Create the library # ------------------------------------------------------- target_link_libraries(openlayer ${ALLEGROGL_LIBRARY} ${PNG_LIB} ${GLYPHKEEPER_LIB} ${FREETYPE_LIB} ${ZLIB_LIB} ${ALLEGRO_LIBRARY} ${OPENGL_LIBRARIES} ${WIN_LIBS}) # ------------------------------------------------------- # Demos # ------------------------------------------------------- add_subdirectory(${CMAKE_SOURCE_DIR}/demos) # ------------------------------------------------------- # Installation # ------------------------------------------------------- if(NOT MSVC) if(NOT ${CMAKE_INSTALL_PREFIX} AND ${CMAKE_INSTALL_PREFIX} STREQUAL "") message(FATAL_ERROR "You need to set the base location where to install OpenLayer (ie /usr/local)") endif(NOT ${CMAKE_INSTALL_PREFIX} AND ${CMAKE_INSTALL_PREFIX} STREQUAL "") install(FILES ${CMAKE_BINARY_DIR}/include/OpenLayer.hpp DESTINATION ${CMAKE_INSTALL_PREFIX}/include) install(DIRECTORY include/OpenLayer DESTINATION ${CMAKE_INSTALL_PREFIX}/include PATTERN ".svn" EXCLUDE PATTERN "*~" EXCLUDE) install(TARGETS openlayer DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) if(UNIX AND NOT CYGWIN) install(PROGRAMS ${CMAKE_BINARY_DIR}/bin/openlayer-config DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) endif(UNIX AND NOT CYGWIN) endif(NOT MSVC) openlayer-2.1.orig/INSTALL0000644000175000017500000000534510572777056015567 0ustar georgeskgeorgeskINSTALLATION Before compiling ensure you have the following installed and in your path: - An ANSI C++ compiler - OpenGL Library - Allegro Library - AllegroGL Library - Freetype library version 2.1.10 or greater - Png library - Zlib library NOTES: - The build system is currently being moved from cbuild to cmake (http://www.cmake.org) - You can still use the cbuild system however it's been reported not to work on some systems * For more information on the build utility known as cbuild go to http://awiki.tomasu.org/bin/view/Main/CBUILD - It is recommended that you use the internal font renderer but if you insist on using GlyphKeeper it should be like this: * GlyphKeeper specifically built for ALLEGROGL * the allegrogl version should be named libglyph-agl.a * The sources have now been included with openlayer in the utils/glyphkeeper directory * You can build it manually or try using cbuild passing 'glyphkeeper' as a param - For precompiled versions of the library please see http://openlayer.berlios.de for more info. - If no package exists for your compiler you'll have to compile OpenLayer's source files and include them in the same archive. Also download the required external libraries and follow the installation instructions included with them. Compilation with cmake: Create a temporary directory in the root directory of where OpenLayer is. Change into it then do the following from the command line: Linux/Unix/OSX: ccmake ../ cofigure it to your hearts content and then generate the makefiles. Then you can proceed to do make && make install Windows: you can run cmakesetup from anywhere as long as you point the source directory to where OpenLayer is and the binary directory to the temporary location you made above. You can have the setup create makefiles for MinGW or MSYS (CYGWIN generated makefiles will be worked on later). Or you can choose to do MSVC project files (which is currently WIP). Then just configure and then hit ok. You can then proceed to compile them via make or use msvc to open the openlayer.sln if you created msvc project files. To Use: - Read the provided documentation found in the Manual folder to know how to use the library - #include in your project's sources LINUX/*NIX and MACOSX - Link your projects with: `openlayer-config --libs` if you need the flags do `openlayer-config --cflags` WINDOWS - Link your projects with: "-lopenlayer -lglyph-agl -lfreetype -lpng -lz -lagl -lalleg -luser32 -lgdi32 -lglu32 -lopengl32" If you have issues with freetype and get messages like: .... #include expects "FILENAME" or you need to pass in the freetype2 dir location when building, ie: "-I%MINGDIR%\include\freetype2" openlayer-2.1.orig/include/0000700000175000017500000000000012262355751016130 5ustar georgeskgeorgeskopenlayer-2.1.orig/include/OpenLayer/0000700000175000017500000000000012262355751020026 5ustar georgeskgeorgeskopenlayer-2.1.orig/include/OpenLayer/RawLineStrip.hpp0000644000175000017500000000427310552323114023126 0ustar georgeskgeorgesk#ifndef OL_RAW_LINE_STRIP #define OL_RAW_LINE_STRIP #include "Rgba.hpp" #include "Bitmap.hpp" #include "Declspec.hpp" namespace ol { template< class std_container1, class std_container2 > class OL_LIB_DECLSPEC RawLineStrip { public: RawLineStrip() : totalLength( 0.0 ) {} // Add a vertex to the end of the line strip // inline void AddToEnd( Vec2D vertex ) { Vec2D *previous = vertices.empty()? 0 : &vertices.back(); vertices.push_back( vertex ); if( vertices.size() > 1 ) { float length = ( vertex - ( *previous )).GetMagnitude(); lengths.push_back( length ); totalLength += length; } } // Add a vertex to the beginning of the line strip // inline void AddToBegin( Vec2D vertex ) { Vec2D *previous = vertices.empty()? 0 : &vertices.front(); vertices.push_front( vertex ); if( vertices.size() > 1 ) { float length = (( *previous ) - vertex ).GetMagnitude(); lengths.push_front( length ); totalLength += length; } } // Delete the first vertex of the line strip // inline void DeleteFirst() { if( !vertices.empty() ) { vertices.pop_front(); totalLength -= lengths.front(); lengths.pop_front(); } } // Delete the first last of the line strip // inline void DeleteLast() { if( !vertices.empty() ) { vertices.pop_back(); totalLength -= lengths.back(); lengths.pop_back(); } } void LineStripRender( const Rgba *color1, const Rgba *color2, const Bitmap *texture, float lineWidth, const Placement &placement, bool connectFirstAndLast ) const; inline const std_container1 &GetVertices() const { return vertices; } inline std_container1 &GetVertices() { return vertices; } inline const std_container2 &GetLengths() const { return lengths; } inline float GetTotalLength() const { return totalLength; } private: std_container1 vertices; std_container2 lengths; float totalLength; }; } #endif // OL_RAW_LINE_STRIP openlayer-2.1.orig/include/OpenLayer/TexturedPoly.hpp0000644000175000017500000000626710552323114023220 0ustar georgeskgeorgesk#ifndef OL_TEXTURED_POLY_HPP #define OL_TEXTURED_POLY_HPP #include "Polygon.hpp" #include "Vec2D.hpp" #include "Declspec.hpp" #include #include //#define OL_DEBUG_TEXTURED_POLY namespace ol { class Bitmap; class OL_LIB_DECLSPEC TexturedPoly : public Poly { public: TexturedPoly( Vec2D rotationPivot = Vec2D( 0.0, 0.0 )) : Poly( rotationPivot ), texture( 0 ), dirty( true ) {} TexturedPoly( const Bitmap &texture, Vec2D rotationPivot = Vec2D( 0.0, 0.0 )) : Poly( rotationPivot ), texture( &texture ), dirty( true ) {} template< class std_container > TexturedPoly( const Bitmap &texture, const std_container &vertices, Vec2D rotationPivot = Vec2D( 0.0, 0.0 )) : Poly( vertices, rotationPivot ), texture( &texture ), dirty( true ) {} TexturedPoly( const Bitmap &texture, const Vec2D *vertices, int numVertices, Vec2D rotationPivot = Vec2D( 0.0, 0.0 )) : Poly( vertices, numVertices, rotationPivot ), texture( &texture ), dirty( true ) {} virtual void Draw( float opacity ); virtual void Add( Vec2D vec ); virtual void SetVertex( int index, const Vec2D &newValue ); virtual void SetTexture( const Bitmap &texture ); void Construct(); protected: void AddEdgePoints( std::vector< Vec2D > &vecs, const Line &segment, Line **textureEdges, bool lowestFirst ); bool LineCollides( const Line &line, std::vector< Vec2D > ::const_iterator start, std::vector< Vec2D > ::const_iterator end ); inline bool isInside( const Vec2D &vec, float x, float y, float w, float h ) const { return vec.x >= x && vec.y >= y && vec.x < x + w && vec.y < y + h; } class SideProcessed { public: SideProcessed() : isEmpty( false ) {} std::vector< Vec2D > vertices; bool isEmpty; }; SideProcessed ProcessSide( std::vector< Vec2D > ::const_iterator start, std::vector< Vec2D > ::const_iterator end, float x, float y, bool isUpper, bool leftToRight ); class SlicePart { public: SlicePart( float top, float bottom, float x, float textureStartX, float textureStartY, const Bitmap *bmp ); inline void RenderStripPart() { glTexCoord2f( textureX, textureTop ); glVertex2f( x, top ); glTexCoord2f( textureX, textureBottom ); glVertex2f( x, bottom ); } inline bool IsHeightZero() { return bottom - top < 2.0; } #ifndef OL_DEBUG_TEXTURED_POLY protected: #endif // OL_DEBUG_TEXTURED_POLY float top, bottom; float textureTop, textureBottom; float x, textureX; }; class HSlice { public: ~HSlice(); inline void AddPart( SlicePart *part ) { parts.push_back( part ); } void Render(); private: std::vector< SlicePart *> parts; }; std::vector< HSlice *> slices; const Bitmap *texture; bool dirty; // Indicates the need of reconstruction }; } #endif // OL_TEXTURED_POLY_HPP openlayer-2.1.orig/include/OpenLayer/Canvas.hpp0000644000175000017500000001240210552323114021747 0ustar georgeskgeorgesk#ifndef OL_CANVAS_HPP #define OL_CANVAS_HPP #include "Includes.hpp" #include "Bitmap.hpp" #include "Rectangle.hpp" #include "OlRectangle.hpp" #include "Declspec.hpp" #include #include #include namespace ol { enum RenderTarget { BITMAP_TARGET, SCREEN_BACKBUF, SCREEN_FRONTBUF }; enum PixelWriteMode { COLOR_AND_ALPHA, COLOR_ONLY, ALPHA_ONLY }; class Rect; // The rendering surface // class OL_LIB_DECLSPEC Canvas { public: // Sets the Bitmap as the active rendering surface // static void SetTo( const Bitmap &image ); // Sets the specified OpenGL buffer as the active backbuffer // // Restores the clipping and pixel write settings of the RenderTarget // static void SetTo( RenderTarget buffer ); // Refresh the active canvas (backbuffer) // static void Refresh(); // Fills the active rendering surface with the specified color // static void Fill( Rgba fillColor, PixelWriteMode filledComponents = COLOR_AND_ALPHA ); // Sets the clipping region of the active rendering surface // static inline void SetClipping( int x, int y, int w, int h ) { activeSurface.SetClipping( x, y, w, h ); } // Sets the clipping region of the active rendering surface // // Warning: The area will be rounded down to whole pixels! // static inline void SetClipping( const Rect &area ) { SetClipping( int(floor( area.pos.x )), int(floor( area.pos.y )), int(ceil( area.size.x )), int(ceil( area.size.y ))); } // Restores previous clipping region // static inline void RevertClipping() { activeSurface.RevertClipping(); } // Disables the clipping region // static inline void DisableClipping() { activeSurface.DisableClipping(); } // Returns the active clipping region // static inline Rect GetClippingRegion() { return activeSurface.GetClippingRegion(); } // Returns the width of the canvas // inline static int Width() { return activeSurface.width; } // Returns the height of the canvas // inline static int Height() { return activeSurface.height; } // Sets which color components OpenLayer will render to the canvas // // Defaults: // - For SCREEN_BACKBUF: COLOR_ONLY (Alpha channel of the canvas is not modified) // // - For Bitmaps: COLOR_AND_ALPHA (All color componens of the canvas are modified) // static void SetPixelWriteMode( PixelWriteMode mode ) { return activeSurface.SetPixelWriteMode( mode ); } // Returns which color componenents will be rendered to the canvas (see above) // static PixelWriteMode GetPixelWriteMode() { return activeSurface.GetPixelWriteMode(); } // Stores the Canvas in a stack // inline static void Push() { pushedSurfaces.push( activeSurface ); } // Pops the topmost Canvas from the stack // // Returns true if there was a Canvas stored in the stack // inline static bool Pop() { if( pushedSurfaces.size() > 0 ) { SetTo( pushedSurfaces.top() ); pushedSurfaces.pop(); return true; } return false; } // Saves the contents of the surface with the given name // static void Save( std::string filename ); // Returns the contents of the surface as a memory bitmap // static OL_MEMORY_IMG *GetMemoryBitmap(); // Retrieves the sizes of the screen buffers from Setup // static void ReadBufferSizes(); static int GetScreenshotBPP(); static int GetScreenshotFormat(); private: static void FinishSurfaceSelection(); static void ReleaseSurface(); static void SelectBuffer( RenderTarget buffer ); static void SelectImage( const Bitmap &image ); class SurfaceInfo { public: SurfaceInfo() : width( 0 ), height( 0 ), target( BITMAP_TARGET ), image( 0 ) {} SurfaceInfo( RenderTarget target, int width, int height, const Bitmap *image = 0 ) : width( width ), height( height ), target( target ), image( image ) {} void ApplySettings(); inline RenderTarget GetType() const { return target; } inline const Bitmap *GetImage() const { return image; } void SetClipping( int x, int y, int w, int h ); Rect GetClippingRegion(); void RevertClipping(); void DisableClipping(); void SelectDefaultBufferSize(); void SetPixelWriteMode( PixelWriteMode mode ); inline PixelWriteMode GetPixelWriteMode() { return writeMode; } void ChooseDefaultPixelWriteMode(); int width, height; private: void ApplyClipping(); void ApplyPixelWriteMode(); std::stack< OlRectangle< int > > clippingRegions; PixelWriteMode writeMode; RenderTarget target; const Bitmap *image; }; static void SetTo( const Canvas::SurfaceInfo &info ); static SurfaceInfo activeSurface; static std::map< RenderTarget, SurfaceInfo > storedSurfaces; static std::stack< SurfaceInfo > pushedSurfaces; }; }; #endif // OL_CANVAS_HPP openlayer-2.1.orig/include/OpenLayer/Settings.hpp0000644000175000017500000000576110552323114022346 0ustar georgeskgeorgesk#ifndef OL_SETTINGS_HPP #define OL_SETTINGS_HPP #include "Includes.hpp" #include "Declspec.hpp" namespace ol { // Settings - General settings of OpenLayer // class OL_LIB_DECLSPEC Settings { public: // Turns the anti-aliasing on or off // // Anti-aliasing produces smoother graphics but slows down the rendering // static void SetAntialiasing( bool turnedOn ); // Sets the accuracy of the circle drawing functions // // The value should be between 0.0 and 1.0 but it should never be zero // // The more accuracy, the better the circles will generally look // // but rendering them will be slower // // This setting can be overridden by passing a different value // to the circle drawing function // static void SetCircleAccuracy( float accuracy ); // Returns the accuracy of the circles // inline static float GetCircleAccuracy() { return circleAccuracy; } // If you use OpenGL directly you might wish to choose // // if the texture mapping is turned on or not // // This doesn't affect OpenLayer's functions // static void SetTextureMapping( bool turnedOn ); // Returns true if texture mapping is used // static bool TextureMappingUsed() { return useTextures; } // Sets the orthographic projection mode (the "2D drawing mode") // // Ortographic projection is on by default // static void SetOrthographicProjection( int screenWidth = SCREEN_W, int screenHeight = SCREEN_H ); // Restores old projection that got changed when you called SetOrtographicProjection() // static void RestoreOldProjection(); // Turn the memory bitmap storage on or off // // Off by default // static void StoreMemoryBitmaps( bool turnedOn ); // Returns true if the Bitmaps are stored in the memory // static bool MemoryBitmapsStored(); // Sets the accuracy of the generated collision polygons // // Accuracy should always be positive and the highest value is 1.0 // // The default value is 0.3 // static void SetCollisionPolyAccuracy( float accuracy ); // Returns the accuracy of the generated collision polygons // static float GetCollisionPolyAccuracy(); // Sets the maxium alpha value which is considered transparent // // by the collision polygon generation // static void SetCollisionPolyAlphaLimit( float limit ) { collisionPolyAlphaLimit = int( limit * 255.0 ); } // Returns the maxium alpha value which is considered transparent // // by the collision polygon generation // static float GetCollisionPolyAlphaLimit() { return float( collisionPolyAlphaLimit )/255.0; } friend class GfxRend; friend class Bitmap; private: static float circleAccuracy; static float collisionPolyAccuracy; static int collisionPolyAlphaLimit; static bool useAntiAlias; static bool useTextures; static bool storeMemoryBitmaps; }; } #endif // OL_SETTINGS_HPP openlayer-2.1.orig/include/OpenLayer/Point.hpp0000644000175000017500000000306510552323114021632 0ustar georgeskgeorgesk#ifndef OL_POINT_HPP #define OL_POINT_HPP #include "Shape.hpp" #include "Vec2D.hpp" #include "Declspec.hpp" namespace ol { class OL_LIB_DECLSPEC Point : public Shape { public: Point( Vec2D pos ) : pos( pos ) {} Point( float x, float y ) : pos( x, y ) {} // Draws the shape with the specified color // inline void Draw( const Rgba &color ) { OL_SHAPE_START_RENDERING() color.Select(); ExecDraw(); OL_SHAPE_FINISH_RENDERING() } // Draws the outline of the shape with the specified color // inline void DrawOutline( const Rgba &color ) { Draw( color ); } static inline void StartFastDrawing() { glBegin( GL_POINTS ); } inline void DrawFast( const Rgba &color ) { color.Select(); glVertex2f( pos.x + 0.5, pos.y + 0.5 ); } static inline void FinishFastDrawing() { glEnd(); } inline void MoveBy( const Vec2D &amount ) { pos += amount; } inline void MoveTo( const Vec2D &position ) { pos = position; } /* * return this back to normal if problems arise virtual void TransformBy( const Placement &placement ); virtual std::string ToString() const; */ virtual void TransformBy(const Placement &placement); virtual std::string ToString() const; Vec2D pos; protected: inline void ExecDraw() const { glBegin( GL_POINTS ); glVertex2f( pos.x + 0.5, pos.y + 0.5 ); glEnd(); } inline void ExecDrawOutline() const { ExecDraw(); } }; } #endif // OL_POINT_HPP openlayer-2.1.orig/include/OpenLayer/TextureInfo.hpp0000644000175000017500000001340410552323114023013 0ustar georgeskgeorgesk#ifndef OL_TEXTURE_INFO_HPP #define OL_TEXTURE_INFO_HPP #include "Includes.hpp" #include "Vec2D.hpp" #include "Rgba.hpp" #include "OlRectangle.hpp" #include "Declspec.hpp" // INTERNAL TEXTURE CLASSES // namespace ol { // Internal rectangle class // /* class OlRect { public: OlRect( float x = 0.0, float y = 0.0, float w = 0.0, float h = 0.0 ) : x( x ), y( y ), w( w ), h( h ) {} OlRect ClippedTo( const OlRect &rect ) const; float x, y, w, h; };*/ typedef OL_LIB_DECLSPEC OlRectangle< float > OlRect; // OpenLayer's internal texture information // class OL_LIB_DECLSPEC OlTextureInfo { public: OlTextureInfo( int textureWidth, int textureHeight, int imageWidth, int imageHeight, GLenum format, GLuint index = 0 ); OlTextureInfo(); // Create a sub-texture // OlTextureInfo( const OlTextureInfo &other, OlRect clipRect ); inline void SetIndex( GLuint index ) { this->index = index; } inline int GetIndex() const { return index; } inline static void StartRendering() { glBegin( GL_QUADS ); } inline void OutputTexturedQuad() const { OutputTexturedQuad( imgWidth, imgHeight ); } inline static void FinishRendering() { glEnd(); } inline void OutputTexturedQuad( float x, float y, float w, float h ) const { glBegin( GL_TRIANGLE_FAN ); OutputVertices( x, y, w, h ); glEnd(); } inline void OutputTexturedQuad( float w, float h ) const { OutputTexturedQuad( 0.0, 0.0, w, h ); } inline void OutputTexturedQuadXY( float x, float y ) const { OutputTexturedQuad( x, y, imgWidth, imgHeight ); } inline void OutputVertices( float x, float y, float w, float h ) const { glTexCoord2f( rect.x, rect.y ); glVertex2f( x, y + h ); glTexCoord2f( rect.x + rect.w, rect.y ); glVertex2f( x + w, y + h ); glTexCoord2f( rect.x + rect.w, rect.y + rect.h ); glVertex2f( x + w, y ); glTexCoord2f( rect.x, rect.y + rect.h ); glVertex2f( x, y ); } /* inline void OutputTexturedQuadSpecialWorkaround() const { float x = 0.0, y = 0.0, w = imgWidth, h = imgHeight; glBegin( GL_TRIANGLE_FAN ); glTexCoord2f( rect.x, rect.y ); glVertex2f( x, y + h+0.99 ); glTexCoord2f( rect.x + rect.w, rect.y ); glVertex2f( x + w+0.5, y + h+0.99 ); glTexCoord2f( rect.x + rect.w, rect.y + rect.h ); glVertex2f( x + w+0.5, y ); glTexCoord2f( rect.x, rect.y + rect.h ); glVertex2f( x, y ); glEnd(); } */ inline void OutputVertices( float x, float y ) const { OutputVertices( x, y, imgWidth, imgHeight ); } inline void OutputTexturedQuad( Vec2D topleft, Vec2D topright, Vec2D bottomright, Vec2D bottomleft ) const { glBegin( GL_TRIANGLE_FAN ); glTexCoord2f( rect.x, rect.y ); glVertex2f( bottomleft.x, bottomleft.y ); glTexCoord2f( rect.x + rect.w, rect.y ); glVertex2f( bottomright.x, bottomright.y ); glTexCoord2f( rect.x + rect.w, rect.y + rect.h ); glVertex2f( topright.x, topright.y ); glTexCoord2f( rect.x, rect.y + rect.h ); glVertex2f( topleft.x, topleft.y ); glEnd(); } inline void Select() const { glBindTexture( GL_TEXTURE_2D, index ); } inline void GetReadyToRender() const { Select(); glEnable( GL_TEXTURE_2D ); Rgba::WHITE.Select(); } int GetBytesPerPixel() const; bool HasAlphaChannel() const; friend class Bitmap; GLenum format; GLuint index; int texWidth, texHeight; int imgWidth, imgHeight; int fullImgWidth, fullImgHeight; float xMul, yMul; OlRect rect; private: inline float ConvDimension( float imgSize, float texSize ) { return float( imgSize )/float( texSize ); } }; // Internal texture coordinate class // class OL_LIB_DECLSPEC OlTexCoords { public: OlTexCoords( const OlTextureInfo &texture ) : texture( texture ), x1( 0.0 ), x2( texture.imgWidth ), y1( 0.0 ), y2( texture.imgHeight ), convx1( 0.0 ), convx2( 0.0 ), convy1( 0.0 ), convy2( 0.0 ), flipW( false ), flipH( false ), colors( 0 ) {} /* OlTexCoords( const OlTexCoords &orign, float x1 = 0.0, float y1 = 0.0, float x2 = 0.0, float y2 = 0.0 ) : w( orign.w ), h( orign.h ), x1( x1 ), y1( y1 ), x2( x2 ), y2( y2 ), convx1( orign.convx1 ), convx2( orign.convx2 ), convy1( orign.convy1 ), convy2( orign.convy2 ), flipW( orign.flipW ), flipH( orign.flipH ) {} */ inline void FlipHorizontal() { flipW = !flipW; } inline void FlipVertical() { flipH = !flipH; } inline float GetAreaW() const { return fabs( x1 - x2 ); } inline float GetAreaH() const { return fabs( y1 - y2 ); } void CalculateTextureCoords(); OlTexCoords ClippedTo( const OlRect &rect ) const; inline bool ChangesColors() const { return colors != 0; } inline const Rgba &GetColor( int index ) const { return colors[index]; } inline void SetColors( const Rgba *colors ) { this->colors = colors; } const OlTextureInfo &texture; float x1, x2, y1, y2; float convx1, convx2, convy1, convy2; bool flipW, flipH; const Rgba *colors; }; } #endif // OL_TEXTURE_INFO_HPP openlayer-2.1.orig/include/OpenLayer/Effects.hpp0000644000175000017500000000537110552323114022122 0ustar georgeskgeorgesk#ifndef OL_EFFECTS_HPP #define OL_EFFECTS_HPP #include #include "Bitmap.hpp" #include "Declspec.hpp" namespace ol { class Effect; class OL_LIB_DECLSPEC EffectSystem { public: // Enables the specified effect // static void Enable( Effect *effect ); // Disables the specified effect // static void Disable( Effect *effect ); // Disables all effects // static void DisableAll(); // Applies all enabled effects to the active canvas // static void Apply(); private: static std::list< Effect *> enabledEffects; }; // The parent class of all effects // class OL_LIB_DECLSPEC Effect { public: Effect( float duration ) : duration( duration ) {} virtual ~Effect(){} // Applies the effect to the active canvas // virtual void Apply() = 0; // Stores the contents of the screen to a Bitmap buffer // static void TakeScreenDump(); // Returns the Bitmap holding the dump of the screen // static Bitmap &GetScreenDump(); // Sets the Bitmap to be used to store the screen dump // // This function will disable the TakeScreenDump function // static void SetScreenDump( Bitmap &bmp ); // Initializes the screen dump // // You don't have to call this function in order to use the effects, // // however it's recommended to call this function during the loading time // // so that initializing the effects won't suddenly slow down the program // // when it runs in realtime // static void InitScreenDump(); private: static Bitmap *screenDump; float duration; }; class OL_LIB_DECLSPEC MotionBlur : public Effect { public: // Create a new motion blur with the given strength // MotionBlur( float duration, float strength ) : Effect( duration ), strength( strength ) {} virtual ~MotionBlur(){} virtual void Apply(); private: float strength; }; class OL_LIB_DECLSPEC RadialBlur : public Effect { public: // Create a new radial blur with the given strength // RadialBlur( float duration, float strength ) : Effect( duration ), strength( strength ) {} virtual ~RadialBlur(){} virtual void Apply(); private: float strength; }; class OL_LIB_DECLSPEC SwirlBlur : public Effect { public: // Create a new swirl blur with the given strength, accuracy and angle spread // SwirlBlur( float duration, float strength, float accuracy, float spread ) : Effect( duration ), strength( strength ), accuracy( accuracy ), spread( spread ) {} virtual ~SwirlBlur(){} virtual void Apply(); private: float strength, accuracy, spread; }; }; #endif // OL_EFFECTS_HPP openlayer-2.1.orig/include/OpenLayer/RenderModes.hpp0000644000175000017500000001342410552417346022763 0ustar georgeskgeorgesk#ifndef OL_RENDER_MODES_HPP #define OL_RENDER_MODES_HPP #include "Rgba.hpp" #include "TextureInfo.hpp" #include "Declspec.hpp" // RENDER MODES // namespace ol { class MultiMode; class Bitmap; enum ETexCoord { OL_TC_TOPLEFT, OL_TC_TOPRIGHT, OL_TC_BOTTOMRIGHT, OL_TC_BOTTOMLEFT }; // RenderMode - The base class of the mode the bitmap is rendered with // class OL_LIB_DECLSPEC RenderMode { public: virtual ~RenderMode(){} // The sum of two RenderModes returns a combination of those two // MultiMode operator+( const RenderMode &other ) const; // Internal functions // virtual void Select() const {} virtual void Unselect() const {} virtual bool SetsTexCoords() const { return false; } virtual void SetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoordRect, float w, float h ) const; static void PrimarySetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoordRect, float w, float h ); virtual OlRect GetRenderRect( OlRect current ) const; virtual OlTexCoords GetTexCoords( OlTexCoords current ) const; //virtual OlRect GetRenderArea() const; }; // Renders the bitmap tinted to a color // class OL_LIB_DECLSPEC TintMode : public RenderMode { public: // The bitmap will be tinted to the given color // // The alpha value of the color tells the intensity of the tinting // TintMode( Rgba color ) : color( color ) {} virtual ~TintMode(){} // Internal functions // virtual void Select() const; virtual void Unselect() const; protected: Rgba color; }; // Renders the bitmap with an additional alpha channel from an another bitmap // // The values of the alpha channels are multiplied together // class OL_LIB_DECLSPEC GainAlphaMode : public RenderMode { public: GainAlphaMode( const Bitmap &alphaFrom, float anchorX = 0.0, float anchorY = 0.0 ) : alphaFrom( alphaFrom ), x( anchorX ), y( anchorY ) {} virtual ~GainAlphaMode(){} // Internal functions // virtual void Select() const; virtual void Unselect() const; virtual bool SetsTexCoords() const { return true; } virtual void SetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoordRect, float w, float h ) const; virtual OlRect GetRenderRect( OlRect current ) const; virtual OlTexCoords GetTexCoords( OlTexCoords current ) const; protected: const Bitmap &alphaFrom; float x, y; }; enum OlFlippingChoise { HORIZONTAL, VERTICAL, BOTH }; // Flips the bitmap in the specified way // class OL_LIB_DECLSPEC FlippedMode : public RenderMode { public: FlippedMode( OlFlippingChoise mode ) : mode( mode ) {} virtual ~FlippedMode(){} virtual OlTexCoords GetTexCoords( OlTexCoords current ) const; protected: OlFlippingChoise mode; }; class Rect; // Clips the bitmap to a region // class OL_LIB_DECLSPEC ClippedMode : public RenderMode { public: ClippedMode( float x, float y, float w, float h ) : clipRect( x, y, w, h ) {} ClippedMode( const Rect &clipArea ); virtual ~ClippedMode(){} virtual OlRect GetRenderRect( OlRect current ) const; virtual OlTexCoords GetTexCoords( OlTexCoords current ) const; private: OlRect clipRect; }; enum OlSlicingChoise { HORIZONTAL_SLICE, VERTICAL_SLICE }; // Stretches a one pixel wide slice of the bitmap to fill the entire bitmap // class OL_LIB_DECLSPEC SliceMultiplyMode : public RenderMode { public: SliceMultiplyMode( float slicePos, OlSlicingChoise mode ) : slicePos( slicePos ), mode( mode ) {} virtual ~SliceMultiplyMode(){} virtual OlTexCoords GetTexCoords( OlTexCoords current ) const; private: float slicePos; OlSlicingChoise mode; }; // Specifies different color channel cofficients for each corner of the Bitmap class OL_LIB_DECLSPEC GradientMode : public RenderMode { public: GradientMode( Rgba topLeft, Rgba topRight, Rgba bottomRight, Rgba bottomLeft ) { corners[0] = topLeft; corners[1] = topRight; corners[2] = bottomRight; corners[3] = bottomLeft; } // Specifies different alpha values for each corner of the Bitmap GradientMode( float topLeft, float topRight, float bottomRight, float bottomLeft ) { corners[0] = Rgba(1.0f, 1.0f, 1.0f, topLeft); corners[1] = Rgba(1.0f, 1.0f, 1.0f, topRight); corners[2] = Rgba(1.0f, 1.0f, 1.0f, bottomRight); corners[3] = Rgba(1.0f, 1.0f, 1.0f, bottomLeft); } virtual ~GradientMode(){} virtual OlTexCoords GetTexCoords( OlTexCoords current ) const; private: enum { NUM_CORNERS = 4 }; Rgba corners[NUM_CORNERS]; }; /* class Perspective : public RenderMode { public: Perspective( float topStretch, float bottomStretch ) : topStretch( topStretch ), bottomStretch( bottomStretch ) {} virtual OlRect GetRenderRect( OlRect current ) const; private: float topStretch; float bottomStretch; };*/ #ifndef OL_NO_RENDER_MODE_ALIASES typedef TintMode Tinted; typedef GainAlphaMode AlphaFrom; typedef FlippedMode Flipped; typedef ClippedMode Clipped; typedef SliceMultiplyMode SliceExpanded; typedef GradientMode Gradient; #endif // Combines two RenderModes to a single entity // // (You can use the sum operator of BlendingModes which returns a MultiMode) // class OL_LIB_DECLSPEC MultiMode : public RenderMode { public: MultiMode( const RenderMode &mode1, const RenderMode &mode2 ) : mode1( mode1 ), mode2( mode2 ) {} virtual ~MultiMode(){} virtual void Select() const; virtual void Unselect() const; virtual bool SetsTexCoords() const; virtual void SetTexCoord( ETexCoord coord, OlRect &renderRect, OlTexCoords &texCoordRect, float w, float h ) const; virtual OlRect GetRenderRect( OlRect current ) const; virtual OlTexCoords GetTexCoords( OlTexCoords current ) const; protected: const RenderMode &mode1; const RenderMode &mode2; }; } #endif // OL_RENDER_MODES_HPP openlayer-2.1.orig/include/OpenLayer/Mouse.hpp0000644000175000017500000000102310552323114021621 0ustar georgeskgeorgesk#ifndef OL_MOUSE_HPP #define OL_MOUSE_HPP #include "Includes.hpp" #include "Vec2D.hpp" #include "Declspec.hpp" namespace ol { class OL_LIB_DECLSPEC Mouse { public: enum MouseButton { LEFT = 0, RIGHT = 1, CENTER = 2 }; bool Click( MouseButton button = LEFT ) { return mouse_b & ((int) button ); } Vec2D GetPos() { return Vec2D( mouse_x, mouse_y ); } bool MouseHits( const OlRect &area ); }; } #endif // OL_MOUSE_HPP openlayer-2.1.orig/include/OpenLayer/Declspec.hpp0000644000175000017500000000071010552323114022255 0ustar georgeskgeorgesk#ifndef OL_DECLSPEC_HPP #define OL_DECLSPEC_HPP #if defined (_WIN32) && defined (OL_LIB_BUILD) && defined (OL_SHARED) #define OL_LIB_DECLSPEC __declspec(dllexport) #define OL_EXT_DECLSPEC __declspec(dllexport) #elif defined (_WIN32) && defined (OL_SHARED) #define OL_LIB_DECLSPEC __declspec(dllimport) #define OL_EXT_DECLSPEC __declspec(dllimport) #else #define OL_LIB_DECLSPEC #define OL_EXT_DECLSPEC #endif #endif // OL_DECLSPEC_HPP openlayer-2.1.orig/include/OpenLayer/Rgba.hpp0000644000175000017500000000661410575626474021443 0ustar georgeskgeorgesk#ifndef OL_RGBA_HPP #define OL_RGBA_HPP #include "Includes.hpp" #include "Transforms.hpp" #include "Declspec.hpp" #include // #include // #include namespace ol { // Rgba - the Color structure // class OL_LIB_DECLSPEC Rgba { public: // Construct the color from float (0.0 ... 1.0) or integer color components (0..255) / // or using the 24-bit packed color value and an alpha value // Rgba( float r, float g, float b, float a = 1.0 ) : r( r ), g( g ), b( b ), a( a ) {} Rgba( double r, double g, double b, double a = 1.0 ) : r( r ), g( g ), b( b ), a( a ) {} Rgba( int r, int g, int b, int a = 255 ) : r( Rgba::CompToF(r)), g( Rgba::CompToF(g)), b( Rgba::CompToF(b)), a( Rgba::CompToF(a)) {} Rgba( int col, int a ) { *this = Rgba( getr32( col ), getg32( col ), getb32( col ), a ); } explicit Rgba( const std::string &hexPresentation ); Rgba() : r( 0.0 ), g( 0.0 ), b( 0.0 ), a( 0.0 ) {} // Color components // float r, g, b, a; // Some default colors // static const Rgba BLACK, WHITE, RED, YELLOW, GREEN, BLUE; static const Rgba INVISIBLE; // Has zero alpha // // Returns a color interpolated between this and otherColor // // using the factor (0...1) such that if factor is zero, it // // returns the calling color, if factor is 1.0 it returns otherColor // // and otherwise it returns a color between this and otherColor // Rgba MixWith( const Rgba &otherColor, float factor ) const; // Returns a color which has the same color componenets as this one // // except a differet alpha value // inline Rgba WithAlpha( float newAlpha ) const { return Rgba( r, g, b, newAlpha ); } // (You'll only need this function if you use OpenGL directly somewhere) // // Selects the color as the current OpenGL color // // Affected by color channel cofficients // // Like Select but unaffected by color channel cofficients // inline void SelectRaw() const { glColor4f( r, g, b, a ); } #ifdef NO_COLOR_CHANNELS inline void Select() const { SelectRaw(); } #else // NO_COLOR_CHANNELS inline void Select() const { const Rgba& colorChannels = ol::Transforms::GetColorChannels(); glColor4f( colorChannels.r * r, colorChannels.g * g, colorChannels.b * b, colorChannels.a * a ); } #endif // NO_COLOR_CHANNELS std::string ToString() const; std::string ToHex() const; // Returns the color in a packed 32-bit integer // int Packed() const; // A previously used name for the function MixWith // inline Rgba InterpolateWith( const Rgba &otherColor, float factor ) const { return MixWith( otherColor, factor ); } friend class TextRenderer; private: unsigned int parseHex( const std::string &hex, int pos ); explicit Rgba( bool invalidiated ); Rgba( int specialPackedColor, bool notUsed ); static inline int CompToI( float c ) { return int( 255.0 * c ); } static inline float CompToF( int c ) { return float(c)/255.0; } int SpecialPacked() const; inline bool IsValid() { return r >= 0.0 && g >= 0.0 && b >= 0.0 && a >= 0.0; } }; } #endif openlayer-2.1.orig/include/OpenLayer/OlRectangle.hpp0000644000175000017500000000240110552323114022731 0ustar georgeskgeorgesk#ifndef OL_INTERNAL_RECT #define OL_INTERNAL_RECT #include #include "Declspec.hpp" #ifdef max #undef max #endif #ifdef min #undef min #endif namespace ol { // Internal rectangle class // template< typename Type > class OL_LIB_DECLSPEC OlRectangle { public: OlRectangle( Type x = 0.0, Type y = 0.0, Type w = 0.0, Type h = 0.0 ) : x( x ), y( y ), w( w ), h( h ) {} OlRectangle ClippedTo( const OlRectangle &rect ) const { OlRectangle returnVal; if( rect.x < 0 ) { returnVal.x = 0; returnVal.w = std::max( std::min( w, rect.x + rect.w ), Type( 0 )); } else { returnVal.x = x + rect.x; returnVal.w = std::max( std::min( w - rect.x, rect.w ), Type( 0 )); } if( rect.y < 0 ) { returnVal.y = 0; returnVal.h = std::max( std::min( h, rect.y + rect.h ), Type( 0 )); } else { returnVal.y = y + rect.y; returnVal.h = std::max( std::min( h - rect.y, rect.h ), Type( 0 )); } return returnVal; } Type x, y, w, h; }; } #endif // OL_INTERNAL_RECT openlayer-2.1.orig/include/OpenLayer/Matrix.hpp0000644000175000017500000000146510552323114022007 0ustar georgeskgeorgesk#ifndef OL_MATRIX_HPP #define OL_MATRIX_HPP #include "Vec2D.hpp" #include "Declspec.hpp" namespace ol { class OL_LIB_DECLSPEC Matrix2D { public: enum { SIDE_LENGTH = 2, NUM_VALUES = SIDE_LENGTH * SIDE_LENGTH }; inline float Get( int x, int y ) const { return values[SIDE_LENGTH * y + x]; } inline void Set( int x, int y, float val ) { values[SIDE_LENGTH * y + x] = val; } inline Vec2D Transform( const Vec2D &vec ) { return Vec2D( Get( 0, 0 ) * vec.x + Get( 1, 0 ) * vec.y, Get( 0, 1 ) * vec.x + Get( 1, 1 ) * vec.y ); } float values[NUM_VALUES]; }; Matrix2D operator*( const Matrix2D &first, const Matrix2D &second ); } #endif // OL_MATRIX_HPP openlayer-2.1.orig/include/OpenLayer/Blenders.hpp0000644000175000017500000000354310552323114022300 0ustar georgeskgeorgesk#ifndef OL_BLENDERS_HPP #define OL_BLENDERS_HPP #include "Includes.hpp" #include "Declspec.hpp" #include namespace ol { // Blenders - different color blending styles // Alpha blender (default): renders translucent bitmaps, // alpha values of the source pixels tell the opacity // // Additive blender: Increases the lightness of the underlying pixels // alpha values of the source pixels tell the intensity // // Subtractive blender: Decreases the lightness of the underlying pixels // alpha values the source pixels tell the intensity enum Blender { ALPHA_BLENDER, ADDITIVE_BLENDER, SUBTRACTIVE_BLENDER, COPY_BLENDER, FULL_ADDITIVE_BLENDER, CUSTOM }; class OL_LIB_DECLSPEC Blenders { public: // Sets the active blending function // // Additive blender lits the destination bitmap, // // subtractive blender darkens it. // static void Set( Blender blender ); // Sets a custom OpenGL blender as the active blending function // static void Set( GLenum sourceFactor, GLenum destFactor ); // Pushes the active blender to the blender stack // inline static void Push() { blenderStack.push( activeBlender ); } // Pops the most recently added blender from the blender stack // static void Pop(); // Selects the active blender (automatically done) // static void SelectBlender(); private: class BlenderObj { public: BlenderObj() : source( GL_ONE ), dest( GL_ZERO ) {} BlenderObj( GLenum source, GLenum dest ) : source( source ), dest( dest ) {} GLenum source, dest; }; static BlenderObj activeBlender; static std::stack< BlenderObj > blenderStack; }; } #endif // OL_BLENDERS_HPP openlayer-2.1.orig/include/OpenLayer/Framebuffer.hpp0000644000175000017500000000734410552323114022771 0ustar georgeskgeorgesk#ifndef OL_FRAMEBUFFER_HPP #define OL_FRAMEBUFFER_HPP #include "Includes.hpp" #include "GlDriver.hpp" #include "Declspec.hpp" #include #include namespace ol { class OL_LIB_DECLSPEC FrameBuffer { public: virtual ~FrameBuffer(); virtual const char *GetName() = 0; virtual bool Initialize() = 0; virtual void BindToTexture( const OlTextureInfo &texture ) = 0; virtual void Release() = 0; virtual void Destroy( OlTextureInfo &texture ) = 0; virtual void DestroySurfaces() = 0; virtual void RefreshSurface() = 0; virtual void ReadPixels( int x, int y, int width, int height, GLenum textureFormat, unsigned char *pixelData ) = 0; virtual void CopyTexSubImage( int x, int y, int width, int height, int yOffset ) = 0; static FrameBuffer &GetInstance(); static void Register( FrameBuffer *buffer ); static void DestroyFramebuffers(); private: static void InitFramebuf(); static std::vector< FrameBuffer *> possibleFramebufs; static FrameBuffer *frameBuffer; }; class OL_LIB_DECLSPEC BackbufFramebuf : public FrameBuffer { public: BackbufFramebuf() : boundTexture(0) {} virtual ~BackbufFramebuf(){} virtual const char *GetName(); virtual bool Initialize(); virtual void BindToTexture( const OlTextureInfo &texture ); virtual void Release(); virtual void Destroy( OlTextureInfo &texture ); virtual void DestroySurfaces(); virtual void RefreshSurface(); virtual void ReadPixels( int x, int y, int width, int height, GLenum textureFormat, unsigned char *pixelData ); virtual void CopyTexSubImage( int x, int y, int width, int height, int yOffset ); private: const OlTextureInfo *boundTexture; }; class OL_LIB_DECLSPEC OlFramebufferObjExt : public FrameBuffer { public: OlFramebufferObjExt() : boundTexture( 0 ) {} virtual ~OlFramebufferObjExt(); virtual const char *GetName(); virtual bool Initialize(); virtual void BindToTexture( const OlTextureInfo &texture ); virtual void Release(); virtual void Destroy( OlTextureInfo &texture ); virtual void DestroySurfaces(); virtual void RefreshSurface(); virtual void ReadPixels( int x, int y, int width, int height, GLenum textureFormat, unsigned char *pixelData ); virtual void CopyTexSubImage( int x, int y, int width, int height, int yOffset ); private: #ifdef GL_EXT_framebuffer_object #ifdef _WIN32 #ifndef PFNGLGENFRAMEBUFFERSEXTPROC typedef void (APIENTRY * PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); #endif #ifndef PFNGLFRAMEBUFFERTEXTURE2DEXTPROC typedef void (APIENTRY * PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLenum level); #endif #ifndef PFNGLBINDFRAMEBUFFEREXTPROC typedef void (APIENTRY * PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); #endif #ifndef PFNGLDELETERENDERBUFFERSEXTPROC typedef void (APIENTRY * PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); #endif PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; #endif // _WIN32 #endif // GL_EXT_framebuffer_object //static const int INTERNAL_FORMAT; std::map< GLuint, GLuint > bufferMap; const OlTextureInfo *boundTexture; }; } #endif // OL_FRAMEBUFFER_HPP openlayer-2.1.orig/include/OpenLayer/TransformMatrix.hpp0000644000175000017500000000036210552323114023676 0ustar georgeskgeorgesk#ifndef OL_TRANSFORM_MATRIX_HPP #define OL_TRANSFORM_MATRIX_HPP #include "Declspec.hpp" namespace ol { class OL_LIB_DECLSPEC TransformMatrix { public: private: }; } #end� // OL_TRANSFORM_MATRIX_HPP openlayer-2.1.orig/include/OpenLayer/General.hpp0000644000175000017500000000125410552417346022127 0ustar georgeskgeorgesk#ifndef OL_GENERAL_HPP #define OL_GENERAL_HPP #include #include "Declspec.hpp" namespace ol { // ToString - Converts a variable to a string // template< class Type > std::string ToString( Type value ) { std::stringstream s; s << value; return s.str(); } template< class Type > std::string VarToString( Type value ) { return ToString( value ); } OL_LIB_DECLSPEC int ToNextPowOfTwo( int num ); enum Axis { X_AXIS, Y_AXIS }; enum OutlineTextureMode { SHRINK, STRETCH, OPTIMIZE }; enum TextAlignment { LEFT, RIGHT, CENTER, JUSTIFY }; } #endif // OL_GENERAL_HPP openlayer-2.1.orig/include/OpenLayer/Bitmap.hpp0000644000175000017500000004406110570160412021756 0ustar georgeskgeorgesk#ifndef OL_BITMAP_HPP #define OL_BITMAP_HPP #include "Includes.hpp" #include "GarbageCollector.hpp" #include "Rgba.hpp" #include "Internal.hpp" #include "PendingLoad.hpp" #include "Collisions.hpp" #include "Vec2D.hpp" #include "RenderModes.hpp" #include "GlDriver.hpp" #include "Declspec.hpp" #include #include #include namespace ol { class RenderMode; class Rect; class Poly; // Conversion options used when converting an Allegro BITMAP to an OpenLayer Bitmap // enum { HAS_ALPHA_CHANNEL = 0x1, CONVERT_MAGIC_PINK = 0x2 }; enum { CREATE_COLLISION_POLY = 0x1 }; // Bitmap - Stores a bitmap and draws it to the screen // class OL_LIB_DECLSPEC Bitmap : public GarbageCollected { public: Bitmap() : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( 0 ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { AddToCollection(); } // The copy constructor will only create a new handler to the same image data // Bitmap( const Bitmap &other ) : bmp( other.bmp ), collisionPoly( other.collisionPoly ), destroyBmp( false ), pendingLoad( 0 ), pivot( other.pivot ), useDefaultPivot( other.useDefaultPivot ), isSubBitmap( true ) { AddToCollection(); } // ExtraFlags should be zero or MAKE_COLLISION_POLY // Construct the Bitmap using a bitmap file // Bitmap( std::string filename, int extraFlags = 0 ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( 0 ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { AddToCollection(); Load( filename.c_str(), extraFlags ); } // Construct the Bitmap using a separate bitmap for // // the color and the transparency information // Bitmap( const char *rgbFilename, const char *alphaFilename, int extraFlags = 0 ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( 0 ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { AddToCollection(); Load( rgbFilename, alphaFilename, extraFlags ); } // Construct a Bitmap from Allegro's BITMAP // // Pass true as convertMagicPink if the bitmap has // // transparent parts marked with the magic pink // Bitmap( OL_MEMORY_IMG *bmp, bool hasAlphaChannel = false, bool convertMagicPink = false, int extraFlags = 0 ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( 0 ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { AddToCollection(); Load( bmp, hasAlphaChannel, convertMagicPink, extraFlags ); } // Same as above but the parameters are passed by using // // a logical "or" of the conversion modes listed above the Bitmap class // Bitmap( OL_MEMORY_IMG *bmp, int conversionMode, int extraFlags = 0 ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( 0 ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { AddToCollection(); Load( bmp, conversionMode, extraFlags ); } // Construct a Bitmap with the specified width and height // // The Bitmap will be filled with some random garbage // Bitmap( int width, int height ); // Same as above but the Bitmap will be filled with the specified color // Bitmap( int width, int height, Rgba fillColor ); // Construct a sub-bitmap of the given Bitmap // Bitmap( const Bitmap &other, float x, float y, float width, float height ); // Construct a sub-bitmap of the given Bitmap // Bitmap( const Bitmap &other, const Rect &area ); // Same as above but for each pixel in the Bitmap // // the color will be retrieved by calling the function: // // Rgba operator()(int x, int y) // of the passed functor object // template< class Functor > Bitmap( int width, int height, Functor functor ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( true ), pendingLoad( 0 ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { AddToCollection(); Load( width, height, functor ); } // ADVANCED: Constructs the Bitmap from the specified pixel data // // The width and height are the width and height of the actual image // // while textureWidth and textureHeight are should be the next powers of two // // The pixel data should be an array of 4 * textureWidth * textureHeight elements // // which represent the color components of the pixels in groups of four components, // // line by line from top to bottom and each line left to right // Bitmap( int width, int height, int textureWidth, int textureHeight, float *pixelData, bool hasAlphaChannel = true ) : bmp( 0 ), collisionPoly( 0 ), destroyBmp( false ), pendingLoad( 0 ), pivot( Vec2D( 0.0, 0.0 )), useDefaultPivot( true ), isSubBitmap( false ) { AddToCollection(); Load( width, height, textureWidth, textureHeight, pixelData, hasAlphaChannel ); } // Create a bitmap by taking a copy of the contents of the screen // //Bitmap( int x, int y, int w, int h ); // The destructor automatically frees the allocated memory and unloads the texture // // and makes sure that the Bitmap won't be garbage collected // virtual ~Bitmap() { Destroy( true ); } // Loads the Bitmap from a bitmap file, returns true in a success // bool Load( const char *filename, int extraFlags = 0 ); // Loads the Bitmap from separate bitmaps for // // the color and the transparency information // bool Load( const char *rgbFilename, const char *alphaFilename, int extraFlags = 0 ); // Loads the Bitmap from a Allegro's BITMAP, returns true in a success // bool Load( OL_MEMORY_IMG *bmp, bool hasAlphaChannel = false, bool convertMagicPink = false, int extraFlags = 0 ); // Same as above but the parameters are passed by using // // a logical "or" of the conversion modes listed above the Bitmap class // bool Load( OL_MEMORY_IMG *bmp, int conversionMode, int extraFlags = 0 ); // Same as above but for each pixel in the Bitmap // // the color will be retrieved by calling the function: // // Rgba operator()(int x, int y) // of the passed functor object // template< class Functor > bool Load( int width, int height, Functor functor ); // ADVANCED: Loads the Bitmap from the specified pixel data // // The width and height are the width and height of the actual image // // while textureWidth and textureHeight are should be the next powers of two // // The pixel data should be an array of 4 * textureWidth * textureHeight elements // // which represent the color components of the pixels in groups of four components, // // line by line from top to bottom and each line left to right // void Load( int width, int height, int textureWidth, int textureHeight, GLfloat *data, GLenum format = GL_RGBA ); // Saves the Bitmap to disk with the specified filename // // The type of the file depends on the extension of the filename // bool Save( const char *filename ); // Draws the bitmap to the screen at the specified top-left coordinates // // Opacity is in range 0.0 ... 1.0, where 1.0 is completely opaque // // and 0.0 completely transparent // // Pass true as horizontallyFlipped to flip the image horizontally // void Blit( float x, float y, float opacity = 1.0 ) const; // Same as the original Blit but uses a RenderMode to modify the output // void Blit( float x, float y, const RenderMode &mode, float opacity = 1.0 ) const; // Selects the default pivot point of the Bitmap // // The default is the center // void SetDefaultPivot( Vec2D point ); inline void SetDefaultPivot( float x, float y ) { SetDefaultPivot( Vec2D( x, y )); } // Returns the default pivot of the Bitmap // inline Vec2D GetDefaultPivot() { return pivot; } // Draws the bitmap to the screen rotated around the default pivot point, angle is in radians // // The defautl pivot point of the bitmap will be positioned at (x, y) in the screen // void BlitRotated( float x, float y, float angle, float opacity = 1.0 ) const; // The passed RenderMode affects the rendering, see the classes RenderMode and TintMode below // void BlitRotated( float x, float y, float angle, const RenderMode &mode, float opacity = 1.0 ) const; // Draws the bitmap rotated around the point (pivotX, pivotY) in the bitmap // // such that the pivot point will be positioned at (x, y) in the screen // void BlitRotated( float x, float y, float pivotX, float pivotY, float angle, float opacity = 1.0 ) const; // The passed RenderMode affects the rendering // void BlitRotated( float x, float y, float pivotX, float pivotY, float angle, const RenderMode &mode, float opacity = 1.0 ) const; // Draws the bitmap stretched to the specified width and height // void BlitStretched( float x, float y, float width, float height, float opacity = 1.0 ) const; // The passed RenderMode affects the rendering // void BlitStretched( float x, float y, float width, float height, const RenderMode &mode, float opacity = 1.0 ) const; // Draws the bitmap to the screen rotated and stretched // void BlitTransformed( float x, float y, float width, float height, float angle, float opacity = 1.0 ) const; // The passed RenderMode affects the rendering // void BlitTransformed( float x, float y, float width, float height, float angle, const RenderMode &mode, float opacity = 1.0 ) const; // Draws the bitmap to the screen rotated around the point (pivotX, pivotY) and stretched // void BlitTransformed( float x, float y, float width, float height, float pivotX, float pivotY, float angle, float opacity = 1.0 ) const; // The passed RenderMode affects the rendering // void BlitTransformed( float x, float y, float width, float height, float pivotX, float pivotY, float angle, const RenderMode &mode, float opacity = 1.0 ) const; // Draws the bitmap distorted such that the given coordinates describe the corner points // // of the bitmap in the screen in clockwise order starting from the top-left coordinate. // // The bitmap will be stretched to fill the quadrate area inside the corner points // void BlitDistorted( float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float opacity = 1.0 ) const; // The passed RenderMode affects the rendering // void BlitDistorted( float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const RenderMode &mode, float opacity = 1.0 ) const; // Returns the width and height of the bitmap // inline int Width() const { return textureInfo.imgWidth; } inline int Height() const { return textureInfo.imgHeight; } // Loads a list of bitmaps stored as filenameBegin01.extension, filenameBegin02.extension etc. // // Where numNumbers is the amount of numbers in the filename // static std::vector< Bitmap *> LoadListOfBitmaps( std::string filenameBegin, std::string extension, unsigned int numNumbers = 2, int extraFlags = 0 ); // Fills this Bitmap with a portion of the active rendering surface // // The coordinates specify the top-left coordinates of the copied portion in the screen // void CopyFromCanvas( int x, int y ); // The old name of the CopyFromCanvas-function, used for backwards compability // inline void CopyFromScreen( int x, int y ) { CopyFromCanvas( x, y ); } // Returns a memory bitmap copy of the Bitmap // OL_MEMORY_IMG *GetMemoryBitmap() const; // Returns a memory bitmap copy of the specified region of the Bitmap // OL_MEMORY_IMG *GetMemoryBitmap( int x, int y, int width, int height ) const; inline Rgba GetPixelFromMemory( int x, int y ) const { return GlDriver::Get()->GetPixel( bmp, x, y ); } // Retrurns the color value of the specified pixel as an Rgba color // // Make sure that you don't try to read out of the bounds of the bitmap // inline Rgba GetPixel( int x, int y ) const { float pixels[3]; glReadPixels( x, y, 1, 1, textureInfo.format, GL_FLOAT, pixels ); return Rgba( pixels[0], pixels[1], pixels[2] ); } // Returns the color value of the specified pixel in a packed 32-bit integer // // Make sure that you don't try to read out of the bounds of the bitmap // inline int GetPixelPacked( int x, int y ) const { return GetPixel( x, y ).Packed(); } // Returns true if the bitmap is ready to be used // virtual bool IsValid() const; // The boolean operator returns the same as the IsValid-method // inline operator bool() const { return IsValid(); } // Returns the generated collision polygon for the Bitmap // // Null if no collision polygon was generated in the constructor // Poly *GetCollisionPoly() const; // You don't usually need to call any of the following functions! // // Creates a collision polygon for the specified memory bitmap // static Poly *GetCollisionPolygon( OL_MEMORY_IMG *bitmap, int alphaLimit, int numSkips, Vec2D rotationPivot = Vec2D( 0.0, 0.0 )); // Returns true if a loading command is waiting for Setup::SetupScreen to be called // virtual bool IsLoadingQueued() const; // Returns true if the bitmap has an alpha channel // bool HasAlphaChannel() const; // Frees the Bitmap from both the memory and the gfx card // virtual void Destroy( bool eraseFromGarbageCollection = false ); // Sends the Bitmap to the Gfx card // // Works only if Settings::StoreMemoryBitmaps is turned on // virtual void SendToGPU(); // Unloads the Bitmap from the Gfx card // // Works only if Settings::StoreMemoryBitmaps is turned on // void UnloadFromGPU(); // Unloads the Bitmap from the Gfx card but // // keeps the image data saved in the Bitmap // // so that it can be restored with SendToGPU() // virtual void UnloadToMemory(); // Selects the Bitmap to be used in texture mapping // inline void Select() const { textureInfo.Select(); } // Execute the queued loading commands (Called by SetupScreen) // virtual OlLoadResult ExecuteQueuedCommands(); // Adds the bitmap to the garbage/auto-loader collection // // (Automatically done) // virtual void AddToCollection(); // LOW LEVEL RENDERING ROUTINES // // This should be called before calling FastBlit // static void StartFastBlitting( float opacity = 1.0 ); // A faster Blit but works only after StartFastBlitting has been called // inline void FastBlit( float x, float y ) const { Select(); textureInfo.OutputTexturedQuadXY( x, y ); } // This function should be called after calling FastBlit // static void FinishFastBlitting(); // Dumps a raw textured quad to the screen // void TexturedQuad( float w, float h, float fact ) const; // Same as above but using a RenderMode // void TexturedQuad( float w, float h, float fact, const RenderMode &mode ) const; inline int TextureWidth() const { return textureInfo.texWidth; } inline int TextureHeight() const { return textureInfo.texHeight; } void GetReadyToRender( float opacity ) const; friend class GainAlphaMode; friend class ClippedMode; friend class Canvas; friend class TexturedPoly; OlTextureInfo textureInfo; protected: // A faster save function to call if the Bitmap is already selected as Canvas // void SaveIfSurface( std::string filename ) const; void HandleExtraFlags( int flags ); void SelectDefaultPivot( int imageWidth, int imageHeight ); inline float GetTextureEndX() const { return textureInfo.rect.x + textureInfo.rect.w; } inline float GetTextureEndY() const { return textureInfo.rect.y + textureInfo.rect.h; } /* inline int GetTextureW() const { return textureInfo.texWidth; } inline int GetTextureH() const { return textureInfo.texHeight; } */ OL_MEMORY_IMG *bmp; Poly *collisionPoly; bool destroyBmp; PendingBitmapLoad *pendingLoad; Vec2D pivot; bool useDefaultPivot; bool isSubBitmap; bool isSolid; }; // Template functions // template< class Functor > bool Bitmap:: Load( int width, int height, Functor functor ) { int textureWidth = width; int textureHeight = height; int dataSize = 4 * textureWidth * textureHeight; GLfloat *data = new GLfloat[dataSize]; int x = 0; int y = 0; GLfloat *iter = data; for( int y = 0; y < height; y++ ) { for( int x = 0; x < width; x++ ) { Rgba color = functor( x, y ); *(iter++) = color.r; *(iter++) = color.g; *(iter++) = color.b; *(iter++) = color.a; } } Load( width, height, textureWidth, textureHeight, data ); delete[] data; return true; } } #endif openlayer-2.1.orig/include/OpenLayer/GfxRend.hpp0000644000175000017500000002456210552323114022103 0ustar georgeskgeorgesk#ifndef OL_GFX_REND_HPP #define OL_GFX_REND_HPP #include "Includes.hpp" #include "Rgba.hpp" #include "Settings.hpp" #include "Declspec.hpp" namespace ol { // THIS CLASS IS DEPRECATED // // Use Shape and Canvas instead // // GfxRend - Primitive graphics rendering functions // class OL_LIB_DECLSPEC GfxRend { public: // Call this after you've finished rendering the current frame // static void RefreshScreen(); // Rectangle functions // // Draws a filled rectangle // static void Rect( float x, float y, float width, float height, Rgba color ); // Draws a non-filled rectangle // static void RectOutline( float x, float y, float width, float height, Rgba color, float lineWidth = 1.0 ); // Draws a rectangle filled with a gradient such that each corner of the // // rectangle is given a color and the colors of all pixels inside the rectangle // // are interpolated along the colors of the corners // // Colors should be an array with 4 color values such that colors[0] is the color // // of the top-left corner, colors[1] top-right corner and so forth in clockwise order // static void RectGradient( float x, float y, float width, float height, Rgba *colors ); // Line functions // // Draws a line between (x1, y1) and (x2, y2) // static void Line( float x1, float y1, float x2, float y2, Rgba col, float lineWidth = 1.0 ); // Draws a line such that the color of the starting point (x1, y1) is color1 // // and the color of the ending point (x2, y2) is color2 and the colors of all // // the pixels in-between change smoothly from color1 to color2 // static void LineGradient( float x1, float y1, float x2, float y2, Rgba color1, Rgba color2, float lineWidth = 1.0 ); // Renders a series of lines between (xCoordinates[i], yCoodrinates[i]) and // // (xCoordinates[i+1], yCoodrinates[i+1]) // static void LineStrip( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba color, float lineWidth = 1.0 ); // Like LineStrip but with colors changing smoothly from startCol to endCol // // along the line // static void LineStripGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba startCol, Rgba endCol, float lineWidth = 1.0 ); // Like LineStrip but with a different color for each coordinate // // The colors along the series of lines will be interpolated between the colors // // of the first and last points of the line series as well as between the colors // // in of left and right sides // static void LineStripGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba startCol, Rgba endCol, Rgba leftCol, Rgba rightCol, float lineWidth = 1.0 ); // Like LineStrip but with a different color for each coordinate // // The colors along the lines will be interpolated between the colors // // of the end points of the line // static void LineStripGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba *colors, float lineWidth = 1.0 ); // Circle functions // // Accuracy is between 0 and 1, though it should never be zero // // If no accuracy is specified, the default accuracy is used (change it in Settings) // // Draws a filled circle // static void Circle( float x, float y, float radius, Rgba col, float accuracy = Settings::GetCircleAccuracy() ); // Draws a non-filled circle // static void CircleOutline( float x, float y, float radius, Rgba col, float lineWidth = 1.0, float accuracy = Settings::GetCircleAccuracy() ); // Draws a circle filled with a circular gradient such that the color of the centre is // // innerColor and the color of the circumference of the circle is outerColor // // and the colors inside the circle change smoothly from innerColor to outerColor // static void CircleGradient( float x, float y, float radius, Rgba innerColor, Rgba outerColor, float accuracy = Settings::GetCircleAccuracy() ); // Draws a filled circle with a circular hole in it // // The radius of the hole is innerRadius and the radius of the circle is outerRadius // static void Disk( float x, float y, float innerRadius, float outerRadius, Rgba color, float accuracy = Settings::GetCircleAccuracy() ); // Draws a disk with colors changing smoothly from innerColor to outerColor along the radius // static void DiskGradient( float x, float y, float innerRadius, float outerRadius, Rgba innerColor, Rgba outerColor, float accuracy = Settings::GetCircleAccuracy() ); // Ellipse routines // // The given angle rotates the ellipse around its centre // // Draws a filled ellipse // static void Ellipse( float x, float y, float xRadius, float yRadius, Rgba col, float angle = 0.0, float accuracy = Settings::GetCircleAccuracy() ); // Draws a non-filled ellipse // static void EllipseOutline( float x, float y, float xRadius, float yRadius, Rgba col, float angle = 0.0, float lineWidth = 1.0, float accuracy = Settings::GetCircleAccuracy() ); // Draws a gradient filled ellipse with colors changing smoothly from innerColor to outerColor along the radius // static void EllipseGradient( float x, float y, float xRadius, float yRadius, Rgba innerCol, Rgba outerCol, float angle = 0.0, float accuracy = Settings::GetCircleAccuracy() ); // Slice and arc functions // // The rendered range is startAngle -> startAngle + sweepAngle // // Draws a filled circle slice // static void Slice( float x, float y, float radius, float startAngle, float sweepAngle, Rgba color, float accuracy = Settings::GetCircleAccuracy() ); // Draws a gradient filled circle slice with colors changing smoothly // // from innerColor to outerColor along the radius // static void SliceGradient( float x, float y, float radius, float startAngle, float sweepAngle, Rgba innerColor, Rgba outerColor, float accuracy = Settings::GetCircleAccuracy() ); // Draws a filled ellipse slice // static void EllipseSlice( float x, float y, float xRad, float yRad, Rgba col, float startAngle, float sweepAngle, float angle = 0.0, float accuracy = Settings::GetCircleAccuracy() ); // Draws a gradient filled ellipse slice // static void EllipseSliceGradient( float x, float y, float xRad, float yRad, Rgba innerColor, Rgba outerColor, float startAngle, float sweepAngle, float angle = 0.0, float accuracy = Settings::GetCircleAccuracy() ); // Draws a double-gradient filled ellipse slice // static void EllipseSliceGradient( float x, float y, float xRad, float yRad, Rgba innerStartColor, Rgba outerStartColor, Rgba innerEndColor, Rgba outerEndColor, float startAngle, float sweepAngle, float angle = 0.0, float accuracy = Settings::GetCircleAccuracy() ); // Draws a filled arc // static void Arc( float x, float y, float innerRad, float outerRad, float startAngle, float sweepAngle, Rgba color, float accuracy = Settings::GetCircleAccuracy() ); // Draws a gradient filled arc with colors changing smoothly // // from innerColor to outerColor along the radius // static void ArcGradient( float x, float y, float innerRad, float outerRad, float startAngle, float sweepAngle, Rgba innerCol, Rgba outerCol, float accuracy = Settings::GetCircleAccuracy() ); // Triangle functions // // Draws a filled triangle // static void Triangle( float x1, float y1, float x2, float y2, float x3, float y3, Rgba color ); // Draws a non-filled triangle // static void TriangleOutline( float x1, float y1, float x2, float y2, float x3, float y3, Rgba color, float lineWidth = 1.0 ); // Renders a gradient filled triangle such that the colors of the pixels inside the triangle // // are interpolated along the colors of the vertices // static void TriangleGradient( float x1, float y1, float x2, float y2, float x3, float y3, Rgba *colors ); // Polygon functions // // Renders a filled polygon // static void Polygon( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba color ); // Renders a non-filled polygon // static void PolygonOutline( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba color, float lineWidth = 1.0 ); // Renders a gradient filled polygon such that the colors of the pixels inside the polygon // // are interpolated along the colors of the vertices // static void PolygonGradient( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba *colors ); // Other drawing functions // // Draws a single point in the screen // static void Point( float x, float y, Rgba color ); // Fills the entire screen with the specified color // // Ignores the alpha value of the color // static void FillScreen( Rgba color ); // Returns the OpenGL error as text or null if no error has occured // static const char *ErrorString(); private: static float GetAngleIncrement( float rad, float accuracy ); static void DiskRender( float x, float y, float innerRad, float outerRad, Rgba innerCol, Rgba outerCol, float accuracy, bool setCols = true ); static void LineStripRender( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba *colors, float lineWidth, bool singleColor, bool useSideColors = false, Rgba leftCol = Rgba::BLACK, Rgba rightCol = Rgba::BLACK ); static Rgba *GenerateColors( float *xCoordinates, float *yCoordinates, int numCoordinates, Rgba col1, Rgba col2 ); }; } #endif // OL_GFX_REND_HPP openlayer-2.1.orig/include/OpenLayer/Internal.hpp0000644000175000017500000000427010552417346022327 0ustar georgeskgeorgesk#ifndef OL_INTERNAL_HPP #define OL_INTERNAL_HPP #include "Includes.hpp" #include #include #include #include #include "Declspec.hpp" namespace ol { extern OL_LIB_DECLSPEC bool firstLog; static inline void OlLog( std::string logStr, bool append = !firstLog ) { firstLog = false; #ifdef OL_TO_STDOUT std::cout << logStr << "\n"; #else std::ofstream file( "openlayer.log", append? std::ios::app : std::ios::trunc ); file << logStr << "\n"; file.close(); #endif } static inline void OlError( std::string errorStr ) { std::string msg = std::string("ERROR: ") + errorStr; OlLog( msg ); } //TTD - change OlAssert to do FILE and LINE correctly #if defined(_MSC_VER) && _MSC_VER < 1300 #define OlAssert( condition ) \ if( !(condition) ) { \ char linechars[64]; \ OlError( "Assertion failed somewhere in a VC6 program. Shutting down. Sorry can't be any more help"); \ exit( -1 ); \ } #elif defined(_MSC_VER) && _MSC_VER > 1300 #define OlAssert( condition ) \ if( !(condition) ) { \ char linechars[64]; \ sprintf( linechars, "%i", __LINE__ ); \ OlError( "Assertion failed in \nFile: " + std::string( __FILE__ ) \ + ", line " + std::string( linechars ) \ + "\nFunction: " + std::string( __FUNCDNAME__ ) \ + "\nProgram shutting down" ); \ exit( -1 ); \ } #else #define OlAssert( condition ) \ if( !(condition) ) { \ char linechars[64]; \ sprintf( linechars, "%i", __LINE__ ); \ OlError( "Assertion failed in \nFile: " + std::string( __FILE__ ) \ + ", line " + std::string( linechars ) \ + "\nFunction: " + std::string( __PRETTY_FUNCTION__ ) \ + "\nProgram shutting down" ); \ exit( -1 ); \ } #endif static inline float RadiansToDegrees( float angle ) { return angle * (180.0/AL_PI); } static inline void RotateMatrix( float angle ) { #ifdef OL_ANGLES_IN_DEGREES glRotatef( angle, 0.0, 0.0, 1.0 ); #else // OL_ANGLES_IN_DEGREES glRotatef( RadiansToDegrees( angle ), 0.0, 0.0, 1.0 ); #endif // OL_ANGLES_IN_DEGREES } } #endif // OL_INTERNAL_HPP openlayer-2.1.orig/include/OpenLayer/Glyph.hpp0000644000175000017500000001502410575626474021646 0ustar georgeskgeorgesk#ifndef OL_GLYPH_HPP #define OL_GLYPH_HPP #include #include #include "Rgba.hpp" #include "Bitmap.hpp" #include "Point.hpp" #include "Canvas.hpp" #include "Declspec.hpp" #ifdef USE_NEW_TTF #include #include FT_FREETYPE_H #include FT_GLYPH_H #endif #define GLYPH_PI 3.14159265358979323846 #define GLYPH_SQRT2 1.41421356237309504880 namespace ol { // Forward decleration of Glyph for libFreeType class OL_LIB_DECLSPEC Glyph; /* * These items are so that we can maintain compatibility with Glyph Keeper * until TextRender adopts the new system and replaces references to * GlyphKeeper in the future. */ class OL_LIB_DECLSPEC GLYPH_FACE { public: GLYPH_FACE(); ~GLYPH_FACE(); Glyph *glyphFace; }; class OL_LIB_DECLSPEC GLYPH_REND { public: GLYPH_REND(); ~GLYPH_REND(); Glyph *glyphFace; }; class OL_LIB_DECLSPEC GLYPH_TEXTURE { public: GLYPH_TEXTURE(); ~GLYPH_TEXTURE(); Glyph *glyphFace; }; OL_LIB_DECLSPEC GLYPH_FACE *gk_load_face_from_file(const char *filename, int index); OL_LIB_DECLSPEC GLYPH_REND *gk_create_renderer( GLYPH_FACE* const face, int index ); OL_LIB_DECLSPEC void gk_rend_set_italic( GLYPH_REND* const rend, int italics ); OL_LIB_DECLSPEC void gk_rend_set_size_pixels( GLYPH_REND* const rend, const unsigned int width, const unsigned int height); OL_LIB_DECLSPEC void gk_rend_set_hinting_default( GLYPH_REND* const rend ); OL_LIB_DECLSPEC void gk_rend_set_hinting_off( GLYPH_REND* const rend ); OL_LIB_DECLSPEC void rend_set_render_mode_normal( GLYPH_REND* const rend ); OL_LIB_DECLSPEC void gk_rend_set_text_alpha_color( GLYPH_REND* const rend, const unsigned alpha_color); OL_LIB_DECLSPEC int gk_rend_ascender_pixels( GLYPH_REND* const rend ); OL_LIB_DECLSPEC int gk_rend_height_pixels( GLYPH_REND* const rend ); OL_LIB_DECLSPEC int gk_text_width_utf8(GLYPH_REND* const rend,const char* const text); OL_LIB_DECLSPEC GLYPH_TEXTURE *gk_create_texture( GLYPH_REND *rend, int rangeStart, int rangeLength ); OL_LIB_DECLSPEC void gk_unload_texture_from_gpu( GLYPH_TEXTURE *texture ); OL_LIB_DECLSPEC void gk_destroy_texture( GLYPH_TEXTURE *texture ); OL_LIB_DECLSPEC void gk_render_line_gl_utf8( GLYPH_TEXTURE *texture, const char *text, int x, int y ); OL_LIB_DECLSPEC void gk_send_texture_to_gpu( GLYPH_TEXTURE *texture ); // OL_LIB_DECLSPEC Rgba colorConvert(const unsigned char *c,short ext); // OL_LIB_DECLSPEC Rgba colorConvert(const unsigned int c); inline Rgba colorConvert(const unsigned char *c,short ext) { const float component = *c / (float)(ext-1); return Rgba(component, component, component, component); } inline Rgba colorConvert(const unsigned int c) { return Rgba( (((c >> 16) & 0xff )/255.0f) ,(((c >> 8) & 0xff )/255.0f) ,(((c ) & 0xff )/255.0f) ,(((c >> 24) & 0xff )/255.0f) ); } class OL_LIB_DECLSPEC dimension { public: dimension() { width = height = 0; italics = 0; } ~dimension(){} bool operator<(const dimension &d) const { if(width < d.width || height < d.height || italics < d.italics)return true; return false; } int width; int height; double italics; }; class OL_LIB_DECLSPEC character { public: //! Constructor character(); //! Destructor ~character(); //! Unicode representation of character signed long unicode; //! Width of character int width; //! Height of character int height; //! Space on the left of a character (assists on positioning the character) int left; //! Space on top of the character (assists on positioning the character) int top; //! Space on the right of a character (assists on positioning the character) int right; //! Pitch of a character (assists on positioning the character) int pitch; //! Amount of shades of grays the FT_Bitmap holds int grays; //! Entire rows of the FT_Bitmap int rows; //! Entire length of the character with spacing and all int length; //! FT_Bitmap raw data unsigned char *line; }; // This class handles face objects class OL_LIB_DECLSPEC Glyph { private: //! ID int ID; //! Comparison of IDs bool operator==(Glyph *g); //! Current file std::string currentFilename; //! Is the face loaded bool faceLoaded; //! Does the face have kerning bool kerning; //! Current index default 0 int currentIndex; //! Font size dimension size; //! Workspace bitmap Bitmap *workBitmap; #ifdef USE_NEW_TTF //! Face FT_Face face; #endif //! Face Name std::string faceName; //! Current character character *currentChar; //! Lookup Table by size std::map >fontTable; //! Load flags unsigned hintingFlag; unsigned renderFlag; //! Extract glyph character extractGlyph(signed long unicode); //! Create single index void createIndex(); //! Render a character from the lookup table (utilizing the workBitmap) void drawCharacter(signed long unicode, double &x1, double &y1, Bitmap *bitmap, const Rgba & col); friend class GLYPH_FACE; friend class GLYPH_REND; friend class GLYPH_TEXTURE; public: //! Constructor Glyph(); //! Destructor ~Glyph(); //! Load font from memory bool loadFromMemory(const unsigned char *memoryFont, unsigned int length, int index=0, unsigned int width=14, unsigned int height=8); //! Load font from file bool load(const std::string & filename, int index=0, unsigned int width=14, unsigned int height=8); //! Get text length double getLength(const char* text); //! Render font to a bitmap void render(double x, double y, const Rgba& col, Bitmap *bmp, int alignment, const char* text, ...); void renderFixed(double x, double y, const Rgba& col, Bitmap *bmp, int alignment, const char* text); //! Set size void setSize(int w, int h); //! Set italics void setItalics(int i); //! Set FreeType LoadFlags void setHinting(bool on=true); //! Set FreeType LoadFlags void setAntialias(bool on=false); //! Get width int getWidth(); //! Get height int getHeight(); //! Get total height int getTotalHeight(); //! Get italics int getItalics(); //! Color Rgba color; //! Enumerator for positioning of text when rendering enum { LEFT=0, CENTERED, RIGHT }; }; } #endif /* OL_GLYPH_HPP */ openlayer-2.1.orig/include/OpenLayer/Line.hpp0000644000175000017500000000732010556123320021427 0ustar georgeskgeorgesk#ifndef OL_LINE_HPP #define OL_LINE_HPP #include "Shape.hpp" #include "Vec2D.hpp" #include "Settings.hpp" #include "Declspec.hpp" namespace ol { class OL_LIB_DECLSPEC Line : public Shape { public: Line() : Shape( 1.0 ) {} Line( float x1, float y1, float x2, float y2, float lineWidth = 1.0 ) : Shape( lineWidth ), start( x1, y1 ), end( x2, y2 ) {} Line( Vec2D start, Vec2D end, float lineWidth = 1.0 ) : Shape( lineWidth ), start( start ), end( end ) {} virtual ~Line() {} inline void Draw( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDraw(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void DrawOutline( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDrawOutline(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } // Draws the line with the color smoothly changing from start of the line to the end // virtual void Draw( const Rgba &startColor, const Rgba &endColor ) const; // Moves the line by the specified amount // virtual void MoveBy( const Vec2D &amount ) { origin += amount; } virtual void MoveTo( const Vec2D &position ) { origin = position; } inline Placement GetPlacement() { return Placement( origin ); } virtual void TransformBy( const Placement &placement ) { origin += placement.GetPosition(); Matrix2D matrix = placement.Get2DMatrix(); start = matrix.Transform( start ); end = matrix.Transform( end ); } virtual void RotateBy( float angle ) { TransformBy( Placement( Vec2D( 0.0f, 0.0f ), angle )); } // Returns the intersection point of two lines // Vec2D GetIntersectionPoint( const Line &other ) const; // Tests if the two line segments collide // inline bool Collides( const Line &other ) const { return Collides( start, end, other.origin, other.start, other.end ); } Vec2D GetNormal() const { Vec2D s = end - start; Vec2D normal( -s.y, s.x ); return normal.Normalized(); } float GetShortestDistanceTo( const Vec2D &point ); inline Placement GetPlacement() const { return Placement( origin ); } inline Collision GetCollision( const Line &other ) const { if( Collides( other )) { return Collision( *this, other ); } else { return Collision( false ); } } bool Collides( const Line &other, const Placement &thisPlacement, const Placement &otherPlacement ) const; inline Collision GetCollision( const Line &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { if( Collides( other, thisPlacement, otherPlacement )) { return Collision( *this, other ); } else { return Collision( false ); } } virtual std::string ToString() const; Vec2D start, end; Vec2D origin; protected: bool Collides( const Vec2D &thisStart, const Vec2D &thisEnd, const Vec2D &otherOrigin, const Vec2D &otherStart, const Vec2D &otherEnd ) const; // Draws the line with the specified color // void ExecDraw() const; // Draws the line with the specified color // void ExecDrawOutline() const { ExecDraw(); } }; } #endif // OL_LINE_HPP openlayer-2.1.orig/include/OpenLayer/Shape.hpp0000644000175000017500000001067010552323114021601 0ustar georgeskgeorgesk#ifndef OL_SHAPE_HPP #define OL_SHAPE_HPP #include "Includes.hpp" #include "Rgba.hpp" #include "Vec2D.hpp" #include "Collisions.hpp" #include "Declspec.hpp" #ifdef OL_NO_STATE_CHANGE #define OL_SHAPE_START_RENDERING() \ GLboolean texturesEnabled; \ glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); \ glDisable( GL_TEXTURE_2D ); #else // OL_NO_STATE_CHANGE #define OL_SHAPE_START_RENDERING() glDisable( GL_TEXTURE_2D ); #endif // OL_NO_STATE_CHANGE #ifdef OL_NO_STATE_CHANGE #define OL_SHAPE_FINISH_RENDERING() \ if( texturesEnabled ) \ glEnable( GL_TEXTURE_2D ); #else // OL_NO_STATE_CHANGE #define OL_SHAPE_FINISH_RENDERING() (void) 0; #endif // OL_NO_STATE_CHANGE namespace ol { class Poly; // The base class of all Shapes // class OL_LIB_DECLSPEC Shape { public: Shape( float lineWidth = 1.0 ) : lineWidth( lineWidth ), displayList( 0 ) {} virtual ~Shape(); void Draw( const Rgba &color ) const { OL_SHAPE_START_RENDERING() color.Select(); ExecDraw(); OL_SHAPE_FINISH_RENDERING() } void DrawOutline( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDrawOutline(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } // Returns true if this and the other Shape collide // bool Collides( const Shape &other, const Placement &thisPlacement, const Placement &otherPlacement ); // Returns true if this and the other Shape collide // Collision GetCollision( const Shape &other, const Placement &thisPlacement, const Placement &otherPlacement ); // Records the results of the drawing function instead of actually drawing the primitive // inline void RecordDraw() { StartRecording(); ExecDraw(); FinishRecording(); } // Same as above but with outlines // inline void RecordDrawOutline() { StartRecording(); ExecDrawOutline(); FinishRecording(); } inline void DrawRecord( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); glCallList( displayList ); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } inline void DrawRecord( const Rgba &color, const Vec2D &displacement ) const { glPushMatrix(); glTranslatef( displacement.x, displacement.y, 0.0 ); DrawRecord( color ); glPopMatrix(); } // Moves the shape by the specified amount // virtual void MoveBy( const Vec2D &amount ) = 0; // Moves the shape to the specified position // virtual void MoveTo( const Vec2D &position ) = 0; // Rotates the shape by the specified angle // virtual void RotateBy( float angle ); // Transforms the shape by a Placement // virtual void TransformBy( const Placement &placement ); // Sets the line width of the shape // inline void SetLineWidth( float lineWidth ) { this->lineWidth = lineWidth; } //virtual Poly ToPolygon() const = 0; // Returns the line width of the shape // inline float GetLineWidth() { return lineWidth; } virtual std::string ToString() const = 0; protected: template< class std_container1, class std_container2 > Collision LineStripCollision( const std_container1 &vertices, const std_container2 &otherVertices, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults, bool thisConnectFirstAndLast, bool otherConnectFirstAndLast ) const; virtual void ExecDraw() const = 0; virtual void ExecDrawOutline() const = 0; inline void StartRecording() { displayList = glGenLists( 1 ); glNewList( displayList, GL_COMPILE ); } inline void FinishRecording() { glEndList(); } inline void RotateMatrix( float angle ) const { #ifdef OL_ANGLES_IN_DEGREES glRotatef( angle, 0.0, 0.0, 1.0 ); #else // OL_ANGLES_IN_DEGREES glRotatef( angle * ( 180.0/AL_PI ), 0.0, 0.0, 1.0 ); #endif // OL_ANGLES_IN_DEGREES } float lineWidth; int displayList; }; } #endif // OL_SHAPES_HPP openlayer-2.1.orig/include/OpenLayer/Collisions.hpp0000644000175000017500000000426710552323114022664 0ustar georgeskgeorgesk#ifndef COLLISIONS_HPP #define COLLISIONS_HPP #include "Vec2D.hpp" #include "Declspec.hpp" #include #include namespace ol { class Line; enum CollidingObject { OBJ_A = 0, OBJ_B = 1, NUM_OBJS = 2 }; class OL_LIB_DECLSPEC Collision { public: Collision( bool isCollision = false ) : isCollision( isCollision ) { normals[(int) OBJ_A] = 0; normals[(int) OBJ_B] = 0; } Collision( const Line &aSegment, const Line &bSegment ); Collision( const std::vector< std::pair< Line, Line > *> &segmentLists ); Collision( const Vec2D &aNormal, const Vec2D &bNormal, const Vec2D &collisionPoint ) : isCollision( true ) { normals[(int) OBJ_A] = new Vec2D( aNormal ); normals[(int) OBJ_B] = new Vec2D( bNormal ); points.push_back( collisionPoint ); } Collision( const Collision& c ); ~Collision(); // Returns true if a collision occured // inline bool IsCollision() { return isCollision; } // Same as above using a conversion to bool // inline operator bool() { return IsCollision(); } // Returns the exact point of collision // inline Vec2D GetPoint() { if( !points.empty() ) { return points[0]; } else { return Vec2D( 0.0f, 0.0f ); } } // Returns the all collision points // inline const std::vector< Vec2D > &GetAllPoints() const { return points; } // Returns a colliding line segment for OBJ_A or OBJ_B // const Line GetSegment( CollidingObject objectID ); // Returns all colliding segments // inline const std::vector< std::pair< Line, Line > *> &GetAllSegments() { return segmentLists; } // Returns the normal of the collision point for OBJ_A or OBJ_B // Vec2D GetNormal( CollidingObject objectID ); Collision& operator =( const Collision& c ); private: Line CreateVirtualSegment( const Vec2D &normal ); bool isCollision; std::vector< Vec2D > points; std::vector< std::pair< Line, Line > *> segmentLists; Vec2D *normals[(int) NUM_OBJS]; const static Line DEFAULT_SEGMENT; const static Vec2D DEFAULT_NORMAL; }; } #endif // COLLISIONS_HPP openlayer-2.1.orig/include/OpenLayer/Includes.hpp0000644000175000017500000000120110552323114022275 0ustar georgeskgeorgesk#ifndef OL_INCLUDES_HPP #define OL_INCLUDES_HPP #include "Declspec.hpp" /* #if (OL_DRIVER == SDL) #define SCREEN_W "notspecified" #define SCREEN_H "notspecified" #define getr32 #define getg32 #define getb32 #define OL_MEMORY_IMG void #else // (OL_DRIVER == ALLEGRO_GL) */ #include #include #define OL_MEMORY_IMG BITMAP inline OL_LIB_DECLSPEC int OlGetAlpha( OL_MEMORY_IMG *bitmap, int x, int y ) { return geta32( _getpixel32( bitmap, x, y )); } //#endif // OL_DRIVER #include #endif // OL_INCLUDES_HPP openlayer-2.1.orig/include/OpenLayer/Rectangle.hpp0000644000175000017500000001201710552323114022442 0ustar georgeskgeorgesk#ifndef OL_RECT_HPP #define OL_RECT_HPP #include "Shape.hpp" #include "Point.hpp" #include "Settings.hpp" #include "Polygon.hpp" #include "Declspec.hpp" #include namespace ol { class OL_LIB_DECLSPEC Rect : public Shape { public: Rect() : Shape( Settings::GetCircleAccuracy()) {} Rect( Vec2D pos, Vec2D size, float lineWidth = 1.0, float roundness = 0.0, float accuracy = Settings::GetCircleAccuracy() ) : Shape( lineWidth ), pos( pos ), size( size ), roundness( roundness ), rotationAngle( 0.0 ) { SetAccuracy( accuracy ); } Rect( float x, float y, float w, float h, float lineWidth = 1.0, float roundness = 0.0, float accuracy = Settings::GetCircleAccuracy() ) : Shape( lineWidth ), pos( x, y ), size( w, h ), roundness( roundness ), rotationAngle( 0.0 ) { SetAccuracy( accuracy ); } virtual ~Rect(){} //virtual ~Rect(){} inline void Draw( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDraw(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void DrawOutline( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDrawOutline(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } // Draws a gradient filled rectangle // void Draw( const Rgba *colors ) const; // Moves the rectangle by the specified amount // virtual void MoveBy( const Vec2D &amount ) { pos += amount; } virtual void MoveTo( const Vec2D &position ) { pos = position; } virtual void RotateBy( float angle ) { rotationAngle += angle; } // Sets the visual accuracy of the rounded rectangle // inline void SetAccuracy( float accuracy ) { angleIncrement = std::min(( 2.0 * asin( 1.0/roundness )/accuracy ), 0.35 * AL_PI ); } inline void SetRoundness( float roundness ) { this->roundness = roundness; SetAccuracy( Settings::GetCircleAccuracy() ); } inline void Expand( float amount ) { Expand( Vec2D( amount, amount )); } inline void Expand( Vec2D amount ) { pos -= amount; size += 2.0 * amount; } //virtual Poly ToPolygon() const; virtual void TransformBy( const Placement &placement ) { float placementRotation = placement.GetRotation(); pos += placement.GetPosition(); pos -= placement.GetRotationPivot(); rotationAngle += placementRotation; size *= placement.GetStretch(); } inline bool Collides( const Poly &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, false ).IsCollision(); } inline bool Collides( const Poly& other ) const { return DoCollisionTest( other, Placement(), other.GetPlacement(), false ).IsCollision(); } inline bool Collides( const Point& other ) const { return other.pos.x >= pos.x && other.pos.x < pos.x + size.x && other.pos.y >= pos.y && other.pos.y < pos.y + size.y; } // Tests if two polygons collide and gives detailed information about the collision // inline Collision GetCollision( const Poly &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, true ); } inline Collision GetCollision( const Poly &other ) const { return DoCollisionTest( other, Placement(), other.GetPlacement(), true ); } inline Poly ToPoly() const { return Poly( GetVertices() ); } inline std::vector< Vec2D > GetVertices() const { std::vector< Vec2D > vertices; vertices.reserve(4); vertices.push_back( pos ); vertices.push_back( Vec2D( pos.x + size.x, pos.y )); vertices.push_back( pos+size ); vertices.push_back( Vec2D( pos.x, pos.y + size.y )); return vertices; } // Returns the common area of this rectangle and an another one // Rect ClippedTo( const Rect &other ) const; virtual std::string ToString() const; Vec2D pos; Vec2D size; protected: Collision DoCollisionTest( const Poly &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults = true ) const; // Draws a filled rectangle // void ExecDraw() const; // Draws a non-filled rectangle // void ExecDrawOutline() const; void RenderCircleQuarter( float angleStart ) const; void RenderCircleOutlineQuarter( float angleStart ) const; void RenderThickCircleOutlineQuarter( float angleStart ) const; float roundness; float angleIncrement; float rotationAngle; }; } #endif // OL_RECT_HPP openlayer-2.1.orig/include/OpenLayer/GlDriver.hpp0000644000175000017500000000503710552323114022260 0ustar georgeskgeorgesk#ifndef GL_DRIVER_HPP #define GL_DRIVER_HPP #include "Includes.hpp" #include "Internal.hpp" #include "Vec2D.hpp" #include "Setup.hpp" #include "Rgba.hpp" #include "Declspec.hpp" #include // The OpenGL driver routines // namespace ol { class OlTextureInfo; class OL_LIB_DECLSPEC GlDriver { public: virtual ~GlDriver(){} virtual bool SetupProgram( bool setupKeyboard, bool setupMouse, bool setupTimer ) = 0; virtual bool SetupScreen( int width, int height, bool fullscreen, int colorDepth, int zDepth, int refreshRate ) = 0; virtual OlTextureInfo UploadTexture( OL_MEMORY_IMG *bmp, bool isSolid ) = 0; virtual OlTextureInfo UploadTexture( float *data, OlTextureInfo textureInfo ) = 0; virtual OL_MEMORY_IMG *GetMemoryBitmap( int width, int height, int bpp, unsigned char *pixelData ) = 0; virtual int GetImageColorDepth( OL_MEMORY_IMG *bmp ) = 0; virtual bool SaveMemoryBitmap( OL_MEMORY_IMG *bmp, std::string filename ) = 0; virtual void DestroyMemoryBitmap( OL_MEMORY_IMG *bmp ) = 0; virtual Rgba GetPixel( OL_MEMORY_IMG *img, int x, int y ) = 0; virtual std::string GetExecutablePath() = 0; virtual std::string ToAbsolutePathname( std::string pathname ) = 0; static void Set( GlDriver *driver ); static GlDriver *Get(); static bool IsExtensionAlvailable( std::string extensionName ); //static glEnum GetBytesPerPixel( glEnum textureFormat, int colorDepth = Setup::GetColorDepth() ); protected: const static std::string TEXTURE_NOT_POWER_OF_TWO_EXT; private: static GlDriver *activeDriver; }; class OL_LIB_DECLSPEC AllegroGLDriver : public GlDriver { public: virtual ~AllegroGLDriver(){} virtual bool SetupProgram( bool setupKeyboard, bool setupMouse, bool setupTimer ); virtual bool SetupScreen( int width, int height, bool fullscreen, int colorDepth, int zDepth, int refreshRate ); virtual OlTextureInfo UploadTexture( OL_MEMORY_IMG *bmp, bool isSolid ); virtual OlTextureInfo UploadTexture( GLfloat *data, OlTextureInfo textureInfo ); virtual OL_MEMORY_IMG *GetMemoryBitmap( int width, int height, int bpp, unsigned char *pixelData ); virtual int GetImageColorDepth( OL_MEMORY_IMG *bmp ); virtual bool SaveMemoryBitmap( OL_MEMORY_IMG *bmp, std::string filename ); virtual void DestroyMemoryBitmap( OL_MEMORY_IMG *bmp ); virtual Rgba GetPixel( OL_MEMORY_IMG *img, int x, int y ); virtual std::string GetExecutablePath(); virtual std::string ToAbsolutePathname( std::string pathname ); }; } #endif openlayer-2.1.orig/include/OpenLayer/Templates.hpp0000644000175000017500000000065010377212142022477 0ustar georgeskgeorgesk#ifndef OL_TEMPLATES_HPP #define OL_TEMPLATES_HPP #include "Includes.hpp" // Template function definitions // namespace ol { template< class Functor > Bitmap:: Bitmap( int width, int heigth, Functor functor ) : bmp( 0 ), destroyBmp( true ), qFilename(0), qAlphaFilename(0), defaultPivotX( 0 ), defaultPivotY( 0 ), useDefaultPivot( true ) { AddToCollection(); } } #endif openlayer-2.1.orig/include/OpenLayer/LineStrip.hpp0000644000175000017500000001264610552323114022457 0ustar georgeskgeorgesk#ifndef OL_LINE_STRIP_HPP #define OL_LINE_STRIP_HPP #include "Shape.hpp" #include "Vec2D.hpp" #include "Placement.hpp" #include "Line.hpp" #include "RawLineStrip.hpp" #include "Declspec.hpp" #include namespace ol { class Bitmap; // A series of lines clued together // class OL_LIB_DECLSPEC LineStrip : public Shape { public: LineStrip( float lineWidth = 1.0, const Bitmap *texture = 0 ) : Shape( lineWidth ), texture( texture ) {} template< class std_container > LineStrip( const std_container &vertices, float lineWidth = 1.0, const Bitmap *texture = 0 ); virtual ~LineStrip() {} // Draw the line strip filled with a color // inline void Draw( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDraw(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void DrawOutline( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDraw(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } // Draw the line strip with a gradient // virtual void Draw( const Rgba &startColor, const Rgba &endColor ) const; // Moves the line strip by the specified amount // virtual void MoveBy( const Vec2D &amount ) { placement.MoveBy( amount ); } virtual void MoveTo( const Vec2D &position ) { this->placement.SetPosition( position ); } inline void SetPlacement( const Placement &placement ) { this->placement = placement; } virtual void TransformBy( const Placement &placement ) { this->placement += placement; } inline const Placement &GetPlacement() const { return placement; } // Sets the filler texture of the line strip // inline void SetTexture( const Bitmap &texture ) { this->texture = &texture; } // Disables the filler texture // inline void DisableTexture() { texture = 0; } // Add a vertex to the end of the line strip // inline void AddToEnd( Vec2D vertex ) { data.AddToEnd( vertex ); } // Add a vertex to the beginning of the line strip // inline void AddToBegin( Vec2D vertex ) { data.AddToBegin( vertex ); } // Delete the first vertex of the line strip // inline void DeleteFirst() { data.DeleteFirst(); } // Delete the first last of the line strip // inline void DeleteLast() { data.DeleteLast(); } // Returns the specified vertex // Vec2D GetVertex( unsigned int index ) const; // Returns the specified segment // inline Line GetSegment( int index ) const { return Line( GetVertex( index ), GetVertex( index+1 )); } // Returns the number of vertices // inline int GetNumOfVertices() const { return data.GetVertices().size(); } const std::list< Vec2D > &GetVertices() const { return data.GetVertices(); } virtual std::string ToString() const; // The following functions could be derived from Set/GetPlacement inline void SetRotationAngle( float angle ) { placement.SetRotation( angle ); } inline float GetRotationAngle() { return placement.GetRotation(); } virtual void RotateBy( float angle ) { placement.RotateBy( angle ); } // Collision routines inline bool Collides( const LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, false ).IsCollision(); } inline Collision GetCollision( const LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, true ); } inline Collision GetCollision( const Line &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, true ); } private: Collision DoCollisionTest( const LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults = true ) const; Collision DoCollisionTest( const Line &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults = true ) const; // Draws the line strip with the specified color // void ExecDraw() const; // Draws the line strip with the specified color // void ExecDrawOutline() const { ExecDraw(); } // Raw line strip rendering function // void Render( const Rgba *color1, const Rgba *color2 ) const; RawLineStrip< std::list< Vec2D >, std::list< float > > data; Placement placement; const Bitmap *texture; }; // TEMPLATES // template< class std_container > LineStrip:: LineStrip( const std_container &theVertices, float lineWidth, const Bitmap *texture ) : Shape( lineWidth ), texture( texture ) { for( typename std_container::const_iterator iter = theVertices.begin(); iter != theVertices.end(); iter++ ) { AddToEnd( *iter ); } } } #endif // OL_LINE_STRIP_HPP openlayer-2.1.orig/include/OpenLayer/PendingLoad.hpp0000644000175000017500000000333710552323114022727 0ustar georgeskgeorgesk#ifndef PENDING_LOADING_HPP #define PENDING_LOADING_HPP #include "Includes.hpp" #include "GarbageCollector.hpp" #include "TextureInfo.hpp" #include "Declspec.hpp" namespace ol { class Bitmap; class OL_LIB_DECLSPEC PendingBitmapLoad { public: virtual ~PendingBitmapLoad(){} virtual OlLoadResult ExecuteLoading( Bitmap &bmp ) = 0; }; class OL_LIB_DECLSPEC PendingFileLoad : public PendingBitmapLoad { public: PendingFileLoad( const char *filename ) : filename( filename ) {} virtual ~PendingFileLoad(){} virtual OlLoadResult ExecuteLoading( Bitmap &bmp ); private: const char *filename; }; class OL_LIB_DECLSPEC PendingFileAlphaLoad : public PendingBitmapLoad { public: PendingFileAlphaLoad( const char *filename, const char *alphaFilename ) : filename( filename ), alphaFilename( alphaFilename ) {} virtual ~PendingFileAlphaLoad(){} virtual OlLoadResult ExecuteLoading( Bitmap &bmp ); private: const char *filename; const char *alphaFilename; }; class OL_LIB_DECLSPEC PendingDataLoad : public PendingBitmapLoad { public: PendingDataLoad( float *data, OlTextureInfo textureInfo ) : data( data ), textureInfo( textureInfo ) {} virtual ~PendingDataLoad(){} virtual OlLoadResult ExecuteLoading( Bitmap &bmp ); private: float *data; OlTextureInfo textureInfo; }; template< class Functor > class OL_LIB_DECLSPEC PendingFunctorLoad : public PendingBitmapLoad { public: PendingFunctorLoad( Functor functor, int width, int height ) : functor( functor ), width( width ), height( height ) {} virtual ~PendingFunctorLoad(){} virtual OlLoadResult ExecuteLoading( Bitmap &bmp ); private: Functor functor; int width, height; }; } #endif // PENDING_LOADING_HPP openlayer-2.1.orig/include/OpenLayer/LineStripRender.hpp0000644000175000017500000002023110552323114023604 0ustar georgeskgeorgesk#ifndef OL_LINE_STRIP_RENDER_HPP #define OL_LINE_STRIP_RENDER_HPP #include "Rgba.hpp" #include "Bitmap.hpp" #include "RawLineStrip.hpp" #include "Declspec.hpp" #define OL_NEAR_ZERO 0.001 namespace ol { template< class std_container_v, class std_container_l > OL_LIB_DECLSPEC void RawLineStrip< std_container_v, std_container_l >:: LineStripRender( const Rgba *color1, const Rgba *color2, const Bitmap *texture, float lineWidth, const Placement &placement, bool connectFirstAndLast ) const { if( vertices.size() < 2 ) { return; } #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif if( texture ) { texture->GetReadyToRender( 1.0 ); } else { glDisable( GL_TEXTURE_2D ); } // The sum of lengths thus far // float sumLengths = 0.0; float texturePos = 0.0; typename std_container_l::const_iterator lengthIter = lengths.begin(); // Find the normal of the beginning of the strip // Vec2D lastS, last; typename std_container_v::const_iterator vertexIter = vertices.begin(); if( connectFirstAndLast ) { last = vertices.back(); lastS = vertices.front() - last; } else { last = vertices.front(); typename std_container_v::const_iterator lastSIter = vertices.begin(); lastSIter++; if( *lastSIter == last ) { unsigned int index = 2; while( *lastSIter == last ) { if( vertices.size() <= index ) return; lastSIter++; index++; lengthIter++; } } lastS = *lastSIter - last; vertexIter++; } lastS /= lastS.GetMagnitude(); glPushMatrix(); placement.Apply(); // Render the begin of the strip // glBegin( GL_QUAD_STRIP ); if( color1 ) { color1->Select(); } float lastUpperX = last.x + lastS.y * lineWidth; float lastUpperY = last.y - lastS.x * lineWidth; float lastLowerX = last.x - lastS.y * lineWidth; float lastLowerY = last.y + lastS.x * lineWidth; if( !texture ) { glVertex2f( lastUpperX, lastUpperY ); glVertex2f( lastLowerX, lastLowerY ); } else { const OlTextureInfo &textureInfo = texture->textureInfo; glTexCoord2f( textureInfo.rect.x, textureInfo.rect.y ); glVertex2f( lastUpperX, lastUpperY ); glTexCoord2f( textureInfo.rect.x, textureInfo.rect.y + textureInfo.rect.h ); glVertex2f( lastLowerX, lastLowerY ); } bool running = true; while( running ) { float x = vertexIter->x; float y = vertexIter->y; vertexIter++; if( vertexIter == vertices.end() ) { if( connectFirstAndLast ) { running = false; vertexIter = vertices.begin(); } else { break; } } if( color1 ) { float factor = sumLengths / totalLength; sumLengths += *lengthIter; color1->InterpolateWith( *color2, factor ).Select(); } if( fabs( x - last.x ) < OL_NEAR_ZERO && fabs( y - last.y ) < OL_NEAR_ZERO ) { continue; } // Find the direction vector from the next point to the current one // float bx = x - vertexIter->x; float by = y - vertexIter->y; float bLength = sqrt( bx * bx + by * by ); if( bLength > -OL_NEAR_ZERO && bLength < OL_NEAR_ZERO ) { continue; } bx /= bLength; by /= bLength; // Find the direction vector of the displacement // float cx = lastS.x + bx; float cy = lastS.y + by; float cLength = sqrt( cx * cx + cy * cy ); float nx, ny; if( cLength > -OL_NEAR_ZERO && cLength < OL_NEAR_ZERO ) { nx = -by; ny = bx; float nRatio = lineWidth/sqrt( nx * nx + ny * ny ); nx *= nRatio; ny *= nRatio; } else { cx /= cLength; cy /= cLength; // Make sure that the displacement happens always in the same side // float diff1 = lastS.x - bx; float diff2 = lastS.y - by; float diff3 = cx - bx; float diff4 = cy - by; if(( diff1 * diff4 ) - ( diff2 * diff3 ) > 0 ) { cx = -cx; cy = -cy; } // Find the displacement multiplicator // float s = lastS.y * cx + (-lastS.x) * cy; if( fabs( s ) < OL_NEAR_ZERO ) { nx = -by; ny = bx; float nRatio = lineWidth/sqrt( nx * nx + ny * ny ); nx *= nRatio; ny *= nRatio; } else { nx = cx * lineWidth / s; ny = cy * lineWidth / s; } } // Find the displaced coordinates // float upperX = x + nx; float upperY = y + ny; float lowerX = x - nx; float lowerY = y - ny; if( !texture ) { glVertex2f( upperX, upperY ); glVertex2f( lowerX, lowerY ); } else { const OlTextureInfo &textureInfo = texture->textureInfo; texturePos += *lengthIter / textureInfo.imgWidth; if( texturePos > textureInfo.rect.w ) { texturePos = 0.0; } glTexCoord2f( textureInfo.rect.x + texturePos, textureInfo.rect.y ); glVertex2f( upperX, upperY ); glTexCoord2f( textureInfo.rect.x + texturePos, textureInfo.rect.y + textureInfo.rect.h ); glVertex2f( lowerX, lowerY ); typename std_container_v::const_iterator nextIter = vertexIter; nextIter++; bool renderingAllowed = nextIter == vertices.end(); if( !renderingAllowed && connectFirstAndLast ) { renderingAllowed = true; nextIter = vertices.begin(); } if( nextIter != vertices.end() ) { glTexCoord2f( textureInfo.rect.x + texturePos, textureInfo.rect.y ); glVertex2f( upperX, upperY ); glTexCoord2f( textureInfo.rect.x + texturePos, textureInfo.rect.y + textureInfo.rect.h ); glVertex2f( lowerX, lowerY ); } } // Store the information which can be used when calculating the next point // last.x = x; last.y = y; lastS.x = -bx; lastS.y = -by; /* lastUpperX = upperX; lastUpperY = upperY; lastLowerX = lowerX; lastLowerY = lowerY; */ lengthIter++; } if( !connectFirstAndLast ) { // Render the end of the strip // float x = vertices.back().x; float y = vertices.back().y; float upperX = x + lastS.y * lineWidth; float upperY = y - lastS.x * lineWidth; float lowerX = x - lastS.y * lineWidth; float lowerY = y + lastS.x * lineWidth; if( color2 ) color2->Select(); glVertex2f( upperX, upperY ); glVertex2f( lowerX, lowerY ); } glEnd(); glPopMatrix(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); else glDisable( GL_TEXTURE_2D ); #endif } } #endif // OL_LINE_STRIP_RENDER_HPP openlayer-2.1.orig/include/OpenLayer/Animation.hpp0000644000175000017500000000311110552323114022450 0ustar georgeskgeorgesk#ifndef OL_ANIMATION_HPP #define OL_ANIMATION_HPP #include "Includes.hpp" #include "Bitmap.hpp" #include "Declspec.hpp" #include namespace ol { // Animation - Loads and animates a sequence of bitmaps // // Animation speed is in animation frames per one game frame // class OL_LIB_DECLSPEC Animation { public: // Loads the animation frames as filenameBegin01.extension, filenameBegin02.extension etc. // Animation( float framesPerTick, std::string filenameBegin, std::string extension, int numNumbers = 2 ) : framesPerTick( framesPerTick ), currentFrame( 0.0 ) { Load( filenameBegin, extension, numNumbers ); } // Loads the animation by using a list of frames // // A copy of the list will be stored in the Animation // Animation( float framesPerTick, const std::vector< Bitmap *> &frames ) : frames( frames ), framesPerTick( framesPerTick ), currentFrame( 0.0 ) {} // Loads the animation frames as filenameBegin01.extension, filenameBegin02.extension etc. // // Where numNumbers is the amount of numbers in the filiname // bool Load( std::string filenameBegin, std::string extension, int numNumbers = 2 ); // Returns a reference to the current visible frame // const Bitmap &GetFrame(); // Updates the animation, deltaTime is the number of game frames elapsed // // Returns true if the animation is finished and stared again at the first frame // bool Update( float deltaTime ); private: std::vector< Bitmap *> frames; float framesPerTick; float currentFrame; }; } #endif openlayer-2.1.orig/include/OpenLayer/TextRenderer.hpp0000644000175000017500000001724210575626474023202 0ustar georgeskgeorgesk//#ifndef OL_NO_TTF #ifndef OL_TEXT_RENDERER_HPP #define OL_TEXT_RENDERER_HPP #ifdef OL_NO_TTF #define USE_NEW_TTF #endif #include "Includes.hpp" #include "Rgba.hpp" #include "GarbageCollector.hpp" #include "General.hpp" #include "Declspec.hpp" #ifdef USE_NEW_TTF #include "Glyph.hpp" #else #define GLYPH_TARGET GLYPH_TARGET_ALLEGGL #include #endif /* USE_NEW_TTF */ namespace ol { #define UNDEFINED_ITALICS -361 // TextRenderer - Renders multi-lined text to the screen using a TrueType font // // Notice that you can use a newline character ('\n') in the middle of the text // // to start a new text line. // // Works the same way as Glyph Keeper's Rend structure // // Uses GlyphKeeper to render text // class OL_LIB_DECLSPEC TextRenderer : public GarbageCollected { public: // Construct the font by loading the face from a .ttf file // // The loaded font face will be automatically destroyed when the TextRenderer is destroyed // TextRenderer( const char *filename, int width = 9, int height = 12, Rgba col = Rgba::BLACK, int italics = 0, bool useHinting = true ); // Construct the font by using the face from an another TextRenderer // // If you don't specify any color or italics angle they'll be inherited from the other renderer! // TextRenderer( const TextRenderer &otherRenderer, int width = 12, int height = 10, Rgba col = Rgba(), int italics = UNDEFINED_ITALICS ); // Construct the font by using a GlyphKeeper font face // TextRenderer( GLYPH_FACE *face, int width = 12, int height = 10, Rgba col = Rgba::BLACK, int italics = 0, bool useHinting = true ); // The default constructor leaves the font invalid (IsValid() returns false) // TextRenderer(); // The destructor destroys the font and makes sure that it's not garbage collected // virtual ~TextRenderer() { Destroy( true ); } // Loads a font from a .ttf file, returns true on success // bool Load( const char *filename, int width, int height, Rgba col = Rgba::BLACK, int italics = 0, bool useHinting = true ); // Loads a font using the face from an another TextRenderer, returns true on success // // If you don't specify any color or italics angle they'll be inherited from the other renderer! // bool Load( const TextRenderer &otherRenderer, int width, int height, Rgba col = Rgba(), int italics = UNDEFINED_ITALICS ); // Loads a font from a Glyph Keeper face, returns true on success // // Pass true to destroyFace if you wish the font face to be automatically destroyed // // when the Destroy() -method or the deconstructor is called // bool Load( GLYPH_FACE *face, int width, int height, Rgba col = Rgba::BLACK, int italics = 0, bool useHinting = true ); // Draws multi-lined text to the screen // void Print( const std::string &text, int x, int baselineY ) const; // Draws multi-lined text to the screen with automatic line wrapping // void Print( const std::string &text, int x, int baselineY, int maxLineWidth, TextAlignment alignment = LEFT ) const; // Calling this function will invalidiate the font // // Frees all memory allocated by this TextRenderer // // and unloads the font from the graphics card // // Notice that the font face isn't unloaded by Glyph Keeper // // until the program exits! // // You can unload it manually if you want by calling GetFace() // // and unloading that // virtual void Destroy( bool eraseFromGarbageCollection = false ); // Sets the font color // void SetColor( const Rgba& col ); // Returns the color of the font // const Rgba& GetColor() const; // Sets the italics angle of the text // void SetItalics( int italicsAngle ); // Returns the italics angle of the text // int GetItalics() const; // Font height int FontHeight() const; // Font total height int FontTotalHeight() const; // Returns the width and height of multi-lined text // int Width( const std::string &text ) const; int Height( const std::string &text ) const; // Returns the width and height of the first text line of multi-lined text // int FirstLineWidth( const std::string &text ) const; int FirstLineHeight( const std::string &text ) const; // Returns true if the TextRenderer is ready to use (loaded and not destroyed) // virtual bool IsValid() const; // The boolean operator returns the same as the IsValid-method // inline operator bool() { return IsValid(); } inline void UseTags( bool turnedOn ) { useTags = turnedOn; } static std::string GetColoredText( const std::string &str, Rgba color ); inline Vec2D GetTextSize( const std::string& str ) { return Vec2D( Width( str ), Height( str )); } // ADVANCED FUNCTIONS // // (You don't usually need to call these) // // Returs the Glyph Keeper face of the font in case if you need it somewhere // GLYPH_FACE *GetFace() const { return face; } // Sends the font to the graphics card // // Automatically done when the font is loaded // virtual void SendToGPU(); // Unloads the font from the graphics card // // Automatically done when the font is destroyed // void UnloadFromGPU(); // Returns true if a loading command is waiting for Setup::SetupScreen to be called // virtual bool IsLoadingQueued() const; // Called by Setup::SetupScreen // virtual OlLoadResult ExecuteQueuedCommands(); // Adds the TextRenderer to the garbage/auto-loader collection // // (automatically done) // virtual void AddToCollection(); // Suspending OpenGL will simply destroy the font texture(s) // virtual void UnloadToMemory() { UnloadFromGPU(); } private: void StartRendering() const { SelectColor( col ); } void SelectColor( const Rgba &color ) const; void FinishRendering() const; void RenderLineAligned( const std::string &line, int x, int y, int maxLineWidth, TextAlignment alignment ) const; GLYPH_REND *rend; GLYPH_TEXTURE *texture; GLYPH_FACE *face; // If you modify this library note that modifying this variable // // doesn't change the italics of the font! // int italics; bool useHinting; Rgba col; bool useTags; // AUTO LOADER ROUTINES // class Loader { public: Loader( int w, int h, int italics, Rgba col ) : w( w ), h( h ), italics( italics ), col( col ) {} virtual ~Loader(){} virtual OlLoadResult Load( TextRenderer &subject ) = 0; protected: TextRenderer *renderer; int w, h; int italics; Rgba col; }; Loader *loader; class FileLoader : public Loader { public: FileLoader( const char *filename, int w, int h, int italics, Rgba col ) : Loader( w, h, italics, col ), filename( filename ) {} virtual ~FileLoader(){} virtual OlLoadResult Load( TextRenderer &subject ); protected: const char *filename; }; class RendLoader : public Loader { public: RendLoader( const TextRenderer &rend, int w, int h, int italics, Rgba col ) : Loader( w, h, italics, col ), rend( rend ) {} virtual ~RendLoader(){} virtual OlLoadResult Load( TextRenderer &subject ); protected: const TextRenderer &rend; }; }; } #endif // OL_TEXT_RENDERER_HPP //#endif // OL_NO_TTF openlayer-2.1.orig/include/OpenLayer/Setup.hpp0000644000175000017500000000560210552323114021640 0ustar georgeskgeorgesk#ifndef OL_SETUP_HPP #define OL_SETUP_HPP #include "Includes.hpp" #include "Declspec.hpp" #include namespace ol { // Setup - Program setup functions // // Possible devices to setup // enum { KEYBOARD = 0x1, MOUSE = 0x2, TIMER = 0x4 }; // Possible screen modes (you can pass these instead of true and false // as the fullscreen -parameter in SetupScreen) // #define WINDOWED false #define FULLSCREEN true class OL_LIB_DECLSPEC Setup { public: // Sets up OpenLayer, Allegro and AllegroGL, returns true on success // static bool SetupProgram( bool setupKeyboard = true, bool setupMouse = true, bool setupTimer = true ); // Same as above but the parameters are passed by using logical "or" // // of any of the devices listed above the Setup class // static bool SetupProgram( int devices ); // Sets up the program window, width and height tell the screen resolution (fullscreen) // // or the window size (windowed) // // Z-depth is the accuracy of the built-in depth sorting (values: 8, 16 or 32), // but you don't usually have to worry about it // // Returns true in success // static bool SetupScreen( int width, int height, bool fullscreen = true, int colorDepth = 32, int zDepth = 8, int refreshRate = 0 ); // Returns true if SetupProgram is called and the program is succesfully set up // static bool IsProgramSetUp(); // Returns true if SetupScreen is called and the program window is created // static bool IsScreenSetUp(); // Returns the width of the screen // static inline int GetWindowWidth() { return windowWidth; } // Returns the height of the screen // static inline int GetWindowHeight() { return windowHeight; } // Returns the color depth of the screen // static inline int GetColorDepth() { return colorDepth; } // Returns the path to the executable // static inline std::string GetExecutablePath() { return executablePath; } // If the passed pathname is relative, an absolute version of the pathname is returned // // Otherwise the pathname is returned unmodified // static std::string ToAbsolutePathname( std::string pathname ); // Unloads most graphics card resources that OpenLayer uses // static void SuspendProgram(); // Reloads resources which were previously unloaded after a call to SuspendProgram // static void WakeUpProgram(); // Returns the OpenGL error, or null if no error has occured // static const char *GetGLError(); private: static bool programIsSetUp; static bool screenIsSetUp; static std::string executablePath; static int windowWidth; static int windowHeight; static int colorDepth; }; } #endif // OL_SETUP_HPP openlayer-2.1.orig/include/OpenLayer/Polygon.hpp0000644000175000017500000002014010552323114022161 0ustar georgeskgeorgesk#ifndef OL_POLYGON_HPP #define OL_POLYGON_HPP #include "RawLineStrip.hpp" #include "Vec2D.hpp" #include "Rgba.hpp" #include "Internal.hpp" #include "General.hpp" #include "Shape.hpp" #include "Placement.hpp" #include "Collisions.hpp" #include "LineStrip.hpp" #include "Line.hpp" #include "Declspec.hpp" #include namespace ol { class Bitmap; class LineStrip; class OL_LIB_DECLSPEC Poly : public Shape { public: Poly( Vec2D rotationPivot = Vec2D( 0.0, 0.0 )) : outlineTexture( 0 ) { placement.SetRotationPivot( rotationPivot ); } // Construct the polygon from a list of vertices // template< class std_container > Poly( const std_container &vertices, Vec2D rotationPivot = Vec2D( 0.0, 0.0 )); // Construct the polygon from a list of vertices // Poly( const Vec2D *vertices, int numVertices, Vec2D rotationPivot = Vec2D( 0.0, 0.0 )); virtual ~Poly(); // Adds a vertex to the polygon // virtual void Add( Vec2D vec ); virtual void SetVertex( int index, const Vec2D &newValue ); // Returns a reference to the vertex with the given index // inline const Vec2D &GetVertex( unsigned int index ) const { static Vec2D dummyValue; if( index < 0 || index >= data.GetVertices().size()) { OlError( "Invalid vertex index: " + VarToString( index ) + " ( Number of vertices: " + VarToString( data.GetVertices().size()) + " )" ); return dummyValue; } return data.GetVertices()[index]; } inline Vec2D &GetVertex( unsigned int index ) { static Vec2D dummyValue; if( index < 0 || index >= data.GetVertices().size()) { OlError( "Invalid vertex index: " + VarToString( index ) + " ( Number of vertices: " + VarToString( data.GetVertices().size()) + " )" ); return dummyValue; } return data.GetVertices()[index]; } inline int GetNumberOfVertices() { return data.GetVertices().size(); } inline void Draw( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDraw(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } void DrawOutline( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDrawOutline(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } // Tests if two polygons collide // inline bool Collides( const Poly &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, false ).IsCollision(); } inline bool Collides( const Poly& other ) const { return DoCollisionTest( other, placement, other.placement, false ).IsCollision(); } // Tests if two polygons collide and gives detailed information about the collision // inline Collision GetCollision( const Poly &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement ); } inline Collision GetCollision( const Poly &other ) const { return DoCollisionTest( other, placement, other.placement ); } // Returns a constant reference to the list of the vertices // inline const std::vector< Vec2D > &GetVertices() const { return data.GetVertices(); } // Returns the specified segment // inline Line GetSegment( unsigned int index ) const { if( index >= 0 && index < data.GetVertices().size()-1 ) { return Line( data.GetVertices()[index], data.GetVertices()[index+1] ); } return Line(); } // Moves the polygon by the specified amount // virtual void MoveBy( const Vec2D &amount ) { placement.MoveBy( amount ); } // Sets the position of the polygon inline virtual void MoveTo( const Vec2D &position ) { placement.SetPosition( position ); } virtual void RotateBy( float angle ) { placement.RotateBy( angle ); } // Sets the placement of the polygon inline void SetPlacement( const Placement &placement ) { this->placement = placement; } virtual void TransformBy( const Placement &placement ) { this->placement += placement; } // Returns the placement of the polygon inline const Placement &GetPlacement() const { return placement; } /* virtual Poly ToPolygon() const { return *this; } */ // Sets the outline texture of the polygon, pass zero to get rid of the outline texture // inline void SetOutlineTexture( ol::Bitmap *texture, OutlineTextureMode mode = OPTIMIZE ) { outlineTexture = texture; } virtual std::string ToString() const; // The following functions could be derived from Set/GetPlacement inline void SetRotationAngle( float angle ) { placement.SetRotation( angle ); } inline float GetRotationAngle() const { return placement.GetRotation(); } inline void SetPivot( Vec2D rotationPivot ) { placement.SetRotationPivot( rotationPivot ); } inline Vec2D GetPivot() const { return placement.GetRotationPivot(); } // Collision between other Shapes inline bool Collides( const LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, false ).IsCollision(); } inline bool Collides( const Line &other ) { return DoCollisionTest( other, placement, other.GetPlacement(), false ); } inline Collision GetCollision( const LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, true ); } inline bool Collides( const LineStrip &other ) const { return DoCollisionTest( other, placement, other.GetPlacement(), false ).IsCollision(); } inline Collision GetCollision( const LineStrip &other ) const { return DoCollisionTest( other, placement, other.GetPlacement(), true ); } inline Collision GetCollision( const Line &other, const Placement &thisPlacement, const Placement &otherPlacement ) const { return DoCollisionTest( other, thisPlacement, otherPlacement, true ); } inline Collision GetCollision( const Line &other ) { return DoCollisionTest( other, placement, other.GetPlacement(), true ); } protected: Collision DoCollisionTest( const Poly &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults = true ) const; Collision DoCollisionTest( const LineStrip &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults = true ) const; Collision DoCollisionTest( const Line &other, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults = true ) const; // Draws the polygon to the active canvas // virtual void ExecDraw() const; // Draws the outline of the polygon to the active canvas // virtual void ExecDrawOutline() const; RawLineStrip< std::vector< Vec2D >, std::vector< float > > data; Placement placement; Bitmap *outlineTexture; OutlineTextureMode outlineMode; }; // TEMPLATES // #include "Internal.hpp" template< class std_container > Poly::Poly( const std_container &theVertices, Vec2D rotationPivot ) : outlineTexture( 0 ) { placement.SetRotationPivot( rotationPivot ); data.GetVertices().reserve( theVertices.size() ); for( typename std_container::const_iterator iter = theVertices.begin(); iter != theVertices.end(); iter++ ) { data.AddToEnd( *iter ); } } } #endif // OL_POLYGON_HPP openlayer-2.1.orig/include/OpenLayer/Placement.hpp0000644000175000017500000000543710552323114022456 0ustar georgeskgeorgesk#ifndef OL_TRANSFORM_MATRIX_HPP #define OL_TRANSFORM_MATRIX_HPP #include "Matrix.hpp" #include "Vec2D.hpp" #include "Declspec.hpp" namespace ol { class OL_LIB_DECLSPEC Placement { public: Placement( Vec2D position = Vec2D( 0.0, 0.0 ), float rotation = 0.0, float stretch = 1.0, Vec2D rotationPivot = Vec2D( 0.0, 0.0 )) : position( position ), rotation( rotation ), stretch( stretch ), rotationPivot( rotationPivot ) {} inline float GetDistance( const Placement &other ) const{ return (position - other.position).GetMagnitude(); } inline void MoveBy( Vec2D value ) { position += value; } inline void RotateBy( float value ) { rotation += value; } inline void StretchBy( float factor ) { stretch *= factor; } inline void SetPosition( Vec2D position ) { this->position = position; } inline Vec2D GetPosition() const { return position; } inline void SetRotation( float rotation ) { this->rotation = rotation; } inline float GetRotation() const { return rotation; } inline void SetRotationPivot( Vec2D rotationPivot ) { this->rotationPivot = rotationPivot; } inline const Vec2D &GetRotationPivot() const { return rotationPivot; } inline void SetStretch( float stretch ) { this->stretch = stretch; } inline float GetStretch() const { return stretch; } inline Placement& operator +( const Vec2D& amount ) { position += amount; return *this; } inline Placement& operator -( const Vec2D& amount ) { position -= amount; return *this; } inline Placement& operator +( const Placement& amount ) { position += amount.position; rotation += amount.rotation; stretch *= amount.stretch; return *this; } inline Placement& operator +=( const Placement& amount ) { position += amount.position; rotation += amount.rotation; stretch *= amount.stretch; return *this; } inline Placement& operator -( const Placement& amount ) { position -= amount.position; rotation -= amount.rotation; stretch /= amount.stretch; return *this; } inline Placement& operator -=( const Placement& amount ) { position += amount.position; rotation += amount.rotation; stretch *= amount.stretch; return *this; } // Returns the rotation and stretch in a matrix // Matrix2D Get2DMatrix() const; // Applies the placement inline void Apply() const { Apply( rotationPivot ); } // Same as above but overrides the pivot void Apply( const Vec2D &pivot ) const; std::string ToString() const; private: Vec2D position; float rotation; float stretch; Vec2D rotationPivot; }; } #endif // OL_TRANSFORM_MATRIX_HPP openlayer-2.1.orig/include/OpenLayer/Vec2D.hpp0000644000175000017500000000572010552323114021444 0ustar georgeskgeorgesk#ifndef OL_VEC2D_HPP #define OL_VEC2D_HPP #include #include #include #include "General.hpp" #include "Declspec.hpp" namespace ol { class OL_LIB_DECLSPEC Vec2D { public: float x, y; // CONSTRUCTORS // Vec2D( float x = 0.0, float y = 0.0 ) : x( x ), y( y ) {} static inline Vec2D PolarCoords( float angle, float magnitude ) { return Vec2D( magnitude * std::cos( angle ), magnitude * std::sin( angle )); } // METHODS // inline float GetAngle() const { return std::atan2( y, x ); } inline float GetMagnitude() const { return std::sqrt( GetMagnitudeSquared() ); } inline float GetMagnitudeSquared() const { return x * x + y * y; } inline Vec2D Normalized() const { float magnitude = GetMagnitude(); return Vec2D( x / magnitude, y / magnitude ); } // OPERATORS // inline void operator += ( const Vec2D &other ) { x += other.x; y += other.y; } inline void operator -= ( const Vec2D &other ) { x -= other.x; y -= other.y; } inline void operator *= ( float factor ) { x *= factor; y *= factor; } inline void operator /= ( float divisor ) { x /= divisor; y /= divisor; } inline bool operator == ( const Vec2D &other ) const { return fabs(x - other.x) < 0.01 && fabs(y - other.y) < 0.01; } inline bool operator != ( const Vec2D &other ) const { return !(*this == other); } inline std::string ToString() const { std::ostringstream str; str << "( " << x << ", " << y << " )"; return str.str(); } inline std::string GetString() const { return ToString(); } }; // ADDITION AND SUBTRACTION // inline Vec2D operator + ( Vec2D first, Vec2D second ) { return Vec2D( first.x + second.x, first.y + second.y ); } inline Vec2D operator - ( Vec2D first, Vec2D second ) { return Vec2D( first.x - second.x, first.y - second.y ); } // MULTIPLICATION AND DIVISION inline Vec2D operator * ( Vec2D vec, float factor ) { return Vec2D( factor * vec.x, factor * vec.y ); } inline Vec2D operator * ( float factor, Vec2D vec ) { return Vec2D( factor * vec.x, factor * vec.y ); } inline Vec2D operator / ( Vec2D vec, float divisor ) { return Vec2D( vec.x / divisor, vec.y / divisor ); } // DOT PRODUCT // inline float operator * ( Vec2D first, Vec2D second ) { return first.x * second.x + first.y * second.y; } // SIGN // inline Vec2D operator - ( Vec2D vec ) { return Vec2D( -vec.x, -vec.y ); } // NORMALIZATION inline Vec2D operator ~ ( Vec2D vec ) { return vec.Normalized(); } // TESTS // Checks if the points are in counter clockwise order // inline OL_LIB_DECLSPEC bool IsCounterClockwise( const Vec2D first, const Vec2D second, const Vec2D third ) { float dx1, dx2, dy1, dy2; dx1 = second.x - first.x; dy1 = second.y - first.y; dx2 = third.x - second.x; dy2 = third.y - second.y; return dy1*dx2 < dy2*dx1; } } #endif openlayer-2.1.orig/include/OpenLayer/GarbageCollector.hpp0000644000175000017500000000353210552323114023737 0ustar georgeskgeorgesk#ifndef OL_GARBAGE_COLLECTOR #define OL_GARBAGE_COLLECTOR #include #include "Includes.hpp" #include "Declspec.hpp" namespace ol { // The type of an Auto Loader result, only used by OpenLayer's internals // enum OlLoadResult { OL_LR_SUCCESS, OL_LR_PENDING, OL_LR_FAILURE }; // Virtual garbace collectector class used by OpenLayer's routines // // to automate the loading and destroying of global variables // // GarbageCollected only defines the interface for garbage collected objects // class OL_LIB_DECLSPEC GarbageCollected { public: GarbageCollected() : autoDelete( false ) {} virtual ~GarbageCollected() {} virtual void Destroy( bool eraseFromGarbageCollection = false ) = 0; virtual OlLoadResult ExecuteQueuedCommands() = 0; virtual void UnloadToMemory() = 0; virtual void SendToGPU() = 0; virtual bool IsValid() const = 0; virtual bool IsLoadingQueued() const = 0; virtual void AddToCollection() = 0; // Chooses this object to be automatically freed from the memory // // when the program quits // void UseAutoDelete() { autoDelete = true; } // Returns true if the auto delete feature is used for this object // bool AutoDeleteUsed() { return autoDelete; } private: bool autoDelete; }; // Garbage collection which stores all Bitmaps and TextRenderers // // Automatically loads and destroys global Bitmaps and TextRenderers // class OL_LIB_DECLSPEC GarbageCollection { public: void Add( GarbageCollected *item ); void Remove( GarbageCollected *item ); void ExecuteQueues(); void DestroyGarbage(); void UnloadAllToMemory(); void LoadAllToGPU(); private: std::list< GarbageCollected *> collection; }; } #endif // OL_GARBAGE_COLLECTOR openlayer-2.1.orig/include/OpenLayer/Circle.hpp0000644000175000017500000001406110552323114021740 0ustar georgeskgeorgesk#ifndef OL_CIRCLE_HPP #define OL_CIRCLE_HPP #include "Shape.hpp" #include "Settings.hpp" #include "Rgba.hpp" #include "Placement.hpp" #include "Declspec.hpp" #include #include #ifdef max #undef max #endif #ifdef min #undef min #endif namespace ol { // The ellipse shape // class OL_LIB_DECLSPEC Ellipse : public Shape { public: virtual ~Ellipse() {} Ellipse() : Shape( 1.0 ) { SetAccuracy( Settings::GetCircleAccuracy()); } Ellipse( float x, float y, float xRadius, float yRadius, float lineWidth = 1.0, float angle = 0.0, float accuracy = Settings::GetCircleAccuracy() ) : Shape( lineWidth ), pos( x, y ), angle( angle ), xRad( xRadius ), yRad( yRadius ) { SetAccuracy( accuracy ); } Ellipse( Vec2D pos, Vec2D radiuses, float lineWidth = 1.0, float angle = 0.0, float accuracy = Settings::GetCircleAccuracy() ) : Shape( lineWidth ), pos( pos ), angle( angle ), xRad( radiuses.x ), yRad( radiuses.y ) { SetAccuracy( accuracy ); } inline void Draw( const Rgba &color ) const { OL_SHAPE_START_RENDERING() color.Select(); ExecDraw(); OL_SHAPE_FINISH_RENDERING() } void DrawOutline( const Rgba &color ) const { #ifdef OL_NO_STATE_CHANGE GLboolean texturesEnabled; glGetBooleanv( GL_TEXTURE_2D, &texturesEnabled ); #endif glDisable( GL_TEXTURE_2D ); color.Select(); ExecDrawOutline(); #ifdef OL_NO_STATE_CHANGE if( texturesEnabled ) glEnable( GL_TEXTURE_2D ); #endif } // Draws the circle with colors smoothly changing from center to outer edge // void Draw( const Rgba &innerColor, const Rgba &outerColor ) const; // Draws a slice of the circle // void DrawSlice( const Rgba &color, float startAngle, float angleSweep ) const; // Draws a gradient filled slice // void DrawSlice( const Rgba &innerColor, const Rgba &outerColor, float startAngle, float angleSweep ) const; // Draws a filled disk // void DrawDisk( const Rgba &color, float innerXRadius, float innerYRadius ) const { color.Select(); DiskRender( color, color, innerXRadius, innerYRadius, false ); } // Draws a gradient filled disk // inline void DrawDisk( const Rgba &innerColor, const Rgba &outerColor, float innerXRadius, float innerYRadius ) const { DiskRender( innerColor, outerColor, innerXRadius, innerYRadius, true ); } // Draws an arc of the ellipse // void DrawArc( const Rgba &color, float startAngle, float angleSweep, float innerXRadius, float innerYRadius ) const; // Draws an arc of the ellipse // void DrawArc( const Rgba &innerColor, const Rgba &outerColor, float startAngle, float angleSweep, float innerXRadius, float innerYRadius ) const; inline std::vector< Vec2D > ToPolygon() const { return ToPolygon( 0.0, 2.0 * AL_PI ); } std::vector< Vec2D > ToPolygon( float startAngle, float angleSweep ) const; // Moves the circle by the specified amount // virtual void MoveBy( const Vec2D &amount ) { pos += amount; } virtual void MoveTo( const Vec2D &position ) { pos = position; } virtual void TransformBy( const Placement &placement ) { pos += placement.GetPosition(); angle += placement.GetRotation(); xRad *= placement.GetStretch(); yRad *= placement.GetStretch(); } // Sets the x or y radius of the ellipse // // Axis should be: X_AXIS or Y_AXIS // inline void SetRadius( Axis axis, float radius ) { switch( axis ) { case X_AXIS: xRad = radius; break; case Y_AXIS: yRad = radius; break; } } // Returns the x or y radius of the ellipse // inline float GetRadius( Axis axis ) { switch( axis ) { case X_AXIS: return xRad; break; case Y_AXIS: return yRad; break; } } virtual void RotateBy( float angle ); // Sets the visual accuracy of the circle // void SetAccuracy( float accuracy ) { float radius = std::max( xRad, yRad ); angleIncrement = std::min(( 2.0 * asin( 1.0/radius )/accuracy ), 0.35 * AL_PI ); } Vec2D pos; float angle; void ExecDraw() const; // Draws the circle // // Draws an outline of the circle // void ExecDrawOutline() const; // Raw disk rendering function // void DiskRender( const Rgba &innerCol, const Rgba &outerCol, float innerXRad, float innerYRad, bool setCols ) const; virtual std::string ToString() const; protected: float xRad; float yRad; float angleIncrement; }; // The circle shape // class OL_LIB_DECLSPEC Circle : public Ellipse { public: Circle( Vec2D pos, float radius, float lineWidth = 1.0, float accuracy = Settings::GetCircleAccuracy() ) : Ellipse( pos, Vec2D( radius, radius ), lineWidth, 0.0, accuracy ) {} Circle( float x, float y, float radius, float lineWidth = 1.0, float accuracy = Settings::GetCircleAccuracy() ) : Ellipse( Vec2D( x, y ), Vec2D( radius, radius ), lineWidth, 0.0, accuracy ) {} // Draws a filled disk // inline void DrawDisk( const Rgba &color, float innerRadius ) const { Ellipse::DrawDisk( color, innerRadius, innerRadius ); } // Draws a gradient filled disk // inline void DrawDisk( const Rgba &innerColor, const Rgba &outerColor, float innerRadius ) const { Ellipse::DrawDisk( innerColor, outerColor, innerRadius, innerRadius ); } // Draws an arc of the circle // inline void DrawArc( const Rgba &color, float startAngle, float angleSweep, float innerRadius ) const { Ellipse::DrawArc( color, startAngle, angleSweep, innerRadius, innerRadius ); } // Sets the radius of the circle // inline void SetRadius( float radius ) { xRad = radius; yRad = radius; } }; } #endif // OL_CIRCLE_HPP openlayer-2.1.orig/include/OpenLayer/loadpng.h0000644000175000017500000000402510552323114021622 0ustar georgeskgeorgesk/* loadpng.h */ /* This file is hereby placed in the public domain. */ #ifndef _included_loadpng_h_ #define _included_loadpng_h_ #ifdef __cplusplus extern "C" { #endif /* Overkill :-) */ #define LOADPNG_VERSION 1 #define LOADPNG_SUBVERSION 4 #define LOADPNG_VERSIONSTR "1.4" /* _png_screen_gamma is slightly overloaded (sorry): * * A value of 0.0 means: Don't do any gamma correction in load_png() * and load_memory_png(). This meaning was introduced in v1.4. * * A value of -1.0 means: Use the value from the environment variable * SCREEN_GAMMA (if available), otherwise fallback to a value of 2.2 * (a good guess for PC monitors, and the value for sRGB colourspace). * This is the default. * * Otherwise, the value of _png_screen_gamma is taken as-is. */ extern double _png_screen_gamma; /* Choose zlib compression level for saving file. * Default is Z_BEST_COMPRESSION. */ extern int _png_compression_level; /* Load a PNG from disk. */ extern BITMAP *load_png(AL_CONST char *filename, RGB *pal); /* Load a PNG from memory. */ extern BITMAP *load_memory_png(AL_CONST void *buffer, int buffer_size, RGB *pal); /* Save a bitmap to disk in PNG format. */ extern int save_png(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal); /* Adds `PNG' to Allegro's internal file type table. * You can then just use load_bitmap and save_bitmap as usual. */ extern void register_png_file_type(void); /* Register an datafile type ID with Allegro, so that when an object * with that type ID is encountered while loading a datafile, that * object will be loaded as a PNG file. */ extern void register_png_datafile_object(int id); /* This is supposed to resemble jpgalleg_init in JPGalleg 2.0, just in * case you are lazier than lazy. It contains these 3 lines of code: * register_png_datafile_object(DAT_ID('P','N','G',' ')); * register_png_file_type(); * return 0; */ extern int loadpng_init(void); #ifdef __cplusplus } #endif #endif /* _included_loadpng_h */ openlayer-2.1.orig/include/OpenLayer/FpsCounter.hpp0000644000175000017500000000345010552323114022627 0ustar georgeskgeorgesk#ifndef OL_FPS_COUNTER_HPP #define OL_FPS_COUNTER_HPP #include "Declspec.hpp" namespace ol { // FpsCounter - Make the game to run at the same speed in every computer and calculate the fps // #define AUTO -1 class OL_LIB_DECLSPEC FpsCounter { public: // Start the timer, defaultFps is the fps you're planning the game to run in // static void Start( float defaultFps ); // Pause the fps counter // static void Pause(); // Resumes the paused fps counter // static void Resume(); // The old name "Continue" for the Resume-function can still be used // inline static void Continue() { Resume(); } // You'll have to call this once per frame! // // This function now also returns the delta time // static float NewFrameStarted(); // Get the delta time of the frame. You'll have to multiply all movements and // // accelerations by the delta time to keep the game speed undependant of the fps // static float GetDeltaTime(); // Retrieve the fps // static float GetFps(); // Called from the timer, don't touch ;) // static void Tick(); // Sets the number of frames between which the delta time will be calculated // // Pass AUTO to let OpenLayer to dynamically adjust the settings for // // the current situation // static void SetNumOfAveragedFrames( int averagedFrames ); private: static float defaultFps; static volatile int timer; static int frameCount; static float fps; static float deltaTime; static bool paused; static int pausedTimer; static int framesPerCheck; static int quickFPC; static int normalFPC; static float actionLimit; static bool useAdvanced; }; } #endif // OL_FPS_COUNTER_HPP openlayer-2.1.orig/include/OpenLayer/Transforms.hpp0000644000175000017500000000603210575626474022720 0ustar georgeskgeorgesk#ifndef OL_TRANSFORMS_HPP #define OL_TRANSFORMS_HPP #include "Includes.hpp" #include "Vec2D.hpp" #include "Placement.hpp" #include "Declspec.hpp" //#include "Rgba.hpp" namespace ol { // Transforms - Global transformations class // // Note that the transformations only apply to the objects which // // are renderd after the transformation is set // // This class was renamed from Screen to Transforms for compability reasons // // Advanced users: Note that the original transformation state is stored // // in the matrix stack // class Rgba; class OL_LIB_DECLSPEC Transforms { public: // Set the position of the whole screen (default: (0.0, 0.0)) // static void SetPosition( float x, float y ); static void SetPosition( const Vec2D& pos ); // Rotate the contents of the whole screen around the pivot (default: 0.0 ) // static void SetRotation( float angle ); // Set the pivot point of the screen rotation (default: centre of the screen) // static void SetRotationPivot( float pivotX, float pivotY ); static void SetRotationPivot( const Vec2D& pivot ); // Sets the stretch of the whole screen, 1.0 is the normal size // static void SetStretch( float xStretch, float yStretch ); static void SetStretch( const Vec2D& stretch ); // Sets the current transform state to the static void SetPlacement( const Placement& placement, const Vec2D& pivot ); // Get rid of all active position transformations // // NOTE: Empties the Transforms stack!! // static void ResetPlacement(); // The old name of the ResetPlacement -function // inline static void ResetTransforms() { ResetPlacement(); } // Pushes the placement state of Transforms (position, rotation and stretch) in a stack // static void PushPlacement(); // Pops the placement state of Transforms from the stack (see above) // static void PopPlacement(); // Tint the whole screen to a color (default: Rgba::INVISIBLE) // static void SetTintColor( const Rgba& color ); // Sets the coefficients of the red, green, blue and alpha channels // // The default is Rgba::WHITE (all channels are 1.0) // static void SetColorChannels( const Rgba& cofficients ); // Returns the coefficients of the color channels // static const Rgba& GetColorChannels(); // You don't usually need to call any of the following functions // // Applies the active transformations // static void ApplyTransforms(); // Applies the active tinting // static void ApplyTinting(); private: static bool transformationStored; static float x, y; static float angle; static float pivotX, pivotY; static float xStretch, yStretch; static Rgba color; static Rgba colorChannels; static int stackCounter; }; // You can #define OL_USE_SCREEN_ALIAS to use // // the name Screen instead of Transforms // #ifdef OL_USE_SCREEN_ALIAS #define Screen Transforms #endif // OL_USE_SCREEN_ALIAS } #endif // OL_TRANSFORMS_HPP openlayer-2.1.orig/include/OpenLayer/VertexListCollision.hpp0000644000175000017500000000762510552323114024534 0ustar georgeskgeorgesk#include "Shape.hpp" #include "Collisions.hpp" #include "Line.hpp" #include "Declspec.hpp" #include template< class std_container1, class std_container2 > ol::Collision ol::Shape:: LineStripCollision( const std_container1 &vertices, const std_container2 &otherVertices, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults, bool thisConnectFirstAndLast, bool otherConnectFirstAndLast ) const { if( vertices.size() < 2 || otherVertices.size() < 2 ) { OlError( "An empty shape can't ever collide!" ); return Collision( false ); } Vec2D thisCo = thisPlacement.GetPosition(); Vec2D otherCo = otherPlacement.GetPosition(); Matrix2D thisTransform = thisPlacement.Get2DMatrix(); Matrix2D otherTransform = otherPlacement.Get2DMatrix(); typename std_container1::const_iterator thisIter = vertices.begin(); const Vec2D rotationPivot = thisPlacement.GetRotationPivot(); const Vec2D otherRotationPivot = otherPlacement.GetRotationPivot(); Vec2D thisPrev = thisTransform.Transform( *thisIter - rotationPivot ) + thisCo + rotationPivot; thisIter++; std::vector< std::pair< Line, Line > *> segmentLists; // Loop through each vertex // while( true ) { bool breakNow = false; // Test if we've reached the last line segment // if( thisIter == vertices.end() ) { if( !thisConnectFirstAndLast ) { break; } breakNow = true; thisIter = vertices.begin(); } Vec2D thisVertex = thisTransform.Transform( *thisIter - rotationPivot ) + thisCo + rotationPivot; thisIter++; typename std_container2::const_iterator otherIter = otherVertices.begin(); Vec2D otherPrev = otherTransform.Transform( *otherIter - otherRotationPivot ) + otherCo + otherRotationPivot; otherIter++; // Loop through each vertex of the other polygon // while( true ) { bool breakNow = false; // Test if we've reached the last line segment of the other polygon // if( otherIter == otherVertices.end() ) { if( !otherConnectFirstAndLast ) { break; } breakNow = true; otherIter = otherVertices.begin(); } Vec2D otherVertex = otherTransform.Transform( *otherIter - otherRotationPivot ) + otherCo + otherRotationPivot; otherIter++; // Test for collision // if( IsCounterClockwise( thisPrev, thisVertex, otherPrev ) != IsCounterClockwise( thisPrev, thisVertex, otherVertex ) && IsCounterClockwise( otherPrev, otherVertex, thisPrev ) != IsCounterClockwise( otherPrev, otherVertex, thisVertex )) { if( !getResults ) { return Collision( true ); } else { Line thisLine( thisVertex, thisPrev ); Line otherLine( otherVertex, otherPrev ); segmentLists.push_back( new std::pair< Line, Line >( thisLine, otherLine )); /* return Collision( thisLine, otherLine );*/ } } // Is last line segment of the other polygon processed? // if( breakNow ) { break; } // Advance to the next vertex of the other polygon // otherPrev = otherVertex; } // Is last line segment processed? // if( breakNow ) { break; } // Advance to the next vertex // thisPrev = thisVertex; } if( !segmentLists.empty() ) { return Collision( segmentLists ); } return Collision( false ); } openlayer-2.1.orig/include/OpenLayer.hpp0000644000175000017500000000362710552323114020545 0ustar georgeskgeorgesk// O p e n L a y e r // // // // by Esa Tanskanen // // // // 2D Graphics routines using // // OpenGL acceleration // // // Use it where ever you want,// // as long as you don't claim // // the code to be your own! // // Requires: // - Glyph Keeper 0.26.1 or later (Compile with -DGLYPH_TARGET=GLYPH_ALLEGGL) // - Allegro 4.0.2 or later // - AllegroGL 0.2.4 or later // - Recommended: LibPNG + ZLib to load png images // - Reading the manual or header files to know the functions // - Linking your programs with: // -lglyph -lfreetype -lpng -lz -lagl -lalleg -luser32 -lgdi32 -lglu32 -lopengl32 //#define FORTIFY //#include #ifndef OPENLAYER_HPP #define OPENLAYER_HPP #define OL_DRIVER ALLEGRO_GL #include "OpenLayer/GarbageCollector.hpp" #include "OpenLayer/Includes.hpp" #include "OpenLayer/Animation.hpp" #include "OpenLayer/Bitmap.hpp" #include "OpenLayer/Blenders.hpp" #include "OpenLayer/FpsCounter.hpp" #include "OpenLayer/GarbageCollector.hpp" #include "OpenLayer/General.hpp" #ifndef OL_NO_OLD_API #include "OpenLayer/GfxRend.hpp" #endif // NO_OLD_API #include "OpenLayer/Rgba.hpp" #include "OpenLayer/Settings.hpp" #include "OpenLayer/Setup.hpp" #include "OpenLayer/TextRenderer.hpp" #include "OpenLayer/Transforms.hpp" #include "OpenLayer/Canvas.hpp" #include "OpenLayer/RenderModes.hpp" #include "OpenLayer/Shape.hpp" #include "OpenLayer/TexturedPoly.hpp" #include "OpenLayer/Polygon.hpp" #include "OpenLayer/Line.hpp" #include "OpenLayer/Rectangle.hpp" #include "OpenLayer/Circle.hpp" #include "OpenLayer/LineStrip.hpp" #include "OpenLayer/Point.hpp" #include "OpenLayer/Vec2D.hpp" #include "OpenLayer/TextureInfo.hpp" #include "OpenLayer/Declspec.hpp" #ifndef OL_NO_PNG #include "OpenLayer/loadpng.h" #endif /* OL_NO_PNG */ #endif openlayer-2.1.orig/build/0000700000175000017500000000000012262355751015604 5ustar georgeskgeorgeskopenlayer-2.1.orig/build/FindALLEGROGL.cmake0000644000175000017500000000271710567602066020740 0ustar georgeskgeorgesk# - Find allegroGL # Find the native ALLEGROGL includes and library # # ALLEGROGL_INCLUDE_DIR - where to find alleggl.h, etc. # ALLEGROGL_LIBRARIES - List of libraries when using allegro. # ALLEGROGL_FOUND - True if allegro found. FIND_PACKAGE(ALLEGRO) FIND_PACKAGE(OpenGL) IF (ALLEGROGL_INCLUDE_DIR) # Already in cache, be silent SET(ALLEGROGL_FIND_QUIETLY TRUE) ENDIF (ALLEGROGL_INCLUDE_DIR) FIND_PATH(ALLEGROGL_INCLUDE_DIR alleggl.h /usr/local/include /usr/include $ENV{MINGDIR}/include ) SET(ALLEGROGL_NAMES agl alleggl agllib agldll) FIND_LIBRARY(ALLEGROGL_LIBRARY NAMES ${ALLEGROGL_NAMES} PATHS /usr/lib /usr/local/lib $ENV{MINGDIR}/lib) IF (ALLEGROGL_INCLUDE_DIR AND ALLEGROGL_LIBRARY) SET(ALLEGROGL_FOUND TRUE) SET( ALLEGROGL_LIBRARIES ${ALLEGROGL_LIBRARY} ${ALLEGRO_LIBRARIES} ${OPENGL_LIBRARIES}) ELSE (ALLEGROGL_INCLUDE_DIR AND ALLEGROGL_LIBRARY) SET(ALLEGROGL_FOUND FALSE) SET( ALLEGROGL_LIBRARIES ) ENDIF (ALLEGROGL_INCLUDE_DIR AND ALLEGROGL_LIBRARY) IF (ALLEGROGL_FOUND) IF (NOT ALLEGROGL_FIND_QUIETLY) MESSAGE(STATUS "Found AllegroGL: ${ALLEGROGL_LIBRARY}") ENDIF (NOT ALLEGROGL_FIND_QUIETLY) ELSE (ALLEGROGL_FOUND) IF (ALLEGROGL_FIND_REQUIRED) MESSAGE(STATUS "Looked for AllegroGL libraries named ${ALLEGROGL_NAMES}.") MESSAGE(FATAL_ERROR "Could NOT find AllegroGL library") ENDIF (ALLEGROGL_FIND_REQUIRED) ENDIF (ALLEGROGL_FOUND) #MARK_AS_ADVANCED( # ALLEGROGL_LIBRARY # ALLEGROGL_INCLUDE_DIR # )openlayer-2.1.orig/build/OpenLayer.hpp.in0000644000175000017500000000455010647144172020634 0ustar georgeskgeorgesk// O p e n L a y e r // // // // by Esa Tanskanen // // // // 2D Graphics routines using // // OpenGL acceleration // // // Use it where ever you want,// // as long as you dont claim // // the code to be your own! // // Requires: // - Glyph Keeper 0.26.1 or later (Compile with -DGLYPH_TARGET=GLYPH_ALLEGGL) // - Allegro 4.0.2 or later // - AllegroGL 0.2.4 or later // - Recommended: Loadpng + LibPNG + ZLib to load png images // - Reading the manual or header files to know the functions // - Linking your programs with: // -lglyph -lfreetype -lloadpng -lpng -lz -lagl -lalleg -luser32 -lgdi32 -lglu32 -lopengl32 //#define FORTIFY //#include #ifndef OPENLAYER_HPP #define OPENLAYER_HPP // Shared library (DLL on windows) #cmakedefine OL_SHARED // Defines set accordingly to compiled settings #define OL_DRIVER ALLEGRO_GL #ifndef OL_NO_PNG #cmakedefine OL_NO_PNG #endif /* OL_NO_PNG */ #ifndef OL_NO_TTF #cmakedefine OL_NO_TTF #endif /* OL_NO_TTF */ #ifndef USE_NEW_TTF #cmakedefine USE_NEW_TTF #endif /* USE_NEW_TTF */ #ifndef OL_NO_OLD_API #cmakedefine OL_NO_OLD_API #endif /* OL_NO_OLD_API */ #ifndef OL_NO_STATE_CHANGE #cmakedefine OL_NO_STATE_CHANGE #endif /* OL_NO_STATE_CHANGE */ #include "OpenLayer/GarbageCollector.hpp" #include "OpenLayer/Includes.hpp" #include "OpenLayer/Animation.hpp" #include "OpenLayer/Bitmap.hpp" #include "OpenLayer/Blenders.hpp" #include "OpenLayer/FpsCounter.hpp" #include "OpenLayer/GarbageCollector.hpp" #include "OpenLayer/General.hpp" #include "OpenLayer/Rgba.hpp" #include "OpenLayer/Settings.hpp" #include "OpenLayer/Setup.hpp" #include "OpenLayer/TextRenderer.hpp" #include "OpenLayer/Transforms.hpp" #include "OpenLayer/Canvas.hpp" #include "OpenLayer/RenderModes.hpp" #include "OpenLayer/Shape.hpp" #include "OpenLayer/TexturedPoly.hpp" #include "OpenLayer/Polygon.hpp" #include "OpenLayer/Line.hpp" #include "OpenLayer/Rectangle.hpp" #include "OpenLayer/Circle.hpp" #include "OpenLayer/LineStrip.hpp" #include "OpenLayer/Point.hpp" #include "OpenLayer/Vec2D.hpp" #include "OpenLayer/TextureInfo.hpp" #include "OpenLayer/Declspec.hpp" #ifndef OL_NO_PNG #include "OpenLayer/loadpng.h" #endif /* OL_NO_PNG */ #ifndef OL_NO_OLD_API // Providing backwards compatibility with apps made before 2.0 #include "OpenLayer/GfxRend.hpp" #endif #endif openlayer-2.1.orig/build/ol-config.cbd0000644000175000017500000000637210520152532020140 0ustar georgeskgeorgesk# Create openlayer-config script for *nix based systems setinput build/options read tempstr read tempstr read tempstr CONFIGFLAGS = ${'tempstr'} read tempstr CONFIGLIBS = ${'tempstr'} setinput writefile ${'LOCATION'}/bin/openlayer-config \#!/bin/sh appendfile ${'LOCATION'}/bin/openlayer-config \# openlayer-config autogenerated by cbuild script from the OpenLayer library appendfile ${'LOCATION'}/bin/openlayer-config appendfile ${'LOCATION'}/bin/openlayer-config version=2.0 appendfile ${'LOCATION'}/bin/openlayer-config prefix=${'LOCATION'} appendfile ${'LOCATION'}/bin/openlayer-config cflags=\"-I\$prefix/include -I\$prefix/include/OpenLayer ${CONFIGFLAGS}\" appendfile ${'LOCATION'}/bin/openlayer-config libs=\"-lopenlayer ${CONFIGLIBS}\" appendfile ${'LOCATION'}/bin/openlayer-config appendfile ${'LOCATION'}/bin/openlayer-config usage() appendfile ${'LOCATION'}/bin/openlayer-config { appendfile ${'LOCATION'}/bin/openlayer-config cat < appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#ifndef OPENLAYER_HPP appendfile include/OpenLayer.hpp \#define OPENLAYER_HPP appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \// Defines set accordingly to compiled settings appendfile include/OpenLayer.hpp \#define OL_DRIVER ALLEGRO_GL do if ${'DROPPNG'}='true' appendfile include/OpenLayer.hpp \#ifndef OL_NO_PNG appendfile include/OpenLayer.hpp \#define OL_NO_PNG appendfile include/OpenLayer.hpp \#endif /* OL_NO_PNG */ done do if ${'DROPTTF'}='true' appendfile include/OpenLayer.hpp \#ifndef OL_NO_TTF appendfile include/OpenLayer.hpp \#define OL_NO_TTF appendfile include/OpenLayer.hpp \#endif /* OL_NO_TTF */ done do if ${'USENEWTTF'}='true' appendfile include/OpenLayer.hpp \#ifndef USE_NEW_TTF appendfile include/OpenLayer.hpp \#define USE_NEW_TTF appendfile include/OpenLayer.hpp \#endif /* USE_NEW_TTF */ done do if ${'DROPOLDAPI'}='true' appendfile include/OpenLayer.hpp \#ifndef OL_NO_OLD_API appendfile include/OpenLayer.hpp \#define OL_NO_OLD_API appendfile include/OpenLayer.hpp \#endif /* OL_NO_OLD_API */ done do if ${'DROPSTATECHANGE'}='true' appendfile include/OpenLayer.hpp \#ifndef OL_NO_STATE_CHANGE appendfile include/OpenLayer.hpp \#define OL_NO_STATE_CHANGE appendfile include/OpenLayer.hpp \#endif /* OL_NO_STATE_CHANGE */ done appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#include \"OpenLayer/GarbageCollector.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Includes.hpp\" appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#include \"OpenLayer/Animation.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Bitmap.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Blenders.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/FpsCounter.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/GarbageCollector.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/General.hpp\" appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#include \"OpenLayer/Rgba.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Settings.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Setup.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/TextRenderer.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Transforms.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Canvas.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/RenderModes.hpp\" appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#include \"OpenLayer/Shape.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/TexturedPoly.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Polygon.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Line.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Rectangle.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Circle.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/LineStrip.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/Point.hpp\" appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#include \"OpenLayer/Vec2D.hpp\" appendfile include/OpenLayer.hpp \#include \"OpenLayer/TextureInfo.hpp\" appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#include \"OpenLayer/Declspec.hpp\" appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#ifndef OL_NO_PNG appendfile include/OpenLayer.hpp \#include \"OpenLayer/loadpng.h\" appendfile include/OpenLayer.hpp \#endif appendfile include/OpenLayer.hpp do ifnot ${'DROPOLDAPI'}='true' appendfile include/OpenLayer.hpp \// Providing backwards compatibility with apps made before 2.0 appendfile include/OpenLayer.hpp \#include \"OpenLayer/GfxRend.hpp\" done appendfile include/OpenLayer.hpp appendfile include/OpenLayer.hpp \#endif appendfile include/OpenLayer.hpp openlayer-2.1.orig/build/cmake_uninstall.cmake.in0000644000175000017500000000155410521707142022372 0ustar georgeskgeorgeskIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"${file}\"") IF(EXISTS "${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF("${rm_retval}" STREQUAL 0) ELSE("${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") ENDIF("${rm_retval}" STREQUAL 0) ELSE(EXISTS "${file}") MESSAGE(STATUS "File \"${file}\" does not exist.") ENDIF(EXISTS "${file}") ENDFOREACH(file)openlayer-2.1.orig/build/openlayer-config.in0000644000175000017500000000155710567602066021417 0ustar georgeskgeorgesk#!/bin/sh # openlayer-config autogenerated by cbuild script from the OpenLayer library version=2.1\(SVN\) prefix=${CMAKE_INSTALL_PREFIX} cflags="-I$prefix/include -I$prefix/include/OpenLayer ${FREETYPE_INCLUDE}" libs="-lopenlayer ${REQUIRED_LIBS}" usage() { cat <OpenLayer Offline Manual


FirstLineWidth

const std::string &text ) const;

Returns the width of the first text line of the given multi-lined text when printed with this TextRenderer.

The width is in pixels. You can pass either single or multi-lined text to this function but it'll always return the width of the first text line.

Notice that like any other function of TextRenderer this function takes a reference to a string so you have to construct a string variable of the text before passing it to this function.

Examples

TextRenderer renderer( ... );

String text = "First line\nSecond line\nThird line";

// Get the width of the first line of the text ("First line") //
int textWidth = renderer.FirstLineWidth( text );


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about FirstLineWidth? Click here.
openlayer-2.1.orig/Manual/TextRenderer/Load.html0000644000175000017500000003121510421451270022102 0ustar georgeskgeorgeskOpenLayer Offline Manual

Load

bool Load(
const char *filename,
int width = 9, int height = 12,
Rgba col = Rgba::BLACK, int italics = 0,
bool useHinting = true );

Load the font from a True Type Font file.


bool Load(
const TextRenderer &otherRenderer,
int width = 9, int height = 12,
Rgba col = [inherit], int italics = [inherit] );

Load the font by making an altered copy of an existing TextRenderer. If you don't pass anything as the color or the italics parameter they'll be inherited from otherRenderer.


bool Load(
GLYPH_FACE *face = 0,
int width = 9, int height = 12,
Rgba col = Rgba::BLACK, int italics = 0,
bool useHinting = true );

Load the font by using a GlyphKeeper font face.

The alpha value of the color controls the opacity of the printed text. The higher the alpha value is, the more visible the text will be. For more information about alpha values see the definition of Bitmap.

If any of these functions fail to load the font an error log will be added to the allegro.log file. In addition the IsValid() -method will return false if the TextRenderer is not ready to use.

A word of caution: You can't load any TextRenderers before Setup::SetupProgram and Setup::SetupScreen are called!

Examples

// The usage of the Load -method is generally the same as with the constructors //

// Construct a new font by loading a true type font Arial.ttf in the fonts -folder //
// with the width of 10, the height of 15 and a black color //
TextRenderer myTextRenderer;
if( myTextRenderer.Load"fonts/Arial.ttf"1015Rgba::BLACK ) == false ) {
   allegro_message( "Couldn't load the font Arial.ttf!" );
   exit( -1 );
}

// Construct a same looking font but with italics angle of 12 (the common italics angle) //
TextRenderer myItalicsRenderer;
if( myItalicsRenderer.Load"fonts/Arial.ttf"1015Rgba::BLACK, 12 ) == false ) {
   allegro_message( "Couldn't load the font Arial.ttf!" );
   exit( -1 );
}

// Construct a font which looks like myTextRenderer but with the opacity of only 30% //
TextRenderer myTranslucentRenderer;
if( myTranslucentRenderer.Load"fonts/Arial.ttf"1015Rgba0.00.00.00.30 )) == false ) {
   allegro_message( "Couldn't load the font Arial.ttf!" );
   exit( -1 );
}

// Construct a smaller copy of an existing font (sized 9x12) //
// If you don't specify a color it'll be inherited //
// from the passed TextRenderer //
TextRenderer smallerTextRenderer;
smallerTextRenderer.Load( myTextRenderer, 912 );

// Construct the font from a glyph keeper font face //
// with a slightly yellow green color //
GLYPH_FACE *glyphKeeperFace = ...; 

TextRenderer otherTextRenderer;
if( otherTextRenderer.Load( glyphKeeperFace, 2015Rgba0.31.00.0 )) == false ) {
   allegro_message( "Couldn't load the font from a Glyph Keeper face!" );
   exit( -1 );
}



Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about Load? Click here.
openlayer-2.1.orig/Manual/TextRenderer/SetItalics.html0000644000175000017500000001312710377350122023275 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetItalics

int italicsAngle );

Sets the italics angle of the text.

The italics angle is in degrees. The commonly used italics angle is 12. You can set the angle to zero if you don't wish to print text with italics anymore.

The default italics angle is zero.

Note that changing the italics is rather slow as the font data in the graphics card has to be refreshed. If you need to render both italic and non-italic text with a TextRenderer, it's best to make a copy of the TextRenderer.

Examples

TextRenderer renderer( ... );

// Set the italics angle of the text to 12 (the commonly used angle) //
renderer.SetItalics12 );

// To not to render italics text anymore you can set the italics angle to 0 //
renderer.SetItalics0 );


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about SetItalics? Click here.
openlayer-2.1.orig/Manual/TextRenderer/UseAutoDelete.html0000644000175000017500000001221510417230626023737 0ustar georgeskgeorgeskOpenLayer Offline Manual

UseAutoDelete

Advanced function


Chooses the TextRender to be automatically deleted when the program quits.

If you have any dynamically allocated TextRenderers you may wish them to be automatically destroyed when the program quits. Note that this function should only be called if the TextRenderer is dynamically allocated!

Examples

// Dynamically allocate a TextRenderer //
TextRenderer *myRenderer = new TextRenderer( ... );

// Choose the TextRenderer to be automatically deleted when the program quits //
myRenderer->UseAutoDelete();


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about UseAutoDelete? Click here.
openlayer-2.1.orig/Manual/TextRenderer/GetColor.html0000644000175000017500000001547110377350122022753 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetColor

Rgba GetColor() const;

Returns the text color of the font.

Examples

TextRenderer renderer( ... );

// Get the color of the text //
Rgba color = renderer.GetColor();


// Hint: You can do the following to pring text with a shadow //

string text = "Some text";
int x = 200;
int y = 100;

// Store the original text color //
Rgba originalColor = renderer.GetColor();

// Select a translucent black color for the shadow (30% opacity) //
renderer.SetColorRgba0.00.00.00.30 ));

// Render the shadow of the text slightly below and left of the original text position //
renderer.Print( text, x-1, y+1 );

// Change the text color back to the original //
renderer.SetColor( originalColor );

// Print the text on top of the shadow //
renderer.Print( text, x, y );


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about GetColor? Click here.
openlayer-2.1.orig/Manual/TextRenderer/IsValid.html0000644000175000017500000001242710421451270022562 0ustar georgeskgeorgeskOpenLayer Offline Manual

IsValid

bool IsValid();

Returns true if the TextRenderer is ready to use (loaded and not destroyed)

If the TextRenderer isn't loaded yet or the Destroy() -method is called the TextRenderer is invalidiated and IsValid() will return false.

Examples

TextRenderer globalTextRenderer;

// Check if globalTextRenderer is not ready to be used (currently it's not) //
if( globalTextRenderer.IsValid() == false ) {
   allegro_message( "globalTextRenderer isn't loaded yet!" );
}


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about IsValid? Click here.
openlayer-2.1.orig/Manual/TextRenderer/Print.html0000644000175000017500000002436510377350122022333 0ustar georgeskgeorgeskOpenLayer Offline Manual

Print

void Print(
const std::string &text, int x, int baselineY ) const;

Prints the given (multi-lined) text to the screen at the given coordinates.

void Print(
const std::string &text, int x, int baselineY,
int maxLineWidth, TextAlignment alignment = LEFT ) const;

Prints the text with automatic line wrapping and alignment. The maxLineWidth tells the maxium width of a text line in pixels. Lines wider than maxLineWidth will be cut to several lines. Possible text alignments are:

* LEFT - Align the text lines to the left
* CENTER - Center the text lines
* RIGHT - Align the text lines to the right
* JUSTIFY - Stretch the full text lines to fill the entire maxLineWidth

Note that the y-coordinate is the y-coordinate of the baseline of the first text line, not the top position of the text (changed from the previous version)!

All coordinates are in pixels. Note that you can print multi-lined text such that the end of a line is marked with an endline character (\n).

Also notice that for performance reasons the function takes a reference to the printed text. This means that you have to construct a text variable first and then pass it to this function.

OpenLayer contains a function ToString that converts a variable (number, for example) to a string so that it can be passed to the Print -function. See the examples of how to do this.

Examples

TextRenderer myTextRenderer(...);

// Print the text Hello World! to the screen such that the //
// top-left corner of the text is positioned at //
// x = 200 and y-coodinate of the baseline = 110 //
String message = "Hello World!";
myTextRenderer.Print( message, 200110 );

// Print a multi-lined message at the same position in the screen //
String message = "First line\nSecond line\nThird line";
myTextRenderer.Print( message, 200110 );

// Print a number in the screen //
int number = 500;
String message = ToString( number );
myTextRenderer.Print( message, 200110 );

// Print a long text in the screen with automatic line wrappings so that //
// the maxium width of a text line is 300 pixels and justify the text //
String longText = "This is a very, very long text which will be automatically "
  + "wrapped to several lines thanks to the overloaded version of the "
  + "text rendering function!"
myTextRenderer.PrintlongText , 200110300, JUSTIFY );


// Print a some text and two numbers in the screen //
int number1 = 500;
float number2 = 750.5;

String message = "The first number is " + ToString( number1 ) +
                        " and the second number is " + ToString( number2 );

// message is: The first number is 500 and the second number is 750.5 //
myTextRenderer.Print( message, 200110 );


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about Print? Click here.
openlayer-2.1.orig/Manual/TextRenderer/GetFace.html0000644000175000017500000001173010377350122022525 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetFace

Advanced function

GLYPH_FACE *GetFace() const;

Returs the Glyph Keeper face of the font.

Usually you don't need the Glyph Keeper face of the font anywhere, but you may still find some use for it.

Notice that the returned face isn't a copy even if it's not const. The reason is that Glyph Keeper doesn't support const GLYPH_FACE's.

Examples

TextRenderer renderer( ... );

// Get the Glyph Keeper face of the font //
GLYPH_FACE *face = renderer.GetFace();


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about GetFace? Click here.
openlayer-2.1.orig/Manual/TextRenderer/UnloadFromGPU.html0000644000175000017500000001245510417230626023657 0ustar georgeskgeorgeskOpenLayer Offline Manual

UnloadFromGPU

Advanced function

void UnloadFromGPU();

Unloads the texture and geometry information of the from the graphics card.

You don't usually need to call this function as OpenLayer automatically calls this function when you a TextRenderer is destroyed (the destructor or the Destroy() -method is called). However, if you wish to have more control of when the font resides in the GPU you can use this function.

Note that the TextRenderer will be invalidated if you call this function but all the resources of the font are not unloaded.

Examples

TextRenderer renderer( ... );

// Unloads the font information from the graphics card. //
renderer.UnloadFromGPU();


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about UnloadFromGPU? Click here.
openlayer-2.1.orig/Manual/TextRenderer/Width.html0000644000175000017500000001223510416463436022316 0ustar georgeskgeorgeskOpenLayer Offline Manual

Width

int Width(
const std::string &text ) const;

Returns the width of the given text when printed with this TextRenderer.

The width is in pixels. Notice that like any other function of TextRenderer this function takes a reference to a string so you have to construct a string variable of the text before passing it to this function.

Examples

TextRenderer renderer( ... );

String text = "Some text";

// Get width of the text //
int textWidth = renderer.Width( text );


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about Width? Click here.
openlayer-2.1.orig/Manual/TextRenderer/Height.html0000644000175000017500000001227710421451270022442 0ustar georgeskgeorgeskOpenLayer Offline Manual

Height

int Height(
const std::string &text ) const;

Returns the height of the given text when printed with this TextRenderer.

The height is in pixels. Notice that like any other function of TextRenderer this function takes a reference to a string so you have to construct a string variable of the text before passing it to this function.

Examples

TextRenderer renderer( ... );

String text = "Some text";

// Get the height of the text //
int textHeight = renderer.Height( text );


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about Height? Click here.
openlayer-2.1.orig/Manual/TextRenderer/GetItalics.html0000644000175000017500000001141110377350122023253 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetItalics

int GetItalics() const;

Returns the italics angle of the text.

The returned angle is in degrees.

Examples

TextRenderer renderer( ... );

// Get the italics angle of the text //
int italicsAngle = renderer.GetItalics();


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about GetItalics? Click here.
openlayer-2.1.orig/Manual/TextRenderer/SetColor.html0000644000175000017500000001402610377350122022762 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetColor

void SetColor(
const Rgba col );

Sets the color of the font.


The alpha value of the color controls the opacity of the printed text. The higher the alpha value is, the more visible the text will be. For more information about alpha values see the definition of Bitmap.

Examples

TextRenderer renderer( ... );

// Sets the color of the font to black //
renderer.SetColorRgba::BLACK );

// Sets the color of the font to light gray //
renderer.SetColorRgba0.80.80.8 ));

// Sets the color of the font to light gray but with the opacity of 30% //
renderer.SetColorRgba0.80.80.80.30 ));


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about SetColor? Click here.
openlayer-2.1.orig/Manual/TextRenderer/SendToGPU.html0000644000175000017500000001202010417230626022771 0ustar georgeskgeorgeskOpenLayer Offline Manual

SendToGPU

Advanced function

void SendToGPU();

Sends the texture and geometry information of the font to the graphcis card.

You don't usually need to call this function as OpenLayer automatically calls this function when you load a TextRenderer. However, if you wish to have more control of when the font resides in the GPU you can use this function.

Examples

TextRenderer renderer( ... );

// Sends the font information to the graphics card //
renderer.SendToGPU();


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about SendToGPU? Click here.
openlayer-2.1.orig/Manual/TextRenderer/FirstLineHeight.html0000644000175000017500000001303210377350122024254 0ustar georgeskgeorgeskOpenLayer Offline Manual

FirstLineHeight

const std::string &text ) const;

Returns the height of the first text line of the given multi-lined text when printed with this TextRenderer.

The height is in pixels. You can pass either single or multi-lined text to this function but it'll always return the height of the first text line.

Notice that like any other function of TextRenderer this function takes a reference to a string so you have to construct a string variable of the text before passing it to this function.

Examples

TextRenderer renderer( ... );

String text = "First line\nSecond line\nThird line";

// Get the height of the first line of the text ("First line") //
int textHeight = renderer.FirstLineHeight( text );


Other functions of the class TextRenderer
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about FirstLineHeight? Click here.
openlayer-2.1.orig/Manual/RenderMode.html0000644000175000017500000001171210377350122020640 0ustar georgeskgeorgeskOpenLayer Offline Manual

RenderMode

The virtual base class of all Bitmap rendering effects.

You can use the sum operator to combine several RenderModes.

Examples

// Load a bitmap //
Bitmap myBmp( ... );

// Render the bitmap to the screen such as the top-left corner is at x = 200.0, y = 100.0 //
// and the bitmap is tinted 35% to red //
myBmp.Blit200.0100.0TintedRgba1.00.00.00.35 )));

// Render the bitmap vertically flipped, clipped to a 100 x 100 region and tinted 30% to red //
myBmp.Blit200.0100.0Flipped( VERTICAL ) +
                                   Clipped0.00.0100.0100.0 ) +
                                   TintedRgba1.01.01.00.30 )));


Derived Classes
Tinted
Tints the Bitmap to the specified color
Flipped
Flips the Bitmap around one or both coordinate axes
Clipped
Clips the Bitmap to the specified region
AlphaFrom
The Bitmap will be rendered with an additional alpha channel from an another Bitmap
SliceExpanded
Stretches a one pixel wide slice of the bitmap to fill the entire bitmap
MultiMode
Combines two RenderModes to a single RenderMode
Gradient
Allows for gradient lighting, shadow and transparency effects


Questions about RenderMode? Click here.
openlayer-2.1.orig/Manual/Bitmap/0000700000175000017500000000000012262355751017136 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Bitmap/Load.html0000644000175000017500000003060710421451270020707 0ustar georgeskgeorgeskOpenLayer Offline Manual

Load

bool Load(
const char *filename );

Loads the Bitmap from a bitmap file, which may contain an alpha channel. Returns true in success.


bool Load(
const char *rgbFilename, const char *alphaFilename );

Loads the Bitmap from two separate bitmaps, one bitmap for the color information and one 8-bit bitmap for the transparency information. Returns true in success.


bool Load(
BITMAP *allegroBmp, bool hasAlphaChannel = false,
bool convertMagicPink = false );

Loads the bitmap from an Allegro bitmap. If convertMagicPink is true the magic pink pixels in the bitmap will be converted to transparent pixels in the Bitmap.

OpenLayer doesn't free the passed BITMAP even if the Bitmap is destroyed.

bool Load(
BITMAP *allegroBmp, int conversionMode );

Same as above but the parameters are given by using a bitwise "or" of the following conversion parameters: HAS_ALPHA_CHANNEL and CONVERT_MAGIC_PINK.


The loaded bitmap may be in any format that is supported by Allegro (bmp, pcx, tga) or by any add-on libraries you've installed (Loadpng for pngs or JPGAlleg for JPEGs, for example).

Installing Loadpng is recommended as png files may contain an alpha channel to allow for transparent or translucent pixels. Png files also compress better than tga files. The latest OpenLayer's packages contain the loadpng, libpng and libz -libraries which are required to load png images.

It's best to check if the loading succeedes or not. The file may not be found or the format may not be supported. OpenLayer logs all loading failures in allegro.log, though, so you can also check the log file to find out if the loading has failed. But instead of letting your program crash it's better to display a message for the end user to let him know what went wrong. You'll get better feedback for your game that way ;)

Examples

// Remember to call Setup::SetupProgram and Setup::SetupScreen before loading any bitmaps! //

// Load myBmp from gfx/Bitmap.png //
Bitmap myBmp;
myBmp.Load"gfx/Bitmap.png" );

// It's best to check if the loading succeedes! (Bitmap really exists) //
Bitmap myBmp;
if( myBmp.Load"gfx/Bitmap.png" ) == false ) {
   // Display an error message //
   allegro_message( "Bitmap couldn't be loaded!" );
   // Exit the program //
   exit(-1);
}

// If you have BitmapColor.bmp that has the color information //
// and an 8-bit BitmapAlpha.bmp that contains the translucency: //
Bitmap myBmp;
myBmp.Load"gfx/BitmapColor.bmp""gfx/BitmapAlpha.bmp" );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Load? Click here.
openlayer-2.1.orig/Manual/Bitmap/UseAutoDelete.html0000644000175000017500000002050110417230626022535 0ustar georgeskgeorgeskOpenLayer Offline Manual

UseAutoDelete

Advanced function


Chooses the Bitmap to be automatically deleted when the program quits.

If you have any dynamically allocated Bitmaps you may wish them to be automatically destroyed when the program quits. Note that this function should only be called if the Bitmap is dynamically allocated!

Examples

// Dynamically allocate a Bitmap //
Bitmap *myBmp = new Bitmap( ... );

// Choose the Bitmap to be automatically deleted when the program quits //
myBmp->UseAutoDelete();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about UseAutoDelete? Click here.
openlayer-2.1.orig/Manual/Bitmap/Select.html0000644000175000017500000002061310411264544021250 0ustar georgeskgeorgeskOpenLayer Offline Manual

Select

Advanced function

inline void Select() const;

Selects the Bitmap as the active texture of OpenGL.

If you use OpenLayer's functions only you won't need to call this as OpenLayer does it automatically for you. However if you wish to plug in your own OpenGL code you may find use for this function.

Notice that calling this function doesn't enable texture mapping if it was disabled. Check the Settings for how to enable texture mapping the way that OpenLayer also notices the change.

Examples

Bitmap myBmp( ... );

// Select the bitmap as the active texture //
myBmp.Select();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Select? Click here.
openlayer-2.1.orig/Manual/Bitmap/BlitDistorted.html0000644000175000017500000002726410377363276022633 0ustar georgeskgeorgeskOpenLayer Offline Manual

BlitDistorted

float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
float opacity = 1.0 ) const;

Draws the bitmap such that the given coordinates describe the positions of the corner points of the bitmap in the screen.

Coordinates are given in a clockwise order starting from the top-left coordinate. The bitmap will be stretched to fill the quadrate area inside the corner points.

float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
float opacity = 1.0,
const RenderMode &mode ) const;

The same as above but the specified RenderMode affects the way the Bitmap is rendered.



Coordinates are in pixels. Opacity should be between 0.0 and 1.0, where 1.0 is completely opaque and 0.0 completely transparent. Notice that if you don't pass any opacity parameter the bitmap will be rendered fully opaque. If you pass true to horizontallyFlipped the bitmap will be drawn to the screen horizontally flipped.

All transformations like stretching use anti-aliased routines by default. Use the Settings if you prefer aliased transformations instead.

BlitDistorted, like any other bitmap rendering function, will take the alpha channel of the bitmap in account. With the default blender the alpha channel describes the opacity of every single pixel in the bitmap. The higher alpha value, the more visible the pixel is. Read more about the alpha channel in the definition of Bitmap.

Examples

// Load a bitmap from an image file //
Bitmap playerBmp( "Player.png" );

// Draw the bitmap to the screen such that the top-left coordinate //
// of the bitmap will be at x = 200, y = 100, the top-right coordinate //
// will be at x = 300, y = 100, the bottom-right coordinate will be at //
// x = 330, y = 200 and the bottom-left coordinate will be at x = 170, y = 200 //
// The bitmap will look like this: /_\  //
playerBmp.BlitDistorted200.0100.0300.0100.0330.0200.0170.0200.0 );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about BlitDistorted? Click here.
openlayer-2.1.orig/Manual/Bitmap/UnloadToMemory.html0000644000175000017500000001730210417230626022750 0ustar georgeskgeorgeskOpenLayer Offline Manual

UnloadToMemory

Advanced function


Unloads the Bitmap from the graphics card but keeps the image data saved in the Bitmap so that it can be restored with SendToGPU.

Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about UnloadToMemory? Click here.
openlayer-2.1.orig/Manual/Bitmap/BlitRotated.html0000644000175000017500000003322210377363276022263 0ustar georgeskgeorgeskOpenLayer Offline Manual

BlitRotated

float x, float y, float angle, float opacity = 1.0 ) const;

Draws the bitmap to the screen rotated anti-clockwise around its centre. The centre of the bitmap will be positioned in the screen at the given x and y -coordinates.

float x, float y, float angle,
const RenderMode &mode, float opacity = 1.0 ) const;

The same as above but the specified RenderMode affects the way the Bitmap is rendered.

float x, float y, float pivotX, float pivotY,
float angle, float opacity = 1.0 ) const;

Draws the bitmap to the screen rotated clockwise around the point (pivotX, pivotY) in the bitmap. The pivot point will be positioned at the given x and y -coordinates in the screen.

float x, float y, float pivotX, float pivotY,
float angle, const RenderMode &mode,
float opacity = 1.0 ) const;

The same as above but the specified RenderMode affects the way the Bitmap is rendered.

Coordinates are in pixels and the angle is in radians. Opacity should be between 0.0 and 1.0, where 1.0 is completely opaque and 0.0 completely transparent. Notice that if you don't pass any opacity parameter the bitmap will be rendered fully opaque.

If you pass true to horizontallyFlipped the bitmap will be drawn to the screen horizontally flipped. Note that the bitmap will always be placed so that the pivot point is positioned at the given coordinates, even if the bitmap is flipped.

All transformations like rotation use anti-aliased routines by default. Use the Settings if you prefer aliased transformations instead.

BlitRotated, like any other bitmap rendering function, will take the alpha channel of the bitmap in account. With the default blender the alpha channel describes the opacity of every single pixel in the bitmap. The higher alpha value, the more visible the pixel is. Read more about the alpha channel in the definition of Bitmap.

Examples

// Load a bitmap from an image file //
Bitmap playerBmp( "Player.png" );

// Draw the bitmap to the screen such that the top-left corner //
// of the bitmap is positioned at x = 200.0, y = 100.0 //
// and the bitmap is rotated clockwise pi/4 radians (45 decrees) //
playerBmp.BlitRotated200.0100.0, AL_PI/4.0 );

// Draw the bitmap at the same position and rotated similiarily //
// but this time around the top-left corner of the bitmap //
playerBmp.BlitRotated200.0100.00.00.0, AL_PI/4.0 );

// Draw the bitmap at the same position and rotated similiarily as in the first example //
// but with only 70% opacity. (You can partially "see through" the bitmap like if it was a ghost) //
playerBmp.BlitRotated200.0100.0, AL_PI/4.00.70 );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about BlitRotated? Click here.
openlayer-2.1.orig/Manual/Bitmap/FastBlit.html0000644000175000017500000002256310377363276021564 0ustar georgeskgeorgeskOpenLayer Offline Manual

FastBlit

Advanced function

inline void FastBlit(
float x, float y ) const

A faster version of Blit but works only after StartFastBlitting has been called.

When you're finished calling FastBlit, you should call FinishFastBlitting.

Examples

// If you're about to render, say, 500 Bitmaps in a row with , you can do the following //

Bitmap bitmaps[500] = { ... };

// Start fast Blitting //
Bitmap::StartFastBlitting();

// Blit all the Bitmaps to random positions in the screen //
for( int i = 0; i < 500; i++ ) {
   bitmaps[i].FastBlit( rand()%SCREEN_W, rand()%SCREEN_H );
}

// Finish rendering //
Bitmap::FinishFastBlitting();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about FastBlit? Click here.
openlayer-2.1.orig/Manual/Bitmap/Destroy.html0000644000175000017500000002314610421451270021461 0ustar georgeskgeorgeskOpenLayer Offline Manual

Destroy

void Destroy();

Frees the Bitmap from both the memory and the gfx card.

If you have any global bitmaps outside the functions you have to destroy them manually before the program exits. Local Bitmaps will be automatically destroyed when they fall out of scope and dynamically allocated Bitmaps will be destroyed when they're deleted.

Note that if you call this function the bitmap can't be used anymore before it's loaded again. Any attempt to render a destroyed bitmap may lead to undefined behavior. Usually then the bitmap will appear in the screen as a white square.

Examples

Bitmap globalBitmap;

int main() {
   Setup::SetupProgram( ... );
   Setup::SetupScreen( ... );
   
   // Bitmaps can't be loaded before the libraries and the graphics mode are set up! //
   // See Setup for more information //
   globalBitmap.Load( ... );
   
   /*
    * The other code of the main function here
    */

   
   // A global bitmap must be destroyed before the program quits! //
   globalBitmap.Destroy();
   return 0;
}
END_OF_MAIN()


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Destroy? Click here.
openlayer-2.1.orig/Manual/Bitmap/BlitStretched.html0000644000175000017500000002665110421451270022574 0ustar georgeskgeorgeskOpenLayer Offline Manual

BlitStretched

float x, float y, float width, float height,
float opacity = 1.0 ) const;

Draws the bitmap to the screen stretched to the specified width and height at the specified top-left coordinates.

float x, float y, float width, float height,
const RenderMode &mode,
float opacity = 1.0 ) const;

The same as above but the specified RenderMode affects the way the Bitmap is rendered.

Coordinates and dimensions are in pixels. Opacity should be between 0.0 and 1.0, where 1.0 is completely opaque and 0.0 completely transparent. Notice that if you don't pass any opacity parameter, the bitmap will be rendered fully opaque. If you pass true to horizontallyFlipped the bitmap will be drawn to the screen horizontally flipped.

All transformations like stretching use anti-aliased routines by default. Use the Settings if you prefer aliased transformations instead.

BlitRotated, like any other bitmap rendering function, will take the alpha channel of the bitmap in account. With the default blender the alpha channel describes the opacity of every single pixel in the bitmap. The higher alpha value, the more visible the pixel is. Read more about the alpha channel in the definition of Bitmap.

Examples

// Load a bitmap from an image file //
Bitmap playerBmp( "Player.png" );

// Draw the bitmap to the screen such that the top-left corner //
// of the bitmap is positioned at x = 200.0, y = 100.0 //
// and the bitmap is stretched to width = 70.0 and height = 50.0 pixels //
playerBmp.BlitStretched200.0100.070.050.0 ); 

// Draw the bitmap at the same position but this time //
// stretched to double the original size of the bitmap //
playerBmp.BlitStretched200.0100.02.0 * playerBmp.Width(), 2.0 * playerBmp.Height() );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about BlitStretched? Click here.
openlayer-2.1.orig/Manual/Bitmap/LoadListOfBitmaps.html0000644000175000017500000002355210377363276023373 0ustar georgeskgeorgeskOpenLayer Offline Manual

LoadListOfBitmaps

static std::vector< Bitmap *>
LoadListOfBitmaps(

std::string filenameBegin,
std::string extension,
int numNumbers = 2,
int extraFlags = [none] );

Returns a list of bitmaps stored as filenameBegin01.extension, filenameBegin02.extension etc. where numNumbers is the amount of numbers in the filename.

numNumbers actually affects the number of preceeding zeros that will be added to the number in the filename. If numNumbers is 3 the filename should always have at least 3 numbers like in animation015.png and if numNumbers is 5 the filename should be animation00015.png instead. If you don't need any preceeding zeros you can pass 1 as numNumbers.

Examples

// Load all tile bitmaps from the gfx folder named //
// tile001.bmp, tile002.bmp, tile003.bmp etc. //
std::vector< Bitmap *> tileBitmaps = Bitmap::LoadListOfBitmaps"gfx/tile""bmp"3 );

// Check if any bitmaps were actually loaded //
if( tileBitmaps.empty() ) {
   allegro_message( "No tile bitmaps could've been loaded!" );
   exit( -1 );
}

// Draw the first bitmap such that the top-left coordinate will be at (200, 100) //
tileBitmaps[0].Blit200.0100.0 );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about LoadListOfBitmaps? Click here.
openlayer-2.1.orig/Manual/Bitmap/IsValid.html0000644000175000017500000002144210421451270021360 0ustar georgeskgeorgeskOpenLayer Offline Manual

IsValid

bool IsValid() const;

Returns true if the bitmap is ready to be used.

If the bitmap isn't loaded yet, the loading has failed or the bitmap is already destroyed this function will return false.

The Bitmap class also has a conversion to bool operator so you can check the validity of a Bitmap simply by doing: if( !bmp )

Examples

Bitmap myBmp( "Gfx/Picture.png" );

// Check if the Bitmap was correctly loaded //
if( !myBmp.IsValid() ) {
   allegro_message( "Couldn't load Picture.png!" );
   exit( -1 );
}

// Also works and is faster to type //
if( !myBmp ) {
   allegro_message( "Couldn't load Picture.png!" );
   exit( -1 );
}


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about IsValid? Click here.
openlayer-2.1.orig/Manual/Bitmap/Blit.html0000644000175000017500000002664010377363276020746 0ustar georgeskgeorgeskOpenLayer Offline Manual

Blit

void Blit(
float x, float y, float opacity = 1.0 ) const;

Draws the bitmap to the screen at the specified top-left coordinates. Opacity should be between 0.0 and 1.0, where 1.0 is completely opaque and 0.0 completely transparent.

void Blit(
float x, float y, const RenderMode &mode,
float opacity = 1.0 ) const;

The same as above but the specified RenderMode affects the way the Bitmap is rendered.

Coordinates are in pixels. Notice that if you don't pass any opacity parameter, the bitmap will be rendered fully opaque. Flipping is now done with FlippedMode.

Blit, like any other bitmap rendering function, will take the alpha channel of the bitmap in account. With the default blender the alpha channel describes the opacity of every single pixel in the bitmap. The higher alpha value, the more visible the pixel is. Read more about the alpha channel in the definition of Bitmap.

Examples

// Load a bitmap from an image file //
Bitmap playerBmp( "Player.png" );

// Draw the bitmap to the screen such that the top-left corner //
// of the bitmap is positioned at x = 200.0, y = 100.0 //
playerBmp.Blit200.0100.0 );

// Draw the bitmap at the same position but with only 40% opacity. //
// (You can partially "see through" the bitmap like a ghost) //
playerBmp.Blit200.0100.00.40 );

// Draw the bitmap at the same position but tinted 30% to red //
playerBmp.Blit200.0100.0, TintMode( Rgba1.00.00.00.30 )));

// Draw the bitmap at the same position but horizontally flipped //
playerBmp.Blit200.0100.0FlippedMode( HORIZONTAL ));


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Blit? Click here.
openlayer-2.1.orig/Manual/Bitmap/GetPixelPacked.html0000644000175000017500000002314310421451270022656 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetPixelPacked

Advanced function

inline int GetPixelPacked(
int x, int y )

Returns the color value of the specified pixel in a packed 32-bit integer.

No checking is done wether the pixel actually lies inside the pixel so make sure that you don't try to read a pixel out of the bounds of the bitmap, which would lead to a crash.

Examples

Bitmap myBmp( ... );

// Get the color of the pixel x = 7, y = 5 in the bitmap //
int color = myBmp.GetPixelPacked75 );

// That would lead to a crash if the size of the bitmap would be less than 8x6 //
// The safe way would be: //

int color;
int x = 7, y = 8;

if( x >= 0 && x < myBmp.Width() &&
    y >= 0 && y < myBmp.Height() ) {

   color = myBmp.GetPixelPacked75 );
}



Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about GetPixelPacked? Click here.
openlayer-2.1.orig/Manual/Bitmap/FinishFastBlitting.html0000644000175000017500000002114310377363276023600 0ustar georgeskgeorgeskOpenLayer Offline Manual

FinishFastBlitting

Advanced function

static void FinishFastBlitting()

This function should be called right after you're finished calling FastBlit.

You shouldn't call any other rendering functions than FastBlit (or call your own OpenGL commands) after calling StartFastBlitting and before calling FinishFastBlitting.

Examples

// Start fast blitting //
Bitmap::StartFastBlitting();

// Do the FastBlits here //

// Finish fast blitting //
Bitmap::FinishFastBlitting();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about FinishFastBlitting? Click here.
openlayer-2.1.orig/Manual/Bitmap/UnloadFromGPU.html0000644000175000017500000002136310417230626022456 0ustar georgeskgeorgeskOpenLayer Offline Manual

UnloadFromGPU

Advanced function

Note that since OpenLayer 1.9 you shouldn't use this function if Settings::StoreMemoryBitmaps is turned off!

void UnloadFromGPU();

Unloads the Bitmap from the graphics card. Automatically done by the destructor and the Destroy()-method.

OpenLayer handles uploading and destroying textures for you so you don't usually need to call this function. But if you wish to have more control of when the bitmap should reside in the gfx card you can use SendToGPU() and UnloadFromGPU() for that.

Examples

Bitmap myBmp( ... );

// Unload the texture information of the bitmap from the graphics card //
myBmp.UnloadFromGPU();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about UnloadFromGPU? Click here.
openlayer-2.1.orig/Manual/Bitmap/StartFastBlitting.html0000644000175000017500000002157410377363276023465 0ustar georgeskgeorgeskOpenLayer Offline Manual

StartFastBlitting

Advanced function

static void StartFastBlitting(
float opacity = 1.0 )

This function should be called right before using FastBlit. The opacity value tells the opacity of the following FastBlits.

After calling this function you can call FastBlit as many times in a row as you want. However, you can't call any other rendering functions (or change OpenGL state in any way) before calling FinishFastBlitting.

Examples

// Start fast blitting //
Bitmap::StartFastBlitting();

// Do the FastBlits here //

// Finish fast blitting //
Bitmap::FinishFastBlitting();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about StartFastBlitting? Click here.
openlayer-2.1.orig/Manual/Bitmap/HasAlphaChannel.html0000644000175000017500000002025010377363276023015 0ustar georgeskgeorgeskOpenLayer Offline Manual

HasAlphaChannel

Advanced function

bool HasAlphaChannel() const;

Returns true if the Bitmap has an alpha channel.

Examples

Bitmap bmp("gfx/myBmp.png");

// Check if the Bitmap has an alpha channel //
if( bmp.HasAlphaChannel() ) {
  allegro_message( "Yes it does!" );
}


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about HasAlphaChannel? Click here.
openlayer-2.1.orig/Manual/Bitmap/Width.html0000644000175000017500000001764310416463436021127 0ustar georgeskgeorgeskOpenLayer Offline Manual

Width

int Width() const;
Returns the width of the bitmap.

All dimensions are in pixels.

Examples

Bitmap myBmp( ... );

// Get the width of the bitmap in pixels //
int width = myBmp.Width();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Width? Click here.
openlayer-2.1.orig/Manual/Bitmap/Height.html0000644000175000017500000001767310421451270021250 0ustar georgeskgeorgeskOpenLayer Offline Manual

Height

int Height() const;
Returns the height of the bitmap.

All dimensions are in pixels.

Examples

Bitmap myBmp( ... );

// Get the height of the bitmap in pixels //
int height = myBmp.Height();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Height? Click here.
openlayer-2.1.orig/Manual/Bitmap/GetMemoryBitmap.html0000644000175000017500000002222310416463436023103 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetMemoryBitmap

BITMAP *GetMemoryBitmap() const

Returns a memory bitmap copy of the Bitmap.

int x, int y, int width, int height ) const

Returns a memory bitmap copy of the specified region of the Bitmap.

If you have rendered to the Bitmap you may wish to retrieve a copy of the modified image to the memory.

Examples

Bitmap bmp( ... );

// Get an Allegro BITMAP copy of the Bitmap //
BITMAP *allegroBmp = bmp.GetMemoryBitmap();

// Get an Allegro BITMAP copy of the 20 x 10 pixel //
// portion of top-left corner of the Bitmap //
BITMAP *anotherAllegroBmp = bmp.GetMemoryBitmap002010 );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about GetMemoryBitmap? Click here.
openlayer-2.1.orig/Manual/Bitmap/GetPixel.html0000644000175000017500000002422610421451270021551 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetPixel

inline Rgba GetPixel(
int x, int y ) const;

Returns the color value of the specified pixel as an Rgba color.

No checking is done wether the pixel actually lies inside the pixel so make sure that you don't try to read a pixel out of the bounds of the bitmap, which would lead to a crash.

This function is relatively slow so it's best to not to call this function per each pixel in the Bitmap! If you read only a few dozen of pixels per frame it shouldn't be too slow, though.

To read the whole Bitmap, you should first get a copy of it in the memory by calling GetMemoryBitmap instead.

Since OpenLayer 2.0, this function reads the color from the texture information in the graphics card. Thus if the Bitmap isn't loaded in the graphics card, this function won't work!

Examples

Bitmap myBmp( ... );

// Get the color of the pixel x = 7, y = 5 in the bitmap //
Rgba color = myBmp.GetPixel75 );

// That would lead to a crash if the size of the bitmap would be less than 8x6 //
// The safe way would be: //

Rgba color;
int x = 7, y = 8;

if( x >= 0 && x < myBmp.Width() &&
    y >= 0 && y < myBmp.Height() ) {

   color = myBmp.GetPixel75 );
}


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about GetPixel? Click here.
openlayer-2.1.orig/Manual/Bitmap/Save.html0000644000175000017500000002166510421451270020732 0ustar georgeskgeorgeskOpenLayer Offline Manual

Save

void Save(
const char *filename ) const

Saves the Bitmap to disk with the specified filename.

The type of the file depends on the extension of the filename.

This function can be used to save a screenshot of the program by first retrieving the contents of the screen to a Bitmap with CopyFromScreen. See the examples for how to do this.

Examples

Bitmap bmp( ... );

// Save the contents of the Bitmap as mybmp.png //
bmp.Save"mybmp.png" );

// Save a screenshot of the program as screenshot.png //

Bitmap screenImage( SCREEN_W, SCREEN_H );
screenImage.CopyFromScreen00 );
screenImage.Save"screenshot.png" );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Save? Click here.
openlayer-2.1.orig/Manual/Bitmap/GetCollisionPoly.html0000644000175000017500000002202710431302056023262 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetCollisionPoly


Returns the generated collision polygon for the Bitmap.

The return value is null if no collision polygon was created in the constructor. To create the collision polygon, pass CREATE_COLLISION_POLY to the extraFlags parameter in the constructor.

Examples

// Load a Bitmap and create a collision polygon //
Bitmap bmp( "mybmp.png", CREATE_COLLISION_POLY );

// Get the collision polygon of the Bitmap //
Poly *collisionPolygon = bmp.GetCollisionPoly();

// Test collision between two Bitmaps //
Bitmap bmp2( ..., CREATE_COLLISION_POLY );

if( bmp.GetCollisionPoly()->Collides( *bmp2.GetCollisionPoly(), ... )) {
  // Collision!
}


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about GetCollisionPoly? Click here.
openlayer-2.1.orig/Manual/Bitmap/CopyFromScreen.html0000644000175000017500000002110210377363276022736 0ustar georgeskgeorgeskOpenLayer Offline Manual

CopyFromScreen

int x, int y )

Copies a region of the game window to the Bitmap.

The given coordinages are the top-left corner of the region. The dimensions of the region depend on the size of the Bitmap.

Examples

// Create a 300 x 150 Bitmap //
Bitmap bmp( 300150 );

// Copy a 300 x 100 region from the screen to the Bitmap //
// The top-left coordinates of the region are 200.0 and 100.0 //
bmp.CopyFromScreen200.0100.0 );


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about CopyFromScreen? Click here.
openlayer-2.1.orig/Manual/Bitmap/TexturedQuad.html0000644000175000017500000002342210421451270022444 0ustar georgeskgeorgeskOpenLayer Offline Manual

TexturedQuad

Advanced function

float w, float h, float fact ) const

Outputs a raw textured quad to the video card.

float w, float h, float fact,
const RenderMode &mode ) const

Same as above, but also transforms the quad by the given RenderMode.

If you wish to extend the Bitmap by making your own subclass you can implement new rendering functions by using this function to finally output the quad to the video card.

Examples

// Make a subclass of Bitmap //

class MyExtendedBitmap : public Bitmap {
public:
   void MySpecialRenderingFunction() {
     // First set the OpenGL state as you want here...
     
     //
 And then output the image to the video card
     TexturedQuadWidth(), Height(), opacity );
     
     // Restore the original OpenGL state here
   }
};


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about TexturedQuad? Click here.
openlayer-2.1.orig/Manual/Bitmap/BlitTransformed.html0000644000175000017500000003231610421451270023126 0ustar georgeskgeorgeskOpenLayer Offline Manual

BlitTransformed

float x, float y, float width, float height,
float angle, float opacity = 1.0 ) const;

Draws the bitmap to the screen stretched to the specified width and height and rotated clockwise around its centre. The centre of the bitmap will be positioned in the screen at the given x and y -coordinates.

float x, float y, float width, float height,
float angle, const RenderMode &mode,
float opacity = 1.0 ) const;

The same as above but the specified RenderMode affects the way the Bitmap is rendered.

float x, float y, float width, float height,
float pivotX, float pivotY, float angle,
float opacity = 1.0 ) const;

Draws the bitmap to the screen stretched to the specified width and height and rotated clockwise around the point (pivotX, pivotY) in the bitmap. The pivot point will be positioned in the screen at the given x and y -coordinates.

float x, float y, float width, float height,
float pivotX, float pivotY, float angle,
const RenderMode &mode,
float opacity = 1.0 ) const;

The same as above but the specified RenderMode affects the way the Bitmap is rendered.

Coordinates and dimensions are in pixels and the angle is in radians. Opacity should be between 0.0 and 1.0, where 1.0 is completely opaque and 0.0 completely transparent. Notice that if you don't pass any opacity parameter, the bitmap will be rendered fully opaque.

If you pass true to horizontallyFlipped the bitmap will be drawn to the screen horizontally flipped. Note that the bitmap will always be placed so that the pivot point is positioned at the given coordinates, even if the bitmap is flipped.

All transformations like rotation and stretching use anti-aliased routines by default. Use the Settings if you prefer aliased transformations instead.

BlitTransformed, like any other bitmap rendering function, will take the alpha channel of the bitmap in account. With the default blender the alpha channel describes the opacity of every single pixel in the bitmap. The higher alpha value, the more visible the pixel is. Read more about the alpha channel in the definition of Bitmap.

Examples

// Load a bitmap from an image file //
Bitmap playerBmp( "Player.png" );

// Draw the bitmap to the screen such that the top-left corner of the bitmap //
// is positioned at x = 200.0, y = 100.0 and the bitmap is stretched to //
// half the original size and rotated anti-clockwise pi/4 radians (90 decrees) //
playerBmp.BlitTransformed200.0100.0, playerBmp.Width()/2, playerBmp.Height()/2, AL_PI/4.0 ); 


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about BlitTransformed? Click here.
openlayer-2.1.orig/Manual/Bitmap/SendToGPU.html0000644000175000017500000002276110417230626021607 0ustar georgeskgeorgeskOpenLayer Offline Manual

SendToGPU

Advanced function

Note that since OpenLayer 1.9 this function won't do anything unless Settings::StoreMemoryBitmaps is turned on or the Bitmap was unloaded from the video card by calling UnloadToMemory! (An error will be logged to allegro.log if this function is used without having a memory bitmap storage)

void SendToGPU();

Sends the Bitmap to the graphics card. Automatically done by the loading functions.

If you wish to have more control of when the bitmap should reside in the gfx card you can use SendToGPU and UnloadFromGPU for that. OpenLayer handles uploading and destroying textures for you so you don't usually need to call this function.

Examples

// Turn on the memory bitmap storage //
Settings::StoreMemoryBitmapstrue );

// The Bitmap will automatically be uploaded to the graphics card //
Bitmap myBmp( ... );

// ... but we unload it //
myBmp.UnloadFromGPU();

// Send the bitmap to the graphics card //
myBmp.SendToGPU();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about SendToGPU? Click here.
openlayer-2.1.orig/Manual/Bitmap/GetDefaultPivot.html0000644000175000017500000002024210402045446023073 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetDefaultPivot


Returns the default pivot point of the Bitmap

The default pivot point will be used if a pivot is not specified in BlitRotated or BlitTransformed. The initial default pivot of a Bitmap is the center.

Examples

Bitmap myBmp( ... );

// Get the default pivot of the Bitmap //
Vec2D defaultPivot = myBmp.GetDefaultPivot();


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about GetDefaultPivot? Click here.
openlayer-2.1.orig/Manual/Bitmap/SetDefaultPivot.html0000644000175000017500000002056310402045446023115 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetDefaultPivot

Vec2D point )

Sets the default pivot point of the Bitmap

The default pivot point will be used if a pivot is not specified in BlitRotated or BlitTransformed. The initial default pivot of a Bitmap is the center.

Examples

Bitmap myBmp( ... );

// Set the default pivot of the Bitmap to x = 30.0, y = 20.0 //
myBmp.SetDefaultPivotVec2D30.020.0 ));


Other functions of the class Bitmap
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about SetDefaultPivot? Click here.
openlayer-2.1.orig/Manual/Blenders/0000700000175000017500000000000012262355751017460 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Blenders/Push.html0000644000175000017500000000577010421451270021274 0ustar georgeskgeorgeskOpenLayer Offline Manual

Push

Advanced function

inline static void Push()

Pushes the active blender to the stack (though still keeping it active)

The blender can can later be restored from the stack by calling the Pop-method.

Examples

// Push the old blender to the stack and select a new one //
Blenders::Push();
Blenders::Set(...);

// Do some drawing here...

//
 Restore the old blender //
Blenders::Pop();


Other functions of the class Blenders
Set
Selects the specified blender as the active color blender

Advanced functions

Push
Pushes the active blender to the stack
Pop
Pops the most recently stored blender from the stack


Questions about Push? Click here.
openlayer-2.1.orig/Manual/Blenders/Set.html0000644000175000017500000001211110402077072021076 0ustar georgeskgeorgeskOpenLayer Offline Manual

Set

static void Set(
Blender blender );

Selects a pre-defined blender as the active color blender.


static void Set(
GLenum sourceFactor, GLenum destFactor )

Selects a custom blender as the active color blender.

A list of the pre-defined blenders:

ALPHA_BLENDER (the default blender)

Alpha values of the source pixels tell the opacity of the pixel. The higher the alpha value is, the more visible the pixel is. See more in Rgba.

Bitmaps are rendered with translucent pixels if they have an alpha channel.

The alpha value of Rgba colors tell the opacity of the primitive or text.


ADDITIVE_BLENDER

Renderind pixels increases the lightness of the underlying pixels. The alpha value tells the intensity of the lighting.

Bitmaps can be used as explosions and spotlights.

Primitives can be used to lit specific areas and glowing explosion particles.

Text can be used to produce lit text in dark background, like a glow in a computer screen.


SUBTRACTIVE_BLENDER

Renderind pixels decreases the lightness of the underlying pixels. The darkening always happens with a full intensity.

Bitmaps can be used as shadows (though the same works usually with ALPHA_BLENDER). Primitives can be used to darken specific areas.


COPY_BLENDER

The alpha channel is discarted and the pixels are simply copied from the source to the destination. In other words, blending is disabled.


FULL_ADDITIVE_BLENDER

Like ADDITIVE_BLENDER and COPY_BLENDER combined - discards the alpha channel and adds the pixels from the source to the destination with full intensity.


A list of custom blender enumerations can be found in OpenGL documentation under glBlendFunc.

Examples

// Select the additive blender //
Blenders::Set( ADDITIVE_BLENDER );

// Select the alpha blender (used by default) //
Blenders::Set( ALPHA_BLENDER );

// Selects a custom blender which is like an inverted ALPHA_BLENDER: //
Blenders::Set( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA );


Other functions of the class Blenders
Set
Selects the specified blender as the active color blender

Advanced functions

Push
Pushes the active blender to the stack
Pop
Pops the most recently stored blender from the stack


Questions about Set? Click here.
openlayer-2.1.orig/Manual/Blenders/Pop.html0000644000175000017500000000573010421451270021107 0ustar georgeskgeorgeskOpenLayer Offline Manual

Pop

Advanced function

static void Pop();

Pops the most recently stored blender from the stack and makes it active

You can use the Push-method to store the active blender to the stack (see the examples).

Examples

// Push the old blender to the stack and select a new one //
Blenders::Push();
Blenders::Set(...);

// Do some drawing here...

//
 Restore the old blender //
Blenders::Pop();


Other functions of the class Blenders
Set
Selects the specified blender as the active color blender

Advanced functions

Push
Pushes the active blender to the stack
Pop
Pops the most recently stored blender from the stack


Questions about Pop? Click here.
openlayer-2.1.orig/Manual/Setup/0000700000175000017500000000000012262355751017022 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Setup/GetExecutablePath.html0000644000175000017500000000772210377350122023260 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetExecutablePath

static inline std::string GetExecutablePath()

Returns the path of the program executable.

This function should only be called after calling Setup::SetupProgram.

Examples

// Get the path of the executable //
std::string executablePath = Setup::GetExecutablePath();


Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about GetExecutablePath? Click here.
openlayer-2.1.orig/Manual/Setup/SetupScreen.html0000644000175000017500000001722210377350122022156 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetupScreen

static bool SetupScreen(
int width, int height,
bool fullscreen = true,
int colorDepth = 32, int zDepth = 8,
int refreshRate = [automatic] );

Sets up the program window or the fullscreen mode with the given color depth and Z depth. Returns true in success.

You can pass FULLSCREEN or WINDOWED as the fullscreen parameter instead of a boolean. Width and height tell the screen resolution (fullscreen mode) or the window size (windowed mode) in pixels. The color depth should be 16 or 32.

Generally this function should be called right after Setup::SetupProgram because you can't use any Bitmaps or TextRenderers before you've set up the screen!

zDepth is the accuracy of the built-in depth sorting and should be 8, 16 or 32, but you don't usually have to worry about it unless you know what you're doing. You can simply leave it to be the default value.

Examples

// Setup 32-bit fullscreen mode with the resolution of 1024 x 768 //
Setup::SetupScreen1024768true32 );

// Does the same as above but by using the FULLSCREEN constant //
Setup::SetupScreen1024768, FULLSCREEN, 32 );


// Setup 32-bit windowed mode with the window size of 800 x 600 //
Setup::SetupScreen800600false32 );

// Does the same as above but by using the WINDOWED constant //
Setup::SetupScreen800600, WINDOWED, 32 );


// You can also leave the color depth parameter out if you want 32-bit graphics //
Setup::SetupScreen800600, WINDOWED );

// Setup 32-bit fullscreen mode with the window size of 800 x 600 //
// and the maxium Z buffer accuracy //
Setup::SetupScreen800600, FULLSCREEN, 3232 );


Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about SetupScreen? Click here.
openlayer-2.1.orig/Manual/Setup/GetWindowWidth.html0000644000175000017500000001022710416463436022632 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetWindowWidth

static inline int GetWindowWidth()

Returns the width of the program window.

Of course this function only works after Setup::SetupScreen is called.

Examples

// Get the width of the window //
int windowWidth = Setup::GetWindowWidth();


Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about GetWindowWidth? Click here.
openlayer-2.1.orig/Manual/Setup/ToAbsolutePathname.html0000644000175000017500000001056710377350122023462 0ustar georgeskgeorgeskOpenLayer Offline Manual

ToAbsolutePathname

static std::string ToAbsolutePathname(
std::string pathname )

Converts the relative path + filename to an absolute path + filename.

All OpenLayer's own loading functions accept both relative and absolute pathnames.

If the passed pathname is already absolute, the passed pathname is returned unmodified. This function can only be used after Setup::SetupScreen is called.

Examples

string relativePathname = "data/SomeTextFile.txt";

// Convert the relative pathname to absolute //
// (For example, C:/mygames/mycoolgame/data/SomeTextFile.txt) //
string absolutePathname = Setup::ToAbsolutePath( relativePathname );


Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about ToAbsolutePathname? Click here.
openlayer-2.1.orig/Manual/Setup/GetWindowHeight.html0000644000175000017500000001031610421451270022747 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetWindowHeight

static inline int GetWindowHeight()

Returns the height of the program window.

Of course this function only works after Setup::SetupScreen is called.

Examples

// Get the width of the window //
int windowWidth = Setup::Width&category=19">GetWindowWidth();


Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about GetWindowHeight? Click here.
openlayer-2.1.orig/Manual/Setup/SetupProgram.html0000644000175000017500000001705310377350122022350 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetupProgram

static bool SetupProgram(
bool setupKeyboard = true,
bool setupMouse = true,
bool setupTimer = true );

Sets up OpenLayer, Allegro, AllegroGL and the specified input devices. Returns true on success.

static bool SetupProgram(
int devices );

Same as above but the parameters are passed by using the bitwise "or" of any of the following devices: KEYBOARD, MOUSE and TIMER.

The first thing you should be doing in your program is to call this function. That's because you can't call any other OpenLayer function or any Allegro or AllegroGL function before you call this one.

Besides setting up the libraries it also sets up the specified input devices. It's usually recommended to set up the keyboard even if you're not using keyboard functions anywhere. Also setting up the mouse will also set up timer functions even if you pass false as setupTimer. That's because the mouse handling routines require the timer routines.

Calling the function with no parameters will by default set up all possible input devices and the timer routines.

It's best to call Setup::SetupScreen right after calling this function because you can't load any Bitmaps or TextRenderers before you've set up the screen!

Examples

// Setup the libraries and all drivers //
Setup::SetupProgram();

// Setup the libraries and the keyboard but not the mouse //
Setup::SetupProgramtruefalse );

// Same as above by using the named arguments //
Setup::SetupProgram( KEYBOARD );

// Setup the libraries and the keyboard and timer routines but not the mouse //
Setup::SetupProgramtruefalsetrue );

// Same as above by using the named arguments //
Setup::SetupProgram( KEYBOARD | TIMER );

// The function sets up all input devices and timer routines by default //
Setup::SetupProgram();
// Now the keyboard, mouse and timer routines are all set up //


Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about SetupProgram? Click here.
openlayer-2.1.orig/Manual/Setup/IsScreenSetUp.html0000644000175000017500000001001610377350122022404 0ustar georgeskgeorgeskOpenLayer Offline Manual

IsScreenSetUp

Advanced function


static bool IsScreenSetUp()

Returns true if Setup::SetupScreen is called.

Examples

// Check if the screen is set up //
ifSetup::IsScreenSetUp() ) {
  allegro_message( "Yes it is!" );
}



Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about IsScreenSetUp? Click here.
openlayer-2.1.orig/Manual/Setup/IsProgramSetUp.html0000644000175000017500000001001410377350122022572 0ustar georgeskgeorgeskOpenLayer Offline Manual

IsProgramSetUp

Advanced function

static bool IsProgramSetUp();

Returns true if Setup::SetupProgram is called.

Examples

// Check if the program is set up //
ifSetup::IsProgramSetUp() ) {
  allegro_message( "Yes it is!" );
}


Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about IsProgramSetUp? Click here.
openlayer-2.1.orig/Manual/Setup/GetColorDepth.html0000644000175000017500000000656610377350122022432 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetColorDepth

static inline int GetColorDepth()

Returns the color depth of the program window.

Other functions of the class Setup
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about GetColorDepth? Click here.
openlayer-2.1.orig/Manual/Point/0000700000175000017500000000000012262355751017013 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Point/DrawFast.html0000644000175000017500000000730010377350122021416 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawFast

void DrawFast(
const Rgba &color )

A faster version of Draw, but requires to call StartFastDrawing and FinishFastDrawing.

Remember that even though using DrawFast is faster than using Draw, it's still not suitable for pixelwise image manipulation, for example.

Examples

// First start fast drawing //
Point::StartFastDrawing();

// Draw a series of points //
for( int i = 0; i = 1000; i++ ) {
   Point( i, i ).DrawFastRgba::RED );
}

// Finish fast drawing //
Point::FinishFastDrawing();


Other functions of the class Point
Draw
Draws the point with the specified color
StartFastDrawing
Call this function before using FastPoint
DrawFast
A faster version of Draw
FinishFastDrawing
Should be called after using DrawFast


Questions about DrawFast? Click here.
openlayer-2.1.orig/Manual/Point/StartFastDrawing.html0000644000175000017500000000700710377350122023136 0ustar georgeskgeorgeskOpenLayer Offline Manual

StartFastDrawing

static void StartFastDrawing()

You should call this function before using DrawFast.

Remember that even though using DrawFast is faster than using Draw, it's still not suitable for pixelwise image manipulation, for example.

Examples

// First start fast drawing //
Point::StartFastDrawing();

// Draw a series of points //
for( int i = 0; i = 1000; i++ ) {
   Point( i, i ).DrawFastRgba::RED );
}

// Finish fast drawing //
Point::FinishFastDrawing();


Other functions of the class Point
Draw
Draws the point with the specified color
StartFastDrawing
Call this function before using FastPoint
DrawFast
A faster version of Draw
FinishFastDrawing
Should be called after using DrawFast


Questions about StartFastDrawing? Click here.
openlayer-2.1.orig/Manual/Point/Draw.html0000644000175000017500000000433110417230626020602 0ustar georgeskgeorgeskOpenLayer Offline Manual

Draw

void Draw(
const Rgba &color )

Draws the point with the specified color

Other functions of the class Point
Draw
Draws the point with the specified color
StartFastDrawing
Call this function before using FastPoint
DrawFast
A faster version of Draw
FinishFastDrawing
Should be called after using DrawFast


Questions about Draw? Click here.
openlayer-2.1.orig/Manual/Point/FinishFastDrawing.html0000644000175000017500000000430010377350122023252 0ustar georgeskgeorgeskOpenLayer Offline Manual

FinishFastDrawing

static void FinishFastDrawing()

This function should be called after using DrawFast.

Other functions of the class Point
Draw
Draws the point with the specified color
StartFastDrawing
Call this function before using FastPoint
DrawFast
A faster version of Draw
FinishFastDrawing
Should be called after using DrawFast


Questions about FinishFastDrawing? Click here.
openlayer-2.1.orig/Manual/Collision.html0000644000175000017500000000572310417230626020555 0ustar georgeskgeorgeskOpenLayer Offline Manual

Collision

Detailed information about a collision

const Line &aSegment, const Line &bSegment )

Creates a new collision object and specifies the colliding line segments.


Using the default constructor means that no collision has happened.

Member functions
GetPoint
Returns the exact point of the collision
GetSegment
Returns the specified colliding line segment
IsCollision
Returns true if a collision has really happened
GetNormal
Returns the normal of a colliding object at the collision point
GetAllPoints
Returns all collision points
GetAllSegments
Returns all pairs of colliding segments


Questions about Collision? Click here.
openlayer-2.1.orig/Manual/Rgba.html0000644000175000017500000002325710377350122017476 0ustar georgeskgeorgeskOpenLayer Offline Manual

Rgba

The color structure which holds the 4 color components: Red, green, blue and alpha components.

float r, float g, float b, float a = 1.0 );

Construct the color from floating-point color components. The values should be between 0.0 and 1.0.

double r, double g, double b, double a = 1.0 );

Construct the color from double color components. The values should be between 0.0 and 1.0.

int r, int g, int b, int a = 255 );

Construct the color from integer color components. The values should be between 0 and 255.

int col, int a );

Construct the color from a 24-bit packed color value and an integer alpha value. The alpha value should be between 0 and 255.

Public fields
float r, g, b, a - The color components

With the default blender the alpha value of the color tells the opacity of the color. This way you can have translucency where ever an Rgba color is needed. The higher the alpha value, the more visible the color is. With the maxium value the color is totally visible and with the minium value the color is totally transparent.

Notice that in most constructors you don't have to pass the alpha value if you want the color to be totally opaque.

There are several color constants to use:
static Rgba BLACK, WHITE, RED, YELLOW, GREEN, BLUE, INVISIBLE;

The color constants.

All constant colors are totally opaque except Rgba::INVISIBLE, which is totally transparent. The name INVISIBLE is used instead of TRANSPARENT because TRANSPARENT seems to be a reserved name. If you can think of a better name then let me know!

Examples

// Create a pure white color using float color components //
// (same as Rgba::WHITE) //
Rgba white( 1.01.01.0 );

// Create a pure white color using integer color components //
// (same as Rgba::WHITE) //
Rgba white( 255255255 );

// Create a pure black color (same as Rgba::BLACK) //
Rgba black( 0.00.00.0 );

// Create a medium gray color //
Rgba gray( 0.50.50.5 );

// Create a pure red color (same as Rgba::RED) //
Rgba red( 1.00.00.0 );

// Create a pure green color (same as Rgba::GREEN) //
Rgba green( 0.01.00.0 );

// Create a pure blue color (same as Rgba::BLUE) //
Rgba blue( 0.00.01.0 );

// Create a yellow color (same as Rgba::YELLOW) //
Rgba yellow( 1.01.00.0 );

// Create a dark yellow color //
Rgba yellowDark( 0.30.30.0 )

// Create a 50% opaque bright yellow color //
Rgba yellowTranslucent( 1.01.00.00.50 );

// Create a 20% opaque (almost transparent) cyan color //
Rgba cyanTranslucent( 0.01.01.00.20 );

// Create an transparent color (same as Rgba::INVISIBLE) //
// It doesn't matter what you pass as the red, green and blue components //
// as the color will be totally transparent anyways //
Rgba transparentColor( 1.01.01.00.0 );


Member functions
MixWith
Mixes two colors together with the given factor
WithAlpha
Creates a new color with the same color components but a different alpha value

Advanced functions

Packed
Returns the color packed in an integer
Select
Selects the color as the active OpenGL color


Questions about Rgba? Click here.
openlayer-2.1.orig/Manual/CrystalStyle.css0000644000175000017500000000314510377350122021103 0ustar georgeskgeorgeskdiv.blogentryheader { font-family: trebuchet, sans-serif; text-align: left; font-size: 130%; border-style: dotted; letter-spacing: 3px; border-style: dotted; border-width: 1px; vertical-align: middle; padding-left: 8px; color: #331100 } div.blogentrybody { font-family: trebuchet, sans-serif; text-align: left; padding-top: 10px; color: #333333 } div.buttonstyle { margin-left: 5px; margin-right: 5px; } div.linkbarstyle { border-bottom-style: dotted; border-bottom-width: 1px; } div.languageselection { font-size: 9px; text-align: right; } div { font-family: trebuchet, sans-serif; color: #333333; } div.SmallHeader { font-style: italic; } div.MediumHeader { font-style: italic; font-size: larger; } div.BigHeader { font-size: 36px; } div.Surrounded { border-style: dotted; border-width: 1px; border-spacing: 10px; padding: 10px; } div.Code { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: smaller; } div.LargeCode { font-family: Verdana, Arial, Helvetica, sans-serif; } div.FuncDef { font-family: Verdana, Arial, Helvetica, sans-serif; } div.SyntaxColored { color: #777733; } div.TopLined { font-family: trebuchet, sans-serif; color: #333333; border-top-style: dotted; border-top-width: 1px; } div.smalltext { font-family: trebuchet, sans-serif; color: #777799; font-size: small; } div.BiggerText { font-size: larger; } a { color: #777777; text-decoration: none; } a.active { color: #8381A3; text-decoration: none; } a:hover { color: #000000; }openlayer-2.1.orig/Manual/Transforms.html0000644000175000017500000000745710377350122020765 0ustar georgeskgeorgeskOpenLayer Offline Manual

Transforms

Global placement and color transformations

The old name for this class is Screen, which was changed in 1.8 for compability reasons. You can still use the old name by defining OL_USE_SCREEN_ALIAS before including OpenLayer.hpp.

Note that the position transformations, color channels and clipping only apply to the objects which are rendered after the transformation is set. The tint color, on the other hand, will take effect during the next call to Canvas::Canvas/Refresh.html">Refresh.

As usual, all positions are in pixels and angles in radians.

For advanced users: Note that the original transformation state is stored in the matrix stack.

Member functions
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about Transforms? Click here.
openlayer-2.1.orig/Manual/RenderMode/0000700000175000017500000000000012262355751017746 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/RenderMode/Clipped.html0000644000175000017500000000706210377350122022223 0ustar georgeskgeorgeskOpenLayer Offline Manual

Clipped

float x, float y, float w, float h );

When the Bitmap is rendered it's clipped to the specified region.

Rect clipArea );

Same as above but the clipping area is specified with a Rect.

The parts of the Bitmap which fall outside of the clipping region won't be visible. In the blitting functions the top-left corner of the Bitmap will be considered to be the top-left corner of the clipping region inside the Bitmap.

Examples

Bitmap bmp( ... );

// Render the Bitmap clipped to the width of 70.0 and the height of 50.0 //
bmp.Blit200.0100.0Clipped0.00.070.050.0 ));

// Render the Bitmap clipped to the same width and height but such that //
// the top-left corner of the clipping region is at 20.0, 10.0 //
bmp.Blit200.0100.0Clipped20.010.070.050.0 ));


Parent Class


Questions about Clipped? Click here.
openlayer-2.1.orig/Manual/RenderMode/SliceMultiplyMode.html0000644000175000017500000000372610377350122024252 0ustar georgeskgeorgeskOpenLayer Offline Manual
SliceMultiplyMode

float slicePos, OlSlicingChoise mode );

Stretches a one pixel wide slice of the bitmap to fill the entire bitmap. The mode should be one of the following: HORIZONTAL_SLICE or VERTICAL_SLICE.

Examples

Bitmap myBmp( ... );

// Blit the Bitmap to the screen such that the fifth row of the Bitmap fills the entire Bitmap //
myBmp.Blit200.0100.0SliceMultiplyMode5.0, VERTICAL ));


Parent Class


Questions about SliceMultiplyMode? Click here.
openlayer-2.1.orig/Manual/RenderMode/Tinted.html0000644000175000017500000000522110377350122022065 0ustar georgeskgeorgeskOpenLayer Offline Manual

Tinted

Renders the bitmap tinted to a color.

Rgba color );

The Bitmap will be tinted to the given color.The alpha value of the color tells the intensity of the tinting.

Note that only one tint effect can take effect at a time!

The old name for this class is TintMode. The old name can still be used. If you wish to disable the new class names, compile OpenLayer with OL_NO_RENDER_MODE_ALIASES.

Examples

// Load a bitmap //
Bitmap myBmp( ... );

// Render the bitmap to the screen such as the top-left corner is at x = 200.0, y = 100.0 //
// and the bitmap is tinted 35% to red //
myBmp.Blit200.0100.0TintedRgba1.00.00.00.35 )));


Parent Class


Questions about Tinted? Click here.
openlayer-2.1.orig/Manual/RenderMode/MultiMode.html0000644000175000017500000000701710377350122022542 0ustar georgeskgeorgeskOpenLayer Offline Manual

MultiMode

const RenderMode &mode1, const RenderMode &mode2 );

Combines two RenderModes to a single entity.

You can use the sum operator to easily create a MultiMode from two RenderModes. See the examples for how to do this.

Examples

Bitmap bmp( ... );

// Render the Bitmap horizontally flipped and tinted 30% to red //
bmp.Blit200.0100.0MultiModeFlipped( HORIZONTAL ), TintedRgba1.01.01.00.30 ))));

// The same thing can be done simply by using the sum operator //
// especially when there's more than two blending modes you wish to combine //
bmp.Blit200.0100.0Flipped( HORIZONTAL ) + TintedRgba1.01.01.00.30 )));


Parent Class


Questions about MultiMode? Click here.
openlayer-2.1.orig/Manual/RenderMode/ClippedMode.html0000644000175000017500000000600510377350122023024 0ustar georgeskgeorgeskOpenLayer Offline Manual
ClippedMode

float x, float y, float w, float h );

When the Bitmap is rendered it's clipped to the specified region.

The parts of the Bitmap which fall outside of the clipping region won't be visible. In the blitting functions the top-left corner of the Bitmap will be considered to be the top-left corner of the clipping region inside the Bitmap.

Examples

Bitmap bmp( ... );

// Render the Bitmap clipped to the width of 70.0 and the height of 50.0 //
bmp.Blit200.0100.0ClippedMode0.00.070.050.0 ));

// Render the Bitmap clipped to the same width and height but such that //
// the top-left corner of the clipping region is at 20.0, 10.0 //
bmp.Blit200.0100.0ClippedMode20.010.070.050.0 ));


Parent Class


Questions about ClippedMode? Click here.
openlayer-2.1.orig/Manual/RenderMode/GainAlphaMode.html0000644000175000017500000000516710377350122023300 0ustar georgeskgeorgeskOpenLayer Offline Manual
GainAlphaMode

const Bitmap &alphaFrom, float anchorX = 0.0,
float anchorY = 0.0 );

The Bitmap will be rendered with an additional alpha channel from an another Bitmap.

The values of the alpha channels are multiplied together to get the final value.

The results are clipped to the areas of both of the Bitmaps. This effectively means that the parts outside the alphaFrom Bitmap are considered to be transparent.

Note that only one GainAlphaMode can take effect at a time!

Examples

Bitmap myBmp( ... ), alphaBmp( ... );

// Render myBmp with an extra alpha channel from alphaBmp //
// The alpha channel is positioned inside myBmp at x = 20.0, y = 10.0  //
myBmp.Blit200.0100.0GainAlphaMode( alphaBmp, 20.010.0 );


Parent Class


Questions about GainAlphaMode? Click here.
openlayer-2.1.orig/Manual/RenderMode/AlphaFrom.html0000644000175000017500000000541510377350122022514 0ustar georgeskgeorgeskOpenLayer Offline Manual

AlphaFrom

const Bitmap &alphaFrom, float anchorX = 0.0,
float anchorY = 0.0 );

The Bitmap will be rendered with an additional alpha channel from an another Bitmap.

The values of the alpha channels are multiplied together to get the final value.

The results are clipped to the areas of both of the Bitmaps. This effectively means that the parts outside the alphaFrom Bitmap are considered to be transparent.

Note that only one GainAlphaMode can take effect at a time!

Examples

Bitmap myBmp( ... ), alphaBmp( ... );

// Render myBmp with an extra alpha channel from alphaBmp //
// The alpha channel is positioned inside myBmp at x = 20.0, y = 10.0  //
myBmp.Blit200.0100.0AlphaFrom( alphaBmp, 20.010.0 ));


Parent Class


Questions about AlphaFrom? Click here.
openlayer-2.1.orig/Manual/RenderMode/TintMode.html0000644000175000017500000000527310377350122022370 0ustar georgeskgeorgeskOpenLayer Offline Manual
TintMode

Renders the bitmap tinted to a color.

Rgba color );

The bitmap will be tinted to the given color.The alpha value of the color tells the intensity of the tinting.

Like any other RenderMode the instance of TintMode is deleted after it's passed to a rendering function. This is to allow for passing a new object to the rendering function without having to worry about destroying it. See the examples of how this works.

If you don't wish the TintMode to be deleted after using it you can call the NoAutoDestroy() -method.

Note that only one TintMode can take effect at a time!

Examples

// Load a bitmap //
Bitmap myBmp( ... );

// Render the bitmap to the screen such as the top-left corner is at x = 200.0, y = 100.0 //
// and the bitmap is tinted 35% to red //
myBmp.Blit200.0100.0TintModeRgba1.00.00.00.35 )));


Parent Class


Questions about TintMode? Click here.
openlayer-2.1.orig/Manual/RenderMode/SliceExpanded.html0000644000175000017500000000415710377350122023355 0ustar georgeskgeorgeskOpenLayer Offline Manual

SliceExpanded

float slicePos, OlSlicingChoise mode );

Stretches a one pixel wide slice of the bitmap to fill the entire bitmap. The mode should be one of the following: HORIZONTAL_SLICE or VERTICAL_SLICE.

Examples

Bitmap myBmp( ... );

// Blit the Bitmap to the screen such that the fifth row of the Bitmap fills the entire Bitmap //
myBmp.Blit200.0100.0SliceExpanded5.0, VERTICAL ));


Parent Class


Questions about SliceExpanded? Click here.
openlayer-2.1.orig/Manual/RenderMode/FlippedMode.html0000644000175000017500000000351410377350122023031 0ustar georgeskgeorgeskOpenLayer Offline Manual
FlippedMode

OlFlippingChoise mode );

The Bitmap will be drawn flipped in the specified way. The mode should be one of these: HORIZONTAL, VERTICAL or BOTH.

Note that the flipping occurs after the other RenderModes have taken effect regardless of its position in a RenderMode list.

Examples

Bitmap bmp( ... );

// Draw the bitmap horizontally flipped //
bmp.Blit200.0100.0FlippedMode( HORIZONTAL ));


Parent Class


Questions about FlippedMode? Click here.
openlayer-2.1.orig/Manual/RenderMode/Flipped.html0000644000175000017500000000373110377350122022225 0ustar georgeskgeorgeskOpenLayer Offline Manual

Flipped

OlFlippingChoise mode );

The Bitmap will be drawn flipped in the specified way. The mode should be one of these: HORIZONTAL, VERTICAL or BOTH.

Note that the flipping occurs after the other RenderModes have taken effect regardless of its position in a RenderMode list.

Examples

Bitmap bmp( ... );

// Draw the bitmap horizontally flipped //
bmp.Blit200.0100.0Flipped( HORIZONTAL ));


Parent Class


Questions about Flipped? Click here.
openlayer-2.1.orig/Manual/RenderMode/Gradient.html0000644000175000017500000001153510377350122022400 0ustar georgeskgeorgeskOpenLayer Offline Manual

Gradient

Allows for gradient lighting, shadow and transparency effects.

float topLeftOpacity, float topRightOpacity,
float bottomRightOpacity, float bottomLeftOpacity )

Create a gradient mode with different opacity values for each Bitmap corner.

Rgba topLeft, Rgba topRight,
Rgba bottomRight, Rgba bottomLeft )

Create a gradient mode with different color channel cofficients for each Bitmap corner.

Examples

// Load a bitmap //
Bitmap myBmp( ... );

// Render the bitmap to the screen such as the top-left corner is at x = 200.0, y = 100.0 //
// and the transparency of the Bitmap changes gradually from full opaque (top) //
// to full transparent (bottom) //
myBmp.Blit200.0100.0Gradient1.01.00.00.0 ));


// Render the bitmap at the same position such as the lightness of the Bitmap changes gradually //
// from dark (lower-left corner) to normal brightness (top-right corner) //

Rgba lightnessInDark( 0.30.30.3 );
Rgba lightnessInBright( 1.01.01.0 );

// Make an even mix of the darkness and bright cofficients //
Rgba lightnessInMiddle = lightnessInDark.MixWith( lightnessInBright, 0.5 );

myBmp.Blit200.0100.0Gradient( lightnessInMiddle, lightnessInBright, lightnessInMiddle, lightnessInDark ));


Parent Class


Questions about Gradient? Click here.
openlayer-2.1.orig/Manual/FpsCounter.html0000644000175000017500000001232410377350122020704 0ustar georgeskgeorgeskOpenLayer Offline Manual

FpsCounter

Helps to make the program to run at the same speed in regardless of the fps and calculates the fps.

To regulate the speed of the program you should start the fps counter before the game loop starts. Then in the beginning of each loop you should call FpsCounter::FpsCounter/NewFrameStarted.html">NewFrameStarted() and to get the delta time using FpsCounter::FpsCounter/GetDeltaTime.html">GetDeltaTime(). Then you should multiply all the position, speed and rotational changes by the delta time.

Examples

// Example of how to make the game to run at the same speed regardless of the fps //

float playerX, playerY;
float playerSpeedX, playerSpeedY;
float playerAccelerationX, playerAccelerationY;

// The default fps is 70.0 //
FpsCounter::Start70.0 );

while( gameRunning ) {
  // Tell OpenLayer that a new game frame has started. //
  FpsCounter::FpsCounter/NewFrameStarted.html">NewFrameStarted();
  
  // Get the delta time //
  float deltaTime = FpsCounter::FpsCounter/GetDeltaTime.html">GetDeltaTime();
  
  // Change the speed of the player according to the acceleration //
  playerSpeedX += deltaTime * playerAccelerationX;
  playerSpeedY += deltaTime * playerAccelerationY;
  
  // Move the player //
  playerX += deltaTime * playerSpeedX;
  playerY += deltaTime * playerSpeedY;
  
  // Other game loop code //
}



Member functions
Start
Starts the FPS counter
NewFrameStarted
Tells OpenLayer that a new game frame has started
GetDeltaTime
Get the elapsed game time between this and the previous frame
GetFps
Returns the frames per second the program runs at
Pause
Pauses the FPS counter
Resume
Resumes the paused FPS counter


Questions about FpsCounter? Click here.
openlayer-2.1.orig/Manual/Circle/0000700000175000017500000000000012262355751017123 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Circle/DrawDisk.html0000644000175000017500000000545310417230626021533 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawDisk

void DrawDisk(
const Rgba &color, float innerRadius )

Draws a filled disk. The outer radius of the disk is the radius of the Circle.

void DrawDisk(
const Rgba &innerColor, const Rgba &outerColor,
float innerRadius )

Draws a gradient filled disk with colors changing smootly along the radius.

Other functions of the class Circle
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of the Circle
SetRadius
Sets the radius of the circle


Questions about DrawDisk? Click here.
openlayer-2.1.orig/Manual/Circle/DrawArc.html0000644000175000017500000000436510402237146021345 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawArc

void DrawArc(
const Rgba &color, float startAngle,
float angleSweep, float innerRadius )

Draws a filled arc of the Circle. The outer radius of the arc is the radius of the Circle.

Other functions of the class Circle
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of the Circle
SetRadius
Sets the radius of the circle


Questions about DrawArc? Click here.
openlayer-2.1.orig/Manual/Circle/SetRadius.html0000644000175000017500000000376410417230626021731 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetRadius

void SetRadius(
float radius )

Sets the radius of the circle.

Other functions of the class Circle
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of the Circle
SetRadius
Sets the radius of the circle


Questions about SetRadius? Click here.
openlayer-2.1.orig/Manual/Shape/0000700000175000017500000000000012262355751016762 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Shape/Line.html0000644000175000017500000001261310417230626020545 0ustar georgeskgeorgeskOpenLayer Offline Manual

Line

float x1, float y1, float x2, float y2, float lineWidth = 1.0 )

Create a new line with starting point of (x1, y1) and ending point (x2, y2).

Vec2D start, Vec2D end, float lineWidth = 1.0 )

Create a new line with the specified starting point, ending point and with.

Public fields
Vec2D start - The starting point of the line
Vec2D end - The end point of the line

See the examples of how to simply render a line to the screen by using a temporary object.

Examples

// Create a new line between x = 50.0, y = 30.0 //
// and x = 200.0, y = 100.0 ( and line width of 1.0 ) //
Line myLine( 50.030.0200.0100.0 );

// Draw that line to the screen in black //
myLine.DrawRgba::BLACK );

// Do the same as above but with a single code line //
Line50.030.0200.0100.0 ).DrawRgba::BLACK );

// Or maybe you wish to store or specify the start and ending points as vectors //
LineVec2D50.030.0 ), Vec2D200.0100.0 )).DrawRgba::BLACK );


Member functions
Draw
Draws the line to the screen filled with a color
GetIntersectionPoint
Returns the intersection point between two lines
Collides
Tests if the two line segments collide
GetNormal
Returns the normal of the line

Parent Class


Questions about Line? Click here.
openlayer-2.1.orig/Manual/Shape/MoveBy.html0000644000175000017500000001155610421451270021057 0ustar georgeskgeorgeskOpenLayer Offline Manual

MoveBy

void MoveBy(
const Vec2D &amount )

Moves the shape with the specified amount.

Examples

Shape myShape = ...;

// Move the shape 20 pixels to the right //
myShape.MoveByVec2D20.00.0 ));

// Move the shape 100 pixels to the left and 150 pixels down //
myShape.MoveByVec2D( -100.0150.0 ));

// Move the shape the same amount as above //
// while taking the game speed regulation in account //
float deltaTime = FpsCounter::GetDeltaTime();
myShape.MoveBy( deltaTime * Vec2D( -100.0150.0 ));


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about MoveBy? Click here.
openlayer-2.1.orig/Manual/Shape/SetLineWidth.html0000644000175000017500000000717110411264544022224 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetLineWidth

float lineWidth )

Sets the width of the outline of the shape.

Examples

Shape myShape = ...;

// Set the width of the outline of the shape to 5.0 pixels //
myShape.SetLineWidth5.0 );


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about SetLineWidth? Click here.
openlayer-2.1.orig/Manual/Shape/Poly.html0000644000175000017500000001134710421451270020577 0ustar georgeskgeorgeskOpenLayer Offline Manual

Poly

Stores a polygon


The default constructor which creates a polygon with no vertices.

const std::vector< Vec2D > &vertices )

Construct the polygon from a list of vertices.

const Vec2D *vertices, int numVertices )

Construct the polygon from a list of vertices. The vertices should point to an array of (at least) numVertices number of vertices.

Member functions
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon

Derived Classes
TexturedPoly
Textured polygon

Parent Class


Questions about Poly? Click here.
openlayer-2.1.orig/Manual/Shape/LineStrip.html0000644000175000017500000001003510377350122021562 0ustar georgeskgeorgeskOpenLayer Offline Manual

LineStrip

A series of lines glued together

float lineWidth = 1.0,
const Bitmap *texture = [none] )

Construct a new LineStrip with the specified width and texture.

const any_std_list< Vec2D > &vertices,
float lineWidth = 1.0,
const Bitmap *texture = [none] )

Construct a new LineStrip from any kind of a list of vertices.

Member functions
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices

Parent Class


Questions about LineStrip? Click here.
openlayer-2.1.orig/Manual/Shape/DrawRecord.html0000644000175000017500000001035010413425714021706 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawRecord

inline void DrawRecord(
const Rgba &color ) const

Draws the latest record created by calling RecordDraw.

If you need to render the primitive the same way many times in a row, it'll be faster to create a record once and draw the same record to the screen several times.

Examples

Shape *myShape = new Circle(...);

// Store the results of the Draw-function to a record //
myShape->RecordDraw();

// Draw the record to the screen in black (outputs a black circle to the screen) //
myShape->DrawRecord( Rgba::BLACK );


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about DrawRecord? Click here.
openlayer-2.1.orig/Manual/Shape/Point.html0000644000175000017500000000612610417230626020751 0ustar georgeskgeorgeskOpenLayer Offline Manual

Point

A single point

float x, float y )

Creates a new point with the specified position.

Vec2D pos )

Same as above but by using a position vector.


Examples

// Render a blue point at x = 200.0, y = 100.0 //
Point200.0100.0 ).DrawRgba::BLUE );


Member functions
Draw
Draws the point with the specified color
StartFastDrawing
Call this function before using FastPoint
DrawFast
A faster version of Draw
FinishFastDrawing
Should be called after using DrawFast

Parent Class


Questions about Point? Click here.
openlayer-2.1.orig/Manual/Shape/RotateBy.html0000644000175000017500000000705510421451270021406 0ustar georgeskgeorgeskOpenLayer Offline Manual

RotateBy

void RotateBy(
float angle )

Rotates the shape by the specified angle

Examples

Circle circle( ... );

// Rotate the circle by 90 decrees //
circle.RotateBy( AL_PI/2 );


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about RotateBy? Click here.
openlayer-2.1.orig/Manual/Shape/Rect.html0000644000175000017500000001414410417230626020554 0ustar georgeskgeorgeskOpenLayer Offline Manual

Rect

float x, float y, float w, float h,
float outlineWidth = 1.0,
float roundness = 0.0
float accuracy = [default] )

Creates a new rectangle with the specified position for the top-left corner, width and roundness.

Line width specifies the width of the outline of the rectangle (See DrawOutline). Accuracy parameter specifies the accuracy of the corners of a rounded rectangle.

Vec2D topleft, Vec2D size,
float lineWidth = 1.0,
float roundness = 0.0
float accuracy = [default] )

Same as above but the position and the size are specified with vectors.

Examples

// Create a new rectangle with top-left corner at x = 200.0, y = 100.0 //
// and size of 300.0 x 400.0 //
Rect myRectangle( 200.0100.0300.0400.0 );

// Render the rectangle to the drawing surface filled with white //
myRectangle.DrawRgba::WHITE );

// You can also create the rectangle and render it in a single line: //
Rect200.0100.0300.0400.0 ).DrawRgba::WHITE );

// Create a new rectangle by using vectors //
Vec2D topleft( 200.0100.0 );
Vec2D size( 300.0400.0 );

Rect myRectangle( topleft, size );

// Or the above with only a single line: //
Rect myRectangle( Vec2D200.0100.0 ), Vec2D300.0400.0 ));


Member functions
Draw
Draws a filled rectangle
DrawOutline
Draws an outline of the rectangle
SetAccuracy
Sets the accuracy of the rounded edges
SetRoundness
Sets the roundness of the corners

Parent Class


Questions about Rect? Click here.
openlayer-2.1.orig/Manual/Shape/RecordDraw.html0000644000175000017500000001025310417230626021710 0ustar georgeskgeorgeskOpenLayer Offline Manual

RecordDraw

void RecordDraw()

Calls Draw but instead of rendering to the canvas it records the results of the drawing.

You can later output the record to the canvas by calling DrawRecord. Thus, if you need to render the primitive the same way many times in a row, it'll be faster to create a record once and draw the same record to the screen several times.

Examples

Shape *myShape = new Circle(...);

// Store the results of the Draw-function to a record //
myShape->RecordDraw();

// Draw the record to the screen in black (outputs a black circle to the screen) //
myShape->DrawRecord( Rgba::BLACK );


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about RecordDraw? Click here.
openlayer-2.1.orig/Manual/Shape/TransformBy.html0000644000175000017500000000755310413425714022133 0ustar georgeskgeorgeskOpenLayer Offline Manual

TransformBy

const Placement &placement )

Transforms the shape by a Placement

Examples

Circle circle( ... );

// Move the circle 20 pixels to the right and rotate it 90 decrees //
circle.TransformByPlacement20.00.0, AL_PI/2 ));


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about TransformBy? Click here.
openlayer-2.1.orig/Manual/Shape/Draw.html0000644000175000017500000001344110417230626020553 0ustar georgeskgeorgeskOpenLayer Offline Manual

Draw

void Draw(
Rgba color ) const

Draws the shape to the drawing surface filled with the specified color.

The actual output of this function depends on what kind of a Shape the object actually is.

Examples

// Create a new circle and store a pointer to it //
Shape *myShape = new Circle200.0100.050.0 );

// Draw the shape to the canvas filled with green //
myShape->Draw( Rgba::GREEN );

// Using a pointer to a shape can be useful if you make a list //
// which contains all the primitives in the screen //
std::list< Shape *> myList;

// Add a circle, line and a rectangle to the list //
myList.push_back( new Circle200.0100.050.0 ));
myList.push_back( new Line200.0100.0250.0150.0 );
myList.push_back( new Rect200.0100.070.050.0 );

// Draw all the primitives filled with black //
for( std::list< Shape *> ::iterator iter = myList.begin(); iter != myList.end(); iter++ ) {
  (*iter)->Draw( Rgba::BLACK );
}


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about Draw? Click here.
openlayer-2.1.orig/Manual/Shape/DrawOutline.html0000644000175000017500000000657710417230626022127 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawOutline

Rgba color ) const

Draws the outline of the shape to the rendering surface with the specified color

The actual output of this function depends on what kind of a Shape the object actually is. See Draw for more information.

Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about DrawOutline? Click here.
openlayer-2.1.orig/Manual/Shape/Ellipse.html0000644000175000017500000001427610417230626021262 0ustar georgeskgeorgeskOpenLayer Offline Manual

Ellipse

float x, float y, float xRadius, float yRadius,
float outlineWidth = 1.0, float angle = 0.0,
float accuracy = [default] )

Creates a new ellipse with the specified centre, horizontal and vertical radiuses and angle.

Vec2D pos, Vec2D radiuses,
float outlineWidth = 1.0, float angle = 0.0,
float accuracy = [default)

Same as above but by using vectors.

Public fields
Vec2D pos - The centre of the ellipse
float angle - The rotation angle of the ellipse

See the examples of how to easily render an ellipse to the screen by using a temporary object. If you want a circle instead of an ellipse, you can either make an ellipse with the same x and y radiuses or to use the Circle class.

Examples

// Create a new ellipse such that the centre is at x = 200.0, y = 100.0 //
// and the radiuses are horizontal: 50.0 and vertical: 30.0 //
Ellipse myEllipse( 200.0100.050.030.0 );

// Draw the ellipse to the canvas filled with blue //
myEllipse.DrawRgba::BLUE );

// You can create and ellipse and draw it with a single line //
Ellipse200.0100.050.030.0 ).DrawRgba::BLUE );


Member functions
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse

Derived Classes
Circle
Stores a circle

Parent Class


Questions about Ellipse? Click here.
openlayer-2.1.orig/Manual/Shape/GetLineWidth.html0000644000175000017500000000671710411264544022215 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetLineWidth

float GetLineWidth()

Returns the width of the outline of the shape.

Examples

Shape *myShape = ...;

// Get the width of the outline of the shape //
float outlineWidth = myShape->GetLineWidth();


Other functions of the class Shape
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement


Questions about GetLineWidth? Click here.
openlayer-2.1.orig/Manual/Placement.html0000644000175000017500000001221010377350122020516 0ustar georgeskgeorgeskOpenLayer Offline Manual

Placement

Stores the position, rotation and stretch of an object.

Vec2D position,
float rotation = 0.0,
Vec2D stretch = Vec2D( 1.0, 1.0 ))

Creates a new Placement with the specified position, rotation and stretch.

Examples

// Create a new placement for an object with the position x = 200.0, y = 100.0 //
Placement myPlacement( Vec2D200.0100.0 ));

// Do the same as above, but also rotate the object 90 decrees counter clockwise //
Placement myPlacement2( Vec2D200.0100.0 ), 0.5 * AL_PI );

// Do the same as above, but also stretch the object to double of its original size //
Placement myPlacement3( Vec2D200.0100.0 ), 0.5 * AL_PI, 2.0 );


Member functions
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about Placement? Click here.
openlayer-2.1.orig/Manual/Collides.html0000644000175000017500000000362510416463436020365 0ustar georgeskgeorgeskOpenLayer Offline Manual

Collides

bool Collides(
const CollisionPoly &other,
const Placement &thisPlacement,
const Placement &otherPlacement ) const

Checks if the two collision polygons collide with each other. The Placements define how the collision polygons are positioned.

Other functions of the class
Collides
Checks if two collision polygons collide


Questions about Collides? Click here.
openlayer-2.1.orig/Manual/Line/0000700000175000017500000000000012262355751016611 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Line/GetIntersectionPoint.html0000644000175000017500000000622110377350122023622 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetIntersectionPoint

const Line &other )

Returns the intersection point between this line and an another one.

The intersection point may not fall inside the line segments. Use the Collides-function to test if the line segments collide.

Examples

Line myLine( ... );
Line otherLine( ... );

// Get the intersection point of the two lines //
Vec2D point = myLine.GetIntersectionPoint( otherLine );


Other functions of the class Line
Draw
Draws the line to the screen filled with a color
GetIntersectionPoint
Returns the intersection point between two lines
Collides
Tests if the two line segments collide
GetNormal
Returns the normal of the line


Questions about GetIntersectionPoint? Click here.
openlayer-2.1.orig/Manual/Line/Collides.html0000644000175000017500000000562210416463436021253 0ustar georgeskgeorgeskOpenLayer Offline Manual

Collides

bool Collides(
const Line &other )

Returns true if the two line segments collide.

Examples

Line myLine( ... );
Line otherLine( ... );

// Test if the two line segments collide //
if( myLine.Collides( otherLine )) {
  allegro_message( "Collision!" );
}


Other functions of the class Line
Draw
Draws the line to the screen filled with a color
GetIntersectionPoint
Returns the intersection point between two lines
Collides
Tests if the two line segments collide
GetNormal
Returns the normal of the line


Questions about Collides? Click here.
openlayer-2.1.orig/Manual/Line/Draw.html0000644000175000017500000001233710417230626020405 0ustar georgeskgeorgeskOpenLayer Offline Manual

Draw

void Draw(
Rgba color ) const

Draws the circle to the screen filled with a color.

void Draw(
const Rgba &startColor, const Rgba &endColor ) const

Draws the line with the color smoothly changing from start of the line to the end

Examples

// Create a new line between x = 50.0, y = 30.0 //
// and x = 200.0, y = 100.0 ( and line width of 1.0 ) //
Line myLine( 50.030.0200.0100.0 );

// Draw that line to the screen in black //
myLine.DrawRgba::BLACK ); 

// Draw that line to the screen in light yellow //
myLine.DrawRgba1.01.00.7 ));

// Do the same as above but with a single code line //
Line50.030.0200.0100.0 ).DrawRgba1.01.00.7 )); 

// Render a gradient-filled line with the color changing from red to yellow //
myLine.DrawRgba::RED, Rgba::YELLOW );


Other functions of the class Line
Draw
Draws the line to the screen filled with a color
GetIntersectionPoint
Returns the intersection point between two lines
Collides
Tests if the two line segments collide
GetNormal
Returns the normal of the line


Questions about Draw? Click here.
openlayer-2.1.orig/Manual/Line/GetNormal.html0000644000175000017500000000420010421451270021361 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetNormal


Returns the normalized normal of the line.

Other functions of the class Line
Draw
Draws the line to the screen filled with a color
GetIntersectionPoint
Returns the intersection point between two lines
Collides
Tests if the two line segments collide
GetNormal
Returns the normal of the line


Questions about GetNormal? Click here.
openlayer-2.1.orig/Manual/Canvas.html0000644000175000017500000000737310377363276020055 0ustar georgeskgeorgeskOpenLayer Offline Manual

Canvas

Canvas holds the information of the target surface of the rendering routines. The surface may be the screen (or actually, the backbuffer of the screen) or the surface may be a selected Bitmap.

Member functions
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Canvas? Click here.
openlayer-2.1.orig/Manual/Ellipse/0000700000175000017500000000000012262355751017317 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Ellipse/DrawDisk.html0000644000175000017500000000727510417230626021733 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawDisk

void DrawDisk(
const Rgba &color,
float innerXRadius, float innerYRadius )

Draws a filled disk. The outer radiuses of the disk are specified by the Ellipse.

void DrawDisk(
const Rgba &innerColor, const Rgba &outerColor,
float innerXRadius, float innerYRadius ) const

Draws a gradient filled disk with colors changing smoothly along the radius.

Other functions of the class Ellipse
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse


Questions about DrawDisk? Click here.
openlayer-2.1.orig/Manual/Ellipse/Circle.html0000644000175000017500000000627510417230626021423 0ustar georgeskgeorgeskOpenLayer Offline Manual

Circle

A circle is only a special case of an Ellipse.

Vec2D pos, float radius,
float lineWidth = 1.0, float accuracy = [default] ))

Creates a circle with the specified centre, and radius.

The line width is the thickness of the outline of the circle.

Examples

// Create a circle with the centre at x = 200.0, y = 100.0 and radius of 50.0 //
Circle myCircle( Vec2D200.0100.0 ), 50.0 );

// Draw the circle to the screen filled with blue //
myCircle.DrawRgba::BLUE );


Member functions
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of the Circle
SetRadius
Sets the radius of the circle

Parent Class


Questions about Circle? Click here.
openlayer-2.1.orig/Manual/Ellipse/GetRadius.html0000644000175000017500000000540510377350122022102 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetRadius

float GetRadius(
Axis axis )
Returns the x or y axis of the ellipse. Axis should be either X_AXIS or Y_AXIS.

Other functions of the class Ellipse
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse


Questions about GetRadius? Click here.
openlayer-2.1.orig/Manual/Ellipse/DrawArc.html0000644000175000017500000000746310402237146021543 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawArc

void DrawArc(
const Rgba &color,
float startAngle, float angleSweep,
float innerXRadius, float innerYRadius )

Draws a filled arc of an ellipse.

void DrawArc(
const Rgba &innerColor, const Rgba &outerColor,
float startAngle, float angleSweep,
float innerXRadius, float innerYRadius )

Draws a gradient filled arc of an ellipse with colors changing smootly along the radius.

Other functions of the class Ellipse
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse


Questions about DrawArc? Click here.
openlayer-2.1.orig/Manual/Ellipse/SetRadius.html0000644000175000017500000000546210417230626022122 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetRadius

void SetRadius(
Axis axis, float radius )

Sets the x or y radius of the ellipse. Axis should be either X_AXIS or Y_AXIS.

Other functions of the class Ellipse
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse


Questions about SetRadius? Click here.
openlayer-2.1.orig/Manual/Ellipse/Draw.html0000644000175000017500000000675310417230626021120 0ustar georgeskgeorgeskOpenLayer Offline Manual

Draw

void Draw(
const Rgba &color ) const

Draws the ellipse to the rendering surface filled with the specified color.

void Draw(
const Rgba &innerColor, const Rgba &outerColor )

Draws the ellipse filled with a gradient so that the colors change smoothly inside the circle along the radius.


Other functions of the class Ellipse
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse


Questions about Draw? Click here.
openlayer-2.1.orig/Manual/Ellipse/DrawOutline.html0000644000175000017500000000552010417230626022447 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawOutline

Rgba color ) const

Draws the outline of the ellipseto the rendering surface with the specified color.

Other functions of the class Ellipse
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse


Questions about DrawOutline? Click here.
openlayer-2.1.orig/Manual/Ellipse/DrawSlice.html0000644000175000017500000000725710377350122022077 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawSlice

void DrawSlice(
const Rgba &color,
float startAngle, float angleSweep )
Draws a slice of the ellipse so that the slice starts from startAngle and fills angleSweep angles.

void DrawSlice(
const Rgba &innerColor, const Rgba &outerColor,
float startAngle, float angleSweep )

Draws a gradient filled slice so that the colors change smoothly along the radius.

Other functions of the class Ellipse
Draw
Draws the ellipse filled with the specified color
DrawOutline
Draws the outline of the ellipse
DrawSlice
Draws a slice of the ellipse
DrawDisk
Draws a filled disk
DrawArc
Draws a filled arc of an ellipse
SetRadius
Sets the x or y radius of the ellipse
GetRadius
Returns the x or y axis of the ellipse


Questions about DrawSlice? Click here.
openlayer-2.1.orig/Manual/Settings/0000700000175000017500000000000012262355751017522 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Settings/SetCircleAccuracy.html0000644000175000017500000001165010402237146023744 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetCircleAccuracy

static void SetCircleAccuracy(
float accuracy );

Sets the accuracy of the circle drawing functions. The value should be between 0.0 and 1.0 but it should never be zero.

The more accuracy, the better the circles will generally look but rendering them will be slower. This setting can be overridden by passing a different accuracy value to the circle drawing functions.

Examples

// Set a rather low circle accuracy //
Settings::SetCircleAccuracy0.2 );

// Set a very high circle accuracy //
Settings::SetCircleAccuracy0.7 );


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about SetCircleAccuracy? Click here.
openlayer-2.1.orig/Manual/Settings/SetCollisionPolyAlphaLimit.html0000644000175000017500000001147710402237146025643 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetCollisionPolyAlphaLimit

float alpha )

Sets the maxium alpha value which is considered transparent by the collision polygon generation

The default value is 0.5.

This setting doesn't, or course, affect collision polygons which are already created.

Examples

// Set the alpha limit to 0.3 and create a Bitmap with a collision polygon //
Settings::SetCollisionPolyAlphaLimit0.3 );
Bitmap myBmp( "gfx/MyImage.png", CREATE_COLLISION_POLY );


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about SetCollisionPolyAlphaLimit? Click here.
openlayer-2.1.orig/Manual/Settings/SetAntialiasing.html0000644000175000017500000001057210402237146023475 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetAntialiasing

static void SetAntialiasing(
bool turnedOn );

Turns the anti-aliasing on or off. On by default.

Anti-aliasing produces smoother graphics but slows down the rendering.

Examples

// Turn off the anti-aliasing //
Settings::SetAntialiasingfalse );


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about SetAntialiasing? Click here.
openlayer-2.1.orig/Manual/Settings/SetTextureMapping.html0000644000175000017500000001145210402237146024044 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetTextureMapping

Advanced function

static void SetTextureMapping(
bool turnedOn );

Turns the OpenGL texture mapping on or off. On by default.

This doesn't affect OpenLayer's functions, but if you use OpenGL directly you might wish to choose if the texture mapping is turned on or not.

You should use this function instead of glEnable( GL_TEXTURE_2D ) or glDisable( GL_TEXTURE_2D ) because it lets OpenLayer to know that the texture mapping preferences have changed. Otherwise either OpenLayer or your own OpenGL code may not function properly.

Examples

// Turn off OpenGL's texture mapping //
Settings::SetTextureMappingfalse );


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about SetTextureMapping? Click here.
openlayer-2.1.orig/Manual/Settings/SetCollisionPolyAccuracy.html0000644000175000017500000001104410402237146025337 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetCollisionPolyAccuracy

float accuracy )

Sets the accuracy of the generated collision polygons


Accuracy should always be positive and the highest value is 1.0. The default value is 0.8.

Examples

// Set the accuracy of the generated collision polygons to 10% //
Settings::SetCollisionPolyAccuracy0.1 );


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about SetCollisionPolyAccuracy? Click here.
openlayer-2.1.orig/Manual/Settings/MemoryBitmapsStored.html0000644000175000017500000001147410402237146024371 0ustar georgeskgeorgeskOpenLayer Offline Manual

MemoryBitmapsStored

Advanced function

static bool MemoryBitmapsStored();

Returns true if the Bitmaps are stored in the memory.

The memory bitmap storing is off by default. However, the storage may be turned on by calling Settings::StoreMemoryBitmaps( true ). You can use this function to check if the storage is on or off.

Examples

// Check if the memory bitmaps are stored //
ifSettings::MemoryBitmapsStored() ) {
   allegro_message( "Bitmaps are also stored in the memory" );
}


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about MemoryBitmapsStored? Click here.
openlayer-2.1.orig/Manual/Settings/SetOrthographicProjection.html0000644000175000017500000001422710402237146025561 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetOrthographicProjection

Advanced function

int screenWidth = SCREEN_W,
int screenHeight = SCREEN_H );

Sets the orthographic projection as the active OpenGL projection mode. Ortographic projection is used by default.

If you've selected a different projection mode in your OpenGL code you may wish to revert to ortographic projection by calling this function. The old projection mode is stored in the matrix stack and can be restored by calling RestoreOldProjection().

Note that you can choose the actual width and height of the screen. If the size of the program window is different from the given width and height the contents of the screen are stretched to fill the program window.

Note: There's an evil typo in the function name in the earlier versions of OpenLayer, where it's called SetOrtographicProjection.

Examples

// Reverts back to the orthographic projection mode if you've changed //
// the projection mode somewhere //
Settings::SetOrthographicProjection();

// If your program is supposed to run with 800 x 600 resolution but the actual resolution //
// is something else you can do this to make everything appear in the screen as if the //
// resolution was 800 x 600 //
Settings::SetOrthographicProjection800600 );


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about SetOrthographicProjection? Click here.
openlayer-2.1.orig/Manual/Settings/TextureMappingUsed.html0000644000175000017500000001116610402237146024213 0ustar georgeskgeorgeskOpenLayer Offline Manual

TextureMappingUsed

Advanced function

static bool TextureMappingUsed();

Returns true if texture mapping is turned on and false if it's not.

You can use this function to check the state of the texture mapping if you use any OpenGL code directly. Texture mapping preferences don't affect OpenLayer's functions.

Examples

// Check if the texture mapping is turned on //
ifSettings::TextureMappingUsed() ) {
   // Texture mapping is used //
}


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about TextureMappingUsed? Click here.
openlayer-2.1.orig/Manual/Settings/RestoreOldProjection.html0000644000175000017500000001144310402237146024533 0ustar georgeskgeorgeskOpenLayer Offline Manual

RestoreOldProjection

Advanced function

static void RestoreOldProjection();

Restores the old projection that got changed when you called SetOrtographicProjection().

If the original projection mode you used got changed when you called SetOrtographicProjection() you can call this function to restore the original projection from OpenGL's matrix stack.

Examples

// Restores back to the old projection mode you used that got changed //
// when you called SetOrtographicProjection() //
Settings::RestoreOldProjection();


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about RestoreOldProjection? Click here.
openlayer-2.1.orig/Manual/Settings/StoreMemoryBitmaps.html0000644000175000017500000001246610417230626024231 0ustar georgeskgeorgeskOpenLayer Offline Manual

StoreMemoryBitmaps

Advanced function

static void StoreMemoryBitmaps(
bool turnedOn )

Choose whether the Bitmaps are stored in the memory or not. Off by default.

The Bitmaps are always stored in the graphics card (unless the UnloadFromGPU -function has been called) but not in the memory.

If you wish to be used the SendToGPU / UnloadFromGPU -functions of Bitmaps you have to turn on the memory bitmap storing before loading the Bitmaps.

Since OpenLayer 2.0 it's possible to use UnloadToMemory instead of UnloadFromGPU if you wish to keep a memory version of the unloaded Bitmap.

Forcing the contents of the bitmap to be stored in the memory increases the memory usage.

Examples

// Choose the Bitmaps to be stored in the memory as well as to the graphics card //
Settings::StoreMemoryBitmapstrue );


Other functions of the class Settings
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about StoreMemoryBitmaps? Click here.
openlayer-2.1.orig/Manual/Poly/0000700000175000017500000000000012262355751016645 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Poly/Add.html0000644000175000017500000001037110377350122020227 0ustar georgeskgeorgeskOpenLayer Offline Manual

Add

inline void Add(
Vec2D vec )

Adds a vertex to the polygon.

The new vertex will be added to the polygon such that it connects the previously added vertex and the first vertex.

Examples

Polygon polygon( ... );

// Add a vertex (x = 200, y = 100) to the polygon //
polygon.AddVec2D200.0100.0 ));


Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about Add? Click here.
openlayer-2.1.orig/Manual/Poly/TexturedPoly.html0000644000175000017500000001023010421453126022177 0ustar georgeskgeorgeskOpenLayer Offline Manual

TexturedPoly

const Bitmap &texture, Vec2D rotationPivot = Vec2D( 0.0, 0.0 ))

Constructs a new textured polygon with the specified texture and rotation pivot.

const Bitmap &texture, const std_container &vertices, Vec2D rotationPivot = Vec2D( 0.0, 0.0 ))

Constructs a new textured polygon with the specified texture, vertices from an STL container and a rotation pivot.

const Bitmap &texture, const Vec2D *vertices, int numVertices, Vec2D rotationPivot = Vec2D( 0.0, 0.0 ))

Constructs a new textured polygon with the specified texture, vertices from an an array and a rotation pivot.

Examples

Bitmap myBmp( ... );

// Construct a new textured polygon with myBmp as the texture //
TexturedPoly myPoly( myBmp );


Member functions

Advanced functions

Construct
Immediately pre-caches the internal structure of the TexturedPoly

Parent Class


Questions about TexturedPoly? Click here.
openlayer-2.1.orig/Manual/Poly/GetPivot.html0000644000175000017500000000673510377350122021311 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetPivot


Returns the rotation pivot.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about GetPivot? Click here.
openlayer-2.1.orig/Manual/Poly/Collides.html0000644000175000017500000000773710416463436021320 0ustar georgeskgeorgeskOpenLayer Offline Manual

Collides

bool Collides(
const Poly &other,
const Placement &thisPlacement,
const Placement &otherPlacement )

Returns true if this polygon collides with the another polygon.

The Placements define how the polygons are placed when testing for a collision.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about Collides? Click here.
openlayer-2.1.orig/Manual/Poly/Draw.html0000644000175000017500000000711610417230626020440 0ustar georgeskgeorgeskOpenLayer Offline Manual

Draw

void Draw(
const Rgba &color )

Draws a filled polygon to the Canvas.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about Draw? Click here.
openlayer-2.1.orig/Manual/Poly/GetCollision.html0000644000175000017500000001010210377350122022122 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetCollision

const Poly &other,
const Placement &thisPlacement,
const Placement &otherPlacement )

Checks for a collision and returns detailed information about the collision.

See Collision for more information.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about GetCollision? Click here.
openlayer-2.1.orig/Manual/Poly/CollisionPoly.html0000644000175000017500000000276010377350122022341 0ustar georgeskgeorgeskOpenLayer Offline Manual

CollisionPoly

The collision polygon is a single enclosed area defined by the vertices of the polygon.

The collision polygons are used to test collisions between two objects. If the polygons are convex a faster collision method may be used.

Member functions
Collides
Checks if two collision polygons collide

Parent Class


Questions about CollisionPoly? Click here.
openlayer-2.1.orig/Manual/Poly/DrawOutline.html0000644000175000017500000000752210417230626022001 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawOutline

const Rgba &color )

Draws an outline of the polygon.

The outline may have a texture, see SetOutlineTexture. In that case the pixel colors in the texture are multiplied with the passed color.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about DrawOutline? Click here.
openlayer-2.1.orig/Manual/Poly/GetNumberOfVertices.html0000644000175000017500000000703710421451270023422 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetNumberOfVertices


Returns the number of vertices in the polygon.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about GetNumberOfVertices? Click here.
openlayer-2.1.orig/Manual/Poly/GetVertices.html0000644000175000017500000000710410377350122021763 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetVertices

const std::vector< Vec2D > &GetVertices()

Returns the list of the vertices in the polygon.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about GetVertices? Click here.
openlayer-2.1.orig/Manual/Poly/SetOutlineTexture.html0000644000175000017500000000722210377350122023214 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetOutlineTexture

Bitmap *texture )

Sets the texture of the outline of the polygon.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about SetOutlineTexture? Click here.
openlayer-2.1.orig/Manual/Poly/GetVertex.html0000644000175000017500000000724510377350122021462 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetVertex

int index )

Returns the specified vertex.

If the index is not in range, an error log is written and Vec2D( 0, 0 ) is returned.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about GetVertex? Click here.
openlayer-2.1.orig/Manual/Poly/SetPivot.html0000644000175000017500000000721710377350122021321 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetPivot

void SetPivot(
Vec2D rotationPivot )

Sets the rotation pivot of the polygon.

The rotation pivot is mainly used by the collision routines.

Other functions of the class Poly
Add
Adds a vertex to the polygon
GetVertex
Returns the specified vertex
GetNumberOfVertices
Returns the number of vertices in the polygon
Draw
Draws a filled polygon.
DrawOutline
Draws an outline of the polygon
Collides
Tests if two polygons collide
GetCollision
Checks for a collision and returns detailed information about the collision
GetVertices
Returns the list of the vertices in the polygon
SetPivot
Sets the rotation pivot
GetPivot
Returns the the rotation pivot
SetOutlineTexture
Sets the texture of the outline of the polygon


Questions about SetPivot? Click here.
openlayer-2.1.orig/Manual/index.html0000644000175000017500000000600610377350122017723 0ustar georgeskgeorgeskOpenLayer Offline Manual
OpenLayer

The official offline documentation

Classes
Bitmap
Stores a bitmap
Blenders
Different color blending styles
Canvas
The rendering surface
Collision
Detailed information about a collision
FpsCounter
Regulates the game speed and calculates the fps
Placement
Stores the position, rotation and stretch of an object
RenderMode
Bitmap rendering modes
Rgba
The color structure
Settings
The general settings
Setup
Program setup functions
Shape
Graphics primitives
TextRenderer
Renders text with a specified font
Transforms
Global placement and color transformations
Vec2D
2D vector
openlayer-2.1.orig/Manual/Settings.html0000644000175000017500000000670410402237146020420 0ustar georgeskgeorgeskOpenLayer Offline Manual

Settings

The general settings of OpenLayer

Use the static member functions to change the common settings like the anti-aliasing and texture mapping preferences and the projection mode.

Member functions
SetAntialiasing
Turns the anti-aliasing on or off
SetCircleAccuracy
Sets the accuracy of the circle drawing functions
SetCollisionPolyAccuracy
Sets the accuracy of the generated collision polygons
SetCollisionPolyAlphaLimit
Sets the maxium alpha value which is considered transparent by the collision polygon generation

Advanced functions

SetTextureMapping
Turns the OpenGL texture mapping on or off
TextureMappingUsed
Returns true if texture mapping is turned on
SetOrthographicProjection
Sets the orthographic projection as the active OpenGL projection mode
RestoreOldProjection
Restores the old projection mode
StoreMemoryBitmaps
Choose the Bitmaps to be stored in the memory
MemoryBitmapsStored
Returns true if the Bitmaps are stored in the memory


Questions about Settings? Click here.
openlayer-2.1.orig/Manual/Vec2D/0000700000175000017500000000000012262355751016625 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Vec2D/GetMagnitudeSquared.html0000644000175000017500000000460010377350122023417 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetMagnitudeSquared

Advanced function

inline float GetMagnitudeSquared() const

Returns the squared magnitude of the vector.

Other functions of the class Vec2D
GetMagnitude
Returns the magnitude (length) of the vector
GetAngle
Returns the angle of the vector
Normalized
Returns a normalized copy of the vector

Advanced functions

GetMagnitudeSquared
Returns the squared magnitude of the vector


Questions about GetMagnitudeSquared? Click here.
openlayer-2.1.orig/Manual/Vec2D/GetMagnitude.html0000644000175000017500000000573410377350122022103 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetMagnitude

inline float GetMagnitude() const

Returns the magnitude (length) of the vector.

Examples

// Create a new vector called theVector with x = 15.0 and y = 20.0 //
Vec2D theVector( 15.020.0 );

// Get the magnitude of the vector //
float magnitude = theVector.GetMagnitude();


Other functions of the class Vec2D
GetMagnitude
Returns the magnitude (length) of the vector
GetAngle
Returns the angle of the vector
Normalized
Returns a normalized copy of the vector

Advanced functions

GetMagnitudeSquared
Returns the squared magnitude of the vector


Questions about GetMagnitude? Click here.
openlayer-2.1.orig/Manual/Vec2D/GetAngle.html0000644000175000017500000000564310377350122021213 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetAngle

inline float GetAngle() const

Returns the angle of the vector.

Examples

// Create a new vector called theVector with x = 15.0 and y = 20.0 //
Vec2D theVector( 15.020.0 );

// Get the angle of the vector //
float angle = theVector.GetAngle();


Other functions of the class Vec2D
GetMagnitude
Returns the magnitude (length) of the vector
GetAngle
Returns the angle of the vector
Normalized
Returns a normalized copy of the vector

Advanced functions

GetMagnitudeSquared
Returns the squared magnitude of the vector


Questions about GetAngle? Click here.
openlayer-2.1.orig/Manual/Vec2D/Normalized.html0000644000175000017500000000663110377350122021627 0ustar georgeskgeorgeskOpenLayer Offline Manual

Normalized

inline Vec2D Normalized() const

Returns a normalized copy of the vector.

The normalized version of the vector has the same angle but its length is one. Instead of this function you could also use the ~ -operator.

Examples

// Create a new vector called theVector with x = 15.0 and y = 20.0 //
Vec2D theVector( 15.020.0 ); 

// Get a normalized copy of the vector //
Vec2D normalizedCopy = theVector.Normalized();

// The same as above by using the ~ -operator //
Vec2D normalizedCopy = ~theVector;


Other functions of the class Vec2D
GetMagnitude
Returns the magnitude (length) of the vector
GetAngle
Returns the angle of the vector
Normalized
Returns a normalized copy of the vector

Advanced functions

GetMagnitudeSquared
Returns the squared magnitude of the vector


Questions about Normalized? Click here.
openlayer-2.1.orig/Manual/Blenders.html0000644000175000017500000000307210377363276020370 0ustar georgeskgeorgeskOpenLayer Offline Manual

Blenders

Different color blending styles

Member functions
Set
Selects the specified blender as the active color blender

Advanced functions

Push
Pushes the active blender to the stack
Pop
Pops the most recently stored blender from the stack


Questions about Blenders? Click here.
openlayer-2.1.orig/Manual/Shape.html0000644000175000017500000001171310411264544017656 0ustar georgeskgeorgeskOpenLayer Offline Manual

Shape

The base class of all Shapes

All Lines, Rectangles, Circles, Ellipses, LineStrips, Polys and Points are different kind of Shapes. See the section Derived Classes, which lists all possible primitives you can create.

An important thing to note is that OpenLayer deviates from most libraries in the way that there's no primitive rendering functions (anymore). Instead, there's primitive classes with member functions to render them.

The idea is that, for example, a filled rectangle, an outline of a rectangle and a gradien filled rectangle can all use a common constructor because they all need to know the position and the size of the rectangle. Also this allows for more specialized constructors, for example rounded rectangles, while still allowing for the same drawing operations.

The idea is even clearer with Circles as they have quite a lot of different ways to render them, for example you might only want to draw a slice of the circle, or maybe a disk...

Note that many parameters are optional. Thus even if a function might seem complicated at first it's in fact simplier to use than it looks. The extra parameters are there just in case if you need them.

Member functions
Draw
Draws the shape filled with the specified color
DrawOutline
Draws the outline of the shape
RecordDraw
Records the results of Draw-function
MoveBy
Moves the shape
SetLineWidth
Sets the width of the outline of the shape
GetLineWidth
Returns the width of the outline of the shape
DrawRecord
Draws the latest record created by RecordDraw
RotateBy
Rotates the shape by the specified angle
TransformBy
Transforms the shape by a Placement

Derived Classes
Poly
Stores a polygon
Line
A single line between two points
Rect
Stores (and renders) a rectangle
Ellipse
Stores an ellipse (or a circle)
LineStrip
A series of lines glued together
Point
A single point


Questions about Shape? Click here.
openlayer-2.1.orig/Manual/Rgba/0000700000175000017500000000000012262355751016575 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Rgba/WithAlpha.html0000644000175000017500000000670510377350122021356 0ustar georgeskgeorgeskOpenLayer Offline Manual

WithAlpha

inline Rgba WithAlpha(
float newAlpha ) const;

Creates a new color with the same color components but a different alpha value

This function can be particulary useful if you wish to create gradients from an opaque version of a color to a rather transparent one. Also in some cases you might wish to not to modify the alpha value of the color but to get a modified copy of the color instead.

Examples

// Get a 30% opaque red color //
Rgba color = Rgba::RED.WithAlpha0.30 );

// Get a 70% opaque red color //
Rgba otherColor = color.WithAlpha0.70 );


Other functions of the class Rgba
MixWith
Mixes two colors together with the given factor
WithAlpha
Creates a new color with the same color components but a different alpha value

Advanced functions

Packed
Returns the color packed in an integer
Select
Selects the color as the active OpenGL color


Questions about WithAlpha? Click here.
openlayer-2.1.orig/Manual/Rgba/Select.html0000644000175000017500000000711310411264544020707 0ustar georgeskgeorgeskOpenLayer Offline Manual

Select

Advanced function

inline void Select();

Selects the color as the active OpenGL color.


If you only use OpenLayer's functions you won't need to call this function. Even if you change the OpenGL's active color by calling this function or by calling glColor it won't affect OpenLayer's functions.

Examples

// Select black to be the active OpenGL color //
Rgba black( 0.00.00.0 );
black.Select();

// Same thing by using a color constant //
Rgba::BLACK.Select();

// Also the following is possible: //
Rgba0.00.00.0 ).Select();


Other functions of the class Rgba
MixWith
Mixes two colors together with the given factor
WithAlpha
Creates a new color with the same color components but a different alpha value

Advanced functions

Packed
Returns the color packed in an integer
Select
Selects the color as the active OpenGL color


Questions about Select? Click here.
openlayer-2.1.orig/Manual/Rgba/MixWith.html0000644000175000017500000001037010377350122021057 0ustar georgeskgeorgeskOpenLayer Offline Manual

MixWith

const Rgba &otherColor, float factor ) const;

Returns a mixed color between this and otherColor using the given factor.

The factor should be between 0.0 and 1.0. If factor is zero, InterpolateWith returns the calling color and if factor is 1.0 it returns the given otherColor. But if the factor is between 0.0 and 1.0 it returns a mix of the two colors.

The lower the factor, the closer the returned color is to the calling color and higher the factor, the closer the returned color is to the given otherColor.

The old name of this function is InterpolateWith, which can still be used as well.

Examples

// Get a color half way between red and blue //
Rgba magneta = Rgba::RED.InterpolateWith( Rgba::BLUE, 0.5 );

// Get a slightly darker blue color //
Rgba darkerBlue = Rgba::BLUE.InterpolateWith( Rgba::BLACK, 0.2 );

// Get a mixed color between magneta and darkerBlue which is slightly closer to darkerBlue than magneta //
Rgba mixedColor = magneta.InterpolateWith( darkerBlue, 0.6 );


Other functions of the class Rgba
MixWith
Mixes two colors together with the given factor
WithAlpha
Creates a new color with the same color components but a different alpha value

Advanced functions

Packed
Returns the color packed in an integer
Select
Selects the color as the active OpenGL color


Questions about MixWith? Click here.
openlayer-2.1.orig/Manual/Rgba/Packed.html0000644000175000017500000000614510377350122020662 0ustar georgeskgeorgeskOpenLayer Offline Manual

Packed

Advanced function

int Packed() const;

Returns the color in a packed 32-bit integer.

The returned color value is in the same format as the colors in Allegro are.

The format is usually: AA|RR|GG|BB where a letter means a byte. The format depends on the current screen mode and several other factors, though. It's best to not to rely on that the components are always positioned the same way inside the integer. Use Allegro's functions to extract the color components if you need to.

Examples

// Convert the Rgba structure to Allegro's color value //
Rgba color( ... );
int colorPacked = color.Packed();


Other functions of the class Rgba
MixWith
Mixes two colors together with the given factor
WithAlpha
Creates a new color with the same color components but a different alpha value

Advanced functions

Packed
Returns the color packed in an integer
Select
Selects the color as the active OpenGL color


Questions about Packed? Click here.
openlayer-2.1.orig/Manual/Rgba/InterpolateWith.html0000644000175000017500000000764210377350122022620 0ustar georgeskgeorgeskOpenLayer Offline Manual
InterpolateWith

const Rgba &otherColor, float factor ) const;

Returns a mixed color between this and otherColor using the given factor.

The factor should be between 0.0 and 1.0. If factor is zero, InterpolateWith returns the calling color and if factor is 1.0 it returns the given otherColor. But if the factor is between 0.0 and 1.0 it returns a mix of the two colors.

The lower the factor, the closer the returned color is to the calling color and higher the factor, the closer the returned color is to the given otherColor.

Examples

// Get a color half way between red and blue //
Rgba magneta = Rgba::RED.InterpolateWithRgba::BLUE, 0.5 );

// Get a slightly darker blue color //
Rgba darkerBlue = Rgba::BLUE.InterpolateWithRgba::BLACK, 0.2 );

// Get a mixed color between magneta and darkerBlue which is slightly closer to darkerBlue than magneta //
Rgba mixedColor = magneta.InterpolateWith( darkerBlue, 0.6 );


Other functions of the class Rgba
InterpolateWith
Mixes two colors together with the given factor

Advanced functions

Packed
Select


Questions about InterpolateWith? Click here.
openlayer-2.1.orig/Manual/FpsCounter/0000700000175000017500000000000012262355751020012 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/FpsCounter/GetFps.html0000644000175000017500000000625410377350122022101 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetFps

static float GetFps();

Returns the frames per second the program runs at.

Using this function requires to start the fps counter before the game loop starts and to call FpsCounter::NewFrameStarted() in the beginning of each frame.

Examples

// Get the fps //
float fps = FpsCounter::GetFps();


Other functions of the class FpsCounter
Start
Starts the FPS counter
NewFrameStarted
Tells OpenLayer that a new game frame has started
GetDeltaTime
Get the elapsed game time between this and the previous frame
GetFps
Returns the frames per second the program runs at
Pause
Pauses the FPS counter
Resume
Resumes the paused FPS counter


Questions about GetFps? Click here.
openlayer-2.1.orig/Manual/FpsCounter/NewFrameStarted.html0000644000175000017500000000665510377350122023751 0ustar georgeskgeorgeskOpenLayer Offline Manual

NewFrameStarted

static float NewFrameStarted();

Tells OpenLayer that a new game frame has started.

You should call this function in the beginning of the game loop if you wish to use the speed regulation. This function now returns the delta time just like GetDeltaTime.

Examples

while( gameRunning ) {
  // Tell OpenLayer that a new game frame has started. //
  FpsCounter::NewFrameStarted();
  
  // Other game loop code //
}


Other functions of the class FpsCounter
Start
Starts the FPS counter
NewFrameStarted
Tells OpenLayer that a new game frame has started
GetDeltaTime
Get the elapsed game time between this and the previous frame
GetFps
Returns the frames per second the program runs at
Pause
Pauses the FPS counter
Resume
Resumes the paused FPS counter


Questions about NewFrameStarted? Click here.
openlayer-2.1.orig/Manual/FpsCounter/GetDeltaTime.html0000644000175000017500000001217610377350122023221 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetDeltaTime

static float GetDeltaTime();

Get the elapsed game time between this and the previous frame.

The speed regulation requires you to multiply all speed and position and rotational changes with the delta time.

Using this function requires to start the fps counter before the game loop starts and to call FpsCounter::NewFrameStarted() in the beginning of each frame.

Note that the fps counter has to be started before calling this function.

Examples

float playerX, playerY;
float playerSpeedX, playerSpeedY;
float playerAccelerationX, playerAccelerationY;

// The default fps is 70.0 //
FpsCounter::Start70.0 );

while( gameRunning ) {
  // Tell OpenLayer that a new game frame has started. //
  FpsCounter::NewFrameStarted();
  
  // Get the delta time //
  float deltaTime = FpsCounter::GetDeltaTime();
  
  // Change the speed of the player according to the acceleration //
  playerSpeedX += deltaTime * playerAccelerationX;
  playerSpeedY += deltaTime * playerAccelerationY;
  
  // Move the player //
  playerX += deltaTime * playerSpeedX;
  playerY += deltaTime * playerSpeedY;
  
  // Other game loop code //
}


Other functions of the class FpsCounter
Start
Starts the FPS counter
NewFrameStarted
Tells OpenLayer that a new game frame has started
GetDeltaTime
Get the elapsed game time between this and the previous frame
GetFps
Returns the frames per second the program runs at
Pause
Pauses the FPS counter
Resume
Resumes the paused FPS counter


Questions about GetDeltaTime? Click here.
openlayer-2.1.orig/Manual/FpsCounter/Start.html0000644000175000017500000001046310377350122022003 0ustar georgeskgeorgeskOpenLayer Offline Manual

Start

static void Start(
float defaultFps );

Start the fps counter. defaultFps is the fps you're planning the game to run in.

This function should be called right before the game loop starts. Note that the speed regulation requires you to multiply all speed and position and rotational changes with the delta time. For an example of how to do this see the definition of FpsCounter.

Note that the actual fps you get may differ a lot from the defaultFps. You can set the default fps to be 70.0 and get 500 fps. But it makes planning the game easier as you can design the speeds and accelerations of the game objects only related to the default fps, not to the actual fps the game runs in.

So you could choose the default fps to be 100.0 and set the speed of an object to 0.05 or to choose the default fps to be 50.0 and set the speed of the object to be 0.10. In both cases the game will run exactly the same way.

Examples

// Start the fps counter such that the choosen default fps is 70.0 //
// (The actual fps can be several hundreds but the objects still appear to move //
// at the same speed as if the fps was 70.0, but only far more accurately) //
FpsCounter::Start70.0 );


Other functions of the class FpsCounter
Start
Starts the FPS counter
NewFrameStarted
Tells OpenLayer that a new game frame has started
GetDeltaTime
Get the elapsed game time between this and the previous frame
GetFps
Returns the frames per second the program runs at
Pause
Pauses the FPS counter
Resume
Resumes the paused FPS counter


Questions about Start? Click here.
openlayer-2.1.orig/Manual/FpsCounter/Resume.html0000644000175000017500000000667510377350122022160 0ustar georgeskgeorgeskOpenLayer Offline Manual

Resume

static void Resume();

Resumes the paused FPS counter.

The old name for this function is Continue. The old name can still be used.

Examples

if( gamePaused ) {
  // Pause the FPS counter //
  FpsCounter::Pause();
  
  // Wait until the game should continue...
  
  //
 Resume the FPS counter //
  FpsCounter::Resume();
}


Other functions of the class FpsCounter
Start
Starts the FPS counter
NewFrameStarted
Tells OpenLayer that a new game frame has started
GetDeltaTime
Get the elapsed game time between this and the previous frame
GetFps
Returns the frames per second the program runs at
Pause
Pauses the FPS counter
Resume
Resumes the paused FPS counter


Questions about Resume? Click here.
openlayer-2.1.orig/Manual/FpsCounter/Pause.html0000644000175000017500000000734410377350122021767 0ustar georgeskgeorgeskOpenLayer Offline Manual

Pause

static void Pause();

Pauses the FPS counter.

If your game pauses for a moment you should pause the FPS counter as well, or otherwise when the game continues the FPS will be totally wrong and the game speed much higher than it should be.

To resume the FPS counter, call FpsCounter::Resume().

Examples

if( gamePaused ) {
  // Pause the FPS counter //
  FpsCounter::Pause();
  
  // Wait until the game should continue...
  
  //
 Resume the FPS counter //
  FpsCounter::Resume();
}


Other functions of the class FpsCounter
Start
Starts the FPS counter
NewFrameStarted
Tells OpenLayer that a new game frame has started
GetDeltaTime
Get the elapsed game time between this and the previous frame
GetFps
Returns the frames per second the program runs at
Pause
Pauses the FPS counter
Resume
Resumes the paused FPS counter


Questions about Pause? Click here.
openlayer-2.1.orig/Manual/Rect/0000700000175000017500000000000012262355751016617 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Rect/SetRoundness.html0000644000175000017500000000440410377350122022145 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetRoundness

float roundness )

Sets the roundness of the corners of the rectangle.

Note that this function resets the accuracy of the corners to default.

Other functions of the class Rect
Draw
Draws a filled rectangle
DrawOutline
Draws an outline of the rectangle
SetAccuracy
Sets the accuracy of the rounded edges
SetRoundness
Sets the roundness of the corners


Questions about SetRoundness? Click here.
openlayer-2.1.orig/Manual/Rect/Draw.html0000644000175000017500000000533610417230626020414 0ustar georgeskgeorgeskOpenLayer Offline Manual

Draw

void Draw(
const Rgba &color )

Draws the rectangle to the Canvas filled with the color.

void Draw(
const Rgba *colors )

Draws a gradient filled rectangle. The colors should be specified clockwise for each corner starting from the top-left corner.

Other functions of the class Rect
Draw
Draws a filled rectangle
DrawOutline
Draws an outline of the rectangle
SetAccuracy
Sets the accuracy of the rounded edges
SetRoundness
Sets the roundness of the corners


Questions about Draw? Click here.
openlayer-2.1.orig/Manual/Rect/DrawOutline.html0000644000175000017500000000437010417230626021751 0ustar georgeskgeorgeskOpenLayer Offline Manual

DrawOutline

const Rgba &color )

Draws an outline of the rectangle with the specified color.

Other functions of the class Rect
Draw
Draws a filled rectangle
DrawOutline
Draws an outline of the rectangle
SetAccuracy
Sets the accuracy of the rounded edges
SetRoundness
Sets the roundness of the corners


Questions about DrawOutline? Click here.
openlayer-2.1.orig/Manual/Rect/SetAccuracy.html0000644000175000017500000000424510377350122021722 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetAccuracy

float accuracy )

Sets the accuracy of the rounded edges.

Other functions of the class Rect
Draw
Draws a filled rectangle
DrawOutline
Draws an outline of the rectangle
SetAccuracy
Sets the accuracy of the rounded edges
SetRoundness
Sets the roundness of the corners


Questions about SetAccuracy? Click here.
openlayer-2.1.orig/Manual/Canvas/0000700000175000017500000000000012262355751017135 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Canvas/Push.html0000644000175000017500000001211710421451270020742 0ustar georgeskgeorgeskOpenLayer Offline Manual

Push

Advanced function

static void Push();

Pushes the active Canvas to a stack

The active canvas can later be restored with Canvas::Pop().

Examples

// Push the old active canvas to the stack and select a new one //
Canvas::Push();
Canvas::SetTo( ... );

// Do some rendering here...

//
 Pop the old active canvas from the stack //
Canvas::Pop();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Push? Click here.
openlayer-2.1.orig/Manual/Canvas/SetPixelWriteMode.html0000644000175000017500000001365010377363276023425 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetPixelWriteMode

Advanced function

static void SetPixelWriteMode(
PixelWriteMode mode )

Selects which color components of the Canvas the rendering functions affect.

Possible choises are:

COLOR_AND_ALPHA - Both the color value and alpha channel are affected (Default for Bitmaps)
COLOR_ONLY - Only the color values are affected (Default for the screen)
ALPHA_ONLY - Only the alpha channel is affected


If you wish to alter the alpha channel of a Bitmap, for example, you can set the Bitmap as the active canvas and set the pixel write mode to ALPHA_ONLY.

Examples

// Select a Bitmap as the active Canvas //
Bitmap bmp( ... );
Canvas::SetTo( bmp );

// Make the rendering functions to affect the alpha channel of the Bitmap //
Canvas::SetPixelWriteMode( ALPHA_ONLY );

// Make the rendering functions to affect only the color channels (the default option) //
Canvas::SetPixelWriteMode( COLOR_ONLY );


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about SetPixelWriteMode? Click here.
openlayer-2.1.orig/Manual/Canvas/DisableClipping.html0000644000175000017500000001134410377363276023077 0ustar georgeskgeorgeskOpenLayer Offline Manual

DisableClipping

static void DisableClipping();

Disables the clipping region.

If you've called Transforms::SetClipping you can call this function to disable the clipping region and to be able to render to the whole screen again.

Examples

// Disable the clipping region //
Transforms::DisableClipping();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about DisableClipping? Click here.
openlayer-2.1.orig/Manual/Canvas/SetTo.html0000644000175000017500000001403010377363276021077 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetTo

Note: If the active surface is a Bitmap, calling this function will refresh the active surface!

static void SetTo(
const Bitmap &buffer )

Sets the Bitmap as the active rendering surface.

static void SetTo(
OlRenderTarget buffer )

Sets specified OpenGL buffer image as the active rendering surface.

The only possible choise for now is SCREEN_BACKBUF (the screen backbuffer).

As you might guess, the screen backbuffer is the default rendering surface.

Warning: You shouldn't render anything to the backbuffer during the frame before selecting a Bitmap as the active surface! Otherwise the program might not work correctly with older hardware.

Also rendering a Bitmap to itself may cause undefined results. Most likely you'll get some gray pixels here and there, but it won't look like what you might expect, anyways.

Examples

Bitmap myBmp( ... );

// Sets myBmp as the active canvas //
Canvas::SetTo( myBmp );

// Set the screen as the active canvas //
Canvas::SetTo( SCREEN_BACKBUF );


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about SetTo? Click here.
openlayer-2.1.orig/Manual/Canvas/Refresh.html0000644000175000017500000001211610377363276021442 0ustar georgeskgeorgeskOpenLayer Offline Manual

Refresh

static void Refresh()

Refresh the contents of the active rendering surface.

If the selected surface is a Bitmap, this call will block until the graphics card has finished rendering to the Bitmap. If the screen backbuffer is selected instead, this call may or may not block depending on the settings and OpenGL implementation.

Before OpenLayer 2.0 (when Canvas didn't exist) the way to refresh the screen was to call GfxRend::RefreshScreen(). However, RefreshScreen doesn't support different rendering surfaces.

GfxRend::RefreshScreen can still be used for backwards compability but it's highly deprecated as it may mess up your code if you use Canvas as well. So if you use Canvas, it's best to use only Canvas, not RefreshScreen.

Examples

// Refresh the contents of the active canvas //
Canvas::Refresh();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Refresh? Click here.
openlayer-2.1.orig/Manual/Canvas/Fill.html0000644000175000017500000001351010377363276020731 0ustar georgeskgeorgeskOpenLayer Offline Manual

Fill

static void Fill(
Rgba fillColor )

Fills the active rendering surface with the specified color.

static void Fill(
Rgba fillColor,
PixelWriteMode filledComponents )

Same as above but affects only to the specified color components.
Possible choises are:

COLOR_AND_ALPHA - Both the color value and alpha channel are affected (Default)
COLOR_ONLY - Only the color values are affected
ALPHA_ONLY - Only the alpha channel is affected


Examples

// Fill the active canvas with blue //
Canvas::FillRgba::BLUE );

// If the surface is a Bitmap you might wish to empty it //
// so that it's totally transparent: //
Canvas::FillRgba::INVISIBLE, ALPHA_ONLY );


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Fill? Click here.
openlayer-2.1.orig/Manual/Canvas/SetClipping.html0000644000175000017500000001306310377363276022267 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetClipping

static void SetClipping(
int x, int y, int w, int h );

Sets the clipping region of the active rendering surface.

The parts of the objects which fall out of the clipping region will not be rendered.

This function could be used to implement split screen views or minimaps, for example.

Examples

// Set the clipping region to a 100 x 100 portion at the top-right side of the screen //
Transforms::SetClipping( SCREEN_W - 1000100100 );

// Set the clipping region to the left half of the screen //
Transforms::SetClipping00, SCREEN_W/2, SCREEN_H );


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about SetClipping? Click here.
openlayer-2.1.orig/Manual/Canvas/GetClippingRegion.html0000644000175000017500000001113710377363276023417 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetClippingRegion


Returns the active clipping region

Examples

// Get the active clipping region //
Rect clippingRegion = Canvas::GetClippingRegion();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about GetClippingRegion? Click here.
openlayer-2.1.orig/Manual/Canvas/Width.html0000644000175000017500000001073310416463436021117 0ustar georgeskgeorgeskOpenLayer Offline Manual

Width

inline static int Width()

Returns the width of the active rendering surface

Examples

// Get the width of the canvas //
int width = Canvas::Width();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Width? Click here.
openlayer-2.1.orig/Manual/Canvas/Height.html0000644000175000017500000001076310421451270021240 0ustar georgeskgeorgeskOpenLayer Offline Manual

Height

inline static int Height()

Returns the height of the active rendering surface

Examples

// Get the height of the canvas //
int height = Canvas::Height();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Height? Click here.
openlayer-2.1.orig/Manual/Canvas/Pop.html0000644000175000017500000001217510421451270020565 0ustar georgeskgeorgeskOpenLayer Offline Manual

Pop

Advanced function

static void Pop();

Pops the most recently stored Canvas from the stack and selects it

A surface must have been stored with Canvas::Push() before calling this function.

Examples

// Push the old active canvas to the stack and select a new one //
Canvas::Push();
Canvas::SetTo( ... );

// Do some rendering here...

//
 Pop the old active canvas from the stack //
Canvas::Pop();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Pop? Click here.
openlayer-2.1.orig/Manual/Canvas/GetMemoryBitmap.html0000644000175000017500000001122210416463436023077 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetMemoryBitmap

Advanced function

BITMAP *GetMemoryBitmap()

Returns the contents of the Canvas in a memory bitmap.

The returned image is a copy - changing the contents of the image doesn't change the contents of the Canvas.

Examples

// Get the contents of the canvas as Allegro BITMAP //
BITMAP *canvasImage = Canvas::GetMemoryBitmap();


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about GetMemoryBitmap? Click here.
openlayer-2.1.orig/Manual/Canvas/Save.html0000644000175000017500000001170210421451270020720 0ustar georgeskgeorgeskOpenLayer Offline Manual

Save

static void SaveScreenshot(
std::string filename )

Saves the contents of the surface to an image file with a given filename. The extension of the filename specifies the image format.

Supported image formats depend on how the library is set up.

This function could be used to save screenshots, for example.

Examples

Canvas::SetTo( SCREEN_BACKBUF );

// Save a screenshot in the Screenshots folder as NewScreenshot.png //
Canvas::Save"MyScreenshot.png" );


Other functions of the class Canvas
SetTo
Selects the active rendering surface
Refresh
Refresh the contents of the active rendering surface
Fill
Fills the active rendering surface with the specified color
SetClipping
Sets the clipping region of the active rendering surface
DisableClipping
Disables the clipping region
GetClippingRegion
GetClippingRegion
Width
Returns the width of the active rendering surface
Height
Returns the height of the active rendering surface
Save
Saves the contents of the surface to an image file

Advanced functions

SetPixelWriteMode
Selects which color components the rendering functions affect
GetMemoryBitmap
Returns the contents of the Canvas in a memory bitmap
Push
Pushes the active Canvas to a stack
Pop
Pops the most recently stored Canvas from the stack


Questions about Save? Click here.
openlayer-2.1.orig/Manual/Collision/0000700000175000017500000000000012262355751017655 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Collision/GetAllPoints.html0000644000175000017500000000650710417230626023123 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetAllPoints

const std::vector< Vec2D > &GetAllPoints() const

Returns all collision points.

There might be more than one collision point in some cases, if several parts of the objects collide at the same time.

Examples

Collision collision = ...;

// Get all collision points //
const std::vector< Vec2D > &collisionPoints = collision.GetAllPoints();


Other functions of the class Collision
GetPoint
Returns the exact point of the collision
GetSegment
Returns the specified colliding line segment
IsCollision
Returns true if a collision has really happened
GetNormal
Returns the normal of a colliding object at the collision point
GetAllPoints
Returns all collision points
GetAllSegments
Returns all pairs of colliding segments


Questions about GetAllPoints? Click here.
openlayer-2.1.orig/Manual/Collision/GetSegment.html0000644000175000017500000000544010417230626022613 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetSegment

CollidingObject objectID )

Returns the specified colliding line segment. ObjectID should be either one of these:
- OBJ_A: The first colliding object
- OBJ_B: The second colliding object

Other functions of the class Collision
GetPoint
Returns the exact point of the collision
GetSegment
Returns the specified colliding line segment
IsCollision
Returns true if a collision has really happened
GetNormal
Returns the normal of a colliding object at the collision point
GetAllPoints
Returns all collision points
GetAllSegments
Returns all pairs of colliding segments


Questions about GetSegment? Click here.
openlayer-2.1.orig/Manual/Collision/GetPoint.html0000644000175000017500000000506510417230626022305 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetPoint


Returns the exact point of the collision.

Other functions of the class Collision
GetPoint
Returns the exact point of the collision
GetSegment
Returns the specified colliding line segment
IsCollision
Returns true if a collision has really happened
GetNormal
Returns the normal of a colliding object at the collision point
GetAllPoints
Returns all collision points
GetAllSegments
Returns all pairs of colliding segments


Questions about GetPoint? Click here.
openlayer-2.1.orig/Manual/Collision/IsCollision.html0000644000175000017500000000673310417230626023006 0ustar georgeskgeorgeskOpenLayer Offline Manual

IsCollision


Returns true if a collision has really happened.

You can also use the conversion to boolean to test if a collision happened. See the examples how to use this.

Examples

Collision collision = ...;

// Test if a collision really happened //
if( collision.IsCollision() ) {
  allegro_message( "Collision!" );
}

// The same as above by using the operator bool() //
if( collision ) {
  allegro_message( "Collision!" );
}


Other functions of the class Collision
GetPoint
Returns the exact point of the collision
GetSegment
Returns the specified colliding line segment
IsCollision
Returns true if a collision has really happened
GetNormal
Returns the normal of a colliding object at the collision point
GetAllPoints
Returns all collision points
GetAllSegments
Returns all pairs of colliding segments


Questions about IsCollision? Click here.
openlayer-2.1.orig/Manual/Collision/GetAllSegments.html0000644000175000017500000001105110417230626023422 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetAllSegments

const std::vector< std::pair< Line, Line > *> &GetAllSegments()

Returns all pairs of colliding segments. The first line of each pair is colliding with the second line of the pair.

There might be more than one collision point in some cases, if several parts of the objects collide at the same time.

Examples

Collision collision = ...;

// Get all colliding segments //
const std::vector< std::pair< LineLine > *> &segments = collision.GetAllSegments();

// Draw the colliding segments //
// (Object A's colliding segments will be green and Object B's red) //

for( std::vector< std::pair< LineLine > *> ::const_iterator iter = segments.begin(); iter != segments.end(); iter++ ) {
  (*iter)->first.DrawRgba::GREEN );
  (*iter)->second.DrawRgba::RED );
}


Other functions of the class Collision
GetPoint
Returns the exact point of the collision
GetSegment
Returns the specified colliding line segment
IsCollision
Returns true if a collision has really happened
GetNormal
Returns the normal of a colliding object at the collision point
GetAllPoints
Returns all collision points
GetAllSegments
Returns all pairs of colliding segments


Questions about GetAllSegments? Click here.
openlayer-2.1.orig/Manual/Collision/GetNormal.html0000644000175000017500000000707510421451270022442 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetNormal

CollidingObject objectID )

Returns the normal of a colliding object at the collision point. ObjectID should be either one of these:
- OBJ_A: The first colliding object
- OBJ_B: The second colliding object

This function returns the same as GetSegment( objectID ).GetNormal(). However this function may execute a lot faster when the segment information isn't meaningful (the colliding objects don't consist of line segments).

Examples

Collision collision = ...;

// Get the normal of the first colliding object at the collision point //
Vec2D objANormal = collision.GetNormal( OBJ_A );


Other functions of the class Collision
GetPoint
Returns the exact point of the collision
GetSegment
Returns the specified colliding line segment
IsCollision
Returns true if a collision has really happened
GetNormal
Returns the normal of a colliding object at the collision point
GetAllPoints
Returns all collision points
GetAllSegments
Returns all pairs of colliding segments


Questions about GetNormal? Click here.
openlayer-2.1.orig/Manual/TextRenderer.html0000644000175000017500000002633010421451270021225 0ustar georgeskgeorgeskOpenLayer Offline Manual

TextRenderer

The font container

const char *filename,
int width = 9, int height = 12,
Rgba col = Rgba::BLACK, int italics = 0,
bool useHinting = true );

Construct the font by loading a True Type Font file.


const TextRenderer &otherRenderer,
int width = 9, int height = 12,
Rgba col = [inherit], int italics = [inherit] );

Construct the font by making an altered copy of an existing TextRenderer. If you don't pass anything as the color or the italics parameter they'll be inherited from otherRenderer.


GLYPH_FACE *face = 0,
int width = 9, int height = 12,
Rgba col = Rgba::BLACK, int italics = 0 );

Construct the font by using a Glyph Keeper font face.



The default constructor. Note that the TextRenderer will not be ready to use before you call the Load -method (IsValid() returns false).

The constructors do the the same as the equivalent Load -methods. The dimensions are in pixels and the italics angle is in degrees.

The alpha value of the color controls the opacity of the printed text. The higher the alpha value is, the more visible the text will be. For more information about alpha values see the definition of Bitmap.

If any of these functions fail to construct the font an error log will be added to the allegro.log file. In addition the IsValid() -method will return false if the TextRenderer is not ready to use. You can also test the validity of a TextRenderer like if the TextRenderer was a boolean value.

Global TextRenderers are now automated.

Examples

// Construct a new font by loading a true type font Arial.ttf in the fonts -folder //
// with the width of 10, the height of 15 and a black color //
TextRenderer myTextRenderer( "fonts/Arial.ttf"1015Rgba::BLACK );

// Construct a same looking font but with italics angle of 12 (the common italics angle) //
TextRenderer myItalicsRenderer( "fonts/Arial.ttf"1015Rgba::BLACK, 12 );

// Test if myItalicsRenderer was loaded correctly (maybe it didn't exist) //
if( !myItalicsRenderer ) {
  allegro_message( "Couldn't load fonts/Arial.ttf" );
}

// Construct a font which looks like myTextRenderer but with the opacity of only 30% //
TextRenderer myTranslucentRenderer( "fonts/Arial.ttf"1015Rgba0.00.00.00.30 ));

// Construct a smaller copy of an existing font (sized 9x12) //
// If you don't specify a color it'll be inherited //
// from the passed TextRenderer //
TextRenderer smallerTextRenderer( myTextRenderer, 912 );

// Construct the font from a glyph keeper font face //
// with a slightly yellow green color //
GLYPH_FACE *glyphKeeperFace = ...; 

TextRenderer otherTextRenderer( glyphKeeperFace, 2015Rgba0.31.00.0 ));


Member functions
Load
Load the font
Print
Prints the given text to the screen
SetColor
Sets the color of the font
GetColor
Returns the text color of the font
SetItalics
Sets the italics angle of the text
GetItalics
Returns the italics angle of the text
Width
Returns the width of the given text
Height
Returns the height of the given text
FirstLineWidth
Returns the width of the first text line of the given text
FirstLineHeight
Returns the height of the first text line of the given text
IsValid
Checks if the TextRenderer was loaded correctly

Advanced functions

GetFace
SendToGPU
UnloadFromGPU
UseAutoDelete


Questions about TextRenderer? Click here.
openlayer-2.1.orig/Manual/EllipseSliceGradient.html0000644000175000017500000000667010377350122022656 0ustar georgeskgeorgeskOpenLayer Offline Manual
EllipseSliceGradient

static void GfxRend/EllipseSlice.html">EllipseSliceGradient.html">EllipseSliceGradient(
float x, float y, float xRad, float yRad,
Rgba innerColor, Rgba outerColor,
float startAngle, float sweepAngle,
float angle = 0.0, float accuracy = [default] );

Draws a gradient filled slice of an ellipse with colors changing smoothly from innerColor to outerColor along the radius.

The centre of the ellipse of which the slice is cut is positioned at the given coordinates. The slice will start at the given radial angle startAngle and will end to startAngle + sweepAngle.

Examples

// Draw a filled first quarter of an ellipse which horizontal radius is 70.0 and //
// vertical radius is 50.0 and colors changing smoothly from white to black //
// along the radius //
GfxRend::GfxRend/EllipseSlice.html">EllipseSliceGradient.html">EllipseSliceGradient200.0100.070.050.00.0, AL_PI/4Rgba::WHITE, Rgba::BLACK ); 


Other functions of the class


Questions about EllipseSliceGradient? Click here.
openlayer-2.1.orig/Manual/Vec2D.html0000644000175000017500000001226310377350122017521 0ustar georgeskgeorgeskOpenLayer Offline Manual

Vec2D

float x = 0.0, float y = 0.0 )

Constructs a new vector with the specified components.

The 2D vector class holds the x and y values of the vector which can be directly accessed from the object.

Several common operators have been overloaded for the vector class. These are sum, subtraction, multiplication, division, normalization (~ -operator) and the dot product (Vec2D * Vec2D). See the exaples to see how to use them.

Examples

// Create a new vector called theVector with x = 15.0 and y = 20.0 //
Vec2D theVector( 15.020.0 );

// Get the x component of the vector //
float x = theVector.x;

// Get the y component of the vector //
float y = theVector.y;

// Create a new vector called secondVector with x = -50.0 and y = 100.0 //
Vec2D secondVector( -50.0100.0 );

// Get a vector sum of theVector and secondVector //
Vec2D sum = theVector + secondVector;

// Get a vector with 5 times the magnitude of secondVector //
Vec2D biggerVector = 5.0 * secondVector;

// Increase biggerVector by x = 40, y = -30.5 //
biggerVector += Vec2D40.0, -30.5 );

// Get a normalized copy of biggerVector //
// (a vector which has the same direction as biggerVector but magnitude of 1.0) //
Vec2D normalizedBigger = ~biggerVector;

// Get a dot product between two vectors //
float dotProduct = theVector * secondVector;


Member functions
GetMagnitude
Returns the magnitude (length) of the vector
GetAngle
Returns the angle of the vector
Normalized
Returns a normalized copy of the vector

Advanced functions

GetMagnitudeSquared
Returns the squared magnitude of the vector


Questions about Vec2D? Click here.
openlayer-2.1.orig/Manual/Setup.html0000644000175000017500000000571210377350122017717 0ustar georgeskgeorgeskOpenLayer Offline Manual

Setup

Program setup functions

The setup class has functions to set up the program, keyboard, mouse, timer system and the program window or screen mode.

Member functions
SetupProgram
Sets up OpenLayer and the other libraries
SetupScreen
Sets up the program window or the fullscreen mode
GetWindowWidth
Returns the width of the program window
GetWindowHeight
Returns the height of the program window
GetColorDepth
Returns the color depth of the program window
GetExecutablePath
Returns the path of the program executable
ToAbsolutePathname
Converts the relative pathname to an absolute one

Advanced functions

IsProgramSetUp
Returns true if SetupProgram is called
IsScreenSetUp
Returns true if SetupScreen is called


Questions about Setup? Click here.
openlayer-2.1.orig/Manual/Bitmap.html0000644000175000017500000003470510421451270020033 0ustar georgeskgeorgeskOpenLayer Offline Manual

Bitmap

Stores a bitmap and draws it to the screen.

const char *filename, int flags = [NONE] );

Constructs the Bitmap by loading a bitmap file. The loaded bitmap may contain an alpha channel. Works like the Load-method.

The only possibile flag is:
MAKE_COLLISION_POLY - Creates a collision polygon

const char *rgbFilename, const char *alphaFilename,
int flags = [NONE] );

Constructs the Bitmap by loading two separate bitmap files, one bitmap for the color information and one 8-bit bitmap for the transparency information. Works like the Load-method.

BITMAP *allegroBmp, int conversionMode, int flags = [NONE] );

Constructs the Bitmap from an Allegro BITMAP. The conversion mode should be one of these:

HAS_ALPHA_CHANNEL - Tells that the BITMAP has an alpha channel
CONVERT_MAGIC_PINK - Converts all magic pink pixels to transparent ones

OpenLayer doesn't free the passed BITMAP even if the Bitmap is destroyed.

int width, int height, Rgba fillColor );

Creates a new Bitmap filled with the specified color.

const Bitmap &other, const Rect &area );

Construct a sub-bitmap of an area of the given Bitmap.

template< class Functor > Bitmap(
int width, int height, Functor functor );

Creates a new Bitmap and calls the 'Rgba operator()(int x, int y)' of the functor object for each pixel.

If you need transparent or translucent parts in the bitmap you need to have an alpha channel for the bitmap. An alpha channel stores the opacity values for each pixel in the bitmap. The higher the alpha value, the more visible the pixel is.

If the alpha value of a pixel is the highest value (1.0) the pixel will be totally solid. But if the alpha value of a pixel is zero it'll be totally transparent and the pixel won't be rendered at all. If the alpha value is between 0.0 and 1.0 the pixel will be partially visible, depending on how high the alpha value is.

There's a version of every Bitmap rendering routine that also takes a RenderMode parameter which affects the way the Bitmap is rendered to the screen. Currently there are quite a few of RenderModes, like Tinted, Clipped and Flipped.

The pixel data will be automatically freed from the memory when the Bitmap object is destroyed. You can also manually free the bitmap data by calling the Destroy()-method.

Loading and destroying of global bitmaps and setting up the PNG image loading are automated now. If you have any dynamically allocated Bitmaps you can choose to let OpenLayer to free them when the program quits by calling the TextRenderer/UseAutoDelete.html">UseAutoDelete() -method.

And a final note about the copy constructor: It won't make a copy of the image, but instead the Bitmap copy will refer to the same image in the memory.

Examples

// Remember that Bitmaps can't be rendered until Setup::SetupProgram and Setup::SetupScreen are called! // 

// Construct a bitmap by loading a bitmap file //
Bitmap myBmp( "gfx/picture.png" );

// Draws the bitmap to the screen such that the top-left //
// corner of the bitmap will be positioned at x = 200, y = 100 //
myBmp.Blit200100 );

// Construct a Bitmap using an Allegro BITMAP with an alpha channel //
// and transparent magic pink pixels //
BITMAP *allegroBmp = create_bitmap(...);
Bitmap myBmp( allegroBmp, HAS_ALPHA_CHANNEL | CONVERT_MAGIC_PINK );

// Construct the Bitmap using a separate bitmap for //
// the color and the transparency information //
// Note that pictureOpacity.bmp must be an 8-bit bitmap! //
Bitmap myBmp( "gfx/picture.bmp""gfx/pictureOpacity.bmp" );


Member functions
Load
Loads the bitmap
Blit
Draws the Bitmap to the screen
BlitRotated
Draws the Bitmap to the screen rotated along a point
BlitStretched
Draws the Bitmap to the screen stretched to the specified size
BlitTransformed
Draws the Bitmap to the screen rotated and stretched
BlitDistorted
Draws the Bitmap to the screen with the given corner points
Width
Returns the width of the Bitmap
Height
Returns the height of the Bitmap
LoadListOfBitmaps
Loads a list of bitmaps from the disk
GetPixel
Returns the color value of a pixel
Destroy
Destroys the Bitmap
IsValid
Checks if the Bitmap was loaded correctly
Save
Saves the Bitmap to disk with the specified filename
CopyFromScreen
Copies a region of the game window to the Bitmap
GetMemoryBitmap
Returns a memory bitmap copy of (part of) the Bitmap
GetCollisionPoly
Returns the generated collision polygon for the Bitmap
SetDefaultPivot
Sets the default pivot point
GetDefaultPivot
Returns the default pivot point

Advanced functions

GetPixelPacked
Returns the color value of the specified pixel in a packed integer
SendToGPU
Sends the Bitmap to the graphics card
UnloadFromGPU
Unloads the Bitmap from the graphics card
Select
Selects the Bitmap as the active texture of OpenGL
UseAutoDelete
Chooses the Bitmap to be automatically deleted when the program quits
HasAlphaChannel
Checks if the Bitmap has an alpha channel
StartFastBlitting
This function should be called right before using FastBlit
FastBlit
A faster version of Blit
FinishFastBlitting
This function should be called after calling FastBlit
UnloadToMemory
Unloads the Bitmap from the graphics card keeping the image data saved in the Bitmap
TexturedQuad
Outputs a raw textured quad to the video card


Questions about Bitmap? Click here.
openlayer-2.1.orig/Manual/Transforms/0000700000175000017500000000000012262355751020060 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Transforms/SetTintColor.html0000644000175000017500000001135710377350122023350 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetTintColor

static void SetTintColor(
Rgba color );

Tint the whole screen to a color.

The alpha value of the color tells the intensity of the tinting. If the alpha value is zero the screen won't be tinted at all and if the alpha value is 1.0 the screen will be filled with the specified color.

Examples

// Tint the whole screen 30% to red //
Transforms::SetTintColorRgba1.00.00.00.30 ));

// Disable tinting //
Transforms::SetTintColorRgba::INVISIBLE );


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about SetTintColor? Click here.
openlayer-2.1.orig/Manual/Transforms/DisableClipping.html0000644000175000017500000000760010377350122024004 0ustar georgeskgeorgeskOpenLayer Offline Manual
DisableClipping

static void DisableClipping();

Disables the clipping region.

If you've called Transforms::SetClipping you can call this function to disable the clipping region and to be able to render to the whole screen again.

Examples

// Disable clipping region //
Transforms::DisableClipping();


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetTransforms
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
SetClipping
Sets the clipping region of the screen
DisableClipping
Disables the clipping region


Questions about DisableClipping? Click here.
openlayer-2.1.orig/Manual/Transforms/SetPosition.html0000644000175000017500000001143210421451270023225 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetPosition

static void SetPosition(
float x, float y );

Set the position of screen contents.

The default position of the screen is x = 0.0, y = 0.0.

This function could be used to implement scrolling but the objects which are rendered outside of the screen will still be sent to the graphics card where they're discarted.

Examples

// Set the position of the screen contents to x = 200.0, y = 100.0 //
Transforms::SetPosition200.0100.0 );

// Set the position of the screen back to the original position //
Transforms::SetPosition0.00.0 );


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about SetPosition? Click here.
openlayer-2.1.orig/Manual/Transforms/SetClipping.html0000644000175000017500000001131610377350122023173 0ustar georgeskgeorgeskOpenLayer Offline Manual
SetClipping

static void SetClipping(
int x, int y, int w, int h );

Sets the clipping region of the screen.

The parts of the objects which fall out of the clipping region will not be rendered.

This function could be used to implement split screen views or minimaps, for example.

Examples

// Set the clipping region to a 100 x 100 portion at the top-right side of the screen //
Transforms::SetClipping( SCREEN_W - 1000100100 );

// Set the clipping region to the left half of the screen //
Transforms::SetClipping00, SCREEN_W/2, SCREEN_H );


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetTransforms
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
SetClipping
Sets the clipping region of the screen
DisableClipping
Disables the clipping region


Questions about SetClipping? Click here.
openlayer-2.1.orig/Manual/Transforms/SetRotationPivot.html0000644000175000017500000001147410377350122024254 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetRotationPivot

static void SetRotationPivot(
float pivotX, float pivotY );

Sets the pivot point of the screen rotation.

The default point is the center of the screen.

Hint: You can set the pivot point to be the player's position in the screen to rotate the screen around the player.

Examples

// Set the rotation point of the screen contents to x = 300.0, y = 400.0 //
Transforms::SetRotationPivot300.0400.0 );

// Set the rotation point back to the center of the screen // 
Transforms::SetRotationPivot( SCREEN_W/2, SCREEN_H/2 );


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about SetRotationPivot? Click here.
openlayer-2.1.orig/Manual/Transforms/SetRotation.html0000644000175000017500000001100010417230626023214 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetRotation

static void SetRotation(
float angle );

Set the rotational angle of the screen contents.

The angle is in clockwise order.

Examples

// Set the rotation of the screen contents to pi/2 //
// (the screen will be rotated 90 decrees clockwise) //
Transforms::SetRotation( AL_PI/2 );

// Get rid of the rotation //
Transforms::SetRotation0.0 );


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about SetRotation? Click here.
openlayer-2.1.orig/Manual/Transforms/SetColorChannels.html0000644000175000017500000001117310377350122024161 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetColorChannels

static void SetColorChannels(
Rgba cofficients );

Sets the coefficients of the red, green, blue and alpha channels.

The default is Rgba::WHITE (all channels are 1.0).

Examples

// Get rid of all red color //
Transforms::SetColorChannelsRgba0.01.01.0 ));

// Revert back to normal //
Transforms::SetColorChannelsRgba::WHITE );


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about SetColorChannels? Click here.
openlayer-2.1.orig/Manual/Transforms/PushPlacement.html0000644000175000017500000001163310421451270023520 0ustar georgeskgeorgeskOpenLayer Offline Manual

PushPlacement

static void PushPlacement()

Pushes the placement state of Transforms (position, rotation and stretch) in a stack.

Subsequent calls of PushPlacement grow the stack. The PopPlacement pops the most recent addition from the stack and applies it.

Examples

// Push the global placement state to the stack //
Transforms::PushPlacement();

// Modify the global placement //
Transforms::SetPosition( x, y );
Transforms::SetRotation( alpha );

// Do stuff...

//
 Revert the old global placement //
Transforms::PopPlacement();


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about PushPlacement? Click here.
openlayer-2.1.orig/Manual/Transforms/PopPlacement.html0000644000175000017500000001157010421451270023337 0ustar georgeskgeorgeskOpenLayer Offline Manual

PopPlacement

static void PopPlacement()

Pops the most recent placement state of Transforms from the stack and applies it. See PushPlacement

An error is logged if you attempt to call PopPlacement before calling PushPlacement.

Examples

// Push the global placement state to the stack //
Transforms::PushPlacement();

// Modify the global placement //
Transforms::SetPosition( x, y );
Transforms::SetRotation( alpha );

// Do stuff...

//
 Revert the old global placement //
Transforms::PopPlacement();


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about PopPlacement? Click here.
openlayer-2.1.orig/Manual/Transforms/ResetTransforms.html0000644000175000017500000000721610377350122024117 0ustar georgeskgeorgeskOpenLayer Offline Manual

ResetTransforms

static void ResetTransforms();

Resets all the active placement transformations to default.

The reseted transformations include the position, rotation and stretching. Note that this function doesn't reset the rotation pivot to the center of the screen.

Examples

// Set the position, rotation and stretching to normal (no active placement transformations) //
Screen::ResetTransforms();


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetTransforms
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels


Questions about ResetTransforms? Click here.
openlayer-2.1.orig/Manual/Transforms/SetStretch.html0000644000175000017500000001137010417230626023043 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetStretch

static void SetStretch(
float xStretch, float yStretch );

Sets the stretch factor of the whole screen.

Note that the given values are a stretch factor such that 1.0 is the original size, 0.5 is half the original size and 2.0 is double the original size.

The default stretch is xStretch = 1.0, yStretch = 1.0.

Hint: You can use this function to zoom in and out of the playfield.

Examples

// Zoom out to 50% of the original size //
Transforms::SetStretch0.500.50 );

// Zoom back in to the original size //
Transforms::SetStretch1.01.0 ); 


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about SetStretch? Click here.
openlayer-2.1.orig/Manual/Transforms/GetColorChannels.html0000644000175000017500000001004310377350122024140 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetColorChannels


Returns the coefficients of the color channels.

Examples

// Get the cofficients of the color channels //
Rgba channels = Transforms::GetColorChannels();


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about GetColorChannels? Click here.
openlayer-2.1.orig/Manual/Transforms/ResetPlacement.html0000644000175000017500000001021310377350122023660 0ustar georgeskgeorgeskOpenLayer Offline Manual

ResetPlacement

static void ResetPlacement();

Resets all the active placement transformations to default.

The reseted transformations include the position, rotation and stretching. Note that this function doesn't reset the rotation pivot to the center of the screen.

Note: Empties the Transforms stack!

Examples

// Set the position, rotation and stretching to normal (no active placement transformations) //
Screen::ResetPlacement();


Other functions of the class Transforms
SetPosition
Set the position of screen contents
SetRotation
Set the rotational angle of the screen contents
SetRotationPivot
Selects the pivot point of the screen rotation
SetStretch
Sets the stretch factor of the screen
SetTintColor
Tints the whole screen to a color
ResetPlacement
Disables all the active placement transformations
SetColorChannels
Sets the coefficients of the color channels
GetColorChannels
Returns the coefficients of the color channels
PushPlacement
Pushes the placement state of Transforms in a stack
PopPlacement
Pops the most recent placement state of Transforms from the stack


Questions about ResetPlacement? Click here.
openlayer-2.1.orig/Manual/Placement/0000700000175000017500000000000012262355751017632 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/Placement/MoveBy.html0000644000175000017500000001031110421451270021713 0ustar georgeskgeorgeskOpenLayer Offline Manual

MoveBy

void MoveBy(
Vec2D value )

Moves the position part of the Placement by the specified amount.

Examples

Placement myPlacement( Vec2D250.0100.0 ), 0.5 * AL_PI );

// Move myPlacement 20 pixels right and 10 pixels down //
myPlacement.MoveByVec2D20.010.0 ));


Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about MoveBy? Click here.
openlayer-2.1.orig/Manual/Placement/GetPosition.html0000644000175000017500000000734510377350122022777 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetPosition


Returns the position value of the Placement.

Examples

// Get the position value of myPlacement //
Vec2D position = myPlacement.GetPosition();


Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about GetPosition? Click here.
openlayer-2.1.orig/Manual/Placement/SetPosition.html0000644000175000017500000000767010421451270023010 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetPosition

Vec2D position )

Sets the position value of the Placement.

Examples

// Set the position of myPlacement to x = 200.0, y = 100.0 //
myPlacement.SetPositionVec2D200.0100.0 ));


Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about SetPosition? Click here.
openlayer-2.1.orig/Manual/Placement/RotateBy.html0000644000175000017500000001010510421451270022244 0ustar georgeskgeorgeskOpenLayer Offline Manual

RotateBy

void RotateBy(
float value )

Changes the rotation angle of the Placement by the specified amount.

Examples

Placement myPlacement( Vec2D250.0100.0 ), 0.5 * AL_PI );

// Rotate myPlacement 90 decrees clockwise //
myPlacement.RotateBy0.5 * AL_PI );


Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about RotateBy? Click here.
openlayer-2.1.orig/Manual/Placement/GetDistance.html0000644000175000017500000000700010377350122022711 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetDistance

const Placement &other )

Returns the distance between this Placement and an another one.

Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about GetDistance? Click here.
openlayer-2.1.orig/Manual/Placement/SetRotation.html0000644000175000017500000000664010417230626023004 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetRotation

float rotation )

Sets the rotation angle of the Placement.

Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about SetRotation? Click here.
openlayer-2.1.orig/Manual/Placement/SetStretch.html0000644000175000017500000000663410417230626022624 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetStretch

float stretch )

Sets the stretching factor of the Placement.

Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about SetStretch? Click here.
openlayer-2.1.orig/Manual/Placement/GetStretch.html0000644000175000017500000000647710377350122022614 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetStretch

float GetStretch()

Returns the stretching factor of the Placement.

Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about GetStretch? Click here.
openlayer-2.1.orig/Manual/Placement/StretchBy.html0000644000175000017500000001014210377350122022427 0ustar georgeskgeorgeskOpenLayer Offline Manual

StretchBy

void StretchBy(
float factor )

Multiplies the stretching value of the Position by the specified amount.

Examples

Placement myPlacement( Vec2D250.0100.0 ), 0.5 * AL_PI );

// Multiply the stretching value of the Position by 1.5 //
myPlacement.StretchBy1.5 );


Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about StretchBy? Click here.
openlayer-2.1.orig/Manual/Placement/GetRotation.html0000644000175000017500000000650310377350122022765 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetRotation

float GetRotation()

Returns the rotation angle of the Placement.

Other functions of the class Placement
MoveBy
Moves the Placement
RotateBy
Rotates the Placement
StretchBy
Stretches the Position
GetDistance
Returns the distance between this Placement and an another one
SetPosition
Sets the position value of the Placement
GetPosition
Returns the position value of the Placement
SetRotation
Sets the rotation angle of the Placement
GetRotation
Returns the rotation angle of the Placement
SetStretch
Sets the stretching factor of the Placement
GetStretch
Returns the stretching factor of the Placement


Questions about GetRotation? Click here.
openlayer-2.1.orig/Manual/LineStrip/0000700000175000017500000000000012262355751017633 5ustar georgeskgeorgeskopenlayer-2.1.orig/Manual/LineStrip/AddToEnd.html0000644000175000017500000000626210377350122022153 0ustar georgeskgeorgeskOpenLayer Offline Manual

AddToEnd

void AddToEnd(
Vec2D vertex )

Adds a new vertex at the end of the line strip.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about AddToEnd? Click here.
openlayer-2.1.orig/Manual/LineStrip/DeleteLast.html0000644000175000017500000000615110377350122022554 0ustar georgeskgeorgeskOpenLayer Offline Manual

DeleteLast

void DeleteLast()

Deletes the last vertex of the line strip.

An empty line strip is not affected.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about DeleteLast? Click here.
openlayer-2.1.orig/Manual/LineStrip/DisableTexture.html0000644000175000017500000000621710377350122023455 0ustar georgeskgeorgeskOpenLayer Offline Manual

DisableTexture


Disables the active texture so that the LineStrip will only be filled with the drawing color.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about DisableTexture? Click here.
openlayer-2.1.orig/Manual/LineStrip/DeleteFirst.html0000644000175000017500000000616110377350122022741 0ustar georgeskgeorgeskOpenLayer Offline Manual

DeleteFirst

void DeleteFirst()

Deletes the first vertex of the line strip.

An empty line strip is not affected.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about DeleteFirst? Click here.
openlayer-2.1.orig/Manual/LineStrip/SetTexture.html0000644000175000017500000000633610377350122022647 0ustar georgeskgeorgeskOpenLayer Offline Manual

SetTexture

const Bitmap &texture )

Sets the texture of the LineStrip.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about SetTexture? Click here.
openlayer-2.1.orig/Manual/LineStrip/Draw.html0000644000175000017500000000753210417230626021430 0ustar georgeskgeorgeskOpenLayer Offline Manual

Draw

void Draw(
const Rgba &color )

Draws the line strip to the Canvas filled with the specified color.

void Draw(
const Rgba &startColor, const Rgba &endColor )

Draws the line strip filled with a gradients so that colors change smoothly from the start of the line strip to the end.


Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about Draw? Click here.
openlayer-2.1.orig/Manual/LineStrip/AddToBegin.html0000644000175000017500000000630610377350122022470 0ustar georgeskgeorgeskOpenLayer Offline Manual

AddToBegin

Vec2D vertex )

Adds a new vertex at the beginning of the line strip.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about AddToBegin? Click here.
openlayer-2.1.orig/Manual/LineStrip/GetNumberOfVertices.html0000644000175000017500000000606110377350122024410 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetNumberOfVertices

int GetNumOfVertices()

Returns the number of vertices in the line strip.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about GetNumberOfVertices? Click here.
openlayer-2.1.orig/Manual/LineStrip/GetVertex.html0000644000175000017500000000625610377350122022451 0ustar georgeskgeorgeskOpenLayer Offline Manual

GetVertex

int index )

Returns a vertex with the given index.

Other functions of the class LineStrip
Draw
Draws the line strip filled with a color
SetTexture
Sets the texture
DisableTexture
Disables the active texture
AddToEnd
Adds a new vertex at the end
AddToBegin
Adds a new vertex at the beginning
DeleteFirst
Deletes the first vertex
DeleteLast
Deletes the last vertex
GetVertex
Returns a vertex
GetNumberOfVertices
Returns the number of vertices


Questions about GetVertex? Click here.
openlayer-2.1.orig/cbuild.c0000644000175000017500000031313310461324066016123 0ustar georgeskgeorgesk#define foobarbaz /* # A shell script within a source file. Ugly, but it works... TRGT=`basename ${0/.c/.exe}` for i in $@ ; do if [ "$i" = "--make-compiled" ] ; then echo "Compiling '$TRGT', please wait..." gcc -W -Wall -O2 -o $TRGT $0 exit $? fi done gcc -W -Wall -Werror -o /tmp/$TRGT "$0" && { "/tmp/$TRGT" $@ ; RET=$? ; rm -f "/tmp/$TRGT" ; exit $RET ; } exit $? */ /* CBuild written by Chris Robinson, copyright 2005-2006 * * Notice of Terms of Use * * CBuild is provided as-is for personal use. You may use and redistribute it * in any manner, with the following terms and conditions: * * * You MAY NOT sell it, or otherwise redistribute it for profit, unless it is * bundled with a seperate commercial product and is used to build said * product. * * You MAY modify it without recompense or notification to the author, as * long as it is clearly marked as a derivitive work. * * You MAY NOT claim it as your own sole work. * * You MAY NOT remove or modify this notice. */ /* Despite what some people may think, no, the name CBuild did not come from my * first name. I got the name from the fact that it uses pure C, and only C. ;) */ #include #include #include #include #include #include #include #include #include #if defined(__unix__) || defined(__MACH__) #include #include #else #define WIFEXITED(x) (1) #define WEXITSTATUS(x) (x) #endif #if defined(__unix__) || defined(__GNUC__) #include #include #endif #ifdef _WIN32 #include #include #ifdef _MSC_VER // MSVC Sucks #define strcasecmp stricmp #define strncasecmp strnicmp #define snprintf _snprintf #define fileno _fileno #define PATH_MAX _MAX_PATH #define lstat slat #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) #define S_IRUSR _S_IREAD #define S_IWUSR _S_IWRITE #define S_IXUSR _S_IEXEC #define S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 struct dirent { char *d_name; }; typedef struct { long handle; /* -1 for failed rewind */ struct _finddata_t info; struct dirent result; /* d_name null iff first time */ char *name; /* null-terminated char string */ } DIR; DIR *opendir(const char *name) { DIR *dir = 0; if(name && name[0]) { /* search pattern must end with suitable wildcard */ size_t base_length = strlen(name); const char *all = strchr("/\\", name[base_length - 1]) ? "*" : "/*"; if((dir=(DIR*)malloc(sizeof(*dir))) != 0 && (dir->name=(char*)malloc(base_length+strlen(all)+1)) != 0) { strcat(strcpy(dir->name, name), all); if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1) { dir->result.d_name = 0; } else /* rollback */ { free(dir->name); free(dir); dir = NULL; } } else /* rollback */ { free(dir); dir = NULL; errno = ENOMEM; } } else errno = EINVAL; return dir; } int closedir(DIR *dir) { int result = -1; if(dir) { if(dir->handle != -1) result = _findclose(dir->handle); free(dir->name); free(dir); } if(result == -1) /* map all errors to EBADF */ errno = EBADF; return result; } struct dirent *readdir(DIR *dir) { struct dirent *result = 0; if(dir && dir->handle != -1) { if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) { result = &dir->result; result->d_name = dir->info.name; } } else errno = EBADF; return result; } void rewinddir(DIR *dir) { if(dir && dir->handle != -1) { _findclose(dir->handle); dir->handle = (long)_findfirst(dir->name, &dir->info); dir->result.d_name = 0; } else errno = EBADF; } #endif /* _MSC_VER */ static int setenv(const char *env, const char *val, int overwrite) { #if 0 /* This doesn't set anything? */ if(!overwrite) { char buf[2]; if(GetEnvironmentVariable(env, buf, sizeof(buf)) != 0 || GetLastError() != ERROR_ENVVAR_NOT_FOUND) return 0; } return (!SetEnvironmentVariable(env, (val&&*val)?val:NULL)) * -1; #else static char buf[64*1024]; if(!overwrite && getenv(env)) return 0; snprintf(buf, sizeof(buf), "%s=%s", env, (val?val:"")); return _putenv(buf); #endif } static int unsetenv(const char *env) { return setenv(env, "", 1); } #endif /* Win32 */ #define DECL_LIST(type, name) \ type (*name) = NULL; \ size_t name##_size = 0; \ size_t name##_len = 0 #define DECL_STATIC_LIST(type, name) \ static type (*name) = NULL; \ static size_t name##_size = 0; \ static size_t name##_len = 0 #define CLEAR_LIST(name) \ { \ name##_size = 0; \ name##_len = 0; \ free(name); \ name = NULL; \ } typedef struct { FILE *f; char *fname; char *bkp_lbuf; char *bkp_nextline; int bkp_line; int bkp_did_else; int bkp_did_cmds; int bkp_do_level; } INVOKE_BKP; DECL_STATIC_LIST(INVOKE_BKP, invoke_backup); typedef struct { char **argv; size_t argc; } ARGS; DECL_STATIC_LIST(ARGS, arg_backup); static size_t argc; DECL_STATIC_LIST(char*, argv); static FILE *f; static char *fname; static struct stat statbuf; static char linebuf[64*1024]; static char buffer[64*1024]; static char obj[PATH_MAX]; DECL_STATIC_LIST(char*, src_paths); DECL_STATIC_LIST(char*, loaded_files); DECL_STATIC_LIST(char*, sources); static int curr_line = 0; static char *nextline; static jmp_buf jmpbuf; static int stdi_bak = -1; static int stdo_bak = -1; static int stde_bak = -1; static FILE *stde_stream = NULL; // Make a define so we'll always have access to the real stderr #define USEABLE_ERR ((stde_stream)?stde_stream:stderr) typedef struct { char *name; char *val; } DEF; DECL_STATIC_LIST(DEF, defines); static inline void resize_list(void **ptr, size_t count, size_t type_size, size_t *len, size_t *size) { if(count == 0) { *size = 0; *len = 0; free(*ptr); *ptr = NULL; return; } if(count < (*len)/2 || count > *len) { void *tmp; size_t newlen = count-1; size_t i; for(i = 1;i < sizeof(size_t)*8;i*=2) newlen |= newlen>>i; ++newlen; tmp = realloc(*ptr, type_size*newlen); if(!tmp) { fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n" "Out of memory allocating %u bytes!\n", (unsigned int)(type_size*newlen)); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *ptr = tmp; *len = newlen; } *size = count; } #define RESIZE_LIST(name, count) \ { \ void *vptr = name; \ resize_list(&vptr, count, sizeof(*name), &name##_len, &name##_size); \ name = vptr; \ } static int libify_name(char *buf, size_t buflen, char *name); /* getvar: Safely gets an environment variable, returning an empty string * instead of NULL */ static const char *getvar(const char *env) { const char *var = getenv(env); return (var?var:""); } /* find_src: Attempts to find the named sourcefile by searching the paths * listed in src_paths. It returns the passed string if the file exists as-is, * or if it couldn't be found. */ static char *find_src(char *src) { static char buf[PATH_MAX]; struct stat statbuf; size_t i; if(stat(src, &statbuf) == 0 || src_paths_size == 0) return src; for(i = 0;i < src_paths_size;++i) { snprintf(buf, sizeof(buf), "%s/%s", src_paths[i], src); if(stat(buf, &statbuf) == 0) return buf; } return src; } #define BUF_SIZE (64*1024) /* expand_string: * The meat of the parser. Reads a string buffer of len bytes, expanding * sub-commands and variables, filling in &entity;'s, and dealing with * escaped characters, until one of the characters denoted in 'stp' is * encountered, non-escaped and outside of quotes, and return a pointer to * that location. If fillmore is non-0, it'll read more data from disk as * needed. */ static char *expand_string(char *str, const char *stp, size_t len, int fillmore) { char *buf, *ptr, *last_pos; int in_quotes = 0; int use_hard_quotes = 0; char *end; int i; if(!(*str) && !fillmore) return str; buf = malloc(BUF_SIZE); if(!buf) { strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } last_pos = str; do { ptr = last_pos; while(1) { if(fillmore) { if(!(*ptr)) { if(nextline) { snprintf(ptr, len+str-ptr, "\n%s", nextline); free(nextline); nextline = NULL; } else { if(fgets(ptr, len+str-ptr, f) == NULL) { free(buf); return ptr; } ++curr_line; } } } if(*ptr == '$') { if(in_quotes != '\'') break; } else if(*ptr == '#') { if(!in_quotes) { char *next = strchr(ptr, '\n'); if(!next) next = ""; memmove(ptr, next, strlen(next)+1); continue; } } if(!in_quotes) { i = 0; do { if((stp[i] == ' ' && isspace(*ptr)) || (stp[i] == '!' && !isspace(*ptr)) || (stp[i] == '^' && !isalpha(*ptr)) || *ptr == stp[i]) { free(buf); return ptr; } } while(stp[i++]); } if(*ptr == '&') { if(in_quotes != '\'') { unsigned int val = '?'; end = NULL; if(ptr[1] != '#') { static struct { char *name; unsigned int val; } val_tab[] = { { "Aacute", 0x00C1 }, { "aacute", 0x00E1 }, { "Acirc", 0x00C2 }, { "acirc", 0x00E2 }, { "acute", 0x00B4 }, { "AElig", 0x00C6 }, { "aelig", 0x00E6 }, { "Agrave", 0x00C0 }, { "agrave", 0x00E0 }, { "alefsym", 0x2135 }, { "Alpha", 0x0391 }, { "alpha", 0x03B1 }, { "amp", 0x0026 }, { "and", 0x2227 }, { "ang", 0x2220 }, { "Aring", 0x00C5 }, { "aring", 0x00E5 }, { "asymp", 0x2248 }, { "Atilde", 0x00C3 }, { "atilde", 0x00E3 }, { "Auml", 0x00C4 }, { "auml", 0x00E4 }, { "bdquo", 0x201E }, { "Beta", 0x0392 }, { "beta", 0x03B2 }, { "brvbar", 0x00A6 }, { "bull", 0x2022 }, { "cap", 0x2229 }, { "Ccedil", 0x00C7 }, { "ccedil", 0x00E7 }, { "cedil", 0x00B8 }, { "cent", 0x00A2 }, { "Chi", 0x03A7 }, { "chi", 0x03C7 }, { "circ", 0x02C6 }, { "clubs", 0x2663 }, { "cong", 0x2245 }, { "copy", 0x00A9 }, { "crarr", 0x21B5 }, { "cup", 0x222A }, { "curren", 0x00A4 }, { "Dagger", 0x2021 }, { "dagger", 0x2020 }, { "dArr", 0x21D3 }, { "darr", 0x2193 }, { "deg", 0x00B0 }, { "Delta", 0x0394 }, { "delta", 0x03B4 }, { "diams", 0x2666 }, { "divide", 0x00F7 }, { "Eacute", 0x00C9 }, { "eacute", 0x00E9 }, { "Ecirc", 0x00CA }, { "ecirc", 0x00EA }, { "Egrave", 0x00C8 }, { "egrave", 0x00E8 }, { "empty", 0x2205 }, { "emsp", 0x2003 }, { "ensp", 0x2002 }, { "Epsilon", 0x0395 }, { "epsilon", 0x03B5 }, { "equiv", 0x2261 }, { "Eta", 0x0397 }, { "eta", 0x03B7 }, { "ETH", 0x00D0 }, { "eth", 0x00F0 }, { "Euml", 0x00CB }, { "euml", 0x00EB }, { "euro", 0x20AC }, { "exist", 0x2203 }, { "fnof", 0x0192 }, { "forall", 0x2200 }, { "frac12", 0x00BD }, { "frac14", 0x00BC }, { "frac34", 0x00BE }, { "frasl", 0x2044 }, { "Gamma", 0x0393 }, { "gamma", 0x03B3 }, { "ge", 0x2265 }, { "gt", 0x003E }, { "hArr", 0x21D4 }, { "harr", 0x2194 }, { "hearts", 0x2665 }, { "hellip", 0x2026 }, { "Iacute", 0x00CD }, { "iacute", 0x00ED }, { "Icirc", 0x00CE }, { "icirc", 0x00EE }, { "iexcl", 0x00A1 }, { "Igrave", 0x00CC }, { "igrave", 0x00EC }, { "image", 0x2111 }, { "infin", 0x221E }, { "int", 0x222B }, { "Iota", 0x0399 }, { "iota", 0x03B9 }, { "iquest", 0x00BF }, { "isin", 0x2208 }, { "Iuml", 0x00CF }, { "iuml", 0x00EF }, { "Kappa", 0x039A }, { "kappa", 0x03BA }, { "Lambda", 0x039B }, { "lambda", 0x03BB }, { "lang", 0x2329 }, { "laquo", 0x00AB }, { "lArr", 0x21D0 }, { "larr", 0x2190 }, { "lceil", 0x2308 }, { "ldquo", 0x201C }, { "le", 0x2264 }, { "lfloor", 0x230A }, { "lowast", 0x2217 }, { "loz", 0x25CA }, { "lrm", 0x200E }, { "lsaquo", 0x2039 }, { "lsquo", 0x2018 }, { "lt", 0x003C }, { "macr", 0x00AF }, { "mdash", 0x2014 }, { "micro", 0x00B5 }, { "middot", 0x00B7 }, { "minus", 0x2212 }, { "Mu", 0x039C }, { "mu", 0x03BC }, { "nabla", 0x2207 }, { "nbsp", 0x00A0 }, { "ndash", 0x2013 }, { "ne", 0x2260 }, { "ni", 0x220B }, { "not", 0x00AC }, { "notin", 0x2209 }, { "nsub", 0x2284 }, { "Ntilde", 0x00D1 }, { "ntilde", 0x00F1 }, { "Nu", 0x039D }, { "nu", 0x03BD }, { "Oacute", 0x00D3 }, { "oacute", 0x00F3 }, { "Ocirc", 0x00D4 }, { "ocirc", 0x00F4 }, { "OElig", 0x0152 }, { "oelig", 0x0153 }, { "Ograve", 0x00D2 }, { "ograve", 0x00F2 }, { "oline", 0x203E }, { "Omega", 0x03A9 }, { "omega", 0x03C9 }, { "Omicron", 0x039F }, { "omicron", 0x03BF }, { "oplus", 0x2295 }, { "or", 0x2228 }, { "ordf", 0x00AA }, { "ordm", 0x00BA }, { "Oslash", 0x00D8 }, { "oslash", 0x00F8 }, { "Otilde", 0x00D5 }, { "otilde", 0x00F5 }, { "otimes", 0x2297 }, { "Ouml", 0x00D6 }, { "ouml", 0x00F6 }, { "para", 0x00B6 }, { "part", 0x2202 }, { "permil", 0x2030 }, { "perp", 0x22A5 }, { "Phi", 0x03A6 }, { "phi", 0x03C6 }, { "Pi", 0x03A0 }, { "pi", 0x03C0 }, { "piv", 0x03D6 }, { "plusmn", 0x00B1 }, { "pound", 0x00A3 }, { "Prime", 0x2033 }, { "prime", 0x2032 }, { "prod", 0x220F }, { "prop", 0x221D }, { "Psi", 0x03A8 }, { "psi", 0x03C8 }, { "quot", 0x0022 }, { "radic", 0x221A }, { "rang", 0x232A }, { "raquo", 0x00BB }, { "rArr", 0x21D2 }, { "rarr", 0x2192 }, { "rceil", 0x2309 }, { "rdquo", 0x201D }, { "real", 0x211C }, { "reg", 0x00AE }, { "rfloor", 0x230B }, { "Rho", 0x03A1 }, { "rho", 0x03C1 }, { "rlm", 0x200F }, { "rsaquo", 0x203A }, { "rsquo", 0x2019 }, { "sbquo", 0x201A }, { "Scaron", 0x0160 }, { "scaron", 0x0161 }, { "sdot", 0x22C5 }, { "sect", 0x00A7 }, { "shy", 0x00AD }, { "Sigma", 0x03A3 }, { "sigma", 0x03C3 }, { "sigmaf", 0x03C2 }, { "sim", 0x223C }, { "spades", 0x2660 }, { "sub", 0x2282 }, { "sube", 0x2286 }, { "sum", 0x2211 }, { "sup", 0x2283 }, { "sup1", 0x00B9 }, { "sup2", 0x00B2 }, { "sup3", 0x00B3 }, { "supe", 0x2287 }, { "szlig", 0x00DF }, { "Tau", 0x03A4 }, { "tau", 0x03C4 }, { "there4", 0x2234 }, { "Theta", 0x0398 }, { "theta", 0x03B8 }, { "thetasym", 0x03D1 }, { "thinsp", 0x2009 }, { "THORN", 0x00DE }, { "thorn", 0x00FE }, { "tilde", 0x02DC }, { "times", 0x00D7 }, { "trade", 0x2122 }, { "Uacute", 0x00DA }, { "uacute", 0x00FA }, { "uArr", 0x21D1 }, { "uarr", 0x2191 }, { "Ucirc", 0x00DB }, { "ucirc", 0x00FB }, { "Ugrave", 0x00D9 }, { "ugrave", 0x00F9 }, { "uml", 0x00A8 }, { "upsih", 0x03D2 }, { "Upsilon", 0x03A5 }, { "upsilon", 0x03C5 }, { "Uuml", 0x00DC }, { "uuml", 0x00FC }, { "weierp", 0x2118 }, { "Xi", 0x039E }, { "xi", 0x03BE }, { "Yacute", 0x00DD }, { "yacute", 0x00FD }, { "yen", 0x00A5 }, { "Yuml", 0x0178 }, { "yuml", 0x00FF }, { "Zeta", 0x0396 }, { "zeta", 0x03B6 }, { "zwj", 0x200D }, { "zwnj", 0x200C }, { NULL, '?' } }; int i; end = expand_string(ptr+1, " ;", len+str-ptr-1, fillmore); if(*end == ';') *(end++) = 0; for(i = 0;val_tab[i].name;++i) { if(strncmp(val_tab[i].name, ptr+1, end-ptr-1) == 0) break; } val = val_tab[i].val; } else { val = strtoul(ptr+2, &end, 0); if(*end == ';') ++end; if(end == ptr+2) val = '?'; } if(val <= 0x7F) { if(val > 0) *(ptr++) = val; } else if(val <= 0x7FF) { *(ptr++) = 0xC0 | (val>>6); *(ptr++) = 0x80 | (val&0x3F); } else if(val <= 0xFFFF) { *(ptr++) = 0xE0 | (val>>12); *(ptr++) = 0x80 | ((val>>6)&0x3F); *(ptr++) = 0x80 | (val&0x3F); } else if(val <= 0x10FFFF) { *(ptr++) = 0xF0 | (val>>18); *(ptr++) = 0x80 | ((val>>12)&0x3F); *(ptr++) = 0x80 | ((val>>6)&0x3F); *(ptr++) = 0x80 | (val&0x3F); } if(end != ptr) memmove(ptr, end, strlen(end)+1); continue; } } else if(*ptr == '"' || *ptr == '\'') { if(!in_quotes || in_quotes == *ptr) { in_quotes ^= *ptr; memmove(ptr, ptr+1, strlen(ptr)); continue; } } else if(*ptr == '\\') memmove(ptr, ptr+1, strlen(ptr)); if(*ptr) ++ptr; } last_pos = ptr; *(ptr++) = 0; use_hard_quotes = 0; /* Run a special command, replacing the section */ if(*ptr == '(') { char *next = NULL; char *opt; ++ptr; if(*ptr == '*') { use_hard_quotes = 1; ++ptr; } opt = expand_string(ptr, " )", len+str-ptr, fillmore); if(!(*opt) || !isspace(*opt)) { *opt = 0; fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed '%s' sub-command!\n\n", fname, curr_line, ptr); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *(opt++) = 0; opt = expand_string(opt, "!", len+str-opt, fillmore); if(use_hard_quotes) i = snprintf(buf, BUF_SIZE, "%s'", str); else i = snprintf(buf, BUF_SIZE, "%s", str); /* Replaces the section with the specified command line * option's value (in the format 'option=value') */ if(strcasecmp(ptr, "getoptval") == 0) { const char *val = ""; size_t optlen, idx; next = expand_string(opt, ")", len+str-opt, fillmore); if(*next) *(next++) = 0; optlen = strlen(opt); for(idx = 1;idx < argc;++idx) { if(strncasecmp(opt, argv[idx], optlen) == 0) { if(argv[idx][optlen] == '=') val = argv[idx]+optlen+1; else if(argv[idx][optlen] == 0) val = argv[idx+1]; else continue; break; } } snprintf(buf+i, BUF_SIZE-i, "%s", val); } else if(strcasecmp(ptr, "word") == 0) { unsigned long val; char *sep = expand_string(opt, ",)", len+str-opt, fillmore); if(*sep != ',') { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed '%s' sub-command!\n\n", fname, curr_line, ptr); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *(sep++) = 0; val = strtoul(opt, NULL, 0); opt = expand_string(sep, "!", len+str-sep, fillmore); while(1) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; next = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { next = next_word; if(*next) *(next++) = 0; if(val == 1) snprintf(buf+i, BUF_SIZE-i, "%s", opt); break; } --val; if(val == 0) { snprintf(buf+i, BUF_SIZE-i, "%s", opt); opt = next_word; next = expand_string(opt, ")", len+str-opt, fillmore); if(*next) *(next++) = 0; break; } opt = next_word; } } else if(strcasecmp(ptr, "add")==0 || strcasecmp(ptr, "sub") == 0 || strcasecmp(ptr, "mult")==0 || strcasecmp(ptr, "div") == 0) { long val1, val2; char *sep = expand_string(opt, ",)", len+str-opt, fillmore); if(*sep != ',') { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed '%s' sub-command!\n\n", fname, curr_line, ptr); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *(sep++) = 0; next = expand_string(sep, ")", len+str-sep, fillmore); if(*next) *(next++) = 0; val1 = atoi(opt); val2 = atoi(sep); if(strcasecmp(ptr, "add") == 0) val1 += val2; else if(strcasecmp(ptr, "sub") == 0) val1 -= val2; else if(strcasecmp(ptr, "mult") == 0) val1 *= val2; else if(strcasecmp(ptr, "div") == 0) { if(!val2) { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Divide-by-0 attempted!\n\n", fname, curr_line); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } val1 /= val2; } snprintf(buf+i, BUF_SIZE-i, "%ld", val1); } /* Returns a library-style name from the specified * filename */ else if(strcasecmp(ptr, "libname") == 0) { next = expand_string(opt, ")", len+str-opt, fillmore); if(*next) *(next++) = 0; libify_name(obj, sizeof(obj), opt); snprintf(buf+i, BUF_SIZE-i, "%s", obj); } /* Returns the full filename for the specified source file by * searching src_path */ else if(strcasecmp(ptr, "findsrc") == 0) { int inc = i; int loop = 1; while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", find_src(opt)); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } /* Returns the string, lower-cased */ else if(strcasecmp(ptr, "tolower") == 0) { int inc = i; next = expand_string(opt, ")", len+str-opt, fillmore); if(*next) *(next++) = 0; snprintf(buf+i, BUF_SIZE-i, "%s", opt); while(buf[inc]) { buf[inc] = tolower(buf[inc]); ++inc; } } /* Returns the string, upper-cased */ else if(strcasecmp(ptr, "toupper") == 0) { int inc = i; next = expand_string(opt, ")", len+str-opt, fillmore); if(*next) *(next++) = 0; snprintf(buf+i, BUF_SIZE-i, "%s", opt); while(buf[inc]) { buf[inc] = toupper(buf[inc]); ++inc; } } else if(strcasecmp("ifeq", ptr) == 0) { char *var2; char *val; var2 = expand_string(opt, ",)", len+str-opt, fillmore); if(*var2 != ',') { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed 'ifeq' sub-command!\n\n", fname, curr_line); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *(var2++) = 0; val = expand_string(var2, ",)", len+str-var2, fillmore); if(*val != ',') { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed 'ifeq' sub-command!\n\n", fname, curr_line); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *(val++) = 0; if(strcmp(opt, var2) == 0) { char *sep = expand_string(val, ",)", len+str-val, fillmore); if(*sep) *(sep++) = 0; next = expand_string(sep, ")", len+str-sep, fillmore); if(*next) *(next++) = 0; } else { val = expand_string(val, ",)", len+str-val, fillmore); if(*val == ',') ++val; next = expand_string(val, ")", len+str-val, fillmore); if(*next) *(next++) = 0; } if(val) snprintf(buf+i, BUF_SIZE-i, "%s", val); } else if(strcasecmp("suffix", ptr) == 0) { char *val; int inc = i; int loop = 1; while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } val = strrchr(opt, '/'); if(!val) val = opt; val = strrchr(val, '.'); if(val) inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", val); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else if(strcasecmp("basename", ptr) == 0) { char *val; int inc = i; int loop = 1; while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } val = strrchr(opt, '/'); if(!val) val = opt; val = strrchr(val, '.'); if(val) *val = 0; inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else if(strcasecmp("addprefix", ptr) == 0) { char *val; int inc = i; int loop = 1; val = opt; opt = expand_string(opt, ",)", len+str-opt, fillmore); if(*opt != ',') { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed 'addprefix' sub-command!\n\n", fname, curr_line); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *(opt++) = 0; opt = expand_string(opt, "!", len+str-opt, fillmore); while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", val, opt); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else if(strcasecmp("addsuffix", ptr) == 0) { char *val; int inc = i; int loop = 1; val = opt; opt = expand_string(opt, ",)", len+str-opt, fillmore); if(*opt != ',') { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed 'addprefix' sub-command!\n\n", fname, curr_line); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } *(opt++) = 0; opt = expand_string(opt, "!", len+str-opt, fillmore); while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", opt, val); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else if(strcasecmp("join", ptr) == 0) { int inc = i; size_t p; DECL_LIST(char*, words); do { char *next_word = expand_string(opt, " ,)", len+str-opt, fillmore); if(*next_word == ')') { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Malformed 'join' sub-command!\n\n", fname, curr_line); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } RESIZE_LIST(words, words_size+1); if(*next_word == ',') { *(next_word++) = 0; words[words_size-1] = opt; opt = expand_string(next_word, "!", len+str-next_word, fillmore); break; } *(next_word++) = 0; words[words_size-1] = opt; opt = expand_string(next_word, "!", len+str-next_word, fillmore); if(*opt == ',') { ++opt; break; } } while(1); opt = expand_string(opt, "!", len+str-opt, fillmore); p = 0; do { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(*next_word == ')') { *(next_word++) = 0; if(p < words_size || *opt) { inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", ((p i) buf[inc-1] = 0; CLEAR_LIST(words); next = opt; } else if(strcasecmp("dir", ptr) == 0) { char *val; int inc = i; int loop = 1; while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } val = strrchr(opt, '/'); if(val) { val[1] = 0; inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt); } else inc += snprintf(buf+inc, BUF_SIZE-inc, "./ "); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else if(strcasecmp("notdir", ptr) == 0) { char *val; int inc = i; int loop = 1; while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } val = strrchr(opt, '/'); if(!val) val = opt; else ++val; opt = next_word; if(val[0]) inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", val); } if(inc > i) buf[inc-1] = 0; next = opt; } /* Finds an executable command by searching the PATH and returns the full absolute path plus the filename, or an empty string if it can't be found */ else if(strcasecmp(ptr, "which") == 0) { char *path = strdup(getvar("PATH")); char *direc; char sep = ':'; next = expand_string(opt, ")", len+str-opt, fillmore); if(*next) *(next++) = 0; if(strchr(path, ';') != NULL || (tolower(path[0]) >= 'a' && tolower(path[0]) <= 'z' && path[1] == ':')) sep = ';'; if(*opt) { direc = path; while(direc && *direc) { struct stat statbuf; char *slash; char *next = strchr(direc, sep); if(next) *(next++) = 0; snprintf(buf+i, BUF_SIZE-i, "%s/%s", direc, opt); while((slash=strchr(buf+i, '\\')) != NULL) *slash = '/'; if(stat(buf+i, &statbuf) == 0) break; buf[i] = 0; direc = next; } } free(path); } else if(strcasecmp("ls", ptr) == 0 || strcasecmp("lsa", ptr) == 0) { struct stat st; int inc = i; int show_hidden = 0; int loop = 1; if(strcasecmp("lsa", ptr) == 0) show_hidden = 1; while(loop) { DIR *dp; char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } dp = opendir(opt); if(dp) { struct dirent *ent; char *slash = strrchr(opt, '/'); if(slash && !slash[1]) *slash = 0; while((ent=readdir(dp)) != NULL) { int i; if(!show_hidden && ent->d_name[0] == '.') continue; i = snprintf(buf+inc, BUF_SIZE-inc, "%s/%s", opt, ent->d_name); if(stat(buf+inc, &st) == 0 && S_ISDIR(st.st_mode)) i += snprintf(buf+inc+i, BUF_SIZE-inc-i, "/ "); else i += snprintf(buf+inc+i, BUF_SIZE-inc-i, " "); inc += i; } closedir(dp); } else { if(show_hidden || opt[0] != '.') { if(stat(opt, &st) == 0) inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt); } } opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else if(strcasecmp("isdir", ptr) == 0) { struct stat st; int inc = i; int loop = 1; while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } if(stat(opt, &st) == 0 && S_ISDIR(st.st_mode)) inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else if(strcasecmp("isfile", ptr) == 0) { struct stat st; int inc = i; int loop = 1; while(loop) { char *next_word = expand_string(opt, " )", len+str-opt, fillmore); if(next_word == opt) { if(isspace(*opt)) { opt = expand_string(opt, "!", len+str-opt, fillmore); continue; } *(next_word++) = 0; opt = next_word; break; } if(isspace(*next_word)) { *(next_word++) = 0; next_word = expand_string(next_word, "!", len+str-next_word, fillmore); } else { *(next_word++) = 0; loop = 0; } if(stat(opt, &st) == 0 && !S_ISDIR(st.st_mode)) inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt); opt = next_word; } if(inc > i) buf[inc-1] = 0; next = opt; } else { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Unknown sub-command '%s'\n\n", fname, curr_line, ptr); free(buf); strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } end = next; } else { /* Insert the named environment var (in the form $FOO or ${FOO}) */ if(*ptr == '{') { ++ptr; if(*ptr == '\'') { use_hard_quotes = 1; ++ptr; end = "'}"; } else end = "}"; end = expand_string(ptr, end, len+str-ptr, fillmore); if(*end == '\'') { *(end++) = 0; end = expand_string(end, "}", len+str-ptr, fillmore); } if(*end) *(end++) = 0; } else end = expand_string(ptr, "^", len+str-ptr, fillmore); if(use_hard_quotes) i = snprintf(buf, BUF_SIZE, "%s'", str); else i = snprintf(buf, BUF_SIZE, "%s", str); if(*ptr >= '0' && *ptr <= '9') { const char *val = ""; size_t idx = atoi(ptr); if(idx < argc) val = argv[idx]; snprintf(buf+i, BUF_SIZE-i, "%s", val); } else if(*ptr == '*' || (use_hard_quotes && *ptr == '@')) { size_t idx = ((ptr+1 >= end || !ptr[1]) ? 1 : atoi(ptr+1)); int inc = i; while(idx < argc) { inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", argv[idx]); ++idx; } if(inc > i) buf[inc-1] = 0; } else if(*ptr == '@') { size_t idx = ((ptr+1 >= end || !ptr[1]) ? 1 : atoi(ptr+1)); while(idx < argc) { i += snprintf(buf+i, BUF_SIZE-i, "${'%u'}", (unsigned int)idx); ++idx; if(idx < argc) i += snprintf(buf+i, BUF_SIZE-i, " "); } snprintf(buf+i, BUF_SIZE-i, "%s", end); strcpy(str, buf); continue; } else { char c = *end; *end = 0; snprintf(buf+i, BUF_SIZE-i, "%s", getvar(ptr)); *end = c; } } while(buf[i]) { if(buf[i] == '&' || buf[i] == '\'' || buf[i] == '"' || buf[i] == '\\' || buf[i] == '#') { memmove(buf+i+1, buf+i, BUF_SIZE-i-1); buf[i] = '\\'; ++i; } ++i; } if(use_hard_quotes) snprintf(buf+i, BUF_SIZE-i, "'%s", end); else snprintf(buf+i, BUF_SIZE-i, "%s", end); strcpy(str, buf); } while(1); } /* extract_word: Extract a word starting at the string pointed to by 'str'. If * the word begins with a ' or " character, everything until that same * character will be considered part of the word. Otherwise, the word ends at * the first encountered whitespace. Returns the beginning of the next word, * or the end of the string. */ static char *extract_word(char *str, size_t len) { char *end = str; if(!(*end)) return end; end = expand_string(end, " \n", len+str-end, 1); if(*end && *end != '\n') *(end++) = 0; if(*end != '\n') end = expand_string(end, "!\n", len+str-end, 1); if(*end == '\n') { if(end[1] != 0) nextline = strdup(end+1); *end = 0; } return end; } static void extract_line(char *str, size_t len) { char *end = str; if(!(*end)) return; end = expand_string(end, "\n", len+str-end, 1); if(end[0] == '\n' && end[1] != 0) nextline = strdup(end+1); *end = 0; } /* check_obj_deps: Checks a file's dependancy list. The dependancy file is a * file expected to be in dep_dir and with the same name, but with a different * extension. The format of the file is simply: 'file.o: dependancy list...'. A * '\' at the end of the line can be used as a next-line continuation. If the * dependancy file exists, none of the dependancies are missing, and none have * a modification time after 'obj_time', the function will return 0. Otherwise * 1 is returned denoting a rebuild may be required. */ static int check_obj_deps(char *base, char *src, time_t obj_time) { static char dep[PATH_MAX]; char *buf; int bufsize; struct stat statbuf; char *ptr = obj; FILE *df; ptr = strrchr(base, '/'); if(!ptr) ptr = base; ptr = strrchr(ptr, '.'); if(ptr) *ptr = 0; snprintf(dep, sizeof(dep), "${DEP_DIR}/'%s'${DEP_EXT}", base); expand_string(dep, "", sizeof(dep), 0); if(ptr) *ptr = '.'; df = fopen(dep, "r"); if(!df) { if(stat(src, &statbuf) != 0 || statbuf.st_mtime-obj_time > 0) return 1; return 0; } fseek(df, 0, SEEK_END); bufsize = ftell(df)+1; buf = malloc(bufsize); if(!buf) { fclose(df); return 1; } fseek(df, 0, SEEK_SET); bufsize = fread(buf, 1, bufsize, df); if(bufsize >= 0) buf[bufsize] = 0; fclose(df); ptr = strchr(buf, ':'); if(!ptr) { free(buf); return 1; } ++ptr; while(*ptr && *ptr != '\n' && isspace(*ptr)) ++ptr; while(*ptr) { char *stp = ptr; while(*stp && !isspace(*stp)) { if(*stp == '\\') memmove(stp, stp+1, strlen(stp)); if(*stp) ++stp; } if(*stp) *(stp++) = 0; while(*stp && isspace(*stp)) ++stp; if(strcmp(ptr, "\n") != 0 && (stat(ptr, &statbuf) != 0 || statbuf.st_mtime > obj_time)) { free(buf); return 1; } ptr = stp; } free(buf); buf = (char*)getvar("EXTRA_SRC_DEPS"); if(*buf) { char *ptr = malloc(BUF_SIZE); strncpy(ptr, buf, BUF_SIZE); buf = ptr; while(*ptr) { char *next = expand_string(ptr, " ", BUF_SIZE+buf-ptr, 0); if(*next) *(next++) = 0; next = expand_string(next, "!", BUF_SIZE+buf-next, 0); if(stat(ptr, &statbuf) != 0 || statbuf.st_mtime > obj_time) { free(buf); return 1; } ptr = next; } free(buf); } return 0; } /* copy_file: Copies the source file 'sf' to 'df', preserving the source's * file mode and permissions, if possible. */ static int copy_file(const char *sf, const char *df) { struct stat statbuf; FILE *src, *dst; int ret, i; int fd; if(stat(sf, &statbuf) != 0) return 1; #ifdef O_BINARY fd = open(df, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, statbuf.st_mode); #else fd = open(df, O_WRONLY|O_TRUNC|O_CREAT, statbuf.st_mode); #endif if(fd < 0) return 1; dst = fdopen(fd, "wb"); if(!dst) { close(fd); return 1; } src = fopen(sf, "rb"); if(!src) { fclose(dst); return 1; } ret = 0; do { i = fread(buffer, 1, sizeof(buffer), src); if(i > 0) i = fwrite(buffer, 1, i, dst); if(i < 0) ret = 1; } while(i > 0); fclose(src); fclose(dst); return ret; } static int libify_name(char *buf, size_t buflen, char *name) { int i; char *curr = strrchr(name, '/'); if(curr) { *curr = 0; i = snprintf(buf, buflen, "'%s'/${LIB_PRE}'%s'${LIB_EXT}", name, curr+1); *curr = '/'; } else i = snprintf(buf, buflen, "${LIB_PRE}'%s'${LIB_EXT}", name); expand_string(buf, "", buflen, 0); return i; } typedef struct { char *ext; char *cmd; } ASSOC; DECL_LIST(static ASSOC, associations); static void add_association(const char *ext, const char *cmd) { size_t i; for(i = 0;i < associations_size;++i) { if(associations[i].cmd[0] == 0 || strcasecmp(ext, associations[i].ext) == 0) break; } if(i == associations_size) { RESIZE_LIST(associations, i+1); associations[i].ext = NULL; associations[i].cmd = NULL; } free(associations[i].ext); free(associations[i].cmd); associations[i].ext = strdup(ext); associations[i].cmd = strdup(cmd); if(!associations[i].ext || !associations[i].cmd) { strcpy(linebuf, "exit -1\n"); longjmp(jmpbuf, 1); } } static int build_command(char *buffer, size_t bufsize, char *barename, const char *srcname, const char *objname) { char dummy[2] = "."; const char *ptr; char *ext; size_t i; ext = strrchr(barename, '.'); if(strchr(ext, '/') || !ext) ext = dummy; for(i = 0;i < associations_size;++i) { if(strcasecmp(ext+1, associations[i].ext) == 0) break; } if(i == associations_size) return 1; ptr = associations[i].cmd; i = 0; while(*ptr && i+1 < bufsize) { if(strncasecmp(ptr, "<*>", 3) == 0) { *ext = 0; i += snprintf(buffer+i, bufsize-i, "'%s'", barename); *ext = '.'; ptr += 3; } else if(strncasecmp(ptr, "", 3) == 0) { i += snprintf(buffer+i, bufsize-i, "'%s'", srcname); ptr += 3; } else if(strncasecmp(ptr, "<@>", 3) == 0) { i += snprintf(buffer+i, bufsize-i, "'%s'", objname); ptr += 3; } else { if(ptr[0] == '\\' && ptr[1] != 0 && i+2 < bufsize) ptr++; buffer[i++] = *(ptr++); buffer[i] = 0; } } return 0; } /* build_obj_list: Builds a list of object files from the list of sources. If * any of the objects don't exist or have a modification time later than * 'base_time', the variable pointed to by 'do_link' will be set non-zero. */ static int build_obj_list(char *buffer, size_t bufsize, time_t base_time, int *do_link) { static char buf[PATH_MAX]; struct stat statbuf; char *ptr; int i = 0; size_t p; for(p = 0;p < sources_size;++p) { char *ext; ptr = sources[p]; ext = strrchr(ptr, '/'); if(!ext) ext = ptr; ext = strrchr(ext, '.'); if(ext) *ext = 0; snprintf(buf, sizeof(buf), "${OBJ_DIR}/'%s'${OBJ_EXT}", ptr); expand_string(buf, "", sizeof(buf), 0); if(ext) *ext = '.'; if(!(*do_link) && (stat(buf, &statbuf) != 0 || base_time < statbuf.st_mtime)) *do_link = 1; if(ext) *ext = 0; i += snprintf(buffer+i, bufsize-i, " \\\"${OBJ_DIR}/'%s'${OBJ_EXT}\\\"", ptr); if(ext) *ext = '.'; } return i; } void cleanup(void) { size_t i; fflush(stdout); for(i = 1;i < arg_backup_size;++i) { size_t i2; argv = arg_backup[i].argv; for(i2 = 0;i2 < arg_backup[i].argc;++i2) free(argv[i2]); CLEAR_LIST(argv); } CLEAR_LIST(arg_backup); for(i = 0;i < defines_size;++i) { free(defines[i].name); free(defines[i].val); } CLEAR_LIST(defines); for(i = 0;i < src_paths_size;++i) free(src_paths[i]); CLEAR_LIST(src_paths); for(i = 0;i < invoke_backup_size;++i) { fclose(invoke_backup[i].f); free(invoke_backup[i].fname); free(invoke_backup[i].bkp_lbuf); free(invoke_backup[i].bkp_nextline); } CLEAR_LIST(invoke_backup); for(i = 0;i < associations_size;++i) { free(associations[i].ext); free(associations[i].cmd); } CLEAR_LIST(associations); for(i = 0;i < sources_size;++i) free(sources[i]); CLEAR_LIST(sources); for(i = 0;i < loaded_files_size;++i) free(loaded_files[i]); CLEAR_LIST(loaded_files); free(nextline); nextline = NULL; free(fname); fname = NULL; if(f) fclose(f); f = NULL; } unsigned int do_level = 0; unsigned int did_cmds = 0, did_else = 0; unsigned int wait_for_done = 0; int ret = 0, tmp = 0; int ignored_errors = 0; int verbose = 0; int shh = 0; int ignore_err = 0; int has_do = 0; int main(int _argc, char **_argv) { char *ptr; int i; setenv("CC", "gcc", 0); setenv("CXX", "g++", 0); setenv("LD", "gcc", 0); setenv("OUT_OPT", "-o ", 0); setenv("SRC_OPT", "-c ", 0); setenv("DEP_OPT", "-MMD -MF ", 0); setenv("OBJ_EXT", ".o", 0); setenv("OBJ_DIR", ".", 0); setenv("DEP_EXT", ".d", 0); setenv("DEP_DIR", ".", 0); #if (defined __WIN32__ || defined __DOS__) setenv("EXE_EXT", ".exe", 0); #else setenv("EXE_EXT", "", 0); #endif setenv("AR", "ar", 0); setenv("AR_OPT", "", 0); setenv("LIB_PRE", "lib", 0); setenv("LIB_EXT", ".a", 0); setenv("CPPFLAGS", "", 0); setenv("CFLAGS", "", 0); setenv("CXXFLAGS", "", 0); setenv("LDFLAGS", "", 0); atexit(cleanup); /* Check to see if there may be a user-specified script to open */ if(_argc > 1) { char *ext = strrchr(_argv[1], '.'); /* Only files with the .cbd extension are allowed (to reduce chances of * accidently swiping filenames a script may want) */ if(ext && strcasecmp(ext, ".cbd") == 0) { fname = strdup(_argv[1]); f = fopen(fname, "r"); if(!f) { fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n" "Could not open %s!\n\n", fname); exit(1); } i = 1; while((_argv[i]=_argv[i+1]) != NULL) ++i; --_argc; } } /* Open the default file */ if(!fname) { fname = strdup("default.cbd"); f = fopen(fname, "r"); if(!f) { fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n" "Could not open %s!\n\n", fname); exit(1); } } setvbuf(stdin, NULL, _IOLBF, 0); argc = _argc; argv = _argv; if(setjmp(jmpbuf)) { free(nextline); nextline = NULL; goto reparse; } main_loop_start: while(1) { int reverse; ignore_err = 0; has_do = 0; if(nextline) { /* If we already have the next line set, go do it */ strncpy(linebuf, nextline, strlen(nextline)+1); free(nextline); nextline = NULL; goto reparse; } /* Grab the next line and increment the line count */ if(fgets(linebuf, sizeof(linebuf), f) == NULL) { /* If end of file, implicitly uninvoke and continue */ snprintf(linebuf, sizeof(linebuf), "uninvoke 0\n"); if(do_level > 0) { fprintf(USEABLE_ERR, "\n\n!!! %s error !!!\n" "Unbalanced do/done pair!\n\n", fname); wait_for_done = 0; did_else = 0; did_cmds = 0; do_level = 0; } goto reparse; } ++curr_line; reparse: reverse = 0; shh = 0; /* Chew up leading whitespace */ ptr = expand_string(linebuf, "!", sizeof(linebuf), 1); if(!*ptr) continue; if(ptr > linebuf) memmove(linebuf, ptr, strlen(ptr)+1); ptr = expand_string(linebuf, " =\n", sizeof(linebuf), 1); if(!linebuf[0] || ptr == linebuf || linebuf[0] == ':') { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); continue; } if(isspace(*ptr)) { if(*ptr != '\n') { *(ptr++) = 0; ptr = expand_string(ptr, "!\n", sizeof(linebuf)+linebuf-ptr, 1); } if(*ptr == '\n') { *ptr = 0; if(ptr[1] != 0) nextline = strdup(ptr+1); } } /* Check for special 'leveling' commands */ /* The 'do' command pushes us up a level, and checks for the next * if-type command, which itself will let us know if we should start * ignoring commands */ if(strcasecmp("do", linebuf) == 0) { ++do_level; if(do_level >= sizeof(int)*8) { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Too many 'do' commands enountered (max: %u)!\n\n", fname, curr_line, (unsigned int)sizeof(int)*8 - 1); snprintf(linebuf, sizeof(linebuf), "exit -1\n"); goto reparse; } if(!*ptr) continue; has_do = 1; memmove(linebuf, ptr, strlen(ptr)+1); goto reparse; } /* 'else' toggles ignoring commands at the current level */ if(strcasecmp("else", linebuf) == 0) { if(do_level <= 0) do_level = 1; /* allow another if-type command to follow an else on the same * level */ if(!(wait_for_done & (1<<(do_level-1)))) { wait_for_done |= 1<<(do_level-1); did_cmds |= 1<<(do_level-1); has_do = 0; } if(!(did_cmds & (1<<(do_level-1)))) { wait_for_done &= ~(1<<(do_level-1)); has_do = 1; } if(!*ptr) continue; memmove(linebuf, ptr, strlen(ptr)+1); goto reparse; } /* 'done' takes us down a level */ if(strcasecmp("done", linebuf) == 0) { if(do_level > 0) { wait_for_done &= ~(1<<(--do_level)); did_else &= ~(1< 300) else if(strcasecmp("i386", ptr) == 0) pass = 1; #endif #if defined(__ia64__) || defined(_M_IA64) else if(strcasecmp("ia64", ptr) == 0) pass = 1; #endif #if defined(__powerpc__) || defined(_M_PPC) else if(strcasecmp("powerpc", ptr) == 0) pass = 1; #endif #if defined(__sparc__) || defined(__sparc) else if(strcasecmp("sparc", ptr) == 0) pass = 1; #endif if((pass != 0) != !!reverse) { memmove(linebuf, next, strlen(next)+1); goto reparse; } if(has_do) wait_for_done |= 1 << (do_level-1); extract_line(next, sizeof(linebuf)+linebuf-next); continue; } if(strcasecmp("ifnplat", linebuf) == 0) { reverse = 1; goto platform_check; } /* Checks if the supplied option name was specified on the command * line */ if(strcasecmp("ifopt", linebuf) == 0) option_check: { char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); int pass = 0; size_t i; for(i = 1;i < argc;++i) { size_t len = strlen(ptr); char *eq = strrchr(argv[i], '='); if(eq && (size_t)(eq-argv[i]) != len) continue; if(strncasecmp(ptr, argv[i], len) == 0) { pass = 1; break; } } if((pass != 0) != !!reverse) { memmove(linebuf, next, strlen(next)+1); goto reparse; } if(has_do) wait_for_done |= 1 << (do_level-1); extract_line(next, sizeof(linebuf)+linebuf-next); continue; } if(strcasecmp("ifnopt", linebuf) == 0) { reverse = 1; goto option_check; } /* Checks if a file or directory exists */ if(strcasecmp("ifexist", linebuf) == 0) file_dir_check: { struct stat statbuf; char *next; next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if((stat(ptr, &statbuf) == 0) != !!reverse) { memmove(linebuf, next, strlen(next)+1); goto reparse; } if(has_do) wait_for_done |= 1 << (do_level-1); extract_line(next, sizeof(linebuf)+linebuf-next); continue; } if(strcasecmp("ifnexist", linebuf) == 0) { reverse = 1; goto file_dir_check; } /* Checks if we have write permissions to the specified file or * directory */ if(strcasecmp("ifwrite", linebuf) == 0) dir_write_check: { char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); int val = 1; #ifdef __unix__ { struct stat stbuf; val = 0; if(stat(ptr, &stbuf) == 0) { if(stbuf.st_uid == getuid()) { if((stbuf.st_mode&S_IWUSR)) val = 1; } else if(stbuf.st_gid == getgid()) { if((stbuf.st_mode&S_IWGRP)) val = 1; } else if((stbuf.st_mode&S_IWOTH)) val = 1; } } #endif if((val != 0) != !!reverse) { memmove(linebuf, next, strlen(next)+1); goto reparse; } if(has_do) wait_for_done |= 1 << (do_level-1); extract_line(next, sizeof(linebuf)+linebuf-next); continue; } if(strcasecmp("ifnwrite", linebuf) == 0) { reverse = 1; goto dir_write_check; } /* Set an environment variable. The value is space sensitive, so if you * wish to use spaces, encapsulate the value in ''s. Using '?=' instead * of '=' will only set the variable if it isn't already set. */ if(strncmp(ptr, "+=", 2) == 0 || strncmp(ptr, "-=", 2) == 0 || strncmp(ptr, "?=", 2) == 0 || ptr[0] == '=') { char *val = ptr; int ovr = 1; if(val[0] != '=') ++val; ptr = linebuf; buffer[0] = 0; if(*(val-1) == '+') { int i; *(val-1) = 0; if(isspace(*(++val))) val = extract_word(val, sizeof(linebuf)+linebuf-val); i = snprintf(buffer, sizeof(buffer), "%s", getvar(ptr)); if(*val) { do { char *next_word = extract_word(val, sizeof(linebuf)+ linebuf-val); i += snprintf(buffer+i, sizeof(buffer)-i, "%s ", val); val = next_word; } while(*val); if(i > 0) buffer[i-1] = 0; } setenv(ptr, buffer, 1); continue; } if(*(val-1) == '-') { char *pos; int len; *(val-1) = 0; if(isspace(*(++val))) val = extract_word(val, sizeof(linebuf)+linebuf-val); extract_line(val, sizeof(linebuf)+linebuf-val); len = strlen(val); if(len <= 0) continue; snprintf(buffer, sizeof(buffer), "%s", getvar(ptr)); while((pos=strstr(buffer, val)) != NULL) { int len = strlen(val); memmove(pos, pos+len, strlen(pos+len)+1); } setenv(ptr, buffer, 1); continue; } if(*(val-1) == '?') { *(val-1) = 0; if(*getvar(ptr)) ovr = 0; } *(val++) = 0; if(isspace(*val)) val = extract_word(val, sizeof(linebuf)+linebuf-val); if(*val) { int i = 0; do { char *next_word = extract_word(val, sizeof(linebuf)+ linebuf-val); i += snprintf(buffer+i, sizeof(buffer)-i, "%s ", val); val = next_word; } while(*val); if(i > 0) buffer[i-1] = 0; } if(buffer[0]) setenv(ptr, buffer, ovr); else if(ovr) unsetenv(ptr); continue; } /* Reset the return value and 'do' status */ has_do = 0; // ret = 0; /* Don't display normal output */ if(linebuf[0] == '@') { shh = 1; memmove(linebuf, linebuf+1, strlen(linebuf)); } /* Set error suppression level */ if(linebuf[0] == '!') { ignore_err = 2; memmove(linebuf, linebuf+1, strlen(linebuf)); } else if(linebuf[0] == '-') { ignore_err = 1; memmove(linebuf, linebuf+1, strlen(linebuf)); } /* Call an external program via the system() function. Parameters are * passed along as-is. */ if(strcasecmp("call", linebuf) == 0) { unsigned int i = 0; char *wrd = ptr; while(*wrd) { char *next = extract_word(wrd, linebuf+sizeof(linebuf)-wrd); #define CHARS_TO_ESC "\\\"%$" #define CHARS_TO_QUOTE "' \t\n()[]<>;&|" if(strpbrk(wrd, CHARS_TO_ESC)) { while(*wrd) { if(strchr(CHARS_TO_ESC CHARS_TO_QUOTE, *wrd) && i < sizeof(buffer)-2) buffer[i++] = '\\'; if(i < sizeof(buffer)-1) buffer[i++] = *(wrd++); } if(i < sizeof(buffer)-1) buffer[i++] = ' '; buffer[i] = 0; } else if(strpbrk(wrd, CHARS_TO_QUOTE)) i += snprintf(buffer+i, sizeof(buffer)-i, "\"%s\" ", wrd); else i += snprintf(buffer+i, sizeof(buffer)-i, "%s ", wrd); wrd = next; } if(i > 0) buffer[i-1] = 0; if(!shh) { printf("%s\n", buffer); fflush(stdout); } ret = system(buffer); if(WIFEXITED(ret)) ret = WEXITSTATUS(ret); else ret = -1; if(ret != 0) { if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) { printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } continue; } /* Invokes an alternate script within the same context, and returns * control when it exits. All variables and command-line options will * persists into and out of invoked scripts. Errors and exit calls will * cause all scripts to abort. To safely exit from an invoked script * before the end of the file, and continue the previous, use * 'uninvoke' */ if(strcasecmp("invoke", linebuf) == 0) { size_t i; FILE *f2; char *fname2; extract_line(ptr, sizeof(linebuf)+linebuf-ptr); f2 = f; fname2 = fname; f = fopen(ptr, "r"); if(!f) { f = f2; ret = 1; if(ignore_err < 2) printf("Could not open script '%s'!\n", ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; fname = strdup(ptr); i = invoke_backup_size; RESIZE_LIST(invoke_backup, i+1); invoke_backup[i].f = f2; invoke_backup[i].fname = fname2; invoke_backup[i].bkp_lbuf = strdup(linebuf); invoke_backup[i].bkp_nextline = nextline; invoke_backup[i].bkp_line = curr_line; invoke_backup[i].bkp_did_else = did_else; invoke_backup[i].bkp_did_cmds = did_cmds; invoke_backup[i].bkp_do_level = do_level; nextline = NULL; curr_line = 0; did_else = 0; did_cmds = 0; do_level = 0; continue; } if(strcasecmp(linebuf, "popfront") == 0) { char *front_word; char *varstr; char *next; next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_word(next, sizeof(linebuf)+linebuf-next); varstr = malloc(65536); if(!varstr) { snprintf(linebuf, sizeof(linebuf), "exit -1\n"); goto reparse; } strncpy(varstr, getvar(ptr), 65536); front_word = varstr; while(*varstr && isspace(*varstr)) ++varstr; if(front_word != varstr) memmove(front_word, varstr, strlen(varstr)+1); varstr = expand_string(front_word, " ", 65536, 0); while(isspace(*varstr)) ++varstr; setenv(ptr, varstr, 1); free(front_word); continue; } if(strcasecmp("define", linebuf) == 0) { char *val = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_line(val, sizeof(linebuf)+linebuf-val); if(*val == 0) { for(i = 0;(size_t)i < defines_size;++i) { if(strcasecmp(ptr, defines[i].name) != 0) continue; free(defines[i].name); free(defines[i].val); if((size_t)i < defines_size) memmove(&defines[i], &defines[i+1], sizeof(defines[0])* (defines_size-i-1)); RESIZE_LIST(defines, defines_size-1); break; } } else { for(i = 0;(size_t)i < defines_size;++i) { if(strcasecmp(ptr, defines[i].name) == 0) break; } if((size_t)i == defines_size) { RESIZE_LIST(defines, i+1); defines[i].val = NULL; defines[i].name = strdup(ptr); if(!defines[i].name) { fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n" "Out of memory duplicating string " "'%s'!!\n\n", ptr); snprintf(linebuf, sizeof(linebuf), "exit -1\n"); goto reparse; } } free(defines[i].val); defines[i].val = strdup(val); if(!defines[i].val) { fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n" "Out of memory duplicating string " "'%s'!!\n\n", val); snprintf(linebuf, sizeof(linebuf), "exit -1\n"); goto reparse; } } continue; } /* Compiles a list of source files, and stores them in a list to be * linked later. Compiled files are placed in the 'OBJ_DIR' with the * extension changed to 'OBJ_EXT'. C and C++ files are compiled by the * programs stored in 'CC' and 'CXX' respectively, using the flags * stored in 'CPPFLAGS', 'CFLAGS', and 'CXXFLAGS' as expected. Unknown * file types are silently ignored. */ if(strcasecmp("compile", linebuf) == 0) { size_t i; for(i = 0;i < sources_size;++i) free(sources[i]); CLEAR_LIST(sources); goto compile_more_sources; } /* Adds more source files to the list, and compiles them as above */ if(strcasecmp("compileadd", linebuf) == 0) { compile_more_sources: tmp = 0; while(*ptr) { char *src, *ext, *next; struct stat statbuf; next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); RESIZE_LIST(sources, sources_size+1); sources[sources_size-1] = strdup(ptr); ext = strrchr(ptr, '/'); if(!ext) ext = ptr; ext = strrchr(ext, '.'); if(!ext) goto next_src_file; *ext = 0; snprintf(obj, sizeof(obj), "${OBJ_DIR}/'%s'${OBJ_EXT}", ptr); expand_string(obj, "", sizeof(obj), 0); *ext = '.'; src = find_src(ptr); if(stat(obj, &statbuf) == 0) { if(!check_obj_deps(ptr, src, statbuf.st_mtime)) goto next_src_file; } i = 0; if(build_command(buffer, sizeof(buffer), ptr, src, obj) == 0) goto compile_it; if(strcasecmp(ext+1, "c") == 0) i += snprintf(buffer+i, sizeof(buffer)-i, "${CC} ${CPPFLAGS} ${CFLAGS}"); else if(strcasecmp(ext+1, "cc") == 0 || strcasecmp(ext+1, "cpp") == 0 || strcasecmp(ext+1, "cxx") == 0) i += snprintf(buffer+i, sizeof(buffer)-i, "${CXX} ${CPPFLAGS} ${CXXFLAGS}"); else goto next_src_file; *ext = 0; if(*getvar("DEP_OPT")) i += snprintf(buffer+i, sizeof(buffer)-i, " ${DEP_OPT}\\\"${DEP_DIR}/'%s'${DEP_EXT}\\\"", ptr); i += snprintf(buffer+i, sizeof(buffer)-i, " ${OUT_OPT}\\\"${OBJ_DIR}/'%s'${OBJ_EXT}\\\"", ptr); *ext = '.'; i += snprintf(buffer+i, sizeof(buffer)-i, " ${SRC_OPT}'\"%s\"'", src); compile_it: expand_string(buffer, "", sizeof(buffer), 0); if(!shh) { if(verbose) printf("%s\n", buffer); else printf("Compiling %s...\n", src); fflush(stdout); } ret = system(buffer); if(WIFEXITED(ret)) ret = WEXITSTATUS(ret); else ret = -1; if(ret != 0) { tmp = ret; if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) { printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } next_src_file: ptr = next; } ret = tmp; continue; } /* Links an executable file, using the previously-compiled source * files. The executable will have 'EXE_EXT' appended. */ if(strcasecmp("linkexec", linebuf) == 0) { struct stat statbuf; time_t exe_time = 0; int do_link = 1; if(sources_size == 0) { ret = 1; if(ignore_err < 2) printf("\n!!! %s error, line %d !!!\n" "Trying to build %s with undefined sources!\n\n", fname, curr_line, ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; extract_line(ptr, sizeof(linebuf)+linebuf-ptr); snprintf(obj, sizeof(obj), "'%s'${EXE_EXT}", ptr); expand_string(obj, "", sizeof(obj), 0); if(stat(obj, &statbuf) == 0) { exe_time = statbuf.st_mtime; do_link = 0; } i = 0; i += snprintf(buffer+i, sizeof(buffer)-i, "${LD}"); i += snprintf(buffer+i, sizeof(buffer)-i, " ${OUT_OPT}'\"%s\"'", obj); i += build_obj_list(buffer+i, sizeof(buffer)-i, exe_time, &do_link); if(!do_link) { char *buf = (char*)getvar("EXTRA_LD_DEPS"); if(*buf) { char *ptr = malloc(BUF_SIZE); strncpy(ptr, buf, BUF_SIZE); buf = ptr; while(*ptr) { char *next = expand_string(ptr, " ", BUF_SIZE+ptr-buf, 0); if(*next) *(next++) = 0; next = expand_string(next, "!", BUF_SIZE+ptr-next, 0); if(stat(ptr, &statbuf) != 0 || statbuf.st_mtime > exe_time) { free(buf); buf = NULL; do_link = 1; break; } ptr = next; } free(buf); } if(!do_link) continue; } i += snprintf(buffer+i, sizeof(buffer)-i, " ${LDFLAGS}"); expand_string(buffer, "", sizeof(buffer), 0); if(!shh) { if(verbose) printf("%s\n", buffer); else printf("Linking %s...\n", obj); fflush(stdout); } ret = system(buffer); if(WIFEXITED(ret)) ret = WEXITSTATUS(ret); else ret = -1; if(ret != 0) { if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) { printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } continue; } /* Links a standard archive library, using the previously-compiled * source files. The file will have 'LIB_PRE' prepended, and is * sub-directory-aware, as well as have 'LIB_EXT' appended. */ if(strcasecmp("linklib", linebuf) == 0) { struct stat statbuf; time_t lib_time = 0; int do_link = 1; if(sources_size == 0) { ret = 1; if(ignore_err < 2) printf("!!! %s error, line %d !!!\n" "Trying to build %s with undefined sources!\n", fname, curr_line, ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; extract_line(ptr, sizeof(linebuf)+linebuf-ptr); libify_name(obj, sizeof(obj), ptr); if(stat(obj, &statbuf) == 0) { lib_time = statbuf.st_mtime; do_link = 0; } i = 0; i += snprintf(buffer+i, sizeof(buffer)-i, "${AR} ${AR_OPT}"); i += snprintf(buffer+i, sizeof(buffer)-i, " '\"%s\"'", obj); i += build_obj_list(buffer+i, sizeof(buffer)-i, lib_time, &do_link); if(!do_link) continue; remove(obj); expand_string(buffer, "", sizeof(buffer), 0); if(!shh) { if(verbose) printf("%s\n", buffer); else printf("Linking %s...\n", obj); fflush(stdout); } ret = system(buffer); if(WIFEXITED(ret)) ret = WEXITSTATUS(ret); else ret = -1; if(ret != 0) { if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) { printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } continue; } /* Loads a list of words into a buffer, to later execute an action on * them */ if(strcasecmp("loadlist", linebuf) == 0) { size_t i; for(i = 0;i < loaded_files_size;++i) free(loaded_files[i]); CLEAR_LIST(loaded_files); while(*ptr) { char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); i = loaded_files_size; RESIZE_LIST(loaded_files, i+1); loaded_files[i] = strdup(ptr); ptr = next; } continue; } /* Executes a command on the loaded file list */ if(strcasecmp("execlist", linebuf) == 0) { size_t p = 0; if(loaded_files_size == 0) { ret = 1; if(ignore_err < 2) printf("\n\n!!! %s error, line %d !!!\n" "'loadexec' called with no list!\n\n", fname, curr_line); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; tmp = 0; extract_line(ptr, sizeof(linebuf)+linebuf-ptr); while(p < loaded_files_size) { char *curr = loaded_files[p++]; char *cmd_ptr = ptr; int i; i = 0; while(*cmd_ptr && (size_t)i+1 < sizeof(buffer)) { if(strncasecmp(cmd_ptr, "<@>", 3) == 0) { i += snprintf(buffer+i, sizeof(buffer)-i, "%s", curr); cmd_ptr += 3; } else { if(cmd_ptr[0] == '\\' && cmd_ptr[1] != 0 && (size_t)i+2 < sizeof(buffer)) cmd_ptr++; buffer[i++] = *(cmd_ptr++); buffer[i] = 0; } } if(!shh) { printf("%s\n", buffer); fflush(stdout); } ret = system(buffer); if(WIFEXITED(ret)) ret = WEXITSTATUS(ret); else ret = -1; if(ret != 0) { tmp = ret; if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } ret = tmp; continue; } /* Prints a string to the console. If a '.' char is used at the * beginning of string, it will be skipped */ if(strcasecmp("echo", linebuf) == 0) { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); printf("%s\n", ptr); fflush(stdout); continue; } /* Prints a string to the console without a newline. If a '.' char is * used at the beginning of string, it will be skipped */ if(strcasecmp("put", linebuf) == 0) { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); printf("%s", ptr); fflush(stdout); continue; } /* Creates/truncates a file and writes a string to it */ if(strcasecmp("writefile", linebuf) == 0) { char *str; FILE *o; str = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); o = fopen(ptr, "w"); if(!o) { ret = 1; if(ignore_err < 2) printf("Could not create file '%s'!\n", ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; extract_line(str, sizeof(linebuf)+linebuf-str); fprintf(o, "%s\n", str); fclose(o); continue; } /* Appends a string to a file */ if(strcasecmp("appendfile", linebuf) == 0) { char *str; FILE *o; str = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); o = fopen(ptr, "a"); if(!o) { ret = 1; if(ignore_err < 2) printf("Could not create file '%s'!\n", ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; extract_line(str, sizeof(linebuf)+linebuf-str); fprintf(o, "%s\n", str); fclose(o); continue; } /* Jumps to the specified label. A label is denoted by a ':' prepended * to it at the beginning of a line */ if(strcasecmp("goto", linebuf) == 0) { int src_line; char *lbl; extract_word(ptr, sizeof(linebuf)+linebuf-ptr); lbl = strdup(ptr); if(!lbl) { fprintf(USEABLE_ERR, "\n\n** Critical Error **\n" "Out of memory duplicating string " "'%s'\n\n", lbl); snprintf(linebuf, sizeof(linebuf), "exit -1\n"); goto reparse; } rewind(f); src_line = curr_line; curr_line = 0; wait_for_done = 0; did_else = 0; did_cmds = 0; do_level = 0; while(fgets(linebuf, sizeof(linebuf), f) != NULL) { ++curr_line; while(linebuf[0]) { int i; extract_line(linebuf, sizeof(linebuf)); for(i = 0;isspace(linebuf[i]);++i) ; memmove(linebuf, &linebuf[i], strlen(&linebuf[i])+1); if(linebuf[0] == ':' && strcasecmp(linebuf+1, lbl) == 0) { free(lbl); goto main_loop_start; } if(!nextline) break; strcpy(linebuf, nextline); free(nextline); nextline = NULL; } } fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Label '%s' not found!\n\n", fname, src_line, lbl); free(lbl); snprintf(linebuf, sizeof(linebuf), "exit 1\n"); goto reparse; } /* Stores a list of paths to look for source files in. Passing only * '.' clears the list. */ if(strcasecmp("src_paths", linebuf) == 0) { unsigned int count = 0; char *next; while(count < src_paths_size) { free(src_paths[count]); ++count; } CLEAR_LIST(src_paths); count = 0; while(*ptr) { next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if(count == 0 && !*next && (strcmp(ptr, ".") == 0 || strlen(ptr) == 0)) break; RESIZE_LIST(src_paths, count+1); src_paths[count] = strdup(ptr); if(!src_paths[count]) { fprintf(USEABLE_ERR, "\n\n** Critical Error **\n" "Out of memory duplicating string " "'%s'\n\n", ptr); snprintf(linebuf, sizeof(linebuf), "exit -1\n"); goto reparse; } ++count; ptr = next; } continue; } /* Deletes the specified executables, appending 'EXE_EXT' to the names * as needed */ if(strcasecmp("rmexec", linebuf) == 0) { char *next = ptr; while(*(ptr=next)) { next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); snprintf(buffer, sizeof(buffer), "'%s'${EXE_EXT}", ptr); expand_string(buffer, "", sizeof(buffer), 0); if(stat(buffer, &statbuf) == -1 && errno == ENOENT) continue; if(!shh) { if(verbose) printf("remove(\"%s\");\n", buffer); else printf("Deleting %s...\n", buffer); fflush(stdout); } if((ret=remove(buffer)) != 0) { if(ignore_err < 2) printf("!!! Could not delete '%s' !!!\n", buffer); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } continue; } /* Deletes the specified libraries, prepending 'LIB_PRE' to the * filename portions and appending with 'LIB_EXT' */ if(strcasecmp("rmlib", linebuf) == 0) { char *next = ptr; while(*(ptr=next)) { next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); libify_name(buffer, sizeof(buffer), ptr); if(stat(buffer, &statbuf) == -1 && errno == ENOENT) continue; if(!shh) { if(verbose) printf("remove(\"%s\");\n", buffer); else printf("Deleting %s...\n", buffer); fflush(stdout); } if((ret=remove(buffer)) != 0) { if(ignore_err < 2) printf("!!! Could not delete '%s' !!!\n", buffer); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } while(*(ptr=next)); continue; } /* Removes a list of object files and their associated dependancy * files, replacing the extension of the named file as necesarry */ if(strcasecmp("rmobj", linebuf) == 0) { char *ext; char *next = ptr; while(*(ptr=next)) { next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); ext = strrchr(ptr, '/'); if(!ext) ext = ptr; ext = strrchr(ext, '.'); if(ext) *ext = 0; snprintf(buffer, sizeof(buffer), "${OBJ_DIR}/'%s'${OBJ_EXT}", ptr); expand_string(buffer, "", sizeof(buffer), 0); if(ext) *ext = '.'; if(stat(buffer, &statbuf) == 0 || errno != ENOENT) { if(!shh) { if(verbose) printf("remove(\"%s\");\n", buffer); else printf("Deleting %s...\n", buffer); fflush(stdout); } if((ret=remove(buffer)) != 0) { if(ignore_err < 2) printf("!!! Could not delete '%s' !!!\n", buffer); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); } } if(ext) *ext = 0; snprintf(buffer, sizeof(buffer), "${DEP_DIR}/'%s'${DEP_EXT}", ptr); expand_string(buffer, "", sizeof(buffer), 0); if(ext) *ext = '.'; if(stat(buffer, &statbuf) == -1 && errno == ENOENT) continue; if(!shh) { if(verbose) printf("remove(\"%s\");\n", buffer); else printf("Deleting %s...\n", buffer); fflush(stdout); } if((ret=remove(buffer)) != 0) { if(ignore_err < 2) printf("!!! Could not delete '%s' !!!\n", buffer); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } continue; } /* Removes a list of files or empty directories */ if(strcasecmp("rm", linebuf) == 0) { #ifdef _WIN32 struct stat sbuf; #endif char *next = ptr; while(*(ptr=next)) { next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if(stat(ptr, &statbuf) == -1 && errno == ENOENT) continue; if(!shh) { if(verbose) printf("remove(\"%s\");\n", ptr); else printf("Deleting %s...\n", ptr); fflush(stdout); } #ifdef _WIN32 if(stat(ptr, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)) ret = rmdir(ptr); else #endif ret = remove(ptr); if(ret != 0) { if(ignore_err < 2) printf("!!! Could not delete '%s' !!!\n", ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } } continue; } /* Creates a directory (with mode 700 in Unix) */ if(strcasecmp("mkdir", linebuf) == 0) { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); if(!shh) { if(!verbose) printf("Creating directory %s/...\n", ptr); #ifdef _WIN32 else printf("mkdir(\"%s\");\n", ptr); fflush(stdout); } if((ret=mkdir(ptr)) != 0) #else else printf("mkdir(\"%s\", S_IRWXU);\n", ptr); fflush(stdout); } if((ret=mkdir(ptr, S_IRWXU)) != 0) #endif { if(ignore_err < 2) printf("!!! Could not create directory !!!\n"); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } continue; } /* Enables/disables command verboseness */ if(strcasecmp("verbose", linebuf) == 0) { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); if(*ptr) verbose = atoi(ptr); continue; } /* Leaves the current script, falling back to the previous if the * current was started with the invoke command. Otherwise, it behaves * like exit */ if(strcasecmp("uninvoke", linebuf) == 0) { size_t i = invoke_backup_size-1; extract_line(ptr, sizeof(linebuf)+linebuf-ptr); ret = atoi(ptr); if(invoke_backup_size == 0) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } fclose(f); f = invoke_backup[i].f; invoke_backup[i].f = NULL; free(fname); fname = invoke_backup[i].fname; strcpy(linebuf, invoke_backup[i].bkp_lbuf); free(invoke_backup[i].bkp_lbuf); free(nextline); nextline = invoke_backup[i].bkp_nextline; curr_line = invoke_backup[i].bkp_line; did_else = invoke_backup[i].bkp_did_else; did_cmds = invoke_backup[i].bkp_did_cmds; do_level = invoke_backup[i].bkp_do_level; RESIZE_LIST(invoke_backup, i); continue; } /* Copies a file */ if(strcasecmp("copy", linebuf) == 0) { char *dfile, *end; struct stat st; dfile = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if(!*ptr || !*dfile) { ret = 1; if(ignore_err < 2) printf("\n\n!!! %s error, line %d !!!\n" "Improper arguments to 'copy'!\n", fname, curr_line); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; end = extract_word(dfile, sizeof(linebuf)+linebuf-dfile); if(dfile[strlen(dfile)-1] == '/' || (stat(dfile, &st) == 0 && S_ISDIR(st.st_mode))) { char *fn = strrchr(ptr, '/'); snprintf(obj, sizeof(obj), "%s%s%s", dfile, ((dfile[strlen(dfile)-1]=='/')?"":"/"), (fn?(fn+1):ptr)); dfile = obj; } if(!shh) { if(verbose) printf("copy_file(\"%s\", \"%s\");\n", ptr, dfile); else printf("Copying '%s' to '%s'...\n", ptr, dfile); fflush(stdout); } if((ret=copy_file(ptr, dfile)) != 0) { if(ignore_err < 2) printf("!!! Could not copy !!!\n"); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } extract_line(end, sizeof(linebuf)+linebuf-end); continue; } /* Copies a library file, prepending and appending the names as * necesarry */ if(strcasecmp("copylib", linebuf) == 0) { char *dfile, *end; dfile = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if(!*ptr || !*dfile) { ret = 1; if(ignore_err < 2) printf("\n\n!!! %s error, line %d !!!\n" "Improper arguments to 'copylib'!\n", fname, curr_line); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; end = extract_word(dfile, sizeof(linebuf)+linebuf-dfile); if(dfile[strlen(dfile)-1] == '/') { char *fn = strrchr(ptr, '/'); snprintf(obj, sizeof(obj), "%s%s", dfile, (fn?(fn+1):ptr)); libify_name(buffer, sizeof(buffer), obj); } else libify_name(buffer, sizeof(buffer), dfile); libify_name(obj, sizeof(obj), ptr); if(!shh) { if(verbose) printf("copy_file(\"%s\", \"%s\");\n", obj, buffer); else printf("Copying '%s' to '%s'...\n", obj, buffer); fflush(stdout); } if((ret=copy_file(obj, buffer)) != 0) { if(ignore_err < 2) printf("!!! Could not copy !!!\n"); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } extract_line(end, sizeof(linebuf)+linebuf-end); continue; } if(strcasecmp("chdir", linebuf) == 0) { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); if(!shh) { if(verbose) printf("chdir(\"%s\");\n", ptr); else printf("Moving to directory '%s'\n", ptr); fflush(stdout); } if((ret=chdir(ptr)) != 0) { if(ignore_err < 2) printf("!!! Could not change directory !!!\n"); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } continue; } /* Creates an association between a file extension and a command to * compile files with that association via the compile command */ if(strcasecmp("associate", linebuf) == 0) { char *cmd = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_line(cmd, sizeof(linebuf)+linebuf-cmd); add_association(ptr, cmd); continue; } /* Yay for DOS/Windows allowing \ as a directory seperator. Modify the * named environment variable to replace \ with / */ if(strcasecmp("fixpath", linebuf) == 0) { char *str, *val; char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_line(end, sizeof(linebuf)+linebuf-ptr); val = strdup(getvar(ptr)); str = val; while((str=strchr(str, '\\')) != NULL) *(str++) = '/'; setenv(ptr, val, 1); free(val); continue; } /* Sets an alternate file for normal output (stdout) */ if(strcasecmp("setoutput", linebuf) == 0) { char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_line(end, sizeof(linebuf)+linebuf-end); ret = 0; if(*ptr) { int fp = open(ptr, O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, S_IRWXU); if(fp == -1) { ret = 1; if(ignore_err < 2) printf("!!! Could not open %s !!!\n", ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } fflush(stdout); if(stdo_bak == -1) stdo_bak = dup(STDOUT_FILENO); close(STDOUT_FILENO); dup2(fp, STDOUT_FILENO); close(fp); continue; } fflush(stdout); if(stdo_bak == -1) continue; close(STDOUT_FILENO); dup2(stdo_bak, STDOUT_FILENO); close(stdo_bak); stdo_bak = -1; continue; } /* Sets an alternate file for error output (stderr) */ if(strcasecmp("seterror", linebuf) == 0) { char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_line(end, sizeof(linebuf)+linebuf-end); ret = 0; if(*ptr) { int fd = open(ptr, O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, S_IRWXU); if(fd == -1) { ret = 1; if(ignore_err < 2) printf("!!! Could not open %s !!!\n", ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } fflush(stderr); if(stde_bak == -1) { stde_bak = dup(STDERR_FILENO); stde_stream = fdopen(stde_bak, "w"); } close(STDERR_FILENO); dup2(fd, STDERR_FILENO); close(fd); continue; } fflush(stderr); if(stde_bak == -1) continue; close(STDERR_FILENO); dup2(stde_bak, STDERR_FILENO); fclose(stde_stream); stde_stream = NULL; stde_bak = -1; continue; } /* Changes the file to read input from. Pass nothing to switch to * stdin. */ if(strcasecmp("setinput", linebuf) == 0) { char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_line(end, sizeof(linebuf)+linebuf-end); ret = 0; if(*ptr) { int fp = open(ptr, O_RDONLY, 0); if(fp == -1) { ret = 1; if(ignore_err < 2) printf("!!! Could not open %s !!!\n", ptr); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } fflush(stdin); if(stdi_bak == -1) stdi_bak = dup(STDIN_FILENO); close(STDIN_FILENO); dup2(fp, STDIN_FILENO); close(fp); continue; } fflush(stdin); if(stdi_bak == -1) continue; close(STDIN_FILENO); dup2(stdi_bak, STDIN_FILENO); close(stdi_bak); stdi_bak = -1; continue; } /* Reads input and stores the string in the named var. The trailing * newline is stripped. */ if(strcasecmp("read", linebuf) == 0) { char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); extract_line(end, sizeof(linebuf)+linebuf-end); if(!(*ptr)) { ret = 1; if(ignore_err < 2) printf("!!! No storage specified for read (line %d) !!!\n", curr_line); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } ret = 0; buffer[0] = 0; if(fgets(buffer, sizeof(buffer), stdin) == NULL) ret = 1; if(buffer[0] && buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0; if(!strlen(buffer)) unsetenv(ptr); else ret |= setenv(ptr, buffer, 1); continue; } /* Executes a command via the system shell and redirects its output to * a temp file, which is then read into the named variable. All * trailing new-lines are stripped. */ if(strcasecmp("readexec", linebuf) == 0) { int fd, old_stdout; char *bufptr, *cmd; size_t len; FILE *tf; ret = 0; /* Create a temp file and get its file descriptor (and for Win32, * change it to text mode) */ tf = tmpfile(); if(!tf) { ret = 1; if(ignore_err < 2) printf("!!! Could not create temp file !!!\n"); if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } fd = fileno(tf); #ifdef _WIN32 _setmode(fd, _O_TEXT); #endif /* Get the var name, and build the command */ len = 0; cmd = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); while(*cmd) { char *next = extract_word(cmd, sizeof(linebuf)+linebuf-cmd); if(strpbrk(cmd, CHARS_TO_ESC)) { while(*cmd) { if(strchr(CHARS_TO_ESC CHARS_TO_QUOTE, *cmd) && len < sizeof(buffer)-2) buffer[len++] = '\\'; if(len < sizeof(buffer)-1) buffer[len++] = *(cmd++); } if(len < sizeof(buffer)-1) buffer[len++] = ' '; buffer[len] = 0; } else if(strpbrk(cmd, CHARS_TO_QUOTE)) len += snprintf(buffer+len, sizeof(buffer)-len, "\"%s\" ", cmd); else len += snprintf(buffer+len, sizeof(buffer)-len, "%s ", cmd); cmd = next; } if(len > 0) buffer[len-1] = 0; if(!shh) printf("%s\n", buffer); fflush(stdout); /* Save stdout, close it, reopen it with the temp file's * descriptor, then run the command */ old_stdout = dup(STDOUT_FILENO); close(STDOUT_FILENO); dup2(fd, STDOUT_FILENO); ret = system(buffer); if(WIFEXITED(ret)) ret = WEXITSTATUS(ret); else ret = -1; if(ret != 0) { if(!ignore_err) { close(fd); close(STDOUT_FILENO); remove(fname); dup2(old_stdout, STDOUT_FILENO); close(old_stdout); snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } } /* Get the size of the out put and read it in */ len = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); bufptr = buffer; len = ((len >= sizeof(buffer)) ? sizeof(buffer)-1 : len); while(len > 0) { size_t b = read(fd, bufptr, len); if(b <= 0) break; len -= b; bufptr += b; } *(bufptr++) = 0; /* Close the temp file, restore stdout, remove trailing newlines * from the program's output, then save it to the var */ fclose(tf); close(STDOUT_FILENO); dup2(old_stdout, STDOUT_FILENO); close(old_stdout); if(buffer[0] && buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0; if(*ptr) ret |= setenv(ptr, buffer, 1); if(ret != 0) { if(!ignore_err) { snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } continue; } continue; } /* Exits the script with the specified exitcode */ if(strcasecmp("exit", linebuf) == 0) { static int already_exited = 0; int inc = 0; int retval; if(already_exited) { fprintf(USEABLE_ERR, "\n\n*** Critical error ***\n" "Recursive exit call, aborting now!\n\n"); exit(-1); } already_exited = 1; extract_line(ptr, sizeof(linebuf)+linebuf-ptr); retval = atoi(ptr); for(i = defines_size-1;(size_t)i < defines_size;--i) { if(strncasecmp(defines[i].name, "atexit_", 7) == 0) inc += snprintf(linebuf+inc, sizeof(linebuf)-inc, "%s\n", defines[i].name); } snprintf(linebuf+inc, sizeof(linebuf)-inc, "__really_exit %d\n", retval); free(nextline); nextline = NULL; goto reparse; } /* Does nothing. Ignores the line */ if(strcasecmp("noop", linebuf) == 0) { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); continue; } if(strcasecmp("__reset_cmd_args__", linebuf) == 0) { size_t i = arg_backup_size-1; size_t i2; if(i == ~0u) { fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "__reset_cmd_args__ called too many times!\n" "You didn't call it yourself, did you?", fname, curr_line); snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } extract_line(ptr, sizeof(linebuf)+linebuf-ptr); for(i2 = 0;i2 < argc;++i2) free(argv[i2]); free(argv); argc = arg_backup[i].argc; argv = arg_backup[i].argv; argv_len = 0; argv_size = argc-1; RESIZE_LIST(arg_backup, i); /* If i == 0, then argv is the _argv given to main. We don't want * to be realloc'ing that. */ if(i > 0) RESIZE_LIST(argv, argc+1); continue; } /* Exits the script with the specified exitcode */ if(strcasecmp("__really_exit", linebuf) == 0) { extract_line(ptr, sizeof(linebuf)+linebuf-ptr); exit(atoi(ptr)); } for(i = 0;(size_t)i < defines_size;++i) { char *next; size_t i2; if(strcasecmp(defines[i].name, linebuf) != 0) continue; i2 = arg_backup_size; RESIZE_LIST(arg_backup, i2+1); arg_backup[i2].argv = argv; arg_backup[i2].argc = argc; argc = 0; argv = NULL; argv_len = 0; RESIZE_LIST(argv, 2); argv[argc++] = strdup(linebuf); while(*ptr) { next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); RESIZE_LIST(argv, argc+2); argv[argc++] = strdup(ptr); ptr = next; } argv[argc] = NULL; snprintf(linebuf, sizeof(linebuf), "%s\n__reset_cmd_args__\n%s\n", defines[i].val, (nextline?nextline:"")); free(nextline); nextline = NULL; goto reparse; } fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n" "Unknown command '%s'\n\n", fname, curr_line, linebuf); snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); goto reparse; } return ret; } openlayer-2.1.orig/README0000644000175000017500000000147510647372404015405 0ustar georgeskgeorgesk--OpenLayer 2.1-- For installation please see INSTALL Requirements: -# GNU Tools -# OpenGL library -# Allegro library -# AllegroGL library -# Glyph Keeper Library (Both Allegro and AllegroGL TARGETS) -# Freetype library -# Png library -# Zlib library Introduction: OpenLayer is a hardware accelerated 2D Graphics library. It specifies a new api to be used alongside of Allegro and takes control of how the contents of the screen are rendered and uses OpenGL functions through AllegroGL to allow hardware acceleration. Implementation: Multi-Platform: Windows / Linux / Unix / Mac OS Language: C++ Written by: Esa Tanskanen (Fladimir da Gorf) Additional: 10/27/2005 by juvinious (Miguel Gavidia) 10/27/2005 by Peter Hull (MACOSX Support) Website: http://openlayer.berlios.deopenlayer-2.1.orig/buildme.bat0000644000175000017500000000033610420161776016626 0ustar georgeskgeorgesk@echo off gcc -O2 cbuild.c -o %TEMP%\cbuild.exe if not errorlevel 0 goto enderror %TEMP%\cbuild.exe %1 %2 %3 %4 %5 del %TEMP%\cbuild.exe goto end :enderror echo Problems with building cbuild.exe (build manually) :end