summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile22
-rw-r--r--Makethird55
-rw-r--r--platform/gl/gl-font.c365
-rw-r--r--platform/gl/gl-main.c (renamed from platform/glut/glut-main.c)315
-rw-r--r--platform/win32/libglfw.vcproj231
-rw-r--r--platform/win32/mupdf-gl.vcproj187
-rw-r--r--platform/win32/mupdf.sln39
7 files changed, 1057 insertions, 157 deletions
diff --git a/Makefile b/Makefile
index d8eb37fe..96963c75 100644
--- a/Makefile
+++ b/Makefile
@@ -71,7 +71,7 @@ ALL_DIR += $(OUT)/gprf
ALL_DIR += $(OUT)/tools
ALL_DIR += $(OUT)/platform/x11
ALL_DIR += $(OUT)/platform/x11/curl
-ALL_DIR += $(OUT)/platform/glut
+ALL_DIR += $(OUT)/platform/gl
FITZ_HDR := include/mupdf/fitz.h $(wildcard include/mupdf/fitz/*.h)
PDF_HDR := include/mupdf/pdf.h $(wildcard include/mupdf/pdf/*.h)
@@ -166,8 +166,8 @@ $(OUT)/platform/x11/%.o: platform/x11/%.rc | $(OUT)
$(OUT)/platform/x11/curl/%.o : platform/x11/%.c | $(ALL_DIR)
$(CC_CMD) $(X11_CFLAGS) $(CURL_CFLAGS) -DHAVE_CURL
-$(OUT)/platform/glut/%.o : platform/glut/%.c | $(ALL_DIR)
- $(CC_CMD) $(GLUT_CFLAGS)
+$(OUT)/platform/gl/%.o : platform/gl/%.c | $(ALL_DIR)
+ $(CC_CMD) $(GLFW_CFLAGS)
.PRECIOUS : $(OUT)/%.o # Keep intermediates from chained rules
@@ -269,11 +269,13 @@ $(MUVIEW_X11) : $(MUPDF_LIB) $(THIRD_LIBS)
$(MUVIEW_X11) : $(MUVIEW_X11_OBJ)
$(LINK_CMD) $(X11_LIBS)
-ifeq "$(HAVE_GLUT)" "yes"
-MUVIEW_GLUT := $(OUT)/mupdf-glut
-$(MUVIEW_GLUT) : $(MUPDF_LIB) $(MUPDF_JS_NONE_LIB) $(THIRD_LIBS)
-$(MUVIEW_GLUT) : $(addprefix $(OUT)/platform/glut/, glut-main.o)
- $(LINK_CMD) $(GLUT_LIBS)
+ifeq "$(HAVE_GLFW)" "yes"
+MUVIEW_GLFW := $(OUT)/mupdf-gl
+MUVIEW_GLFW_OBJ := $(addprefix $(OUT)/platform/gl/, gl-font.o gl-main.o)
+$(MUVIEW_GLFW_OBJ) : $(FITZ_HDR) $(PDF_HDR)
+$(MUVIEW_GLFW) : $(MUPDF_LIB) $(THIRD_LIBS) $(GLFW_LIB)
+$(MUVIEW_GLFW) : $(MUVIEW_GLFW_OBJ)
+ $(LINK_CMD) $(GLFW_LIBS)
endif
ifeq "$(HAVE_CURL)" "yes"
@@ -295,7 +297,7 @@ $(MUVIEW_WIN32) : $(MUVIEW_WIN32_OBJ)
$(LINK_CMD) $(WIN32_LIBS)
endif
-MUVIEW := $(MUVIEW_X11) $(MUVIEW_WIN32) $(MUVIEW_GLUT)
+MUVIEW := $(MUVIEW_X11) $(MUVIEW_WIN32) $(MUVIEW_GLFW)
MUVIEW_CURL := $(MUVIEW_X11_CURL) $(MUVIEW_WIN32_CURL)
INSTALL_APPS := $(MUTOOL) $(MUVIEW) $(MUJSTEST) $(MUVIEW_CURL)
@@ -335,7 +337,7 @@ incdir ?= $(prefix)/include
mandir ?= $(prefix)/share/man
docdir ?= $(prefix)/share/doc/mupdf
-third: $(THIRD_LIBS) $(CURL_LIB)
+third: $(THIRD_LIBS) $(CURL_LIB) $(GLFW_LIB)
libs: $(INSTALL_LIBS)
apps: $(INSTALL_APPS)
diff --git a/Makethird b/Makethird
index ac4b2857..79f4dc07 100644
--- a/Makethird
+++ b/Makethird
@@ -14,6 +14,7 @@ OPENJPEG_DIR := thirdparty/openjpeg/libopenjpeg
OPENSSL_DIR := thirdparty/openssl
ZLIB_DIR := thirdparty/zlib
CURL_DIR := thirdparty/curl
+GLFW_DIR := thirdparty/glfw
# --- V8 ---
#
@@ -460,6 +461,60 @@ CURL_CFLAGS := $(SYS_CURL_CFLAGS)
CURL_LIBS := $(SYS_CURL_LIBS)
endif
+# --- GLFW ---
+
+ifneq "$(wildcard $(GLFW_DIR)/README.md)" ""
+
+GLFW_LIB := $(OUT)/libglfw.a
+GLFW_OUT := $(OUT)/glfw
+GLFW_SRC := \
+ context.c \
+ glx_context.c \
+ init.c \
+ input.c \
+ linux_joystick.c \
+ monitor.c \
+ posix_time.c \
+ posix_tls.c \
+ window.c \
+ x11_init.c \
+ x11_monitor.c \
+ x11_window.c \
+ xkb_unicode.c \
+
+GLFW_SRC_UNUSED := \
+ egl_context.c \
+ mach_time.c \
+ mir_init.c \
+ mir_monitor.c \
+ mir_window.c \
+ win32_init.c \
+ win32_monitor.c \
+ win32_time.c \
+ win32_tls.c \
+ win32_window.c \
+ winmm_joystick.c \
+ wgl_context.c \
+ wl_init.c \
+ wl_monitor.c \
+ wl_window.c \
+
+$(GLFW_LIB): $(addprefix $(GLFW_OUT)/, $(GLFW_SRC:%.c=%.o))
+$(GLFW_OUT):
+ $(MKDIR_CMD)
+$(GLFW_OUT)/%.o: $(GLFW_DIR)/src/%.c | $(GLFW_OUT)
+ $(CC_CMD) -D_GLFW_X11 -D_GLFW_GLX -D_GLFW_USE_OPENGL -D_GLFW_HAS_GLXGETPROCADDRESS
+
+GLFW_CFLAGS := -I$(GLFW_DIR)/include
+GLFW_LIBS := -lGL -lX11 -lXcursor -lXrandr -lXinerama -lpthread
+
+HAVE_GLFW := yes
+
+else ifeq "$(HAVE_GLFW)" "yes"
+GLFW_CFLAGS := $(SYS_GLFW_CFLAGS)
+GLFW_LIBS := $(SYS_GLFW_LIBS)
+endif
+
# --- X11 ---
ifeq "$(HAVE_X11)" "yes"
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