mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
Merge branch 'master' into deploy-ng
This commit is contained in:
commit
0ee6a46a62
22
README.md
22
README.md
@ -18,6 +18,23 @@ resources. If you get stuck, ask for help from our active
|
|||||||
Panda3D is licensed under the Modified BSD License. See the LICENSE file for
|
Panda3D is licensed under the Modified BSD License. See the LICENSE file for
|
||||||
more details.
|
more details.
|
||||||
|
|
||||||
|
Installing Panda3D
|
||||||
|
==================
|
||||||
|
|
||||||
|
By far, the easiest way to install the latest development build of Panda3D
|
||||||
|
into an existing Python installation is using the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install --pre --extra-index-url https://archive.panda3d.org/ panda3d
|
||||||
|
```
|
||||||
|
|
||||||
|
If you prefer to install the full SDK with all tools, the latest development
|
||||||
|
builds can be obtained from this page:
|
||||||
|
|
||||||
|
https://www.panda3d.org/download.php?sdk&version=devel
|
||||||
|
|
||||||
|
These are automatically kept up-to-date with the latest GitHub version of Panda.
|
||||||
|
|
||||||
Building Panda3D
|
Building Panda3D
|
||||||
================
|
================
|
||||||
|
|
||||||
@ -64,7 +81,7 @@ for you to install, depending on your distribution).
|
|||||||
The following command illustrates how to build Panda3D with some common
|
The following command illustrates how to build Panda3D with some common
|
||||||
options:
|
options:
|
||||||
```bash
|
```bash
|
||||||
python2.7 makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-gles2
|
python makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-gles2 --no-opencv
|
||||||
```
|
```
|
||||||
|
|
||||||
You will probably see some warnings saying that it's unable to find several
|
You will probably see some warnings saying that it's unable to find several
|
||||||
@ -93,6 +110,9 @@ may have to use the installpanda.py script instead, which will directly copy the
|
|||||||
files into the appropriate locations on your computer. You may have to run the
|
files into the appropriate locations on your computer. You may have to run the
|
||||||
`ldconfig` tool in order to update your library cache after installing Panda3D.
|
`ldconfig` tool in order to update your library cache after installing Panda3D.
|
||||||
|
|
||||||
|
Alternatively, you can add the `--wheel` option, which will produce a .whl
|
||||||
|
file that can be installed into a Python installation using `pip`.
|
||||||
|
|
||||||
macOS
|
macOS
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -35,7 +35,8 @@ class OnscreenText(NodePath):
|
|||||||
font = None,
|
font = None,
|
||||||
parent = None,
|
parent = None,
|
||||||
sort = 0,
|
sort = 0,
|
||||||
mayChange = True):
|
mayChange = True,
|
||||||
|
direction = None):
|
||||||
"""
|
"""
|
||||||
Make a text node from string, put it into the 2d sg and set it
|
Make a text node from string, put it into the 2d sg and set it
|
||||||
up with all the indicated parameters.
|
up with all the indicated parameters.
|
||||||
@ -95,6 +96,9 @@ class OnscreenText(NodePath):
|
|||||||
mayChange: pass true if the text or its properties may need
|
mayChange: pass true if the text or its properties may need
|
||||||
to be changed at runtime, false if it is static once
|
to be changed at runtime, false if it is static once
|
||||||
created (which leads to better memory optimization).
|
created (which leads to better memory optimization).
|
||||||
|
|
||||||
|
direction: this can be set to 'ltr' or 'rtl' to override the
|
||||||
|
direction of the text.
|
||||||
"""
|
"""
|
||||||
if parent == None:
|
if parent == None:
|
||||||
parent = aspect2d
|
parent = aspect2d
|
||||||
@ -192,6 +196,17 @@ class OnscreenText(NodePath):
|
|||||||
textNode.setFrameColor(frame[0], frame[1], frame[2], frame[3])
|
textNode.setFrameColor(frame[0], frame[1], frame[2], frame[3])
|
||||||
textNode.setFrameAsMargin(0.1, 0.1, 0.1, 0.1)
|
textNode.setFrameAsMargin(0.1, 0.1, 0.1, 0.1)
|
||||||
|
|
||||||
|
if direction is not None:
|
||||||
|
if isinstance(direction, str):
|
||||||
|
direction = direction.lower()
|
||||||
|
if direction == 'rtl':
|
||||||
|
direction = TextProperties.D_rtl
|
||||||
|
elif direction == 'ltr':
|
||||||
|
direction = TextProperties.D_ltr
|
||||||
|
else:
|
||||||
|
raise ValueError('invalid direction')
|
||||||
|
textNode.setDirection(direction)
|
||||||
|
|
||||||
# Create a transform for the text for our scale and position.
|
# Create a transform for the text for our scale and position.
|
||||||
# We'd rather do it here, on the text itself, rather than on
|
# We'd rather do it here, on the text itself, rather than on
|
||||||
# our NodePath, so we have one fewer transforms in the scene
|
# our NodePath, so we have one fewer transforms in the scene
|
||||||
|
@ -531,7 +531,6 @@ class Messenger:
|
|||||||
keys.sort()
|
keys.sort()
|
||||||
for event in keys:
|
for event in keys:
|
||||||
if repr(event).find(needle) >= 0:
|
if repr(event).find(needle) >= 0:
|
||||||
print(self.__eventRepr(event))
|
|
||||||
return {event: self.__callbacks[event]}
|
return {event: self.__callbacks[event]}
|
||||||
|
|
||||||
def findAll(self, needle, limit=None):
|
def findAll(self, needle, limit=None):
|
||||||
@ -545,7 +544,6 @@ class Messenger:
|
|||||||
keys.sort()
|
keys.sort()
|
||||||
for event in keys:
|
for event in keys:
|
||||||
if repr(event).find(needle) >= 0:
|
if repr(event).find(needle) >= 0:
|
||||||
print(self.__eventRepr(event))
|
|
||||||
matches[event] = self.__callbacks[event]
|
matches[event] = self.__callbacks[event]
|
||||||
# if the limit is not None, decrement and
|
# if the limit is not None, decrement and
|
||||||
# check for break:
|
# check for break:
|
||||||
|
@ -1658,7 +1658,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_function:
|
case T_function:
|
||||||
out << _u._fgroup->_name;
|
// Pick any instance; they all have the same name anyway.
|
||||||
|
if (!_u._fgroup->_instances.empty() && _u._fgroup->_instances[0]->_ident != NULL) {
|
||||||
|
_u._fgroup->_instances[0]->_ident->output(out, scope);
|
||||||
|
} else {
|
||||||
|
out << _u._fgroup->_name;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_unknown_ident:
|
case T_unknown_ident:
|
||||||
|
@ -58,18 +58,6 @@
|
|||||||
#pragma warning (disable : 4267)
|
#pragma warning (disable : 4267)
|
||||||
/* C4577: 'noexcept' used with no exception handling mode specified */
|
/* C4577: 'noexcept' used with no exception handling mode specified */
|
||||||
#pragma warning (disable : 4577)
|
#pragma warning (disable : 4577)
|
||||||
|
|
||||||
#if _MSC_VER >= 1300
|
|
||||||
#if _MSC_VER >= 1310
|
|
||||||
#define USING_MSVC7_1
|
|
||||||
// #pragma message("VC 7.1")
|
|
||||||
#else
|
|
||||||
// #pragma message("VC 7.0")
|
|
||||||
#endif
|
|
||||||
#define USING_MSVC7
|
|
||||||
#else
|
|
||||||
// #pragma message("VC 6.0")
|
|
||||||
#endif
|
|
||||||
#endif /* WIN32_VC */
|
#endif /* WIN32_VC */
|
||||||
|
|
||||||
#ifndef __has_builtin
|
#ifndef __has_builtin
|
||||||
|
@ -29,6 +29,7 @@ class FT_Library;
|
|||||||
class FT_Bitmap;
|
class FT_Bitmap;
|
||||||
class FT_Vector;
|
class FT_Vector;
|
||||||
class FT_Span;
|
class FT_Span;
|
||||||
|
class FT_Outline;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -152,8 +152,6 @@ private:
|
|||||||
|
|
||||||
#define nassert_raise(message) Notify::write_string(message)
|
#define nassert_raise(message) Notify::write_string(message)
|
||||||
|
|
||||||
#define enter_debugger_if(condition) ((void)0)
|
|
||||||
|
|
||||||
#else // NDEBUG
|
#else // NDEBUG
|
||||||
|
|
||||||
#define nassertr(condition, return_value) \
|
#define nassertr(condition, return_value) \
|
||||||
@ -183,13 +181,6 @@ private:
|
|||||||
|
|
||||||
#define nassert_raise(message) Notify::ptr()->assert_failure(message, __LINE__, __FILE__)
|
#define nassert_raise(message) Notify::ptr()->assert_failure(message, __LINE__, __FILE__)
|
||||||
|
|
||||||
#define enter_debugger_if(condition) \
|
|
||||||
if (_nassert_check(condition)) { \
|
|
||||||
Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__); \
|
|
||||||
__asm { int 3 } \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
#if __cplusplus >= 201103
|
#if __cplusplus >= 201103
|
||||||
|
@ -80,8 +80,9 @@ PkgListSet(["PYTHON", "DIRECT", # Python support
|
|||||||
"VORBIS", "FFMPEG", "SWSCALE", "SWRESAMPLE", # Audio decoding
|
"VORBIS", "FFMPEG", "SWSCALE", "SWRESAMPLE", # Audio decoding
|
||||||
"ODE", "PHYSX", "BULLET", "PANDAPHYSICS", # Physics
|
"ODE", "PHYSX", "BULLET", "PANDAPHYSICS", # Physics
|
||||||
"SPEEDTREE", # SpeedTree
|
"SPEEDTREE", # SpeedTree
|
||||||
"ZLIB", "PNG", "JPEG", "TIFF", "OPENEXR", "SQUISH", "FREETYPE", # 2D Formats support
|
"ZLIB", "PNG", "JPEG", "TIFF", "OPENEXR", "SQUISH", # 2D Formats support
|
||||||
] + MAYAVERSIONS + MAXVERSIONS + [ "FCOLLADA", "ASSIMP", "EGG", # 3D Formats support
|
] + MAYAVERSIONS + MAXVERSIONS + [ "FCOLLADA", "ASSIMP", "EGG", # 3D Formats support
|
||||||
|
"FREETYPE", "HARFBUZZ", # Text rendering
|
||||||
"VRPN", "OPENSSL", # Transport
|
"VRPN", "OPENSSL", # Transport
|
||||||
"FFTW", # Algorithm helpers
|
"FFTW", # Algorithm helpers
|
||||||
"ARTOOLKIT", "OPENCV", "DIRECTCAM", "VISION", # Augmented Reality
|
"ARTOOLKIT", "OPENCV", "DIRECTCAM", "VISION", # Augmented Reality
|
||||||
@ -638,6 +639,7 @@ if (COMPILER == "MSVC"):
|
|||||||
if (PkgSkip("NVIDIACG")==0): LibName("CGDX9", GetThirdpartyDir() + "nvidiacg/lib/cgD3D9.lib")
|
if (PkgSkip("NVIDIACG")==0): LibName("CGDX9", GetThirdpartyDir() + "nvidiacg/lib/cgD3D9.lib")
|
||||||
if (PkgSkip("NVIDIACG")==0): LibName("NVIDIACG", GetThirdpartyDir() + "nvidiacg/lib/cg.lib")
|
if (PkgSkip("NVIDIACG")==0): LibName("NVIDIACG", GetThirdpartyDir() + "nvidiacg/lib/cg.lib")
|
||||||
if (PkgSkip("FREETYPE")==0): LibName("FREETYPE", GetThirdpartyDir() + "freetype/lib/freetype.lib")
|
if (PkgSkip("FREETYPE")==0): LibName("FREETYPE", GetThirdpartyDir() + "freetype/lib/freetype.lib")
|
||||||
|
if (PkgSkip("HARFBUZZ")==0): LibName("HARFBUZZ", GetThirdpartyDir() + "harfbuzz/lib/harfbuzz.lib")
|
||||||
if (PkgSkip("FFTW")==0): LibName("FFTW", GetThirdpartyDir() + "fftw/lib/rfftw.lib")
|
if (PkgSkip("FFTW")==0): LibName("FFTW", GetThirdpartyDir() + "fftw/lib/rfftw.lib")
|
||||||
if (PkgSkip("FFTW")==0): LibName("FFTW", GetThirdpartyDir() + "fftw/lib/fftw.lib")
|
if (PkgSkip("FFTW")==0): LibName("FFTW", GetThirdpartyDir() + "fftw/lib/fftw.lib")
|
||||||
if (PkgSkip("ARTOOLKIT")==0):LibName("ARTOOLKIT",GetThirdpartyDir() + "artoolkit/lib/libAR.lib")
|
if (PkgSkip("ARTOOLKIT")==0):LibName("ARTOOLKIT",GetThirdpartyDir() + "artoolkit/lib/libAR.lib")
|
||||||
@ -803,6 +805,7 @@ if (COMPILER=="GCC"):
|
|||||||
SmartPkgEnable("FFTW", "", ("rfftw", "fftw"), ("fftw.h", "rfftw.h"))
|
SmartPkgEnable("FFTW", "", ("rfftw", "fftw"), ("fftw.h", "rfftw.h"))
|
||||||
SmartPkgEnable("FMODEX", "", ("fmodex"), ("fmodex", "fmodex/fmod.h"))
|
SmartPkgEnable("FMODEX", "", ("fmodex"), ("fmodex", "fmodex/fmod.h"))
|
||||||
SmartPkgEnable("FREETYPE", "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h"))
|
SmartPkgEnable("FREETYPE", "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h"))
|
||||||
|
SmartPkgEnable("HARFBUZZ", "harfbuzz", ("harfbuzz"), ("harfbuzz", "harfbuzz/hb-ft.h"))
|
||||||
SmartPkgEnable("GL", "gl", ("GL"), ("GL/gl.h"), framework = "OpenGL")
|
SmartPkgEnable("GL", "gl", ("GL"), ("GL/gl.h"), framework = "OpenGL")
|
||||||
SmartPkgEnable("GLES", "glesv1_cm", ("GLESv1_CM"), ("GLES/gl.h"), framework = "OpenGLES")
|
SmartPkgEnable("GLES", "glesv1_cm", ("GLESv1_CM"), ("GLES/gl.h"), framework = "OpenGLES")
|
||||||
SmartPkgEnable("GLES2", "glesv2", ("GLESv2"), ("GLES2/gl2.h")) #framework = "OpenGLES"?
|
SmartPkgEnable("GLES2", "glesv2", ("GLESv2"), ("GLES2/gl2.h")) #framework = "OpenGLES"?
|
||||||
@ -3807,7 +3810,10 @@ if (PkgSkip("FREETYPE")==0 and not RUNTIME):
|
|||||||
#
|
#
|
||||||
|
|
||||||
if (not RUNTIME):
|
if (not RUNTIME):
|
||||||
OPTS=['DIR:panda/src/text', 'BUILDING:PANDA', 'ZLIB', 'FREETYPE']
|
if not PkgSkip("HARFBUZZ"):
|
||||||
|
DefSymbol("HARFBUZZ", "HAVE_HARFBUZZ")
|
||||||
|
|
||||||
|
OPTS=['DIR:panda/src/text', 'BUILDING:PANDA', 'ZLIB', 'FREETYPE', 'HARFBUZZ']
|
||||||
TargetAdd('p3text_composite1.obj', opts=OPTS, input='p3text_composite1.cxx')
|
TargetAdd('p3text_composite1.obj', opts=OPTS, input='p3text_composite1.cxx')
|
||||||
TargetAdd('p3text_composite2.obj', opts=OPTS, input='p3text_composite2.cxx')
|
TargetAdd('p3text_composite2.obj', opts=OPTS, input='p3text_composite2.cxx')
|
||||||
|
|
||||||
@ -3957,7 +3963,7 @@ if (not RUNTIME):
|
|||||||
#
|
#
|
||||||
|
|
||||||
if (not RUNTIME):
|
if (not RUNTIME):
|
||||||
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG',
|
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'HARFBUZZ',
|
||||||
'TIFF', 'OPENEXR', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
'TIFF', 'OPENEXR', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
||||||
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
||||||
|
|
||||||
|
@ -1501,6 +1501,16 @@ open_buffer() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is normally called only from within make_texture_buffer(). When
|
||||||
|
* called on a ParasiteBuffer, it returns the host of that buffer; but when
|
||||||
|
* called on some other buffer, it returns the buffer itself.
|
||||||
|
*/
|
||||||
|
GraphicsOutput *CLP(GraphicsBuffer)::
|
||||||
|
get_host() {
|
||||||
|
return _host;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the buffer right now. Called from the window thread.
|
* Closes the buffer right now. Called from the window thread.
|
||||||
*/
|
*/
|
||||||
|
@ -77,6 +77,8 @@ public:
|
|||||||
void unregister_shared_depth_buffer(GraphicsOutput *graphics_output);
|
void unregister_shared_depth_buffer(GraphicsOutput *graphics_output);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual GraphicsOutput *get_host();
|
||||||
|
|
||||||
virtual void close_buffer();
|
virtual void close_buffer();
|
||||||
virtual bool open_buffer();
|
virtual bool open_buffer();
|
||||||
|
|
||||||
|
@ -1139,7 +1139,7 @@ reset() {
|
|||||||
_supports_multisample = false;
|
_supports_multisample = false;
|
||||||
#else
|
#else
|
||||||
_supports_multisample =
|
_supports_multisample =
|
||||||
has_extension("GL_ARB_multisample") || is_at_least_gl_version(1, 3);
|
is_at_least_gl_version(1, 3) || has_extension("GL_ARB_multisample");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef OPENGLES_1
|
#ifdef OPENGLES_1
|
||||||
@ -1305,7 +1305,7 @@ reset() {
|
|||||||
if (gl_support_shadow_filter &&
|
if (gl_support_shadow_filter &&
|
||||||
_supports_depth_texture &&
|
_supports_depth_texture &&
|
||||||
(is_at_least_gl_version(1, 4) || has_extension("GL_ARB_shadow")) &&
|
(is_at_least_gl_version(1, 4) || has_extension("GL_ARB_shadow")) &&
|
||||||
has_extension("GL_ARB_fragment_program_shadow")) {
|
(is_at_least_gl_version(2, 0) || has_extension("GL_ARB_fragment_program_shadow"))) {
|
||||||
_supports_shadow_filter = true;
|
_supports_shadow_filter = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2550,8 +2550,8 @@ reset() {
|
|||||||
_border_clamp = _edge_clamp;
|
_border_clamp = _edge_clamp;
|
||||||
#ifndef OPENGLES
|
#ifndef OPENGLES
|
||||||
if (gl_support_clamp_to_border &&
|
if (gl_support_clamp_to_border &&
|
||||||
(has_extension("GL_ARB_texture_border_clamp") ||
|
(is_at_least_gl_version(1, 3) ||
|
||||||
is_at_least_gl_version(1, 3))) {
|
has_extension("GL_ARB_texture_border_clamp"))) {
|
||||||
_border_clamp = GL_CLAMP_TO_BORDER;
|
_border_clamp = GL_CLAMP_TO_BORDER;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2580,6 +2580,11 @@ reset() {
|
|||||||
_mirror_clamp = GL_MIRROR_CLAMP_EXT;
|
_mirror_clamp = GL_MIRROR_CLAMP_EXT;
|
||||||
_mirror_edge_clamp = GL_MIRROR_CLAMP_TO_EDGE_EXT;
|
_mirror_edge_clamp = GL_MIRROR_CLAMP_TO_EDGE_EXT;
|
||||||
_mirror_border_clamp = GL_MIRROR_CLAMP_TO_BORDER_EXT;
|
_mirror_border_clamp = GL_MIRROR_CLAMP_TO_BORDER_EXT;
|
||||||
|
|
||||||
|
} else if (is_at_least_gl_version(4, 4) ||
|
||||||
|
has_extension("GL_ARB_texture_mirror_clamp_to_edge")) {
|
||||||
|
_mirror_clamp = GL_MIRROR_CLAMP_TO_EDGE;
|
||||||
|
_mirror_edge_clamp = GL_MIRROR_CLAMP_TO_EDGE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -52,7 +52,13 @@ ConfigVariableBool text_kerning
|
|||||||
("text-kerning", false,
|
("text-kerning", false,
|
||||||
PRC_DESC("Set this true to enable kerning when the font provides kerning "
|
PRC_DESC("Set this true to enable kerning when the font provides kerning "
|
||||||
"tables. This can result in more aesthetically pleasing spacing "
|
"tables. This can result in more aesthetically pleasing spacing "
|
||||||
"between individual glyphs."));
|
"between individual glyphs. Has no effect when text-use-harfbuzz "
|
||||||
|
"is true, since HarfBuzz offers superior kerning support."));
|
||||||
|
|
||||||
|
ConfigVariableBool text_use_harfbuzz
|
||||||
|
("text-use-harfbuzz", false,
|
||||||
|
PRC_DESC("Set this true to enable HarfBuzz support, which offers superior "
|
||||||
|
"text shaping and better support for non-Latin text."));
|
||||||
|
|
||||||
ConfigVariableInt text_anisotropic_degree
|
ConfigVariableInt text_anisotropic_degree
|
||||||
("text-anisotropic-degree", 1,
|
("text-anisotropic-degree", 1,
|
||||||
|
@ -31,6 +31,7 @@ NotifyCategoryDecl(text, EXPCL_PANDA_TEXT, EXPTP_PANDA_TEXT);
|
|||||||
extern ConfigVariableBool text_flatten;
|
extern ConfigVariableBool text_flatten;
|
||||||
extern ConfigVariableBool text_dynamic_merge;
|
extern ConfigVariableBool text_dynamic_merge;
|
||||||
extern ConfigVariableBool text_kerning;
|
extern ConfigVariableBool text_kerning;
|
||||||
|
extern ConfigVariableBool text_use_harfbuzz;
|
||||||
extern ConfigVariableInt text_anisotropic_degree;
|
extern ConfigVariableInt text_anisotropic_degree;
|
||||||
extern ConfigVariableInt text_texture_margin;
|
extern ConfigVariableInt text_texture_margin;
|
||||||
extern ConfigVariableDouble text_poly_margin;
|
extern ConfigVariableDouble text_poly_margin;
|
||||||
|
@ -44,6 +44,10 @@
|
|||||||
#include "textureAttrib.h"
|
#include "textureAttrib.h"
|
||||||
#include "transparencyAttrib.h"
|
#include "transparencyAttrib.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
#include <hb-ft.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
TypeHandle DynamicTextFont::_type_handle;
|
TypeHandle DynamicTextFont::_type_handle;
|
||||||
|
|
||||||
|
|
||||||
@ -114,7 +118,8 @@ DynamicTextFont(const DynamicTextFont ©) :
|
|||||||
_has_outline(copy._has_outline),
|
_has_outline(copy._has_outline),
|
||||||
_tex_format(copy._tex_format),
|
_tex_format(copy._tex_format),
|
||||||
_needs_image_processing(copy._needs_image_processing),
|
_needs_image_processing(copy._needs_image_processing),
|
||||||
_preferred_page(0)
|
_preferred_page(0),
|
||||||
|
_hb_font(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +128,11 @@ DynamicTextFont(const DynamicTextFont ©) :
|
|||||||
*/
|
*/
|
||||||
DynamicTextFont::
|
DynamicTextFont::
|
||||||
~DynamicTextFont() {
|
~DynamicTextFont() {
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
if (_hb_font != nullptr) {
|
||||||
|
hb_font_destroy(_hb_font);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,6 +213,13 @@ clear() {
|
|||||||
_cache.clear();
|
_cache.clear();
|
||||||
_pages.clear();
|
_pages.clear();
|
||||||
_empty_glyphs.clear();
|
_empty_glyphs.clear();
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
if (_hb_font != nullptr) {
|
||||||
|
hb_font_destroy(_hb_font);
|
||||||
|
_hb_font = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,6 +322,55 @@ get_kerning(int first, int second) const {
|
|||||||
return delta.x / (_font_pixels_per_unit * 64);
|
return delta.x / (_font_pixels_per_unit * 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like get_glyph, but uses a glyph index.
|
||||||
|
*/
|
||||||
|
bool DynamicTextFont::
|
||||||
|
get_glyph_by_index(int character, int glyph_index, CPT(TextGlyph) &glyph) {
|
||||||
|
if (!_is_valid) {
|
||||||
|
glyph = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache::iterator ci = _cache.find(glyph_index);
|
||||||
|
if (ci != _cache.end()) {
|
||||||
|
glyph = (*ci).second;
|
||||||
|
} else {
|
||||||
|
FT_Face face = acquire_face();
|
||||||
|
glyph = make_glyph(character, face, glyph_index);
|
||||||
|
_cache.insert(Cache::value_type(glyph_index, glyph.p()));
|
||||||
|
release_face(face);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyph.is_null()) {
|
||||||
|
glyph = get_invalid_glyph();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If Panda was compiled with HarfBuzz enabled, returns a HarfBuzz font for
|
||||||
|
* this font.
|
||||||
|
*/
|
||||||
|
hb_font_t *DynamicTextFont::
|
||||||
|
get_hb_font() const {
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
if (_hb_font != nullptr) {
|
||||||
|
return _hb_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Face face = acquire_face();
|
||||||
|
_hb_font = hb_ft_font_create(face, nullptr);
|
||||||
|
release_face(face);
|
||||||
|
|
||||||
|
return _hb_font;
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from both constructors to set up some initial values.
|
* Called from both constructors to set up some initial values.
|
||||||
*/
|
*/
|
||||||
@ -328,6 +394,8 @@ initialize() {
|
|||||||
_winding_order = WO_default;
|
_winding_order = WO_default;
|
||||||
|
|
||||||
_preferred_page = 0;
|
_preferred_page = 0;
|
||||||
|
|
||||||
|
_hb_font = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
class NurbsCurveResult;
|
class NurbsCurveResult;
|
||||||
|
|
||||||
|
typedef struct hb_font_t hb_font_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DynamicTextFont is a special TextFont object that rasterizes its glyphs
|
* A DynamicTextFont is a special TextFont object that rasterizes its glyphs
|
||||||
* from a standard font file (e.g. a TTF file) on the fly. It requires the
|
* from a standard font file (e.g. a TTF file) on the fly. It requires the
|
||||||
@ -125,6 +127,9 @@ public:
|
|||||||
virtual bool get_glyph(int character, CPT(TextGlyph) &glyph);
|
virtual bool get_glyph(int character, CPT(TextGlyph) &glyph);
|
||||||
virtual PN_stdfloat get_kerning(int first, int second) const;
|
virtual PN_stdfloat get_kerning(int first, int second) const;
|
||||||
|
|
||||||
|
bool get_glyph_by_index(int character, int glyph_index, CPT(TextGlyph) &glyph);
|
||||||
|
hb_font_t *get_hb_font() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initialize();
|
void initialize();
|
||||||
void update_filters();
|
void update_filters();
|
||||||
@ -171,6 +176,8 @@ private:
|
|||||||
typedef pvector< PT(TextGlyph) > EmptyGlyphs;
|
typedef pvector< PT(TextGlyph) > EmptyGlyphs;
|
||||||
EmptyGlyphs _empty_glyphs;
|
EmptyGlyphs _empty_glyphs;
|
||||||
|
|
||||||
|
mutable hb_font_t *_hb_font;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static TypeHandle get_class_type() {
|
static TypeHandle get_class_type() {
|
||||||
return _type_handle;
|
return _type_handle;
|
||||||
|
@ -31,10 +31,15 @@
|
|||||||
#include "geomVertexData.h"
|
#include "geomVertexData.h"
|
||||||
#include "geom.h"
|
#include "geom.h"
|
||||||
#include "modelNode.h"
|
#include "modelNode.h"
|
||||||
|
#include "dynamicTextFont.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdio.h> // for sprintf
|
#include <stdio.h> // for sprintf
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
#include <hb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// This is the factor by which CT_small scales the character down.
|
// This is the factor by which CT_small scales the character down.
|
||||||
static const PN_stdfloat small_accent_scale = 0.6f;
|
static const PN_stdfloat small_accent_scale = 0.6f;
|
||||||
|
|
||||||
@ -1408,6 +1413,12 @@ assemble_row(TextAssembler::TextRow &row,
|
|||||||
PN_stdfloat underscore_start = 0.0f;
|
PN_stdfloat underscore_start = 0.0f;
|
||||||
const TextProperties *underscore_properties = NULL;
|
const TextProperties *underscore_properties = NULL;
|
||||||
|
|
||||||
|
const ComputedProperties *prev_cprops;
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
hb_buffer_t *harfbuff = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
TextString::const_iterator si;
|
TextString::const_iterator si;
|
||||||
for (si = row._string.begin(); si != row._string.end(); ++si) {
|
for (si = row._string.begin(); si != row._string.end(); ++si) {
|
||||||
const TextCharacter &tch = (*si);
|
const TextCharacter &tch = (*si);
|
||||||
@ -1448,10 +1459,29 @@ assemble_row(TextAssembler::TextRow &row,
|
|||||||
LVecBase4 frame = graphic->get_frame();
|
LVecBase4 frame = graphic->get_frame();
|
||||||
line_height = max(line_height, frame[3] - frame[2]);
|
line_height = max(line_height, frame[3] - frame[2]);
|
||||||
} else {
|
} else {
|
||||||
// [fabius] this is not the right place to calc line height (see below)
|
line_height = max(line_height, font->get_line_height() * properties->get_glyph_scale() * properties->get_text_scale());
|
||||||
// line_height = max(line_height, font->get_line_height());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
if (tch._cprops != prev_cprops || graphic != nullptr) {
|
||||||
|
if (harfbuff != nullptr && hb_buffer_get_length(harfbuff) > 0) {
|
||||||
|
// Shape the buffer accumulated so far.
|
||||||
|
shape_buffer(harfbuff, placed_glyphs, xpos, prev_cprops->_properties);
|
||||||
|
hb_buffer_reset(harfbuff);
|
||||||
|
|
||||||
|
} else if (harfbuff == nullptr && text_use_harfbuzz &&
|
||||||
|
font->is_of_type(DynamicTextFont::get_class_type())) {
|
||||||
|
harfbuff = hb_buffer_create();
|
||||||
|
}
|
||||||
|
prev_cprops = tch._cprops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (graphic == nullptr && harfbuff != nullptr) {
|
||||||
|
hb_buffer_add(harfbuff, character, character);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (character == ' ') {
|
if (character == ' ') {
|
||||||
// A space is a special case.
|
// A space is a special case.
|
||||||
xpos += properties->get_glyph_scale() * properties->get_text_scale() * font->get_space_advance();
|
xpos += properties->get_glyph_scale() * properties->get_text_scale() * font->get_space_advance();
|
||||||
@ -1613,10 +1643,16 @@ assemble_row(TextAssembler::TextRow &row,
|
|||||||
}
|
}
|
||||||
|
|
||||||
xpos += advance * glyph_scale;
|
xpos += advance * glyph_scale;
|
||||||
line_height = max(line_height, font->get_line_height() * glyph_scale);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
if (harfbuff != nullptr && hb_buffer_get_length(harfbuff) > 0) {
|
||||||
|
shape_buffer(harfbuff, placed_glyphs, xpos, prev_cprops->_properties);
|
||||||
|
}
|
||||||
|
hb_buffer_destroy(harfbuff);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (underscore && underscore_start != xpos) {
|
if (underscore && underscore_start != xpos) {
|
||||||
draw_underscore(placed_glyphs, underscore_start, xpos,
|
draw_underscore(placed_glyphs, underscore_start, xpos,
|
||||||
underscore_properties);
|
underscore_properties);
|
||||||
@ -1640,6 +1676,88 @@ assemble_row(TextAssembler::TextRow &row,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places the glyphs collected from a HarfBuzz buffer.
|
||||||
|
*/
|
||||||
|
void TextAssembler::
|
||||||
|
shape_buffer(hb_buffer_t *buf, PlacedGlyphs &placed_glyphs, PN_stdfloat &xpos,
|
||||||
|
const TextProperties &properties) {
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
// If we did not specify a text direction, harfbuzz will guess it based on
|
||||||
|
// the script we are using.
|
||||||
|
hb_direction_t direction = HB_DIRECTION_INVALID;
|
||||||
|
if (properties.has_direction()) {
|
||||||
|
switch (properties.get_direction()) {
|
||||||
|
case TextProperties::D_ltr:
|
||||||
|
direction = HB_DIRECTION_LTR;
|
||||||
|
break;
|
||||||
|
case TextProperties::D_rtl:
|
||||||
|
direction = HB_DIRECTION_RTL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hb_buffer_set_direction(buf, direction);
|
||||||
|
hb_buffer_guess_segment_properties(buf);
|
||||||
|
|
||||||
|
DynamicTextFont *font = DCAST(DynamicTextFont, properties.get_font());
|
||||||
|
hb_font_t *hb_font = font->get_hb_font();
|
||||||
|
hb_shape(hb_font, buf, NULL, 0);
|
||||||
|
|
||||||
|
PN_stdfloat glyph_scale = properties.get_glyph_scale() * properties.get_text_scale();
|
||||||
|
PN_stdfloat scale = glyph_scale / (font->get_pixels_per_unit() * font->get_scale_factor() * 64.0);
|
||||||
|
|
||||||
|
unsigned int glyph_count;
|
||||||
|
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||||
|
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < glyph_count; ++i) {
|
||||||
|
int character = glyph_info[i].cluster;
|
||||||
|
int glyph_index = glyph_info[i].codepoint;
|
||||||
|
|
||||||
|
CPT(TextGlyph) glyph;
|
||||||
|
if (!font->get_glyph_by_index(character, glyph_index, glyph)) {
|
||||||
|
char buffer[512];
|
||||||
|
sprintf(buffer, "U+%04x", character);
|
||||||
|
text_cat.warning()
|
||||||
|
<< "No definition in " << font->get_name()
|
||||||
|
<< " for character " << buffer;
|
||||||
|
if (character < 128 && isprint((unsigned int)character)) {
|
||||||
|
text_cat.warning(false)
|
||||||
|
<< " ('" << (char)character << "')";
|
||||||
|
}
|
||||||
|
text_cat.warning(false)
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
PN_stdfloat advance = glyph_pos[i].x_advance * scale;
|
||||||
|
if (glyph->is_whitespace()) {
|
||||||
|
// A space is a special case.
|
||||||
|
xpos += advance;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PN_stdfloat x_offset = glyph_pos[i].x_offset * scale;
|
||||||
|
PN_stdfloat y_offset = glyph_pos[i].y_offset * scale;
|
||||||
|
|
||||||
|
// Build up a GlyphPlacement, indicating all of the Geoms that go into
|
||||||
|
// this character. Normally, there is only one Geom per character, but
|
||||||
|
// it may involve multiple Geoms if we need to add cheesy accents or
|
||||||
|
// ligatures.
|
||||||
|
GlyphPlacement placement;
|
||||||
|
placement._glyph = move(glyph);
|
||||||
|
placement._scale = glyph_scale;
|
||||||
|
placement._xpos = xpos + x_offset;
|
||||||
|
placement._ypos = properties.get_glyph_shift() + y_offset;
|
||||||
|
placement._slant = properties.get_slant();
|
||||||
|
placement._properties = &properties;
|
||||||
|
placed_glyphs.push_back(placement);
|
||||||
|
|
||||||
|
xpos += advance;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the geometry to render the underscore line for the indicated range
|
* Creates the geometry to render the underscore line for the indicated range
|
||||||
* of glyphs in this row.
|
* of glyphs in this row.
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "pmap.h"
|
#include "pmap.h"
|
||||||
|
|
||||||
|
typedef struct hb_buffer_t hb_buffer_t;
|
||||||
|
|
||||||
class TextEncoder;
|
class TextEncoder;
|
||||||
class TextGraphic;
|
class TextGraphic;
|
||||||
@ -247,6 +248,9 @@ private:
|
|||||||
PN_stdfloat &row_width, PN_stdfloat &line_height,
|
PN_stdfloat &row_width, PN_stdfloat &line_height,
|
||||||
TextProperties::Alignment &align, PN_stdfloat &wordwrap);
|
TextProperties::Alignment &align, PN_stdfloat &wordwrap);
|
||||||
|
|
||||||
|
void shape_buffer(hb_buffer_t *buf, PlacedGlyphs &glyphs, PN_stdfloat &xpos,
|
||||||
|
const TextProperties &properties);
|
||||||
|
|
||||||
// These interfaces are for implementing cheesy accent marks and ligatures
|
// These interfaces are for implementing cheesy accent marks and ligatures
|
||||||
// when the font doesn't support them.
|
// when the font doesn't support them.
|
||||||
enum CheesyPosition {
|
enum CheesyPosition {
|
||||||
|
@ -797,3 +797,39 @@ INLINE PN_stdfloat TextProperties::
|
|||||||
get_text_scale() const {
|
get_text_scale() const {
|
||||||
return _text_scale;
|
return _text_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the text direction. If none is specified, it will be guessed
|
||||||
|
* based on the contents of the string.
|
||||||
|
*/
|
||||||
|
INLINE void TextProperties::
|
||||||
|
set_direction(Direction direction) {
|
||||||
|
_direction = direction;
|
||||||
|
_specified |= F_has_direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the text direction setting. If no text direction is specified, it
|
||||||
|
* will be guessed based on the contents of the string.
|
||||||
|
*/
|
||||||
|
INLINE void TextProperties::
|
||||||
|
clear_direction() {
|
||||||
|
_specified &= ~F_has_direction;
|
||||||
|
_direction = D_ltr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
INLINE bool TextProperties::
|
||||||
|
has_direction() const {
|
||||||
|
return (_specified & F_has_direction) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the direction of the text as specified by set_direction().
|
||||||
|
*/
|
||||||
|
INLINE TextProperties::Direction TextProperties::
|
||||||
|
get_direction() const {
|
||||||
|
return _direction;
|
||||||
|
}
|
||||||
|
@ -31,26 +31,27 @@ TypeHandle TextProperties::_type_handle;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
TextProperties::
|
TextProperties::
|
||||||
TextProperties() {
|
TextProperties() :
|
||||||
_specified = 0;
|
_specified(0),
|
||||||
|
|
||||||
_small_caps = text_small_caps;
|
_small_caps(text_small_caps),
|
||||||
_small_caps_scale = text_small_caps_scale;
|
_small_caps_scale(text_small_caps_scale),
|
||||||
_slant = 0.0f;
|
_slant(0.0f),
|
||||||
_underscore = false;
|
_underscore(false),
|
||||||
_underscore_height = 0.0f;
|
_underscore_height(0.0f),
|
||||||
_align = A_left;
|
_align(A_left),
|
||||||
_indent_width = 0.0f;
|
_indent_width(0.0f),
|
||||||
_wordwrap_width = 0.0f;
|
_wordwrap_width(0.0f),
|
||||||
_preserve_trailing_whitespace = false;
|
_preserve_trailing_whitespace(false),
|
||||||
_text_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
_text_color(1.0f, 1.0f, 1.0f, 1.0f),
|
||||||
_shadow_color.set(0.0f, 0.0f, 0.0f, 1.0f);
|
_shadow_color(0.0f, 0.0f, 0.0f, 1.0f),
|
||||||
_shadow_offset.set(0.0f, 0.0f);
|
_shadow_offset(0.0f, 0.0f),
|
||||||
_draw_order = 1;
|
_draw_order(1),
|
||||||
_tab_width = text_tab_width;
|
_tab_width(text_tab_width),
|
||||||
_glyph_scale = 1.0f;
|
_glyph_scale(1.0f),
|
||||||
_glyph_shift = 0.0f;
|
_glyph_shift(0.0f),
|
||||||
_text_scale = 1.0f;
|
_text_scale(1.0f),
|
||||||
|
_direction(D_rtl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,6 +90,7 @@ operator = (const TextProperties ©) {
|
|||||||
_glyph_scale = copy._glyph_scale;
|
_glyph_scale = copy._glyph_scale;
|
||||||
_glyph_shift = copy._glyph_shift;
|
_glyph_shift = copy._glyph_shift;
|
||||||
_text_scale = copy._text_scale;
|
_text_scale = copy._text_scale;
|
||||||
|
_direction = copy._direction;
|
||||||
|
|
||||||
_text_state.clear();
|
_text_state.clear();
|
||||||
_shadow_state.clear();
|
_shadow_state.clear();
|
||||||
@ -163,6 +165,9 @@ operator == (const TextProperties &other) const {
|
|||||||
if ((_specified & F_has_text_scale) && _text_scale != other._text_scale) {
|
if ((_specified & F_has_text_scale) && _text_scale != other._text_scale) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ((_specified & F_has_direction) && _direction != other._direction) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +243,9 @@ add_properties(const TextProperties &other) {
|
|||||||
if (other.has_text_scale()) {
|
if (other.has_text_scale()) {
|
||||||
set_text_scale(other.get_text_scale());
|
set_text_scale(other.get_text_scale());
|
||||||
}
|
}
|
||||||
|
if (other.has_direction()) {
|
||||||
|
set_direction(other.get_direction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -361,6 +369,20 @@ write(ostream &out, int indent_level) const {
|
|||||||
indent(out, indent_level)
|
indent(out, indent_level)
|
||||||
<< "text scale is " << get_text_scale() << "\n";
|
<< "text scale is " << get_text_scale() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_direction()) {
|
||||||
|
indent(out, indent_level)
|
||||||
|
<< "direction is ";
|
||||||
|
switch (get_direction()) {
|
||||||
|
case D_ltr:
|
||||||
|
out << "D_ltr\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case D_rtl:
|
||||||
|
out << "D_rtl\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +49,11 @@ PUBLISHED:
|
|||||||
A_boxed_center
|
A_boxed_center
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Direction {
|
||||||
|
D_ltr,
|
||||||
|
D_rtl,
|
||||||
|
};
|
||||||
|
|
||||||
TextProperties();
|
TextProperties();
|
||||||
TextProperties(const TextProperties ©);
|
TextProperties(const TextProperties ©);
|
||||||
void operator = (const TextProperties ©);
|
void operator = (const TextProperties ©);
|
||||||
@ -160,6 +165,11 @@ PUBLISHED:
|
|||||||
INLINE bool has_text_scale() const;
|
INLINE bool has_text_scale() const;
|
||||||
INLINE PN_stdfloat get_text_scale() const;
|
INLINE PN_stdfloat get_text_scale() const;
|
||||||
|
|
||||||
|
INLINE void set_direction(Direction direction);
|
||||||
|
INLINE void clear_direction();
|
||||||
|
INLINE bool has_direction() const;
|
||||||
|
INLINE Direction get_direction() const;
|
||||||
|
|
||||||
void add_properties(const TextProperties &other);
|
void add_properties(const TextProperties &other);
|
||||||
|
|
||||||
void write(ostream &out, int indent_level = 0) const;
|
void write(ostream &out, int indent_level = 0) const;
|
||||||
@ -197,6 +207,8 @@ PUBLISHED:
|
|||||||
set_glyph_shift, clear_glyph_shift);
|
set_glyph_shift, clear_glyph_shift);
|
||||||
MAKE_PROPERTY2(text_scale, has_text_scale, get_text_scale,
|
MAKE_PROPERTY2(text_scale, has_text_scale, get_text_scale,
|
||||||
set_text_scale, clear_text_scale);
|
set_text_scale, clear_text_scale);
|
||||||
|
MAKE_PROPERTY2(direction, has_direction, get_direction,
|
||||||
|
set_direction, clear_direction);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const RenderState *get_text_state() const;
|
const RenderState *get_text_state() const;
|
||||||
@ -225,6 +237,7 @@ private:
|
|||||||
F_has_underscore = 0x00010000,
|
F_has_underscore = 0x00010000,
|
||||||
F_has_underscore_height = 0x00020000,
|
F_has_underscore_height = 0x00020000,
|
||||||
F_has_text_scale = 0x00040000,
|
F_has_text_scale = 0x00040000,
|
||||||
|
F_has_direction = 0x00080000,
|
||||||
};
|
};
|
||||||
|
|
||||||
int _specified;
|
int _specified;
|
||||||
@ -248,6 +261,7 @@ private:
|
|||||||
PN_stdfloat _glyph_scale;
|
PN_stdfloat _glyph_scale;
|
||||||
PN_stdfloat _glyph_shift;
|
PN_stdfloat _glyph_shift;
|
||||||
PN_stdfloat _text_scale;
|
PN_stdfloat _text_scale;
|
||||||
|
Direction _direction;
|
||||||
|
|
||||||
mutable CPT(RenderState) _text_state;
|
mutable CPT(RenderState) _text_state;
|
||||||
mutable CPT(RenderState) _shadow_state;
|
mutable CPT(RenderState) _shadow_state;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user