diff options
author | Tor Lillqvist <tml@collabora.com> | 2015-11-19 11:46:03 +0200 |
---|---|---|
committer | Tor Lillqvist <tml@collabora.com> | 2015-11-19 14:05:31 +0200 |
commit | a12454b390a718e982461255491c0f26a5a3bbca (patch) | |
tree | 16a99b5a6f4d795d89a53329fa8444b5eed91a49 /vcl | |
parent | 2afd347f508a3e30dd7065061c48f4f738e17934 (diff) |
Use GLyphy for text on Windows (broken)
Work in progress. Produces visible text in some cases, but not nearly
all. The text that is visible is roughly in the right place and of the
right size, but horribly ugly. Compare to glyphy-demo, which does
produce beautiful text, so the problem is not in the GLyphy code but
in the way we use it.
Include sources from GLyphy's "demo" directory (with only slight
modifications to avoid unconditional debug output) and use that "demo"
API from vcl.
The changes to existing vcl code are all in one place, in the
winlayout.cxx file.
Change-Id: I69cce5d66db534c6f4c1ab85d520b6090baf8fe0
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/Library_vcl.mk | 2 | ||||
-rwxr-xr-x | vcl/glyphy/demo.cxx | 19 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-atlas.cc | 144 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-buffer.cc | 191 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-font.cc | 333 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-shader.cc | 212 | ||||
-rw-r--r-- | vcl/glyphy/demo/matrix4x4.c | 481 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo.hxx | 21 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-atlas-glsl.h | 18 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-atlas.h | 54 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-buffer.h | 64 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-common.h | 186 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-font.h | 88 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-fshader-glsl.h | 88 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-shader.h | 47 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-vshader-glsl.h | 24 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/matrix4x4.h | 107 | ||||
-rw-r--r-- | vcl/win/source/gdi/winlayout.cxx | 499 |
18 files changed, 2270 insertions, 308 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 983e10fd228a..f3981dd774e1 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -41,6 +41,7 @@ $(eval $(call gb_Library_set_include,vcl,\ $$(INCLUDE) \ -I$(SRCDIR)/vcl/inc \ $(if $(filter WNTGCC,$(OS)$(COM)),-I$(MINGW_SYSROOT)/include/gdiplus) \ + $(if $(filter WNT,$(OS)),-I$(SRCDIR)/vcl/inc/glyphy/demo) \ )) ifeq ($(ENABLE_DBUS),TRUE) @@ -690,6 +691,7 @@ endif ifeq ($(OS),WNT) $(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/glyphy/demo \ vcl/opengl/win/gdiimpl \ vcl/opengl/win/WinDeviceInfo \ vcl/opengl/win/blocklist_parser \ diff --git a/vcl/glyphy/demo.cxx b/vcl/glyphy/demo.cxx new file mode 100755 index 000000000000..7f4f12adc74e --- /dev/null +++ b/vcl/glyphy/demo.cxx @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <prewin.h> +#include <postwin.h> + +namespace GLyphyDemo { +#include "demo/demo-atlas.cc" +#include "demo/demo-buffer.cc" +#include "demo/demo-font.cc" +#include "demo/demo-shader.cc" +#include "demo/matrix4x4.c" +} diff --git a/vcl/glyphy/demo/demo-atlas.cc b/vcl/glyphy/demo/demo-atlas.cc new file mode 100644 index 000000000000..d84da068363a --- /dev/null +++ b/vcl/glyphy/demo/demo-atlas.cc @@ -0,0 +1,144 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-atlas.h" + + +struct demo_atlas_t { + unsigned int refcount; + + GLuint tex_unit; + GLuint tex_name; + GLuint tex_w; + GLuint tex_h; + GLuint item_w; + GLuint item_h_q; /* height quantum */ + GLuint cursor_x; + GLuint cursor_y; +}; + + +demo_atlas_t * +demo_atlas_create (unsigned int w, + unsigned int h, + unsigned int item_w, + unsigned int item_h_quantum) +{ + TRACE(); + + demo_atlas_t *at = (demo_atlas_t *) calloc (1, sizeof (demo_atlas_t)); + at->refcount = 1; + + glGetIntegerv (GL_ACTIVE_TEXTURE, (GLint *) &at->tex_unit); + glGenTextures (1, &at->tex_name); + at->tex_w = w; + at->tex_h = h; + at->item_w = item_w; + at->item_h_q = item_h_quantum; + at->cursor_x = 0; + at->cursor_y = 0; + + demo_atlas_bind_texture (at); + + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + gl(TexImage2D) (GL_TEXTURE_2D, 0, GL_RGBA, at->tex_w, at->tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + return at; +} + +demo_atlas_t * +demo_atlas_reference (demo_atlas_t *at) +{ + if (at) at->refcount++; + return at; +} + +void +demo_atlas_destroy (demo_atlas_t *at) +{ + if (!at || --at->refcount) + return; + + glDeleteTextures (1, &at->tex_name); + free (at); +} + +void +demo_atlas_bind_texture (demo_atlas_t *at) +{ + glActiveTexture (at->tex_unit); + glBindTexture (GL_TEXTURE_2D, at->tex_name); +} + +void +demo_atlas_set_uniforms (demo_atlas_t *at) +{ + GLuint program; + glGetIntegerv (GL_CURRENT_PROGRAM, (GLint *) &program); + + glUniform4i (glGetUniformLocation (program, "u_atlas_info"), + at->tex_w, at->tex_h, at->item_w, at->item_h_q); + glUniform1i (glGetUniformLocation (program, "u_atlas_tex"), at->tex_unit - GL_TEXTURE0); +} + +void +demo_atlas_alloc (demo_atlas_t *at, + glyphy_rgba_t *data, + unsigned int len, + unsigned int *px, + unsigned int *py) +{ + GLuint w, h, x, y; + + w = at->item_w; + h = (len + w - 1) / w; + + if (at->cursor_y + h > at->tex_h) { + /* Go to next column */ + at->cursor_x += at->item_w; + at->cursor_y = 0; + } + + if (at->cursor_x + w <= at->tex_w && + at->cursor_y + h <= at->tex_h) + { + x = at->cursor_x; + y = at->cursor_y; + at->cursor_y += (h + at->item_h_q - 1) & ~(at->item_h_q - 1); + } else + die ("Ran out of atlas memory"); + + demo_atlas_bind_texture (at); + if (w * h == len) + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data); + else { + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h - 1, GL_RGBA, GL_UNSIGNED_BYTE, data); + /* Upload the last row separately */ + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y + h - 1, len - (w * (h - 1)), 1, GL_RGBA, GL_UNSIGNED_BYTE, + data + w * (h - 1)); + } + + *px = x / at->item_w; + *py = y / at->item_h_q; +} diff --git a/vcl/glyphy/demo/demo-buffer.cc b/vcl/glyphy/demo/demo-buffer.cc new file mode 100644 index 000000000000..8ce5b34fcd78 --- /dev/null +++ b/vcl/glyphy/demo/demo-buffer.cc @@ -0,0 +1,191 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-buffer.h" + +struct demo_buffer_t { + unsigned int refcount; + + glyphy_point_t cursor; + std::vector<glyph_vertex_t> *vertices; + glyphy_extents_t ink_extents; + glyphy_extents_t logical_extents; + bool dirty; + GLuint buf_name; +}; + +demo_buffer_t * +demo_buffer_create (void) +{ + demo_buffer_t *buffer = (demo_buffer_t *) calloc (1, sizeof (demo_buffer_t)); + buffer->refcount = 1; + + buffer->vertices = new std::vector<glyph_vertex_t>; + glGenBuffers (1, &buffer->buf_name); + + demo_buffer_clear (buffer); + + return buffer; +} + +demo_buffer_t * +demo_buffer_reference (demo_buffer_t *buffer) +{ + if (buffer) buffer->refcount++; + return buffer; +} + +void +demo_buffer_destroy (demo_buffer_t *buffer) +{ + if (!buffer || --buffer->refcount) + return; + + glDeleteBuffers (1, &buffer->buf_name); + delete buffer->vertices; + free (buffer); +} + + +void +demo_buffer_clear (demo_buffer_t *buffer) +{ + buffer->vertices->clear (); + glyphy_extents_clear (&buffer->ink_extents); + glyphy_extents_clear (&buffer->logical_extents); + buffer->dirty = true; +} + +void +demo_buffer_extents (demo_buffer_t *buffer, + glyphy_extents_t *ink_extents, + glyphy_extents_t *logical_extents) +{ + if (ink_extents) + *ink_extents = buffer->ink_extents; + if (logical_extents) + *logical_extents = buffer->logical_extents; +} + +void +demo_buffer_move_to (demo_buffer_t *buffer, + const glyphy_point_t *p) +{ + buffer->cursor = *p; +} + +void +demo_buffer_current_point (demo_buffer_t *buffer, + glyphy_point_t *p) +{ + *p = buffer->cursor; +} + +void +demo_buffer_add_text (demo_buffer_t *buffer, + const char *utf8, + demo_font_t *font, + double font_size) +{ +#ifndef _WIN32 + FT_Face face = demo_font_get_face (font); +#else + HDC hdc = demo_font_get_face (font); +#endif + glyphy_point_t top_left = buffer->cursor; + buffer->cursor.y += font_size /* * font->ascent */; + unsigned int unicode; + for (const unsigned char *p = (const unsigned char *) utf8; *p; p++) { + if (*p < 128) { + unicode = *p; + } else { + unsigned int j; + if (*p < 0xE0) { + unicode = *p & ~0xE0; + j = 1; + } else if (*p < 0xF0) { + unicode = *p & ~0xF0; + j = 2; + } else { + unicode = *p & ~0xF8; + j = 3; + continue; + } + p++; + for (; j && *p; j--, p++) + unicode = (unicode << 6) | (*p & ~0xC0); + p--; + } + + if (unicode == '\n') { + buffer->cursor.y += font_size; + buffer->cursor.x = top_left.x; + continue; + } + +#ifndef _WIN32 + unsigned int glyph_index = FT_Get_Char_Index (face, unicode); +#else + wchar_t wc = unicode; /* FIXME: What about non-BMP chars? */ + WORD glyph_index; + if (GetGlyphIndicesW (hdc, &wc, 1, &glyph_index, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) + die ("GetGlyphIndicesW failed"); +#endif + glyph_info_t gi; + demo_font_lookup_glyph (font, glyph_index, &gi); + + /* Update ink extents */ + glyphy_extents_t ink_extents; + demo_shader_add_glyph_vertices (buffer->cursor, font_size, &gi, buffer->vertices, &ink_extents); + glyphy_extents_extend (&buffer->ink_extents, &ink_extents); + + /* Update logical extents */ + glyphy_point_t corner; + corner.x = buffer->cursor.x; + corner.y = buffer->cursor.y - font_size; + glyphy_extents_add (&buffer->logical_extents, &corner); + corner.x = buffer->cursor.x + font_size * gi.advance; + corner.y = buffer->cursor.y; + glyphy_extents_add (&buffer->logical_extents, &corner); + + buffer->cursor.x += font_size * gi.advance; + } + + buffer->dirty = true; +} + +void +demo_buffer_draw (demo_buffer_t *buffer) +{ + GLint program; + glGetIntegerv (GL_CURRENT_PROGRAM, &program); + GLuint a_glyph_vertex_loc = glGetAttribLocation (program, "a_glyph_vertex"); + glBindBuffer (GL_ARRAY_BUFFER, buffer->buf_name); + if (buffer->dirty) { + glBufferData (GL_ARRAY_BUFFER, sizeof (glyph_vertex_t) * buffer->vertices->size (), (const char *) &(*buffer->vertices)[0], GL_STATIC_DRAW); + buffer->dirty = false; + } + glEnableVertexAttribArray (a_glyph_vertex_loc); + glVertexAttribPointer (a_glyph_vertex_loc, 4, GL_FLOAT, GL_FALSE, sizeof (glyph_vertex_t), 0); + glDrawArrays (GL_TRIANGLES, 0, buffer->vertices->size ()); + glDisableVertexAttribArray (a_glyph_vertex_loc); +} diff --git a/vcl/glyphy/demo/demo-font.cc b/vcl/glyphy/demo/demo-font.cc new file mode 100644 index 000000000000..c28778e899c3 --- /dev/null +++ b/vcl/glyphy/demo/demo-font.cc @@ -0,0 +1,333 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-font.h" + +#ifndef _WIN32 +#include <glyphy-freetype.h> +#endif + +#ifdef _WIN32 +#include <glyphy-windows.h> +#endif + +#include <map> +#include <vector> + +typedef std::map<unsigned int, glyph_info_t> glyph_cache_t; + +struct demo_font_t { + unsigned int refcount; + +#ifndef _WIN32 + FT_Face face; +#endif + +#ifdef _WIN32 + HDC face; /* A memory DC that has the font instance selected into it */ +#endif + + glyph_cache_t *glyph_cache; + demo_atlas_t *atlas; + glyphy_arc_accumulator_t *acc; + + /* stats */ + unsigned int num_glyphs; + double sum_error; + unsigned int sum_endpoints; + double sum_fetch; + unsigned int sum_bytes; +}; + +demo_font_t * +demo_font_create ( +#ifndef _WIN32 + FT_Face face, +#endif +#ifdef _WIN32 + HDC face, +#endif + demo_atlas_t *atlas) +{ + demo_font_t *font = (demo_font_t *) calloc (1, sizeof (demo_font_t)); + font->refcount = 1; + + font->face = face; + font->glyph_cache = new glyph_cache_t (); + font->atlas = demo_atlas_reference (atlas); + font->acc = glyphy_arc_accumulator_create (); + + font->num_glyphs = 0; + font->sum_error = 0; + font->sum_endpoints = 0; + font->sum_fetch = 0; + font->sum_bytes = 0; + + return font; +} + +demo_font_t * +demo_font_reference (demo_font_t *font) +{ + if (font) font->refcount++; + return font; +} + +void +demo_font_destroy (demo_font_t *font) +{ + if (!font || --font->refcount) + return; + + glyphy_arc_accumulator_destroy (font->acc); + demo_atlas_destroy (font->atlas); + delete font->glyph_cache; + free (font); +} + + +#ifndef _WIN32 +FT_Face +#endif +#ifdef _WIN32 +HDC +#endif +demo_font_get_face (demo_font_t *font) +{ + return font->face; +} + +demo_atlas_t * +demo_font_get_atlas (demo_font_t *font) +{ + return font->atlas; +} + + +static glyphy_bool_t +accumulate_endpoint (glyphy_arc_endpoint_t *endpoint, + std::vector<glyphy_arc_endpoint_t> *endpoints) +{ + endpoints->push_back (*endpoint); + return true; +} + +static void +encode_glyph (demo_font_t *font, + unsigned int glyph_index, + double tolerance_per_em, + glyphy_rgba_t *buffer, + unsigned int buffer_len, + unsigned int *output_len, + unsigned int *nominal_width, + unsigned int *nominal_height, + glyphy_extents_t *extents, + double *advance) +{ +/* Used for testing only */ +#define SCALE (1. * (1 << 0)) + +#ifndef _WIN32 + FT_Face face = font->face; + if (FT_Err_Ok != FT_Load_Glyph (face, + glyph_index, + FT_LOAD_NO_BITMAP | + FT_LOAD_NO_HINTING | + FT_LOAD_NO_AUTOHINT | + FT_LOAD_NO_SCALE | + FT_LOAD_LINEAR_DESIGN | + FT_LOAD_IGNORE_TRANSFORM)) + die ("Failed loading FreeType glyph"); + + if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) + die ("FreeType loaded glyph format is not outline"); + + unsigned int upem = face->units_per_EM; + double tolerance = upem * tolerance_per_em; /* in font design units */ + double faraway = double (upem) / (MIN_FONT_SIZE * M_SQRT2); + std::vector<glyphy_arc_endpoint_t> endpoints; + + glyphy_arc_accumulator_reset (font->acc); + glyphy_arc_accumulator_set_tolerance (font->acc, tolerance); + glyphy_arc_accumulator_set_callback (font->acc, + (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint, + &endpoints); + + if (FT_Err_Ok != glyphy_freetype(outline_decompose) (&face->glyph->outline, font->acc)) + die ("Failed converting glyph outline to arcs"); +#endif + +#ifdef _WIN32 + HDC hdc = font->face; + + GLYPHMETRICS glyph_metrics; + MAT2 matrix; + + matrix.eM11.value = 1; + matrix.eM11.fract = 0; + matrix.eM12.value = 0; + matrix.eM12.fract = 0; + matrix.eM21.value = 0; + matrix.eM21.fract = 0; + matrix.eM22.value = 1; + matrix.eM22.fract = 0; + + DWORD size = GetGlyphOutlineW (hdc, glyph_index, GGO_NATIVE|GGO_GLYPH_INDEX, &glyph_metrics, 0, NULL, &matrix); + if (size == GDI_ERROR) + die ("GetGlyphOutlineW failed"); + std::vector<char> buf(size); + size = GetGlyphOutlineW (hdc, glyph_index, GGO_NATIVE|GGO_GLYPH_INDEX, &glyph_metrics, size, buf.data(), &matrix); + if (size == GDI_ERROR) + die ("GetGlyphOutlineW failed"); + + size = GetGlyphOutlineW (hdc, glyph_index, GGO_METRICS|GGO_GLYPH_INDEX, &glyph_metrics, 0, NULL, &matrix); + if (size == GDI_ERROR) + die ("GetGlyphOutlineW failed"); + + OUTLINETEXTMETRICW outline_text_metric; + if (!GetOutlineTextMetricsW (hdc, sizeof (OUTLINETEXTMETRICW), &outline_text_metric)) + die ("GetOutlineTextMetricsW failed"); + + unsigned int upem = outline_text_metric.otmEMSquare; + double tolerance = upem * tolerance_per_em; /* in font design units */ + double faraway = double (upem) / (MIN_FONT_SIZE * M_SQRT2); + std::vector<glyphy_arc_endpoint_t> endpoints; + + glyphy_arc_accumulator_reset (font->acc); + glyphy_arc_accumulator_set_tolerance (font->acc, tolerance); + glyphy_arc_accumulator_set_callback (font->acc, + (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint, + &endpoints); + + if (0 != glyphy_windows(outline_decompose) ((TTPOLYGONHEADER *) buf.data(), buf.size(), font->acc)) + die ("Failed converting glyph outline to arcs"); +#endif + + assert (glyphy_arc_accumulator_get_error (font->acc) <= tolerance); + + if (endpoints.size ()) + { +#if 0 + /* Technically speaking, we want the following code, + * however, crappy fonts have crappy flags. So we just + * fixup unconditionally... */ + if (face->glyph->outline.flags & FT_OUTLINE_EVEN_ODD_FILL) + glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false); + else if (face->glyph->outline.flags & FT_OUTLINE_REVERSE_FILL) + glyphy_outline_reverse (&endpoints[0], endpoints.size ()); +#else + glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false); +#endif + } + + if (SCALE != 1.) + for (unsigned int i = 0; i < endpoints.size (); i++) + { + endpoints[i].p.x /= SCALE; + endpoints[i].p.y /= SCALE; + } + + double avg_fetch_achieved; + if (!glyphy_arc_list_encode_blob (endpoints.size () ? &endpoints[0] : NULL, endpoints.size (), + buffer, + buffer_len, + faraway / SCALE, + 4, /* UNUSED */ + &avg_fetch_achieved, + output_len, + nominal_width, + nominal_height, + extents)) + die ("Failed encoding arcs"); + + glyphy_extents_scale (extents, 1. / upem, 1. / upem); + glyphy_extents_scale (extents, SCALE, SCALE); + +#ifndef _WIN32 + *advance = face->glyph->metrics.horiAdvance / (double) upem; +#endif + +#ifdef _WIN32 + *advance = glyph_metrics.gmCellIncX / (double) upem; /* ??? */ +#endif + + if (0) + LOGI ("gid%3u: endpoints%3d; err%3g%%; tex fetch%4.1f; mem%4.1fkb\n", + glyph_index, + (unsigned int) glyphy_arc_accumulator_get_num_endpoints (font->acc), + round (100 * glyphy_arc_accumulator_get_error (font->acc) / tolerance), + avg_fetch_achieved, + (*output_len * sizeof (glyphy_rgba_t)) / 1024.); + + font->num_glyphs++; + font->sum_error += glyphy_arc_accumulator_get_error (font->acc) / tolerance; + font->sum_endpoints += glyphy_arc_accumulator_get_num_endpoints (font->acc); + font->sum_fetch += avg_fetch_achieved; + font->sum_bytes += (*output_len * sizeof (glyphy_rgba_t)); +} + +static void +_demo_font_upload_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info) +{ + glyphy_rgba_t buffer[4096 * 16]; + unsigned int output_len; + + encode_glyph (font, + glyph_index, + TOLERANCE, + buffer, ARRAY_LEN (buffer), + &output_len, + &glyph_info->nominal_w, + &glyph_info->nominal_h, + &glyph_info->extents, + &glyph_info->advance); + + glyph_info->is_empty = glyphy_extents_is_empty (&glyph_info->extents); + if (!glyph_info->is_empty) + demo_atlas_alloc (font->atlas, buffer, output_len, + &glyph_info->atlas_x, &glyph_info->atlas_y); +} + +void +demo_font_lookup_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info) +{ + if (font->glyph_cache->find (glyph_index) == font->glyph_cache->end ()) { + _demo_font_upload_glyph (font, glyph_index, glyph_info); + (*font->glyph_cache)[glyph_index] = *glyph_info; + } else + *glyph_info = (*font->glyph_cache)[glyph_index]; +} + +void +demo_font_print_stats (demo_font_t *font) +{ + LOGI ("%3d glyphs; avg num endpoints%6.2f; avg error%5.1f%%; avg tex fetch%5.2f; avg %5.2fkb per glyph\n", + font->num_glyphs, + (double) font->sum_endpoints / font->num_glyphs, + 100. * font->sum_error / font->num_glyphs, + font->sum_fetch / font->num_glyphs, + font->sum_bytes / 1024. / font->num_glyphs); +} diff --git a/vcl/glyphy/demo/demo-shader.cc b/vcl/glyphy/demo/demo-shader.cc new file mode 100644 index 000000000000..9b8212333175 --- /dev/null +++ b/vcl/glyphy/demo/demo-shader.cc @@ -0,0 +1,212 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-shader.h" + +#include "demo-atlas-glsl.h" +#include "demo-vshader-glsl.h" +#include "demo-fshader-glsl.h" + + +static unsigned int +glyph_encode (unsigned int atlas_x , /* 7 bits */ + unsigned int atlas_y, /* 7 bits */ + unsigned int corner_x, /* 1 bit */ + unsigned int corner_y, /* 1 bit */ + unsigned int nominal_w, /* 6 bits */ + unsigned int nominal_h /* 6 bits */) +{ + assert (0 == (atlas_x & ~0x7F)); + assert (0 == (atlas_y & ~0x7F)); + assert (0 == (corner_x & ~1)); + assert (0 == (corner_y & ~1)); + assert (0 == (nominal_w & ~0x3F)); + assert (0 == (nominal_h & ~0x3F)); + + unsigned int x = (((atlas_x << 6) | nominal_w) << 1) | corner_x; + unsigned int y = (((atlas_y << 6) | nominal_h) << 1) | corner_y; + + return (x << 16) | y; +} + +static void +glyph_vertex_encode (double x, double y, + unsigned int corner_x, unsigned int corner_y, + const glyph_info_t *gi, + glyph_vertex_t *v) +{ + unsigned int encoded = glyph_encode (gi->atlas_x, gi->atlas_y, + corner_x, corner_y, + gi->nominal_w, gi->nominal_h); + v->x = x; + v->y = y; + v->g16hi = encoded >> 16; + v->g16lo = encoded & 0xFFFF; +} + +void +demo_shader_add_glyph_vertices (const glyphy_point_t &p, + double font_size, + glyph_info_t *gi, + std::vector<glyph_vertex_t> *vertices, + glyphy_extents_t *extents) +{ + if (gi->is_empty) + return; + + glyph_vertex_t v[4]; + +#define ENCODE_CORNER(_cx, _cy) \ + do { \ + double _vx = p.x + font_size * ((1-_cx) * gi->extents.min_x + _cx * gi->extents.max_x); \ + double _vy = p.y - font_size * ((1-_cy) * gi->extents.min_y + _cy * gi->extents.max_y); \ + glyph_vertex_encode (_vx, _vy, _cx, _cy, gi, &v[_cx * 2 + _cy]); \ + } while (0) + ENCODE_CORNER (0, 0); + ENCODE_CORNER (0, 1); + ENCODE_CORNER (1, 0); + ENCODE_CORNER (1, 1); +#undef ENCODE_CORNER + + vertices->push_back (v[0]); + vertices->push_back (v[1]); + vertices->push_back (v[2]); + + vertices->push_back (v[1]); + vertices->push_back (v[2]); + vertices->push_back (v[3]); + + if (extents) { + glyphy_extents_clear (extents); + for (unsigned int i = 0; i < 4; i++) { + glyphy_point_t p = {v[i].x, v[i].y}; + glyphy_extents_add (extents, &p); + } + } +} + + + + +static GLuint +compile_shader (GLenum type, + GLsizei count, + const GLchar** sources) +{ + TRACE(); + + GLuint shader; + GLint compiled; + + if (!(shader = glCreateShader (type))) + return shader; + + glShaderSource (shader, count, sources, 0); + glCompileShader (shader); + + glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint info_len = 0; + LOGW ("%s shader failed to compile\n", + type == GL_VERTEX_SHADER ? "Vertex" : "Fragment"); + glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len); + + if (info_len > 0) { + char *info_log = (char*) malloc (info_len); + glGetShaderInfoLog (shader, info_len, NULL, info_log); + + LOGW ("%s\n", info_log); + free (info_log); + } + + abort (); + } + + return shader; +} + +static GLuint +link_program (GLuint vshader, + GLuint fshader) +{ + TRACE(); + + GLuint program; + GLint linked; + + program = glCreateProgram (); + glAttachShader (program, vshader); + glAttachShader (program, fshader); + glLinkProgram (program); + glDeleteShader (vshader); + glDeleteShader (fshader); + + glGetProgramiv (program, GL_LINK_STATUS, &linked); + if (!linked) { + GLint info_len = 0; + LOGW ("Program failed to link\n"); + glGetProgramiv (program, GL_INFO_LOG_LENGTH, &info_len); + + if (info_len > 0) { + char *info_log = (char*) malloc (info_len); + glGetProgramInfoLog (program, info_len, NULL, info_log); + + LOGW ("%s\n", info_log); + free (info_log); + } + + abort (); + } + + return program; +} + +#ifdef GL_ES_VERSION_2_0 +# define GLSL_HEADER_STRING \ + "#extension GL_OES_standard_derivatives : enable\n" \ + "precision highp float;\n" \ + "precision highp int;\n" +#else +# define GLSL_HEADER_STRING \ + "#version 110\n" +#endif + +GLuint +demo_shader_create_program (void) +{ + TRACE(); + + GLuint vshader, fshader, program; + const GLchar *vshader_sources[] = {GLSL_HEADER_STRING, + demo_vshader_glsl}; + vshader = compile_shader (GL_VERTEX_SHADER, ARRAY_LEN (vshader_sources), vshader_sources); + const GLchar *fshader_sources[] = {GLSL_HEADER_STRING, + demo_atlas_glsl, + glyphy_common_shader_source (), + "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n", + glyphy_sdf_shader_source (), + demo_fshader_glsl}; + fshader = compile_shader (GL_FRAGMENT_SHADER, ARRAY_LEN (fshader_sources), fshader_sources); + + program = link_program (vshader, fshader); + return program; +} diff --git a/vcl/glyphy/demo/matrix4x4.c b/vcl/glyphy/demo/matrix4x4.c new file mode 100644 index 000000000000..f103589e6593 --- /dev/null +++ b/vcl/glyphy/demo/matrix4x4.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2009, Mozilla Corp + * Copyright (c) 2012, Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers + * the following header: + * + * Book: OpenGL(R) ES 2.0 Programming Guide + * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner + * ISBN-10: 0321502795 + * ISBN-13: 9780321502797 + * Publisher: Addison-Wesley Professional + * URLs: http://safari.informit.com/9780321563835 + * http://www.opengles-book.com + */ + +/* + * Ported from JavaScript to C by Behdad Esfahbod, 2012. + * Added MultMatrix. Converting from fixed-function OpenGL matrix + * operations to these functions should be as simple as renaming the + * 'gl' prefix to 'm4' and adding the matrix argument to the call. + * + * The C version lives at http://code.google.com/p/matrix4x4-c/ + */ + +#include "matrix4x4.h" +#include <math.h> + +/* + * A simple 4x4 matrix utility implementation + */ + + +float * +m4LoadIdentity (float *mat) { + unsigned int i; + for (i = 0; i < 16; i++) + mat[i] = 0; + mat[0*4+0] = 1.0; + mat[1*4+1] = 1.0; + mat[2*4+2] = 1.0; + mat[3*4+3] = 1.0; + return mat; +} + +/* Copies other matrix into mat */ +float * +m4Copy (float *mat, const float *other) { + unsigned int i; + for (i = 0; i < 16; i++) { + mat[i] = other[i]; + } + return mat; +} + +float * +m4Multiply (float *mat, const float *right) { + float tmp[16]; + unsigned int i; + + for (i = 0; i < 4; i++) { + tmp[i*4+0] = + (mat[i*4+0] * right[0*4+0]) + + (mat[i*4+1] * right[1*4+0]) + + (mat[i*4+2] * right[2*4+0]) + + (mat[i*4+3] * right[3*4+0]) ; + + tmp[i*4+1] = + (mat[i*4+0] * right[0*4+1]) + + (mat[i*4+1] * right[1*4+1]) + + (mat[i*4+2] * right[2*4+1]) + + (mat[i*4+3] * right[3*4+1]) ; + + tmp[i*4+2] = + (mat[i*4+0] * right[0*4+2]) + + (mat[i*4+1] * right[1*4+2]) + + (mat[i*4+2] * right[2*4+2]) + + (mat[i*4+3] * right[3*4+2]) ; + + tmp[i*4+3] = + (mat[i*4+0] * right[0*4+3]) + + (mat[i*4+1] * right[1*4+3]) + + (mat[i*4+2] * right[2*4+3]) + + (mat[i*4+3] * right[3*4+3]) ; + } + + return m4Copy (mat, tmp); +} + +float +m4Get (float *mat, unsigned int row, unsigned int col) { + return mat[4*row+col]; +} + +float * +m4MultMatrix (float *mat, const float *left) { + float tmp[16]; + return m4Copy (mat, m4Multiply (m4Copy (tmp, left), mat)); +} + +float * +m4Scale (float *mat, float sx, float sy, float sz) { + mat[0*4+0] *= sx; + mat[0*4+1] *= sx; + mat[0*4+2] *= sx; + mat[0*4+3] *= sx; + + mat[1*4+0] *= sy; + mat[1*4+1] *= sy; + mat[1*4+2] *= sy; + mat[1*4+3] *= sy; + + mat[2*4+0] *= sz; + mat[2*4+1] *= sz; + mat[2*4+2] *= sz; + mat[2*4+3] *= sz; + + return mat; +} + +float * +m4Translate (float *mat, float tx, float ty, float tz) { + mat[3*4+0] += mat[0*4+0] * tx + mat[1*4+0] * ty + mat[2*4+0] * tz; + mat[3*4+1] += mat[0*4+1] * tx + mat[1*4+1] * ty + mat[2*4+1] * tz; + mat[3*4+2] += mat[0*4+2] * tx + mat[1*4+2] * ty + mat[2*4+2] * tz; + mat[3*4+3] += mat[0*4+3] * tx + mat[1*4+3] * ty + mat[2*4+3] * tz; + + return mat; +} + +float * +m4Rotate (float *mat, float angle, float x, float y, float z) { + float mag = sqrt(x*x + y*y + z*z); + float sinAngle = sin(angle * M_PI / 180.0); + float cosAngle = cos(angle * M_PI / 180.0); + + float xx, yy, zz, xy, yz, zx, xs, ys, zs; + float oneMinusCos; + + float rotMat[16]; + + if (mag <= 0) + return mat; + + m4LoadIdentity (rotMat); + + x /= mag; + y /= mag; + z /= mag; + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * sinAngle; + ys = y * sinAngle; + zs = z * sinAngle; + oneMinusCos = 1.0 - cosAngle; + + rotMat[0*4+0] = (oneMinusCos * xx) + cosAngle; + rotMat[0*4+1] = (oneMinusCos * xy) - zs; + rotMat[0*4+2] = (oneMinusCos * zx) + ys; + rotMat[0*4+3] = 0.0; + + rotMat[1*4+0] = (oneMinusCos * xy) + zs; + rotMat[1*4+1] = (oneMinusCos * yy) + cosAngle; + rotMat[1*4+2] = (oneMinusCos * yz) - xs; + rotMat[1*4+3] = 0.0; + + rotMat[2*4+0] = (oneMinusCos * zx) - ys; + rotMat[2*4+1] = (oneMinusCos * yz) + xs; + rotMat[2*4+2] = (oneMinusCos * zz) + cosAngle; + rotMat[2*4+3] = 0.0; + + rotMat[3*4+0] = 0.0; + rotMat[3*4+1] = 0.0; + rotMat[3*4+2] = 0.0; + rotMat[3*4+3] = 1.0; + + return m4Copy (mat, m4Multiply (rotMat, mat)); +} + +float * +m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + + float frust[16]; + + if ( (nearZ <= 0.0) || (farZ <= 0.0) || + (deltaX <= 0.0) || (deltaY <= 0.0) || (deltaZ <= 0.0) ) + return mat; + + m4LoadIdentity (frust); + + frust[0*4+0] = 2.0 * nearZ / deltaX; + frust[0*4+1] = frust[0*4+2] = frust[0*4+3] = 0.0; + + frust[1*4+1] = 2.0 * nearZ / deltaY; + frust[1*4+0] = frust[1*4+2] = frust[1*4+3] = 0.0; + + frust[2*4+0] = (right + left) / deltaX; + frust[2*4+1] = (top + bottom) / deltaY; + frust[2*4+2] = -(nearZ + farZ) / deltaZ; + frust[2*4+3] = -1.0; + + frust[3*4+2] = -2.0 * nearZ * farZ / deltaZ; + frust[3*4+0] = frust[3*4+1] = frust[3*4+3] = 0.0; + + return m4Copy (mat, m4Multiply (frust, mat)); +} + +float * +m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ) { + float frustumH = tan(fovy / 360.0 * M_PI) * nearZ; + float frustumW = frustumH * aspect; + + return m4Frustum(mat, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ); +} + +float * +m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + + float ortho[16]; + + if ( (deltaX == 0.0) || (deltaY == 0.0) || (deltaZ == 0.0) ) + return mat; + + m4LoadIdentity (ortho); + + ortho[0*4+0] = 2.0 / deltaX; + ortho[3*4+0] = -(right + left) / deltaX; + ortho[1*4+1] = 2.0 / deltaY; + ortho[3*4+1] = -(top + bottom) / deltaY; + ortho[2*4+2] = -2.0 / deltaZ; + ortho[3*4+2] = -(nearZ + farZ) / deltaZ; + + return m4Copy (mat, m4Multiply (ortho, mat)); +} + +/* In-place inversion */ +float * +m4Invert (float *mat) { + float tmp_0 = m4Get(mat,2,2) * m4Get(mat,3,3); + float tmp_1 = m4Get(mat,3,2) * m4Get(mat,2,3); + float tmp_2 = m4Get(mat,1,2) * m4Get(mat,3,3); + float tmp_3 = m4Get(mat,3,2) * m4Get(mat,1,3); + float tmp_4 = m4Get(mat,1,2) * m4Get(mat,2,3); + float tmp_5 = m4Get(mat,2,2) * m4Get(mat,1,3); + float tmp_6 = m4Get(mat,0,2) * m4Get(mat,3,3); + float tmp_7 = m4Get(mat,3,2) * m4Get(mat,0,3); + float tmp_8 = m4Get(mat,0,2) * m4Get(mat,2,3); + float tmp_9 = m4Get(mat,2,2) * m4Get(mat,0,3); + float tmp_10 = m4Get(mat,0,2) * m4Get(mat,1,3); + float tmp_11 = m4Get(mat,1,2) * m4Get(mat,0,3); + float tmp_12 = m4Get(mat,2,0) * m4Get(mat,3,1); + float tmp_13 = m4Get(mat,3,0) * m4Get(mat,2,1); + float tmp_14 = m4Get(mat,1,0) * m4Get(mat,3,1); + float tmp_15 = m4Get(mat,3,0) * m4Get(mat,1,1); + float tmp_16 = m4Get(mat,1,0) * m4Get(mat,2,1); + float tmp_17 = m4Get(mat,2,0) * m4Get(mat,1,1); + float tmp_18 = m4Get(mat,0,0) * m4Get(mat,3,1); + float tmp_19 = m4Get(mat,3,0) * m4Get(mat,0,1); + float tmp_20 = m4Get(mat,0,0) * m4Get(mat,2,1); + float tmp_21 = m4Get(mat,2,0) * m4Get(mat,0,1); + float tmp_22 = m4Get(mat,0,0) * m4Get(mat,1,1); + float tmp_23 = m4Get(mat,1,0) * m4Get(mat,0,1); + + float t0 = ((tmp_0 * m4Get(mat,1,1) + tmp_3 * m4Get(mat,2,1) + tmp_4 * m4Get(mat,3,1)) - + (tmp_1 * m4Get(mat,1,1) + tmp_2 * m4Get(mat,2,1) + tmp_5 * m4Get(mat,3,1))); + float t1 = ((tmp_1 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,2,1) + tmp_9 * m4Get(mat,3,1)) - + (tmp_0 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,2,1) + tmp_8 * m4Get(mat,3,1))); + float t2 = ((tmp_2 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,3,1)) - + (tmp_3 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,3,1))); + float t3 = ((tmp_5 * m4Get(mat,0,1) + tmp_8 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,2,1)) - + (tmp_4 * m4Get(mat,0,1) + tmp_9 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,2,1))); + + float d = 1.0 / (m4Get(mat,0,0) * t0 + m4Get(mat,1,0) * t1 + m4Get(mat,2,0) * t2 + m4Get(mat,3,0) * t3); + + float out_00 = d * t0; + float out_01 = d * t1; + float out_02 = d * t2; + float out_03 = d * t3; + + float out_10 = d * ((tmp_1 * m4Get(mat,1,0) + tmp_2 * m4Get(mat,2,0) + tmp_5 * m4Get(mat,3,0)) - + (tmp_0 * m4Get(mat,1,0) + tmp_3 * m4Get(mat,2,0) + tmp_4 * m4Get(mat,3,0))); + float out_11 = d * ((tmp_0 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,2,0) + tmp_8 * m4Get(mat,3,0)) - + (tmp_1 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,2,0) + tmp_9 * m4Get(mat,3,0))); + float out_12 = d * ((tmp_3 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,3,0)) - + (tmp_2 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,3,0))); + float out_13 = d * ((tmp_4 * m4Get(mat,0,0) + tmp_9 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,2,0)) - + (tmp_5 * m4Get(mat,0,0) + tmp_8 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,2,0))); + + float out_20 = d * ((tmp_12 * m4Get(mat,1,3) + tmp_15 * m4Get(mat,2,3) + tmp_16 * m4Get(mat,3,3)) - + (tmp_13 * m4Get(mat,1,3) + tmp_14 * m4Get(mat,2,3) + tmp_17 * m4Get(mat,3,3))); + float out_21 = d * ((tmp_13 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,2,3) + tmp_21 * m4Get(mat,3,3)) - + (tmp_12 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,2,3) + tmp_20 * m4Get(mat,3,3))); + float out_22 = d * ((tmp_14 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,3,3)) - + (tmp_15 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,3,3))); + float out_23 = d * ((tmp_17 * m4Get(mat,0,3) + tmp_20 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,2,3)) - + (tmp_16 * m4Get(mat,0,3) + tmp_21 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,2,3))); + + float out_30 = d * ((tmp_14 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,1,2)) - + (tmp_16 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,1,2) + tmp_15 * m4Get(mat,2,2))); + float out_31 = d * ((tmp_20 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,2,2)) - + (tmp_18 * m4Get(mat,2,2) + tmp_21 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,0,2))); + float out_32 = d * ((tmp_18 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,3,2) + tmp_15 * m4Get(mat,0,2)) - + (tmp_22 * m4Get(mat,3,2) + tmp_14 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,1,2))); + float out_33 = d * ((tmp_22 * m4Get(mat,2,2) + tmp_16 * m4Get(mat,0,2) + tmp_21 * m4Get(mat,1,2)) - + (tmp_20 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,0,2))); + + mat[0*4+0] = out_00; + mat[0*4+1] = out_01; + mat[0*4+2] = out_02; + mat[0*4+3] = out_03; + mat[1*4+0] = out_10; + mat[1*4+1] = out_11; + mat[1*4+2] = out_12; + mat[1*4+3] = out_13; + mat[2*4+0] = out_20; + mat[2*4+1] = out_21; + mat[2*4+2] = out_22; + mat[2*4+3] = out_23; + mat[3*4+0] = out_30; + mat[3*4+1] = out_31; + mat[3*4+2] = out_32; + mat[3*4+3] = out_33; + return mat; +} + +/* Puts the inverse of other matrix into mat */ +float * +m4Inverse (float *mat, const float *other) { + m4Copy (mat, other); + m4Invert (mat); + return mat; +} + +/* In-place transpose */ +float * +m4Transpose (float *mat) { + float tmp = mat[0*4+1]; + mat[0*4+1] = mat[1*4+0]; + mat[1*4+0] = tmp; + + tmp = mat[0*4+2]; + mat[0*4+2] = mat[2*4+0]; + mat[2*4+0] = tmp; + + tmp = mat[0*4+3]; + mat[0*4+3] = mat[3*4+0]; + mat[3*4+0] = tmp; + + tmp = mat[1*4+2]; + mat[1*4+2] = mat[2*4+1]; + mat[2*4+1] = tmp; + + tmp = mat[1*4+3]; + mat[1*4+3] = mat[3*4+1]; + mat[3*4+1] = tmp; + + tmp = mat[2*4+3]; + mat[2*4+3] = mat[3*4+2]; + mat[3*4+2] = tmp; + + return mat; +} + +float * +m4ApplyToVect (float *mat, float *vec) +{ + float tmp[4] = {vec[0], vec[1], vec[2], vec[3]}; + + vec[0] = mat[0]*tmp[0] + mat[4]*tmp[1] + mat[8]*tmp[2] + mat[12]*tmp[3]; + vec[1] = mat[1]*tmp[0] + mat[5]*tmp[1] + mat[9]*tmp[2] + mat[13]*tmp[3]; + vec[2] = mat[2]*tmp[0] + mat[6]*tmp[1] + mat[10]*tmp[2] + mat[14]*tmp[3]; + vec[3] = mat[3]*tmp[0] + mat[7]*tmp[1] + mat[11]*tmp[2] + mat[15]*tmp[3]; + + return vec; +} + +#ifdef TEST + +#include <stdio.h> + +static void setvec (float *vec, float x, float y, float z, float w) +{ + vec[0] = x; + vec[1] = y; + vec[2] = z; + vec[3] = w; +} + +static void printmat (float *mat) +{ + printf("(%f,%f,%f,%f,\n", mat[0], mat[1], mat[2], mat[3]); + printf(" %f,%f,%f,%f,\n", mat[4], mat[5], mat[6], mat[7]); + printf(" %f,%f,%f,%f,\n", mat[8], mat[9], mat[10], mat[11]); + printf(" %f,%f,%f,%f)\n", mat[12], mat[13], mat[14], mat[15]); +} + +static void printvec (float *vec) +{ + printf("(%f,%f,%f,%f)\n", vec[0], vec[1], vec[2], vec[3]); +} + +int main(int argc, char **argv) +{ + float mat[16]; + float vec[4]; + + setvec (vec, 1, 2, 3, 1); + printf ("vec:\n"); + printvec (vec); + + m4LoadIdentity (mat); + printf ("Identity matrix:\n"); + printmat (mat); + + m4Scale (mat, 2, 2, 2); + printf ("Scale by 2:\n"); + printmat (mat); + + m4LoadIdentity (mat); + m4Translate (mat, 2, 3, 0); + printf ("Translate by (2,3,0):\n"); + printmat (mat); + + printf ("Apply that to vec:\n"); + m4ApplyToVect (mat, vec); + printvec (vec); + + m4LoadIdentity (mat); + m4Scale (mat, 2, 2, 2); + m4ApplyToVect (mat, vec); + printf ("Scale then by 2:\n"); + printvec (vec); + + setvec (vec, 1, 2, 3, 1); + m4LoadIdentity (mat); + m4Scale (mat, 2, 2, 2); + m4Translate (mat, 2, 3, 0); + m4ApplyToVect (mat, vec); + printf ("Both in one step:\n"); + printvec (vec); + + return 0; +} + +#endif diff --git a/vcl/inc/glyphy/demo.hxx b/vcl/inc/glyphy/demo.hxx new file mode 100644 index 000000000000..2323186764cf --- /dev/null +++ b/vcl/inc/glyphy/demo.hxx @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_GLYPHY_DEMO_HXX +#define INCLUDED_VCL_INC_GLYPHY_DEMO_HXX + +namespace GLyphyDemo { +#include "demo-atlas.h" +#include "demo-buffer.h" +#include "demo-font.h" +#include "demo-shader.h" +#include "matrix4x4.h" +} + +#endif // INCLUDED_VCL_INC_GLYPHY_DEMO_HXX diff --git a/vcl/inc/glyphy/demo/demo-atlas-glsl.h b/vcl/inc/glyphy/demo/demo-atlas-glsl.h new file mode 100644 index 000000000000..9b93c2ab129f --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-atlas-glsl.h @@ -0,0 +1,18 @@ +static const char *demo_atlas_glsl = +"uniform sampler2D u_atlas_tex;\n" +"uniform ivec4 u_atlas_info;\n" +"\n" +"#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos\n" +"#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos\n" +"#define GLYPHY_DEMO_EXTRA_ARGS , u_atlas_tex, u_atlas_info, gi.atlas_pos\n" +"\n" +"vec4\n" +"glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)\n" +"{\n" +" ivec2 item_geom = _atlas_info.zw;\n" +" vec2 pos = (vec2 (_atlas_pos.xy * item_geom +\n" +" ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +\n" +" + vec2 (.5, .5)) / vec2(_atlas_info.xy);\n" +" return texture2D (_tex, pos);\n" +"}\n" +; diff --git a/vcl/inc/glyphy/demo/demo-atlas.h b/vcl/inc/glyphy/demo/demo-atlas.h new file mode 100644 index 000000000000..729403f472fa --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-atlas.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju + */ + +#ifndef DEMO_ATLAS_H +#define DEMO_ATLAS_H + +#include "demo-common.h" + + +typedef struct demo_atlas_t demo_atlas_t; + +demo_atlas_t * +demo_atlas_create (unsigned int w, + unsigned int h, + unsigned int item_w, + unsigned int item_h_quantum); + +demo_atlas_t * +demo_atlas_reference (demo_atlas_t *at); + +void +demo_atlas_destroy (demo_atlas_t *at); + + +void +demo_atlas_alloc (demo_atlas_t *at, + glyphy_rgba_t *data, + unsigned int len, + unsigned int *px, + unsigned int *py); + +void +demo_atlas_bind_texture (demo_atlas_t *at); + +void +demo_atlas_set_uniforms (demo_atlas_t *at); + + +#endif /* DEMO_ATLAS_H */ diff --git a/vcl/inc/glyphy/demo/demo-buffer.h b/vcl/inc/glyphy/demo/demo-buffer.h new file mode 100644 index 000000000000..2948a7ff0a04 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-buffer.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_BUFFER_H +#define DEMO_BUFFER_H + +#include "demo-common.h" +#include "demo-font.h" +#include "demo-shader.h" + +typedef struct demo_buffer_t demo_buffer_t; + +demo_buffer_t * +demo_buffer_create (void); + +demo_buffer_t * +demo_buffer_reference (demo_buffer_t *buffer); + +void +demo_buffer_destroy (demo_buffer_t *buffer); + + +void +demo_buffer_clear (demo_buffer_t *buffer); + +void +demo_buffer_extents (demo_buffer_t *buffer, + glyphy_extents_t *ink_extents, + glyphy_extents_t *logical_extents); + +void +demo_buffer_move_to (demo_buffer_t *buffer, + const glyphy_point_t *p); + +void +demo_buffer_current_point (demo_buffer_t *buffer, + glyphy_point_t *p); + +void +demo_buffer_add_text (demo_buffer_t *buffer, + const char *utf8, + demo_font_t *font, + double font_size); + +void +demo_buffer_draw (demo_buffer_t *buffer); + + +#endif /* DEMO_BUFFER_H */ diff --git a/vcl/inc/glyphy/demo/demo-common.h b/vcl/inc/glyphy/demo/demo-common.h new file mode 100644 index 000000000000..380942f82297 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-common.h @@ -0,0 +1,186 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju + */ + +#ifndef DEMO_COMMON_H +#define DEMO_COMMON_H + +#include <glyphy.h> + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> + +#include <algorithm> +#include <vector> + +/* Tailor config for various platforms. */ + +#ifdef EMSCRIPTEN +/* https://github.com/kripken/emscripten/issues/340 */ +# undef HAVE_GLEW + /* WebGL shaders are ES2 */ +# define GL_ES_VERSION_2_0 1 +#endif + +#if defined(__ANDROID__) +# define HAVE_GLES2 1 +# define HAVE_GLUT 1 +#endif + +#ifdef _WIN32 +# define HAVE_GL 1 +# define HAVE_GLEW 1 +#endif + +/* Get Glew out of the way. */ +#ifdef HAVE_GLEW +# include <GL/glew.h> +#else +# define GLEW_OK 0 + static inline int glewInit (void) { return GLEW_OK; } + static inline int glewIsSupported (const char *s) + { return 0 == strcmp ("GL_VERSION_2_0", s); } +#endif /* HAVE_GLEW */ + +/* WTF this block?! */ +#if defined(HAVE_GLES2) +# include <GLES2/gl2.h> +#elif defined(HAVE_GL) +# ifndef HAVE_GLEW +# define GL_GLEXT_PROTOTYPES 1 +# if defined(__APPLE__) +# include <OpenGL/gl.h> +# else +# include <GL/gl.h> +# endif +# endif +# if defined(__APPLE__) +# include <OpenGL/OpenGL.h> +# else +# ifdef HAVE_GLEW +# ifdef _WIN32 +# include <GL/wglew.h> +# else +# include <GL/glxew.h> +# endif +# endif +# endif +#endif /* HAVE_GL */ + +/* Finally, Glut. */ +#ifdef HAVE_GLUT +# if defined(__APPLE__) +# include <GLUT/glut.h> +# else +# include <GL/glut.h> +# endif +#endif + + + + +/* Logging. */ +#ifdef __ANDROID__ +# include <android/log.h> +# define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "glyphy-demo", __VA_ARGS__)) +# define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "glyphy-demo", __VA_ARGS__)) +# define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "glyphy-demo", __VA_ARGS__)) +#else /* !__ANDROID__ */ +#if 0 +# define LOGI(...) ((void) fprintf (stderr, __VA_ARGS__)) +# define LOGW(...) ((void) fprintf (stderr, __VA_ARGS__)) +# define LOGE(...) ((void) fprintf (stderr, __VA_ARGS__), abort ()) +#else +# define LOGI(...) do { } while(false) +# define LOGW(...) do { } while(false) +# define LOGE(...) do { } while(false) +#endif +#endif + + + +#define STRINGIZE1(Src) #Src +#define STRINGIZE(Src) STRINGIZE1(Src) + +#define ARRAY_LEN(Array) (sizeof (Array) / sizeof (*Array)) + + +#define MIN_FONT_SIZE 10 +#define TOLERANCE (1./2048) + + +#define gl(name) \ + for (GLint __ee, __ii = 0; \ + __ii < 1; \ + (__ii++, \ + (__ee = glGetError()) && \ + (reportGLerror (__ee, #name, __LINE__, __FILE__), 0))) \ + gl##name + + +static inline void +reportGLerror(GLint e, const char *api, int line, const char *file) +{ + fflush(stdout); + fprintf(stderr, "\nwglGetCurrentDC=%p wglGetCurrentContext=%p\n", wglGetCurrentDC(), wglGetCurrentContext()); + fprintf (stderr, "gl%s failed with error %04X on %s:%d\n", api, e, file, line); + fflush (stderr); + exit (1); +} + +static inline void +die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + exit (1); +} + +template <typename T> +T clamp (T v, T m, T M) +{ + return v < m ? m : v > M ? M : v; +} + + +#if defined(_MSC_VER) +#define DEMO_FUNC __FUNCSIG__ +#else +#define DEMO_FUNC __func__ +#endif + +struct auto_trace_t +{ + auto_trace_t (const char *func_) : func (func_) + { printf ("Enter: %s\n", func); } + + ~auto_trace_t (void) + { printf ("Leave: %s\n", func); } + + private: + const char * const func; +}; + +#if 0 +#define TRACE() auto_trace_t trace(DEMO_FUNC) +#else +#define TRACE() do { } while(false) +#endif + +#endif /* DEMO_COMMON_H */ diff --git a/vcl/inc/glyphy/demo/demo-font.h b/vcl/inc/glyphy/demo/demo-font.h new file mode 100644 index 000000000000..d4e75ff3f2d6 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-font.h @@ -0,0 +1,88 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_FONT_H +#define DEMO_FONT_H + +#include "demo-common.h" +#include "demo-atlas.h" + +#ifndef _WIN32 +#include <ft2build.h> +#include FT_FREETYPE_H +#endif + +#ifdef _WIN32 +#include <windows.h> +#define DEFAULT_FONT "Calibri" +#undef near +#undef far +#endif + +typedef struct { + glyphy_extents_t extents; + double advance; + glyphy_bool_t is_empty; /* has no outline; eg. space; don't draw it */ + unsigned int nominal_w; + unsigned int nominal_h; + unsigned int atlas_x; + unsigned int atlas_y; +} glyph_info_t; + + +typedef struct demo_font_t demo_font_t; + +demo_font_t * +demo_font_create ( +#ifndef _WIN32 + FT_Face face, +#endif +#ifdef _WIN32 + HDC hdc, +#endif + demo_atlas_t *atlas); + +demo_font_t * +demo_font_reference (demo_font_t *font); + +void +demo_font_destroy (demo_font_t *font); + + +#ifndef _WIN32 +FT_Face +#endif +#ifdef _WIN32 +HDC +#endif +demo_font_get_face (demo_font_t *font); + +demo_atlas_t * +demo_font_get_atlas (demo_font_t *font); + + +void +demo_font_lookup_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info); + +void +demo_font_print_stats (demo_font_t *font); + + +#endif /* DEMO_FONT_H */ diff --git a/vcl/inc/glyphy/demo/demo-fshader-glsl.h b/vcl/inc/glyphy/demo/demo-fshader-glsl.h new file mode 100644 index 000000000000..d80a6cc82b26 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-fshader-glsl.h @@ -0,0 +1,88 @@ +static const char *demo_fshader_glsl = +"uniform float u_contrast;\n" +"uniform float u_gamma_adjust;\n" +"uniform float u_outline_thickness;\n" +"uniform bool u_outline;\n" +"uniform float u_boldness;\n" +"uniform bool u_debug;\n" +"\n" +"varying vec4 v_glyph;\n" +"\n" +"\n" +"#define SQRT2_2 0.70710678118654757 /* 1 / sqrt(2.) */\n" +"#define SQRT2 1.4142135623730951\n" +"\n" +"struct glyph_info_t {\n" +" ivec2 nominal_size;\n" +" ivec2 atlas_pos;\n" +"};\n" +"\n" +"glyph_info_t\n" +"glyph_info_decode (vec4 v)\n" +"{\n" +" glyph_info_t gi;\n" +" gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;\n" +" gi.atlas_pos = ivec2 (v_glyph.zw) / 256;\n" +" return gi;\n" +"}\n" +"\n" +"\n" +"float\n" +"antialias (float d)\n" +"{\n" +" return smoothstep (-.75, +.75, d);\n" +"}\n" +"\n" +"vec4\n" +"source_over (const vec4 src, const vec4 dst)\n" +"{\n" +" // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover\n" +" float alpha = src.a + (dst.a * (1. - src.a));\n" +" return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);\n" +"}\n" +"\n" +"void\n" +"main()\n" +"{\n" +" vec2 p = v_glyph.xy;\n" +" glyph_info_t gi = glyph_info_decode (v_glyph);\n" +"\n" +" /* isotropic antialiasing */\n" +" vec2 dpdx = dFdx (p);\n" +" vec2 dpdy = dFdy (p);\n" +" float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;\n" +"\n" +" vec4 color = vec4 (0,0,0,1);\n" +"\n" +" float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n" +" float sdist = gsdist / m * u_contrast;\n" +"\n" +" if (!u_debug) {\n" +" sdist -= u_boldness * 10.;\n" +" if (u_outline)\n" +" sdist = abs (sdist) - u_outline_thickness * .5;\n" +" if (sdist > 1.)\n" +" discard;\n" +" float alpha = antialias (-sdist);\n" +" if (u_gamma_adjust != 1.)\n" +" alpha = pow (alpha, 1./u_gamma_adjust);\n" +" color = vec4 (color.rgb,color.a * alpha);\n" +" } else {\n" +" float gudist = abs (gsdist);\n" +" float debug_color = 0.4;\n" +" // Color the distance field red inside and green outside\n" +" if (!glyphy_isinf (gudist))\n" +" color = source_over (vec4 (debug_color * smoothstep (1., -1., sdist), debug_color * smoothstep (-1., 1., sdist), 0, 1. - gudist), color);\n" +"\n" +" glyphy_arc_list_t arc_list = glyphy_arc_list (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n" +" // Color the number of endpoints per cell blue\n" +" color = source_over (vec4 (0, 0, debug_color, float(arc_list.num_endpoints) / float(GLYPHY_MAX_NUM_ENDPOINTS)), color);\n" +"\n" +" float pdist = glyphy_point_dist (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n" +" // Color points yellow\n" +" color = source_over (vec4 (1, 1, 0, smoothstep (.06, .05, pdist)), color);\n" +" }\n" +"\n" +" gl_FragColor = color;\n" +"}\n" +; diff --git a/vcl/inc/glyphy/demo/demo-shader.h b/vcl/inc/glyphy/demo/demo-shader.h new file mode 100644 index 000000000000..dfa548091039 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-shader.h @@ -0,0 +1,47 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_SHADERS_H +#define DEMO_SHADERS_H + +#include "demo-common.h" +#include "demo-font.h" + + +struct glyph_vertex_t { + /* Position */ + GLfloat x; + GLfloat y; + /* Glyph info */ + GLfloat g16hi; + GLfloat g16lo; +}; + +void +demo_shader_add_glyph_vertices (const glyphy_point_t &p, + double font_size, + glyph_info_t *gi, + std::vector<glyph_vertex_t> *vertices, + glyphy_extents_t *extents); + + +GLuint +demo_shader_create_program (void); + + +#endif /* DEMO_SHADERS_H */ diff --git a/vcl/inc/glyphy/demo/demo-vshader-glsl.h b/vcl/inc/glyphy/demo/demo-vshader-glsl.h new file mode 100644 index 000000000000..c952ab719b2c --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-vshader-glsl.h @@ -0,0 +1,24 @@ +static const char *demo_vshader_glsl = +"uniform mat4 u_matViewProjection;\n" +"\n" +"attribute vec4 a_glyph_vertex;\n" +"\n" +"varying vec4 v_glyph;\n" +"\n" +"vec4\n" +"glyph_vertex_transcode (vec2 v)\n" +"{\n" +" ivec2 g = ivec2 (v);\n" +" ivec2 corner = ivec2 (mod (v, 2.));\n" +" g /= 2;\n" +" ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));\n" +" return vec4 (corner * nominal_size, g * 4);\n" +"}\n" +"\n" +"void\n" +"main()\n" +"{\n" +" gl_Position = u_matViewProjection * vec4 (a_glyph_vertex.xy, 0, 1);\n" +" v_glyph = glyph_vertex_transcode (a_glyph_vertex.zw);\n" +"}\n" +; diff --git a/vcl/inc/glyphy/demo/matrix4x4.h b/vcl/inc/glyphy/demo/matrix4x4.h new file mode 100644 index 000000000000..2169561007e3 --- /dev/null +++ b/vcl/inc/glyphy/demo/matrix4x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2009, Mozilla Corp + * Copyright (c) 2012, Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers + * the following header: + * + * Book: OpenGL(R) ES 2.0 Programming Guide + * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner + * ISBN-10: 0321502795 + * ISBN-13: 9780321502797 + * Publisher: Addison-Wesley Professional + * URLs: http://safari.informit.com/9780321563835 + * http://www.opengles-book.com + */ + +/* + * Ported from JavaScript to C by Behdad Esfahbod, 2012. + * Added MultMatrix. Converting from fixed-function OpenGL matrix + * operations to these functions should be as simple as renaming the + * 'gl' prefix to 'm4' and adding the matrix argument to the call. + * + * The C version lives at http://code.google.com/p/matrix4x4-c/ + */ + +/* + * A simple 4x4 matrix utility implementation + */ + +#ifndef MATRIX4x4_H +#define MATRIX4x4_H + +/* Copies other matrix into mat */ +float * +m4Copy (float *mat, const float *other); + +float * +m4Multiply (float *mat, const float *right); + +float * +m4MultMatrix (float *mat, const float *left); + +float +m4Get (float *mat, unsigned int row, unsigned int col); + +float * +m4Scale (float *mat, float sx, float sy, float sz); + +float * +m4Translate (float *mat, float tx, float ty, float tz); + +float * +m4Rotate (float *mat, float angle, float x, float y, float z); + +float * +m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ); + +float * +m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ); + +float * +m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ); + +/* In-place inversion */ +float * +m4Invert (float *mat); + +/* Puts the inverse of other matrix into mat */ +float * +m4Inverse (float *mat, const float *other); + +/* In-place transpose */ +float * +m4Transpose (float *mat); + +float * +m4LoadIdentity (float *mat); + +float * +m4ApplyToVect (float *mat, float *vec); + +#endif diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 2409d4b36303..5ae2ce4b4722 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -33,6 +33,7 @@ #include "sft.hxx" #include "sallayout.hxx" +#include "glyphy/demo.hxx" #include <cstdio> #include <cstdlib> @@ -46,8 +47,6 @@ #include <unordered_map> -typedef std::unordered_map<int,int> IntMap; - // Graphite headers #include <config_graphite.h> #if ENABLE_GRAPHITE @@ -67,33 +66,13 @@ const int GLYPH_SPACE_RATIO = 8; const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2; } -struct OpenGLGlyphCacheChunk -{ - WORD mnFirstGlyph; - int mnGlyphCount; - std::vector<Rectangle> maLocation; - std::shared_ptr<OpenGLTexture> mpTexture; - int mnAscent; - int mnHeight; - bool mbVertical; - - int getExtraSpace() const - { - return std::max(mnHeight / GLYPH_SPACE_RATIO, 4); - } - - int getExtraOffset() const - { - return std::max(mnHeight / GLYPH_OFFSET_RATIO, 2); - } -}; - // win32 specific physical font instance class ImplWinFontEntry : public ImplFontEntry { public: explicit ImplWinFontEntry( FontSelectPattern& ); virtual ~ImplWinFontEntry(); + void setupGLyphy(HDC hDC); private: // TODO: also add HFONT??? Watch out for issues with too many active fonts... @@ -103,162 +82,31 @@ public: { return maScriptCache; } private: mutable SCRIPT_CACHE maScriptCache; - std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache; public: - int GetCachedGlyphWidth( int nCharCode ) const; - void CacheGlyphWidth( int nCharCode, int nCharWidth ); - bool InitKashidaHandling( HDC ); int GetMinKashidaWidth() const { return mnMinKashidaWidth; } int GetMinKashidaGlyph() const { return mnMinKashidaGlyph; } + static GLuint mnGLyphyProgram; + GLyphyDemo::demo_atlas_t* mpGLyphyAtlas; + GLyphyDemo::demo_font_t* mpGLyphyFont; + private: - IntMap maWidthMap; mutable int mnMinKashidaWidth; mutable int mnMinKashidaGlyph; - -public: - bool GlyphIsCached(int nGlyphIndex) const; - bool AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics); - const OpenGLGlyphCacheChunk& GetCachedGlyphChunkFor(int nGlyphIndex) const; + bool mbGLyphySetupCalled; }; -#ifdef SAL_LOG_INFO - -namespace { - -char ColorFor(COLORREF aColor) -{ - if (aColor == RGB(0xFF, 0xFF, 0xFF)) - return ' '; - else if (aColor == RGB(0x00, 0x00, 0x00)) - return 'X'; - - return '0' + (10*(GetRValue(aColor) + GetGValue(aColor) + GetBValue(aColor))) / (0xFF*3); -} - -void DumpGlyphBitmap(HDC hDC) -{ - HBITMAP hBitmap = static_cast<HBITMAP>(GetCurrentObject(hDC, OBJ_BITMAP)); - if (hBitmap == NULL) - { - SAL_WARN("vcl.gdi", "GetCurrentObject failed: " << WindowsErrorString(GetLastError())); - return; - } - - BITMAP aBitmap; - if (!GetObjectW(hBitmap, sizeof(aBitmap), &aBitmap)) - { - SAL_WARN("vcl.gdi", "GetObjectW failed: " << WindowsErrorString(GetLastError())); - return; - } - - SAL_INFO("vcl.gdi.opengl", "Bitmap " << hBitmap << ": " << aBitmap.bmWidth << "x" << aBitmap.bmHeight << ":"); - - std::ostringstream sLine("\n"); - for (long y = 0; y < aBitmap.bmHeight; y++) - { - for (long x = 0; x < std::min(75l, aBitmap.bmWidth); x++) - sLine << ColorFor(GetPixel(hDC, x, y)); - if (y < aBitmap.bmHeight - 1) - sLine << "\n"; - } - SAL_INFO("vcl.gdi.opengl", sLine.str()); -} - -} // anonymous namespace - -#endif // SAL_LOG_INFO - -template< typename charT, typename traits > -inline std::basic_ostream<charT, traits> & operator <<( - std::basic_ostream<charT, traits> & stream, const std::vector<OpenGLGlyphCacheChunk>& rCache ) -{ - stream << "{"; - for (auto i = rCache.cbegin(); i != rCache.cend(); ++i) - { - stream << "[" << i->mnFirstGlyph; - if (i->mnGlyphCount > 1) - stream << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1); - stream << "]"; - if (i+1 != rCache.cend()) - { - stream << ","; - assert(i->mnFirstGlyph + i->mnGlyphCount <= (i+1)->mnFirstGlyph); - } - } - - return stream << "}"; -} - -inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth ) -{ - maWidthMap[ nCharCode ] = nCharWidth; -} - -inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const -{ - IntMap::const_iterator it = maWidthMap.find( nCharCode ); - if( it == maWidthMap.end() ) - return -1; - return it->second; -} - -bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const -{ - if (nGlyphIndex == DROPPED_OUTGLYPH) - return true; - - for (size_t i = 0; i < maOpenGLGlyphCache.size(); i++) - if (nGlyphIndex >= maOpenGLGlyphCache[i].mnFirstGlyph && - nGlyphIndex < maOpenGLGlyphCache[i].mnFirstGlyph + maOpenGLGlyphCache[i].mnGlyphCount) - return true; +GLuint ImplWinFontEntry::mnGLyphyProgram = 0; - return false; -} +#if 0 -bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics) +bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics) { - const int DEFAULT_CHUNK_SIZE = 20; - if (nGlyphIndex == DROPPED_OUTGLYPH) return true; - SAL_INFO("vcl.gdi.opengl", "this=" << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache); - - auto n = maOpenGLGlyphCache.begin(); - while (n != maOpenGLGlyphCache.end() && - nGlyphIndex > n->mnFirstGlyph) - ++n; - assert(n == maOpenGLGlyphCache.end() || nGlyphIndex < n->mnFirstGlyph); - - int nCount = DEFAULT_CHUNK_SIZE; - if (n != maOpenGLGlyphCache.end() && nGlyphIndex + nCount >= n->mnFirstGlyph) - nCount = n->mnFirstGlyph - nGlyphIndex; - - if (nCount < DEFAULT_CHUNK_SIZE) - { - if (n == maOpenGLGlyphCache.begin()) - { - nGlyphIndex = std::max(0, n->mnFirstGlyph - DEFAULT_CHUNK_SIZE); - } - else - { - nGlyphIndex = std::max(n[-1].mnFirstGlyph + n[-1].mnGlyphCount, - n->mnFirstGlyph - DEFAULT_CHUNK_SIZE); - } - nCount = n->mnFirstGlyph - nGlyphIndex; - } - - OpenGLGlyphCacheChunk aChunk; - aChunk.mnFirstGlyph = nGlyphIndex; - aChunk.mnGlyphCount = nCount; - - std::vector<WORD> aGlyphIndices(nCount); - for (int i = 0; i < nCount; i++) - aGlyphIndices[i] = nGlyphIndex + i; - HDC hDC = CreateCompatibleDC(rLayout.mhDC); if (hDC == NULL) { @@ -275,7 +123,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou SIZE aSize; - if (!GetTextExtentExPointI(hDC, aGlyphIndices.data(), nCount, 0, NULL, NULL, &aSize)) + if (!GetTextExtentExPointI(hDC, &nGlyphIndex, 1, 0, NULL, NULL, &aSize)) { SAL_WARN("vcl.gdi", "GetTextExtentExPointI failed: " << WindowsErrorString(GetLastError())); SelectObject(hDC, hOrigFont); @@ -283,8 +131,8 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou return false; } - std::vector<ABC> aABC(nCount); - if (!GetCharABCWidthsI(hDC, 0, nCount, aGlyphIndices.data(), aABC.data())) + ABC aABC; + if (!GetCharABCWidthsI(hDC, 0, 1, &nGlyphIndex, &aABC)) { SAL_WARN("vcl.gdi", "GetCharABCWidthsI failed: " << WindowsErrorString(GetLastError())); SelectObject(hDC, hOrigFont); @@ -292,10 +140,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou return false; } - std::ostringstream sLine; - for (int i = 0; i < nCount; i++) - sLine << aABC[i].abcA << ":" << aABC[i].abcB << ":" << aABC[i].abcC << " "; - SAL_INFO("vcl.gdi.opengl", "ABC widths: " << sLine.str()); + SAL_INFO("vcl.gdi.opengl", "ABC width: " << aABC.abcA << ":" << aABC.abcB << ":" << aABC.abcC); TEXTMETRICW aTextMetric; if (!GetTextMetricsW(hDC, &aTextMetric)) @@ -305,25 +150,6 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou DeleteDC(hDC); return false; } - aChunk.mnAscent = aTextMetric.tmAscent; - aChunk.mnHeight = aTextMetric.tmHeight; - - // Try hard to avoid overlap as we want to be able to use - // individual rectangles for each glyph. The ABC widths don't - // take anti-aliasing into consideration. Let's hope that leaving - // "extra" space inbetween glyphs will help. - std::vector<int> aDX(nCount); - int totWidth = 0; - for (int i = 0; i < nCount; i++) - { - aDX[i] = aABC[i].abcB + std::abs(aABC[i].abcC); - if (i == 0) - aDX[0] += std::abs(aABC[0].abcA); - if (i < nCount-1) - aDX[i] += std::abs(aABC[i+1].abcA); - aDX[i] += aChunk.getExtraSpace(); - totWidth += aDX[i]; - } LOGFONTW aLogfont; if (!GetObjectW(rLayout.mhFont, sizeof(aLogfont), &aLogfont)) @@ -349,120 +175,73 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou " Orientation=" << aLogfont.lfOrientation << " Ascent=" << aTextMetric.tmAscent << " InternalLeading=" << aTextMetric.tmInternalLeading << - " Size=(" << aSize.cx << "," << aSize.cy << ") totWidth=" << totWidth); + " Size=(" << aSize.cx << "," << aSize.cy << ")"); if (SelectObject(hDC, hOrigFont) == NULL) SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); if (!DeleteDC(hDC)) SAL_WARN("vcl.gdi", "DeleteDC failed: " << WindowsErrorString(GetLastError())); - // Leave extra space also at top and bottom - int nBitmapWidth, nBitmapHeight; - if (sFaceName[0] == '@') - { - nBitmapWidth = aSize.cy + aChunk.getExtraSpace(); - nBitmapHeight = totWidth; - aChunk.mbVertical = true; - } - else - { - nBitmapWidth = totWidth; - nBitmapHeight = aSize.cy + aChunk.getExtraSpace(); - aChunk.mbVertical = false; - } + // FIXME HERE, in case this code snipet actually is needed any more? - if (aChunk.mbVertical && aLogfont.lfEscapement != 2700) - return false; + return true; +} - OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight); +#endif - HFONT hNonAntialiasedFont = NULL; +void ImplWinFontEntry::setupGLyphy(HDC hDC) +{ + if (mbGLyphySetupCalled) + return; -#ifdef DBG_UTIL - static bool bNoAntialias = (std::getenv("VCL_GLYPH_CACHING_HACK_NO_ANTIALIAS") != NULL); - if (bNoAntialias) - { - aLogfont.lfQuality = NONANTIALIASED_QUALITY; - hNonAntialiasedFont = CreateFontIndirectW(&aLogfont); - if (hNonAntialiasedFont == NULL) - { - SAL_WARN("vcl.gdi", "CreateFontIndirect failed: " << WindowsErrorString(GetLastError())); - return false; - } - } -#endif + mbGLyphySetupCalled = true; - hOrigFont = SelectFont(aDC.getCompatibleHDC(), hNonAntialiasedFont != NULL ? hNonAntialiasedFont : rLayout.mhFont); - if (hOrigFont == NULL) + // First get the OUTLINETEXTMETRIC to find the font's em unit. Then, to get an unmodified (not + // grid-fitted) glyph outline, create the font anew at that size. That is as the doc for + // GetGlyphOutline() suggests. + OUTLINETEXTMETRICW aOutlineTextMetric; + if (!GetOutlineTextMetricsW (hDC, sizeof (OUTLINETEXTMETRICW), &aOutlineTextMetric)) { - SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); - return false; + SAL_WARN("vcl.gdi.opengl", "GetOutlineTextMetricsW failed: " << WindowsErrorString(GetLastError())); + return; } - SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); - SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); - - aDC.fill(MAKE_SALCOLOR(0xff, 0xff, 0xff)); + HFONT hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT); + LOGFONTW aLogFont; + GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont); - int nY = aChunk.getExtraOffset(); - int nX = nY; - if (aChunk.mbVertical) - nX += aDX[0]; - if (!ExtTextOutW(aDC.getCompatibleHDC(), nX, nY, ETO_GLYPH_INDEX, NULL, aGlyphIndices.data(), nCount, aDX.data())) + HDC hNewDC = GetDC(NULL); + if (hNewDC == NULL) { - SAL_WARN("vcl.gdi", "ExtTextOutW failed: " << WindowsErrorString(GetLastError())); - SelectFont(aDC.getCompatibleHDC(), hOrigFont); - if (hNonAntialiasedFont != NULL) - DeleteObject(hNonAntialiasedFont); - return false; + SAL_WARN("vcl.gdi.opengl", "GetDC failed: " << WindowsErrorString(GetLastError())); + return; } - aChunk.maLocation.resize(nCount); - UINT nPos = 0; - for (int i = 0; i < nCount; i++) + hNewDC = CreateCompatibleDC(hNewDC); + if (hNewDC == NULL) { - if (aChunk.mbVertical) - { - aChunk.maLocation[i].Left() = 0; - aChunk.maLocation[i].Right() = nBitmapWidth; - aChunk.maLocation[i].Top() = nPos; - aChunk.maLocation[i].Bottom() = nPos + aDX[i]; - nPos = aChunk.maLocation[i].Bottom(); - } - else - { - aChunk.maLocation[i].Left() = nPos; - aChunk.maLocation[i].Right() = nPos + aDX[i]; - nPos = aChunk.maLocation[i].Right(); - aChunk.maLocation[i].Top() = 0; - aChunk.maLocation[i].Bottom() = aSize.cy + aChunk.getExtraSpace(); - } + SAL_WARN("vcl.gdi.opengl", "CreateCompatibleDC failed: " << WindowsErrorString(GetLastError())); + return; } - aChunk.mpTexture = std::unique_ptr<OpenGLTexture>(aDC.getTexture()); - - maOpenGLGlyphCache.insert(n, aChunk); - - SelectFont(aDC.getCompatibleHDC(), hOrigFont); - if (hNonAntialiasedFont != NULL) - DeleteObject(hNonAntialiasedFont); - -#ifdef SAL_LOG_INFO - SAL_INFO("vcl.gdi.opengl", "this=" << this << " now: " << maOpenGLGlyphCache); - DumpGlyphBitmap(aDC.getCompatibleHDC()); -#endif + aLogFont.lfHeight = aOutlineTextMetric.otmEMSquare; + hFont = CreateFontIndirectW(&aLogFont); + if (hFont == NULL) + { + SAL_WARN("vcl.gdi.opengl", "CreateFontIndirectW failed: " << WindowsErrorString(GetLastError())); + return; + } + if (SelectObject(hNewDC, hFont) == NULL) + { + SAL_WARN("vcl.gdi.opengl", "SelectObject failed: " << WindowsErrorString(GetLastError())); + return; + } - return true; -} + if (mnGLyphyProgram == 0) + mnGLyphyProgram = GLyphyDemo::demo_shader_create_program(); -const OpenGLGlyphCacheChunk& ImplWinFontEntry::GetCachedGlyphChunkFor(int nGlyphIndex) const -{ - auto i = maOpenGLGlyphCache.cbegin(); - while (i != maOpenGLGlyphCache.cend() && nGlyphIndex >= i->mnFirstGlyph + i->mnGlyphCount) - ++i; - assert(i != maOpenGLGlyphCache.cend()); - assert(nGlyphIndex >= i->mnFirstGlyph && nGlyphIndex < i->mnFirstGlyph + i->mnGlyphCount); - return *i; + mpGLyphyAtlas = GLyphyDemo::demo_atlas_create(2048, 1024, 64, 8); + mpGLyphyFont = GLyphyDemo::demo_font_create(hNewDC, mpGLyphyAtlas); } WinLayout::WinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE, bool bUseOpenGL) @@ -1765,20 +1544,26 @@ void UniscribeLayout::DrawTextImpl(HDC hDC) const DeleteFont(SelectFont(hDC, hOrigFont)); } -bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const +bool UniscribeLayout::CacheGlyphs(SalGraphics&) const { static bool bDoGlyphCaching = (std::getenv("SAL_DISABLE_GLYPH_CACHING") == NULL); if (!bDoGlyphCaching) return false; + if (!mrWinFontEntry.maMetric.mbTrueTypeFont) + return false; + + mrWinFontEntry.setupGLyphy(mhDC); + for (int i = 0; i < mnGlyphCount; i++) { - if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])) + if (mpOutGlyphs[i] == DROPPED_OUTGLYPH) continue; - if (!mrWinFontEntry.AddChunkOfGlyphs(mpOutGlyphs[i], *this, rGraphics)) - return false; + GLyphyDemo::glyph_info_t aGI; + VCL_GL_INFO("vcl.opengl", "Calling demo_font_lookup_glyph"); + GLyphyDemo::demo_font_lookup_glyph( mrWinFontEntry.mpGLyphyFont, mpOutGlyphs[i], &aGI ); } return true; @@ -1787,20 +1572,53 @@ bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const { WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics); - HDC hDC = rWinGraphics.getHDC(); Rectangle aRect; GetBoundRect(rGraphics, aRect); - COLORREF color = GetTextColor(hDC); - SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color)); - WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get()); if (!pImpl) return false; pImpl->PreDraw(); + rGraphics.GetOpenGLContext()->UseNoProgram(); + glUseProgram( mrWinFontEntry.mnGLyphyProgram ); + CHECK_GL_ERROR(); + GLyphyDemo::demo_atlas_set_uniforms( mrWinFontEntry.mpGLyphyAtlas ); + + GLint nLoc; + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_debug" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 0 ); // FIXME: Try to get the "debug" thing displayed first + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_contrast" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 1 ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_gamma_adjust" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 1 ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_outline" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, false ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_outline_thickness" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 1 ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_boldness" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 0 ); + CHECK_GL_ERROR(); + // FIXME: This code snippet is mostly copied from the one in // UniscribeLayout::DrawTextImpl. Should be factored out. int nBaseClusterOffset = 0; @@ -1842,35 +1660,97 @@ bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const // positioning) match. const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances; + double font_size = mrWinFontEntry.maFontSelData.mfExactHeight; // ??? + + // font_size = 1; // ??? + + std::vector<GLyphyDemo::glyph_vertex_t> vertices; for (int i = nMinGlyphPos; i < nEndGlyphPos; i++) { // Ignore dropped glyphs. if (mpOutGlyphs[i] == DROPPED_OUTGLYPH) continue; - assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])); + // Total crack + GLyphyDemo::glyphy_point_t pt; + pt.x = nAdvance + aPos.X() + mpGlyphOffsets[i].du; + pt.y = aPos.Y() + mpGlyphOffsets[i].dv; + GLyphyDemo::glyph_info_t gi; + GLyphyDemo::demo_font_lookup_glyph( mrWinFontEntry.mpGLyphyFont, mpOutGlyphs[i], &gi ); + GLyphyDemo::demo_shader_add_glyph_vertices( pt, font_size, &gi, &vertices, NULL ); - const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]); - const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph; - - if (rChunk.mbVertical) - { - SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), - aPos.X(), nAdvance + aPos.Y(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ??? - pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects); - } - else - { - SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), - nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset(), aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnAscent - rChunk.getExtraOffset(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ??? - pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects); - } nAdvance += pGlyphWidths[i]; } + + GLfloat mat[16]; + GLyphyDemo::m4LoadIdentity( mat ); + + GLint viewport[4]; + glGetIntegerv( GL_VIEWPORT, viewport ); + CHECK_GL_ERROR(); + + double width = viewport[2]; + double height = viewport[3]; + +#if 0 + // Based on demo_view_apply_transform(). I don't really understand it. + + // No scaling, no translation needed here + + // Perspective (but why would we want that in LO; it's needed in glyphy-demo because there + // you can rotate the "sheet" the text is drawn on) + { + double d = std::max( width, height ); + double near = d / 4; + double far = near + d; + double factor = near / (2 * near + d); + GLyphyDemo::m4Frustum( mat, -width * factor, width * factor, -height * factor, height * factor, near, far ); + GLyphyDemo::m4Translate( mat, 0, 0, -(near + d * 0.5) ); + } + + // No rotation here + + // Fix 'up' + GLyphyDemo::m4Scale( mat, 1, -1, 1 ); + + // Foo + // GLyphyDemo::m4Scale( mat, 0.5, 0.5, 1 ); + + // The "Center buffer" part in demo_view_display() + GLyphyDemo::m4Translate( mat, width/2, height/2, 0 ); + +#else + // Crack that just happens to show something (even if not completely in correct location) in + // some cases, but not all. I don't understand why. + double scale = std::max( 2/width, 2/height ); + GLyphyDemo::m4Scale( mat, scale, -scale, 1); + GLyphyDemo::m4Translate( mat, -width/2, -height/2, 0 ); +#endif + + GLuint u_matViewProjection_loc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_matViewProjection" ); + CHECK_GL_ERROR(); + glUniformMatrix4fv( u_matViewProjection_loc, 1, GL_FALSE, mat ); + CHECK_GL_ERROR(); + + GLuint a_glyph_vertex_loc = glGetAttribLocation( mrWinFontEntry.mnGLyphyProgram, "a_glyph_vertex" ); + GLuint buf_name; + glGenBuffers( 1, &buf_name ); + CHECK_GL_ERROR(); + glBindBuffer( GL_ARRAY_BUFFER, buf_name ); + CHECK_GL_ERROR(); + + glBufferData( GL_ARRAY_BUFFER, sizeof(GLyphyDemo::glyph_vertex_t) * vertices.size(), (const char *) &vertices[0], GL_STATIC_DRAW ); + CHECK_GL_ERROR(); + glEnableVertexAttribArray( a_glyph_vertex_loc ); + CHECK_GL_ERROR(); + glVertexAttribPointer( a_glyph_vertex_loc, 4, GL_FLOAT, GL_FALSE, sizeof(GLyphyDemo::glyph_vertex_t), 0 ); + CHECK_GL_ERROR(); + glDrawArrays( GL_TRIANGLES, 0, vertices.size() ); + CHECK_GL_ERROR(); + glDisableVertexAttribArray( a_glyph_vertex_loc ); + CHECK_GL_ERROR(); + glDeleteBuffers( 1, &buf_name ); + CHECK_GL_ERROR(); } pImpl->PostDraw(); @@ -2625,11 +2505,14 @@ int WinSalGraphics::GetMinKashidaWidth() ImplWinFontEntry::ImplWinFontEntry( FontSelectPattern& rFSD ) : ImplFontEntry( rFSD ) -, maWidthMap( 512 ) +, mpGLyphyAtlas( nullptr ) +, mpGLyphyFont( nullptr ) , mnMinKashidaWidth( -1 ) , mnMinKashidaGlyph( -1 ) { maScriptCache = NULL; + mpGLyphyFont = NULL; + mbGLyphySetupCalled = false; } ImplWinFontEntry::~ImplWinFontEntry() |