diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/gl/gl-font.c | 365 | ||||
-rw-r--r-- | platform/gl/gl-main.c (renamed from platform/glut/glut-main.c) | 315 | ||||
-rw-r--r-- | platform/win32/libglfw.vcproj | 231 | ||||
-rw-r--r-- | platform/win32/mupdf-gl.vcproj | 187 | ||||
-rw-r--r-- | platform/win32/mupdf.sln | 39 |
5 files changed, 990 insertions, 147 deletions
diff --git a/platform/gl/gl-font.c b/platform/gl/gl-font.c new file mode 100644 index 00000000..92dad110 --- /dev/null +++ b/platform/gl/gl-font.c @@ -0,0 +1,365 @@ +/* + * A very simple font cache and rasterizer that uses FreeType + * to draw fonts from a single OpenGL texture. The code uses + * a linear-probe hashtable, and writes new glyphs into + * the texture using glTexSubImage2D. When the texture fills + * up, or the hash table gets too crowded, the cache is emptied. + * + * This is designed to be used for horizontal text only, + * and draws unhinted text with subpixel accurate metrics + * and kerning. As such, you should always call the drawing + * function with an orthogonal transform that maps units + * to pixels accurately. + */ + +#include "mupdf/fitz.h" + +#include "mupdf/pdf.h" /* for builtin fonts */ + +#include <GLFW/glfw3.h> + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_ADVANCES_H + +#define PADDING 1 /* set to 0 to save some space but disallow arbitrary transforms */ + +#define MAXGLYPHS 4093 /* prime number for hash table goodness */ +#define CACHESIZE 256 +#define XPRECISION 4 +#define YPRECISION 1 + +struct key +{ + FT_Face face; + short gid; + short subx; + short suby; +}; + +struct glyph +{ + char lsb, top, w, h; + short s, t; + float advance; +}; + +struct table +{ + struct key key; + struct glyph glyph; +}; + +static FT_Library g_freetype_lib = NULL; +static struct table g_table[MAXGLYPHS]; +static int g_table_load = 0; +static unsigned int g_cache_tex = 0; +static int g_cache_w = CACHESIZE; +static int g_cache_h = CACHESIZE; +static int g_cache_row_y = 0; +static int g_cache_row_x = 0; +static int g_cache_row_h = 0; + +static FT_Face g_helvetica = NULL; +static FT_Face g_droidsansfallback = NULL; + +static void clear_font_cache(void) +{ +#if PADDING > 0 + unsigned char *zero = malloc(g_cache_w * g_cache_h); + memset(zero, 0, g_cache_w * g_cache_h); + glBindTexture(GL_TEXTURE_2D, g_cache_tex); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_cache_w, g_cache_h, GL_ALPHA, GL_UNSIGNED_BYTE, zero); + free(zero); +#endif + + memset(g_table, 0, sizeof(g_table)); + g_table_load = 0; + + g_cache_row_y = PADDING; + g_cache_row_x = PADDING; + g_cache_row_h = 0; +} + +void ui_init_fonts(fz_context *ctx, float pixelsize) +{ + int fontsize = pixelsize * 64; + unsigned char *data; + unsigned int size; + int code; + int index; + + code = FT_Init_FreeType(&g_freetype_lib); + if (code) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot initialize freetype"); + + glGenTextures(1, &g_cache_tex); + glBindTexture(GL_TEXTURE_2D, g_cache_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g_cache_w, g_cache_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); + + clear_font_cache(); + + data = pdf_lookup_builtin_font(ctx, "Times-Roman", &size); + code = FT_New_Memory_Face(g_freetype_lib, data, size, 0, &g_helvetica); + if (code) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load helvetica"); + + data = pdf_lookup_substitute_cjk_font(ctx, 0, 0, 0, &size, &index); + code = FT_New_Memory_Face(g_freetype_lib, data, size, 0, &g_droidsansfallback); + if (code) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load droid sans fallback"); + + FT_Select_Charmap(g_helvetica, ft_encoding_unicode); + FT_Select_Charmap(g_droidsansfallback, ft_encoding_unicode); + + FT_Set_Char_Size(g_helvetica, fontsize, fontsize, 72, 72); + FT_Set_Char_Size(g_droidsansfallback, fontsize, fontsize, 72, 72); +} + +void ui_finish_fonts(fz_context *ctx) +{ + clear_font_cache(); + FT_Done_Face(g_helvetica); + FT_Done_Face(g_droidsansfallback); +} + +static unsigned int hashfunc(struct key *key) +{ + unsigned char *buf = (unsigned char *)key; + unsigned int len = sizeof(struct key); + unsigned int h = 0; + while (len--) + h = *buf++ + (h << 6) + (h << 16) - h; + return h; +} + +static unsigned int lookup_table(struct key *key) +{ + unsigned int pos = hashfunc(key) % MAXGLYPHS; + while (1) + { + if (!g_table[pos].key.face) /* empty slot */ + return pos; + if (!memcmp(key, &g_table[pos].key, sizeof(struct key))) /* matching slot */ + return pos; + pos = (pos + 1) % MAXGLYPHS; + } +} + +static struct glyph *lookup_glyph(FT_Face face, int gid, int subx, int suby) +{ + FT_Vector subv; + struct key key; + unsigned int pos; + int code; + int w, h; + + /* + * Look it up in the table + */ + + memset(&key, 0, sizeof key); + key.face = face; + key.gid = gid; + key.subx = subx; + key.suby = suby; + + pos = lookup_table(&key); + if (g_table[pos].key.face) + return &g_table[pos].glyph; + + /* + * Render the bitmap + */ + + glEnd(); + + subv.x = subx; + subv.y = suby; + + FT_Set_Transform(face, NULL, &subv); + + code = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); + if (code < 0) + return NULL; + + code = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); + if (code < 0) + return NULL; + + w = face->glyph->bitmap.width; + h = face->glyph->bitmap.rows; + + /* + * Find an empty slot in the texture + */ + + if (g_table_load == (MAXGLYPHS * 3) / 4) + { + puts("font cache table full, clearing cache"); + clear_font_cache(); + pos = lookup_table(&key); + } + + if (h + PADDING > g_cache_h || w + PADDING > g_cache_w) + return NULL; + + if (g_cache_row_x + w + PADDING > g_cache_w) + { + g_cache_row_y += g_cache_row_h + PADDING; + g_cache_row_x = PADDING; + g_cache_row_h = 0; + } + if (g_cache_row_y + h + PADDING > g_cache_h) + { + puts("font cache texture full, clearing cache"); + clear_font_cache(); + pos = lookup_table(&key); + } + + /* + * Copy bitmap into texture + */ + + memcpy(&g_table[pos].key, &key, sizeof(struct key)); + g_table[pos].glyph.w = face->glyph->bitmap.width; + g_table[pos].glyph.h = face->glyph->bitmap.rows; + g_table[pos].glyph.lsb = face->glyph->bitmap_left; + g_table[pos].glyph.top = face->glyph->bitmap_top; + g_table[pos].glyph.s = g_cache_row_x; + g_table[pos].glyph.t = g_cache_row_y; + g_table[pos].glyph.advance = face->glyph->advance.x / 64.0; + g_table_load ++; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ROW_LENGTH, face->glyph->bitmap.pitch); + glTexSubImage2D(GL_TEXTURE_2D, 0, g_cache_row_x, g_cache_row_y, w, h, + GL_ALPHA, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + glBegin(GL_QUADS); + + g_cache_row_x += w + PADDING; + if (g_cache_row_h < h + PADDING) + g_cache_row_h = h + PADDING; + + return &g_table[pos].glyph; +} + +static float ui_draw_glyph(FT_Face face, int gid, float x, float y) +{ + struct glyph *glyph; + float s0, t0, s1, t1, xc, yc; + + int subx = (x - floor(x)) * XPRECISION; + int suby = (y - floor(y)) * YPRECISION; + subx = (subx * 64) / XPRECISION; + suby = (suby * 64) / YPRECISION; + + glyph = lookup_glyph(face, gid, subx, suby); + if (!glyph) + return 0.0; + + s0 = (float) glyph->s / g_cache_w; + t0 = (float) glyph->t / g_cache_h; + s1 = (float) (glyph->s + glyph->w) / g_cache_w; + t1 = (float) (glyph->t + glyph->h) / g_cache_h; + xc = floor(x) + glyph->lsb; + yc = floor(y) - glyph->top + glyph->h; + + glTexCoord2f(s0, t0); glVertex2f(xc, yc - glyph->h); + glTexCoord2f(s1, t0); glVertex2f(xc + glyph->w, yc - glyph->h); + glTexCoord2f(s1, t1); glVertex2f(xc + glyph->w, yc); + glTexCoord2f(s0, t1); glVertex2f(xc, yc); + + return glyph->advance; +} + +float ui_measure_character(fz_context *ctx, int ucs) +{ + FT_Fixed advance; + FT_Face face; + int gid; + + face = g_helvetica; + gid = FT_Get_Char_Index(face, ucs); + if (gid <= 0) + { + face = g_droidsansfallback; + gid = FT_Get_Char_Index(face, ucs); + } + + FT_Get_Advance(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING, &advance); + return advance / 65536.0f; +} + +float ui_draw_character(fz_context *ctx, int ucs, float x, float y) +{ + FT_Face face; + int gid; + + face = g_helvetica; + gid = FT_Get_Char_Index(face, ucs); + if (gid <= 0) + { + face = g_droidsansfallback; + gid = FT_Get_Char_Index(face, ucs); + } + + return ui_draw_glyph(face, gid, x, y); +} + +void ui_begin_text(fz_context *ctx) +{ + glBindTexture(GL_TEXTURE_2D, g_cache_tex); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glBegin(GL_QUADS); +} + +void ui_end_text(fz_context *ctx) +{ + glEnd(); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); +} + +float ui_draw_string(fz_context *ctx, float x, float y, const char *str) +{ + int ucs; + + ui_begin_text(ctx); + + while (*str) + { + str += fz_chartorune(&ucs, str); + x += ui_draw_character(ctx, ucs, x, y); + } + + ui_end_text(ctx); + + return x; +} + +float ui_measure_string(fz_context *ctx, char *str) +{ + int ucs; + float x = 0; + + ui_begin_text(ctx); + + while (*str) + { + str += fz_chartorune(&ucs, str); + x += ui_measure_character(ctx, ucs); + } + + ui_end_text(ctx); + + return x; +} diff --git a/platform/glut/glut-main.c b/platform/gl/gl-main.c index 2a4dbc3b..70085909 100644 --- a/platform/glut/glut-main.c +++ b/platform/gl/gl-main.c @@ -1,15 +1,31 @@ #include "mupdf/fitz.h" -// TODO: event queue and handle key/mouse based on 'active' inside display() +#ifdef _WIN32 +#include <windows.h> +#endif -#ifdef __APPLE__ -#include <OpenGL/OpenGL.h> -#include <GLUT/glut.h> -#else -#include <GL/gl.h> -#include <GL/freeglut.h> +#ifdef _MSC_VER +#define main main_utf8 #endif +#include <GLFW/glfw3.h> + +// TODO: event queue and handle key/mouse based on 'active' inside display() + +void ui_init_fonts(fz_context *ctx, float pixelsize); +void ui_finish_fonts(fz_context *ctx); +float ui_measure_character(fz_context *ctx, int ucs); +void ui_begin_text(fz_context *ctx); +float ui_draw_character(fz_context *ctx, int ucs, float x, float y); +void ui_end_text(fz_context *ctx); +float ui_draw_string(fz_context *ctx, float x, float y, const char *str); +float ui_measure_string(fz_context *ctx, char *str); + +static GLFWwindow *window; +static int fontsize = 15; +static int baseline = 14; +static int lineheight = 18; + struct input { int text[256]; @@ -36,7 +52,7 @@ static void ui_end(void) static void open_browser(const char *uri) { #ifdef _WIN32 - ShellExecuteA(hwndframe, "open", uri, 0, 0, SW_SHOWNORMAL); + ShellExecuteA(NULL, "open", uri, 0, 0, SW_SHOWNORMAL); #else const char *browser = getenv("BROWSER"); if (!browser) @@ -66,22 +82,9 @@ const char *ogl_error_string(GLenum code) CASE(GL_INVALID_ENUM); CASE(GL_INVALID_VALUE); CASE(GL_INVALID_OPERATION); - CASE(GL_INVALID_FRAMEBUFFER_OPERATION); CASE(GL_OUT_OF_MEMORY); CASE(GL_STACK_UNDERFLOW); CASE(GL_STACK_OVERFLOW); - - /* glCheckFramebufferStatus */ - CASE(GL_FRAMEBUFFER_COMPLETE); - CASE(GL_FRAMEBUFFER_UNDEFINED); - CASE(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT); - CASE(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT); - CASE(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER); - CASE(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER); - CASE(GL_FRAMEBUFFER_UNSUPPORTED); - CASE(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE); - CASE(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS); - default: return "(unknown)"; } #undef CASE @@ -195,8 +198,7 @@ static void update_title(void) sprintf(buf, "...%s - %d / %d", title + n - 50, currentpage + 1, fz_count_pages(ctx, doc)); else sprintf(buf, "%s - %d / %d", title, currentpage + 1, fz_count_pages(ctx, doc)); - glutSetWindowTitle(buf); - glutSetIconTitle(buf); + glfwSetWindowTitle(window, buf); } void render_page(int pagenumber, float zoom, float rotate) @@ -320,8 +322,9 @@ static void do_copy_region(fz_rect *sel, int xofs, int yofs, float zoom, float r { fz_rect hitbox; fz_matrix ctm; - int c, i, p, need_newline; + int c, i, need_newline; int block_num; + fz_buffer *buf; int x0 = sel->x0 - xofs; int y0 = sel->y0 - yofs; @@ -338,9 +341,10 @@ static void do_copy_region(fz_rect *sel, int xofs, int yofs, float zoom, float r fz_scale(&ctm, zoom / 72, zoom / 72); fz_pre_rotate(&ctm, -rotate); - p = 0; need_newline = 0; + buf = fz_new_buffer(ctx, 256); + for (block_num = 0; block_num < text->len; block_num++) { fz_text_line *line; @@ -369,12 +373,12 @@ static void do_copy_region(fz_rect *sel, int xofs, int yofs, float zoom, float r if (need_newline) { #if defined(_WIN32) || defined(_WIN64) - putchar('\r'); + fz_write_buffer_rune(ctx, buf, '\r'); #endif - putchar('\n'); + fz_write_buffer_rune(ctx, buf, '\n'); need_newline = 0; } - putchar(c); + fz_write_buffer_rune(ctx, buf, c); } } } @@ -384,56 +388,38 @@ static void do_copy_region(fz_rect *sel, int xofs, int yofs, float zoom, float r } } - fz_drop_text_page(ctx, text); - fz_drop_text_sheet(ctx, sheet); - fz_drop_page(ctx, page); -} + fz_write_buffer_byte(ctx, buf, 0); + glfwSetClipboardString(window, (char*)buf->data); -static void draw_string(float x, float y, const char *s) -{ - int c; - glRasterPos2f(x + 0.375f, y + 0.375f + 11); - while (*s) - { - s += fz_chartorune(&c, s); - glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, c); - } -} + fz_drop_buffer(ctx, buf); -#if 0 -static float measure_string(const char *s) -{ - int w = 0, c; - while (*s) - { - s += fz_chartorune(&c, s); - w += glutBitmapWidth(GLUT_BITMAP_HELVETICA_12, c); - } - return w; + fz_drop_text_page(ctx, text); + fz_drop_text_sheet(ctx, sheet); + fz_drop_page(ctx, page); } -#endif static void ui_label_draw(int x0, int y0, int x1, int y1, const char *text) { glColor4f(1, 1, 1, 1); glRectf(x0, y0, x1, y1); glColor4f(0, 0, 0, 1); - draw_string(x0 + 2, y0 + 2, text); + ui_draw_string(ctx, x0 + 2, y0 + 2 + baseline, text); } -static void draw_string_part(float x, float y, const int *s, const int *e) +static void ui_draw_string_part(float x, float y, const int *s, const int *e) { - glRasterPos2f(x + 0.375f, y + 0.375f + 11); + ui_begin_text(ctx); while (s < e) - glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *s++); + x += ui_draw_character(ctx, *s++, x, y + baseline); + ui_end_text(ctx); } static float measure_string_part(const int *s, const int *e) { - int w = 0; + float w = 0; while (s < e) - w += glutBitmapWidth(GLUT_BITMAP_HELVETICA_12, *s++); + w += ui_measure_character(ctx, *s++); return w; } @@ -441,7 +427,7 @@ static int *find_string_location(int *s, int *e, float w, float x) { while (s < e) { - int cw = glutBitmapWidth(GLUT_BITMAP_HELVETICA_12, *s); + float cw = ui_measure_character(ctx, *s); if (w + (cw / 2) >= x) return s; w += cw; @@ -450,7 +436,7 @@ static int *find_string_location(int *s, int *e, float w, float x) return e; } -static inline int isalnum(int c) +static inline int myisalnum(int c) { int cat = ucdn_get_general_category(c); if (cat >= UCDN_GENERAL_CATEGORY_LL && cat <= UCDN_GENERAL_CATEGORY_LU) @@ -462,15 +448,15 @@ static inline int isalnum(int c) static int *skip_word_left(int *p, int *start) { - while (p > start && !isalnum(p[-1])) --p; - while (p > start && isalnum(p[-1])) --p; + while (p > start && !myisalnum(p[-1])) --p; + while (p > start && myisalnum(p[-1])) --p; return p; } static int *skip_word_right(int *p, int *end) { - while (p < end && !isalnum(p[0])) ++p; - while (p < end && isalnum(p[0])) ++p; + while (p < end && !myisalnum(p[0])) ++p; + while (p < end && myisalnum(p[0])) ++p; return p; } @@ -506,7 +492,7 @@ static void ui_input_draw(int x0, int y0, int x1, int y1, struct input *input) glRectf(px, y0 + 2, qx+1, y1 - 2); glColor4f(0, 0, 0, 1); - draw_string_part(x0 + 2, y0 + 2, input->text, input->end); + ui_draw_string_part(x0 + 2, y0 + 2, input->text, input->end); } static void ui_input_delete_selection(struct input *input) @@ -588,72 +574,72 @@ static int ui_input_keyboard(int key, struct input *input) static void ui_input_special(int key, int mod, struct input *input) { - if (mod == GLUT_ACTIVE_CTRL + GLUT_ACTIVE_SHIFT) + if (mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) { switch (key) { - case GLUT_KEY_LEFT: input->q = skip_word_left(input->q, input->text); break; - case GLUT_KEY_RIGHT: input->q = skip_word_right(input->q, input->end); break; - case GLUT_KEY_UP: case GLUT_KEY_HOME: input->q = input->text; break; - case GLUT_KEY_DOWN: case GLUT_KEY_END: input->q = input->end; break; + case GLFW_KEY_LEFT: input->q = skip_word_left(input->q, input->text); break; + case GLFW_KEY_RIGHT: input->q = skip_word_right(input->q, input->end); break; + case GLFW_KEY_UP: case GLFW_KEY_HOME: input->q = input->text; break; + case GLFW_KEY_DOWN: case GLFW_KEY_END: input->q = input->end; break; } } - else if (mod == GLUT_ACTIVE_CTRL) + else if (mod == GLFW_MOD_CONTROL) { switch (key) { - case GLUT_KEY_LEFT: + case GLFW_KEY_LEFT: if (input->p != input->q) input->p = input->q = input->p < input->q ? input->p : input->q; else input->p = input->q = skip_word_left(input->q, input->text); break; - case GLUT_KEY_RIGHT: + case GLFW_KEY_RIGHT: if (input->p != input->q) input->p = input->q = input->p > input->q ? input->p : input->q; else input->p = input->q = skip_word_right(input->q, input->end); break; - case GLUT_KEY_HOME: - case GLUT_KEY_UP: + case GLFW_KEY_HOME: + case GLFW_KEY_UP: input->p = input->q = input->text; break; - case GLUT_KEY_END: - case GLUT_KEY_DOWN: + case GLFW_KEY_END: + case GLFW_KEY_DOWN: input->p = input->q = input->end; break; } } - else if (mod == GLUT_ACTIVE_SHIFT) + else if (mod == GLFW_MOD_SHIFT) { switch (key) { - case GLUT_KEY_LEFT: if (input->q > input->text) input->q = --(input->q); break; - case GLUT_KEY_RIGHT: if (input->q < input->end) input->q = ++(input->q); break; - case GLUT_KEY_HOME: input->q = input->text; break; - case GLUT_KEY_END: input->q = input->end; break; + case GLFW_KEY_LEFT: if (input->q > input->text) input->q = --(input->q); break; + case GLFW_KEY_RIGHT: if (input->q < input->end) input->q = ++(input->q); break; + case GLFW_KEY_HOME: input->q = input->text; break; + case GLFW_KEY_END: input->q = input->end; break; } } else if (mod == 0) { switch (key) { - case GLUT_KEY_LEFT: + case GLFW_KEY_LEFT: if (input->p != input->q) input->p = input->q = input->p < input->q ? input->p : input->q; else if (input->q > input->text) input->p = input->q = --(input->q); break; - case GLUT_KEY_RIGHT: + case GLFW_KEY_RIGHT: if (input->p != input->q) input->p = input->q = input->p > input->q ? input->p : input->q; else if (input->q < input->end) input->p = input->q = ++(input->q); break; - case GLUT_KEY_HOME: + case GLFW_KEY_HOME: input->p = input->q = input->text; break; - case GLUT_KEY_END: + case GLFW_KEY_END: input->p = input->q = input->end; break; } @@ -728,7 +714,7 @@ static int measure_outline_height(fz_outline *node) int h = 0; while (node) { - h += 15; + h += lineheight; if (node->down) h += measure_outline_height(node->down); node = node->next; @@ -748,14 +734,14 @@ static int draw_outline_imp(fz_outline *node, int end, int x0, int x1, int x, in { p = node->dest.ld.gotor.page; - if (ui.x >= x0 && ui.x < x1 && ui.y >= y + h && ui.y < y + h + 15) + if (ui.x >= x0 && ui.x < x1 && ui.y >= y + h && ui.y < y + h + lineheight) { ui.hot = node; if (!ui.active && ui.down) { ui.active = node; jump_to_page(p); - glutPostRedisplay(); /* we changed the current page, so force a redraw */ + // glfwPostEmptyEvent(); /* we changed the current page, so force a redraw */ } } @@ -767,15 +753,15 @@ static int draw_outline_imp(fz_outline *node, int end, int x0, int x1, int x, in if (currentpage == p || (currentpage > p && currentpage < n)) { glColor4f(0.9, 0.9, 0.9, 1); - glRectf(x0, y + h, x1, y + h + 15); + glRectf(x0, y + h, x1, y + h + lineheight); } } glColor4f(0, 0, 0, 1); - draw_string(x, y + h, node->title); - h += 15; + ui_draw_string(ctx, x, y + h + baseline, node->title); + h += lineheight; if (node->down) - h += draw_outline_imp(node->down, n, x0, x1, x + 15, y + h); + h += draw_outline_imp(node->down, n, x0, x1, x + lineheight, y + h); node = node->next; } @@ -872,7 +858,7 @@ static void draw_links(fz_link *link, int xofs, int yofs, float zoom, float rota else if (link->dest.kind == FZ_LINK_URI) open_browser(link->dest.ld.uri.uri); } - glutPostRedisplay(); + // glfwPostEmptyEvent(); } link = link->next; @@ -912,10 +898,8 @@ static void draw_page_selection(int x0, int y0, int x1, int y1, float zoom, floa if (ui.active == &sel && !ui.right) { - printf("--- copy to clipboard ---\n"); do_copy_region(&sel, x0, y0, zoom, rotate); - printf("\n---\n"); - glutPostRedisplay(); + // glfwPostEmptyEvent(); } } @@ -949,6 +933,7 @@ static void draw_search_hits(int xofs, int yofs, float zoom, float rotate) static void toggle_fullscreen(void) { +#if 0 static int oldw = 100, oldh = 100, oldx = 0, oldy = 0; if (!isfullscreen) @@ -966,6 +951,7 @@ static void toggle_fullscreen(void) glutReshapeWindow(oldw, oldh); isfullscreen = 0; } +#endif } static void shrinkwrap(void) @@ -974,7 +960,7 @@ static void shrinkwrap(void) int h = page_h + canvas_y; if (isfullscreen) toggle_fullscreen(); - glutReshapeWindow(w, h); + glfwSetWindowSize(window, w, h); } static void auto_zoom_w(void) @@ -1047,14 +1033,13 @@ static void smart_move_forward(void) } } - -static void reshape(int w, int h) +static void on_reshape(GLFWwindow *window, int w, int h) { screen_w = w; screen_h = h; } -static void display(void) +static void on_display(GLFWwindow *window) { fz_rect r; float x, y; @@ -1079,8 +1064,8 @@ static void display(void) if (search_active) { - int start_time = glutGet(GLUT_ELAPSED_TIME); - while (glutGet(GLUT_ELAPSED_TIME) < start_time + 200) + float start_time = glfwGetTime(); + while (glfwGetTime() < start_time + 0.2) { do_search_page(search_page, search_needle, NULL); if (search_hit_count) @@ -1103,7 +1088,7 @@ static void display(void) /* keep searching later */ if (search_active) - glutPostRedisplay(); + glfwPostEmptyEvent(); } if (showoutline) @@ -1203,19 +1188,19 @@ static void display(void) if (showsearch) { - ui_input_draw(canvas_x, 0, canvas_x + canvas_w, 15+4, &search_input); + ui_input_draw(canvas_x, 0, canvas_x + canvas_w, lineheight+4, &search_input); } if (search_active) { char buf[256]; sprintf(buf, "searching page %d / %d", search_page + 1, fz_count_pages(ctx, doc)); - ui_label_draw(canvas_x, 0, canvas_x + canvas_w, 15+4, buf); + ui_label_draw(canvas_x, 0, canvas_x + canvas_w, lineheight+4, buf); } ui_end(); - glutSwapBuffers(); + glfwSwapBuffers(window); ogl_assert(ctx, "swap buffers"); } @@ -1243,13 +1228,13 @@ utf8_from_rune_string(fz_context *ctx, const int *s, const int *e) return d; } -static void keyboard(unsigned char key, int x, int y) +static void on_keyboard(GLFWwindow *window, unsigned int key) { if (search_active) { if (key == 27) search_active = 0; - glutPostRedisplay(); +// glfwPostEmptyEvent(); return; } @@ -1275,7 +1260,7 @@ static void keyboard(unsigned char key, int x, int y) printf("search '%s'\n", search_needle); } } - glutPostRedisplay(); + // glfwPostEmptyEvent(); return; } @@ -1365,31 +1350,40 @@ static void keyboard(unsigned char key, int x, int y) if (search_hit_page != currentpage) search_hit_page = -1; /* clear highlights when navigating */ - glutPostRedisplay(); + // glfwPostEmptyEvent(); } -static void special(int key, int x, int y) +static void on_special(GLFWwindow *window, int key, int scan, int action, int mod) { - int mod = glutGetModifiers(); + if (action != GLFW_PRESS) + return; - if (key == GLUT_KEY_F4 && mod == GLUT_ACTIVE_ALT) + if (key == GLFW_KEY_F4 && mod == GLFW_MOD_ALT) exit(0); + switch (key) + { + case GLFW_KEY_ESCAPE: on_keyboard(window, 27); return; + case GLFW_KEY_ENTER: on_keyboard(window, '\r'); return; + case GLFW_KEY_BACKSPACE: on_keyboard(window, '\b'); return; + case GLFW_KEY_DELETE: on_keyboard(window, 127); return; + } + if (showsearch) { ui_input_special(key, mod, &search_input); - glutPostRedisplay(); + // glfwPostEmptyEvent(); return; } switch (key) { - case GLUT_KEY_UP: scroll_y -= 10; break; - case GLUT_KEY_DOWN: scroll_y += 10; break; - case GLUT_KEY_LEFT: scroll_x -= 10; break; - case GLUT_KEY_RIGHT: scroll_x += 10; break; - case GLUT_KEY_PAGE_UP: currentpage -= fz_maxi(number, 1); break; - case GLUT_KEY_PAGE_DOWN: currentpage += fz_maxi(number, 1); break; + case GLFW_KEY_UP: scroll_y -= 10; break; + case GLFW_KEY_DOWN: scroll_y += 10; break; + case GLFW_KEY_LEFT: scroll_x -= 10; break; + case GLFW_KEY_RIGHT: scroll_x += 10; break; + case GLFW_KEY_PAGE_UP: currentpage -= fz_maxi(number, 1); break; + case GLFW_KEY_PAGE_DOWN: currentpage += fz_maxi(number, 1); break; } number = 0; @@ -1398,38 +1392,33 @@ static void special(int key, int x, int y) if (search_hit_page != currentpage) search_hit_page = -1; /* clear highlights when navigating */ - - glutPostRedisplay(); } -static void mouse(int button, int state, int x, int y) +static void on_mouse_button(GLFWwindow *window, int button, int action, int mod) { switch (button) { - case GLUT_LEFT_BUTTON: ui.down = (state == GLUT_DOWN); break; - case GLUT_MIDDLE_BUTTON: ui.middle = (state == GLUT_DOWN); break; - case GLUT_RIGHT_BUTTON: ui.right = (state == GLUT_DOWN); break; + case GLFW_MOUSE_BUTTON_LEFT: ui.down = (action == GLFW_PRESS); break; + case GLFW_MOUSE_BUTTON_MIDDLE: ui.middle = (action == GLFW_PRESS); break; + case GLFW_MOUSE_BUTTON_RIGHT: ui.right = (action == GLFW_PRESS); break; } - ui.x = x; - ui.y = y; - glutPostRedisplay(); } -static void motion(int x, int y) +static void on_mouse_motion(GLFWwindow *window, double x, double y) { ui.x = x; ui.y = y; - glutPostRedisplay(); } -int main(int argc, char **argv) +static void on_error(int error, const char *msg) { - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); - glutInitWindowSize(800, 1000); + fprintf(stderr, "gl error %d: %s\n", error, msg); +} +int main(int argc, char **argv) +{ if (argc < 2) { - fprintf(stderr, "usage: mupdf-glut input.pdf\n"); + fprintf(stderr, "usage: mupdf-gl input.pdf\n"); exit(1); } @@ -1448,7 +1437,20 @@ int main(int argc, char **argv) search_input.q = search_input.p; search_input.end = search_input.p; - glutCreateWindow(filename); + if (!glfwInit()) { + fprintf(stderr, "cannot initialize glfw\n"); + exit(1); + } + + glfwSetErrorCallback(on_error); + + window = glfwCreateWindow(800, 1000, filename, NULL, NULL); + if (!window) { + fprintf(stderr, "cannot create glfw window\n"); + exit(1); + } + + glfwMakeContextCurrent(window); ctx = fz_new_context(NULL, NULL, 0); fz_register_document_handlers(ctx); @@ -1459,14 +1461,23 @@ int main(int argc, char **argv) update_title(); shrinkwrap(); - glutReshapeFunc(reshape); - glutDisplayFunc(display); - glutKeyboardFunc(keyboard); - glutSpecialFunc(special); - glutMouseFunc(mouse); - glutMotionFunc(motion); - glutPassiveMotionFunc(motion); - glutMainLoop(); + ui_init_fonts(ctx, fontsize); + + glfwSetCursorPosCallback(window, on_mouse_motion); + glfwSetMouseButtonCallback(window, on_mouse_button); + glfwSetFramebufferSizeCallback(window, on_reshape); + glfwSetCharCallback(window, on_keyboard); + glfwSetKeyCallback(window, on_special); + + glfwGetFramebufferSize(window, &screen_w, &screen_h); + + while (!glfwWindowShouldClose(window)) + { + glfwWaitEvents(); + on_display(window); + } + + ui_finish_fonts(ctx); fz_drop_link(ctx, links); fz_drop_document(ctx, doc); @@ -1474,3 +1485,13 @@ int main(int argc, char **argv) return 0; } + +#ifdef _MSC_VER +int wmain(int argc, wchar_t *wargv[]) +{ + char **argv = fz_argv_from_wargv(argc, wargv); + int ret = main(argc, argv); + fz_free_argv(argc, argv); + return ret; +} +#endif diff --git a/platform/win32/libglfw.vcproj b/platform/win32/libglfw.vcproj new file mode 100644 index 00000000..f209c823 --- /dev/null +++ b/platform/win32/libglfw.vcproj @@ -0,0 +1,231 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="libglfw" + ProjectGUID="{A1B75D29-9F5C-4A0F-B368-322A10477D0C}" + RootNamespace="libglfw" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="4" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_GLFW_WIN32;_GLFW_WGL;_GLFW_USE_OPENGL" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="4" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_GLFW_WIN32;_GLFW_WGL;_GLFW_USE_OPENGL" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="include" + > + <File + RelativePath="..\..\thirdparty\glfw\include\GLFW\glfw3.h" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\include\GLFW\glfw3native.h" + > + </File> + </Filter> + <Filter + Name="src" + > + <File + RelativePath="..\..\thirdparty\glfw\src\context.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\init.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\input.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\internal.h" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\monitor.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\wgl_context.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\wgl_context.h" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\win32_init.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\win32_monitor.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\win32_platform.h" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\win32_time.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\win32_tls.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\win32_tls.h" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\win32_window.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\window.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\winmm_joystick.c" + > + </File> + <File + RelativePath="..\..\thirdparty\glfw\src\winmm_joystick.h" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/platform/win32/mupdf-gl.vcproj b/platform/win32/mupdf-gl.vcproj new file mode 100644 index 00000000..b1adc8c2 --- /dev/null +++ b/platform/win32/mupdf-gl.vcproj @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="mupdf-gl" + ProjectGUID="{CE3A76A8-A28F-4991-8FB9-C9453D922037}" + RootNamespace="mupdfgl" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\glfw\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="opengl32.lib" + LinkIncremental="0" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\include;..\..\thirdparty\glfw\include;..\..\scripts\freetype;..\..\thirdparty\freetype\include" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="opengl32.lib" + LinkIncremental="0" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath="..\gl\gl-font.c" + > + </File> + <File + RelativePath="..\gl\gl-main.c" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/platform/win32/mupdf.sln b/platform/win32/mupdf.sln index c7d3b0b5..1a7982bd 100644 --- a/platform/win32/mupdf.sln +++ b/platform/win32/mupdf.sln @@ -39,6 +39,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdf-curl", "mupdf-curl.vc EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mujstest", "mujstest.vcproj", "{21E28758-E4D2-4B84-8EC5-B631CEE66B30}" ProjectSection(ProjectDependencies) = postProject + {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} + {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libglfw", "libglfw.vcproj", "{A1B75D29-9F5C-4A0F-B368-322A10477D0C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdf-gl", "mupdf-gl.vcproj", "{CE3A76A8-A28F-4991-8FB9-C9453D922037}" + ProjectSection(ProjectDependencies) = postProject + {A1B75D29-9F5C-4A0F-B368-322A10477D0C} = {A1B75D29-9F5C-4A0F-B368-322A10477D0C} {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} EndProjectSection @@ -237,6 +246,36 @@ Global {21E28758-E4D2-4B84-8EC5-B631CEE66B30}.ReleaseOpenssl|Win32.Build.0 = ReleaseOpenssl|Win32 {21E28758-E4D2-4B84-8EC5-B631CEE66B30}.ReleaseOpenssl|x64.ActiveCfg = ReleaseOpenssl|x64 {21E28758-E4D2-4B84-8EC5-B631CEE66B30}.ReleaseOpenssl|x64.Build.0 = ReleaseOpenssl|x64 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Debug|Win32.ActiveCfg = Debug|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Debug|Win32.Build.0 = Debug|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Debug|x64.ActiveCfg = Debug|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.DebugOpenssl|Win32.ActiveCfg = Debug|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.DebugOpenssl|Win32.Build.0 = Debug|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.DebugOpenssl|x64.ActiveCfg = Debug|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Memento|Win32.ActiveCfg = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Memento|Win32.Build.0 = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Memento|x64.ActiveCfg = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Release|Win32.ActiveCfg = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Release|Win32.Build.0 = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.Release|x64.ActiveCfg = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.ReleaseOpenssl|Win32.ActiveCfg = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.ReleaseOpenssl|Win32.Build.0 = Release|Win32 + {A1B75D29-9F5C-4A0F-B368-322A10477D0C}.ReleaseOpenssl|x64.ActiveCfg = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Debug|Win32.ActiveCfg = Debug|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Debug|Win32.Build.0 = Debug|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Debug|x64.ActiveCfg = Debug|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.DebugOpenssl|Win32.ActiveCfg = Debug|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.DebugOpenssl|Win32.Build.0 = Debug|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.DebugOpenssl|x64.ActiveCfg = Debug|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Memento|Win32.ActiveCfg = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Memento|Win32.Build.0 = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Memento|x64.ActiveCfg = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Release|Win32.ActiveCfg = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Release|Win32.Build.0 = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.Release|x64.ActiveCfg = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.ReleaseOpenssl|Win32.ActiveCfg = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.ReleaseOpenssl|Win32.Build.0 = Release|Win32 + {CE3A76A8-A28F-4991-8FB9-C9453D922037}.ReleaseOpenssl|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE |