mirror of
https://github.com/panda3d/panda3d.git
synced 2026-04-24 07:29:13 -05:00
Merge branch 'master' into input-overhaul
This commit is contained in:
@@ -15,9 +15,6 @@
|
||||
#include "typeRegistryNode.h"
|
||||
#include "atomicAdjust.h"
|
||||
|
||||
// This is initialized to zero by static initialization.
|
||||
TypeHandle TypeHandle::_none;
|
||||
|
||||
/**
|
||||
* Returns the total allocated memory used by objects of this type, for the
|
||||
* indicated memory class. This is only updated if track-memory-usage is set
|
||||
|
||||
@@ -147,9 +147,6 @@ public:
|
||||
private:
|
||||
constexpr TypeHandle(int index);
|
||||
|
||||
// Only kept temporarily for ABI compatibility.
|
||||
static TypeHandle _none;
|
||||
|
||||
int _index;
|
||||
friend class TypeRegistry;
|
||||
};
|
||||
|
||||
@@ -116,13 +116,6 @@ write(ostream &out, int indent_level) const {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty search path.
|
||||
*/
|
||||
DSearchPath::
|
||||
DSearchPath() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -139,30 +132,6 @@ DSearchPath(const Filename &directory) {
|
||||
append_directory(directory);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DSearchPath::
|
||||
DSearchPath(const DSearchPath ©) :
|
||||
_directories(copy._directories)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void DSearchPath::
|
||||
operator = (const DSearchPath ©) {
|
||||
_directories = copy._directories;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DSearchPath::
|
||||
~DSearchPath() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the directories from the search list.
|
||||
*/
|
||||
|
||||
@@ -52,12 +52,15 @@ PUBLISHED:
|
||||
Files _files;
|
||||
};
|
||||
|
||||
DSearchPath();
|
||||
DSearchPath() = default;
|
||||
DSearchPath(const std::string &path, const std::string &separator = std::string());
|
||||
DSearchPath(const Filename &directory);
|
||||
DSearchPath(const DSearchPath ©);
|
||||
void operator = (const DSearchPath ©);
|
||||
~DSearchPath();
|
||||
DSearchPath(const DSearchPath ©) = default;
|
||||
DSearchPath(DSearchPath &&from) = default;
|
||||
~DSearchPath() = default;
|
||||
|
||||
DSearchPath &operator = (const DSearchPath ©) = default;
|
||||
DSearchPath &operator = (DSearchPath &&from) = default;
|
||||
|
||||
void clear();
|
||||
void append_directory(const Filename &directory);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
typedef struct __dirstream DIR;
|
||||
struct dirent;
|
||||
typedef unsigned long ino_t;
|
||||
@@ -0,0 +1 @@
|
||||
struct inotify_event;
|
||||
@@ -0,0 +1,3 @@
|
||||
struct winsize;
|
||||
struct termio;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
struct posix_typed_mem_info;
|
||||
@@ -0,0 +1 @@
|
||||
#include <sys/time.h>
|
||||
@@ -0,0 +1 @@
|
||||
struct sysinfo;
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "config_prc.h"
|
||||
#include "pstrtod.h"
|
||||
#include "string_utils.h"
|
||||
#include "executionEnvironment.h"
|
||||
#include "mutexImpl.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
@@ -131,6 +133,41 @@ set_double_word(size_t n, double value) {
|
||||
invalidate_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets the string value as a filename and returns it, with any
|
||||
* variables expanded.
|
||||
*/
|
||||
Filename ConfigDeclaration::
|
||||
get_filename_value() const {
|
||||
// Since we are about to set THIS_PRC_DIR globally, we need to ensure that
|
||||
// no two threads call this method at the same time.
|
||||
// NB. MSVC doesn't guarantee that this mutex is initialized in a
|
||||
// thread-safe manner. But chances are that the first time this is called
|
||||
// is at static init time, when there is no risk of data races.
|
||||
static MutexImpl lock;
|
||||
|
||||
string str = _string_value;
|
||||
|
||||
// Are there any variables to be expanded?
|
||||
if (str.find('$') != string::npos) {
|
||||
Filename page_filename(_page->get_name());
|
||||
Filename page_dirname = page_filename.get_dirname();
|
||||
|
||||
lock.lock();
|
||||
ExecutionEnvironment::shadow_environment_variable("THIS_PRC_DIR", page_dirname.to_os_specific());
|
||||
str = ExecutionEnvironment::expand_string(str);
|
||||
ExecutionEnvironment::clear_shadow("THIS_PRC_DIR");
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
Filename fn;
|
||||
if (!str.empty()) {
|
||||
fn = Filename::from_os_specific(str);
|
||||
fn.make_true_case();
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "configPage.h"
|
||||
#include "vector_string.h"
|
||||
#include "numeric_types.h"
|
||||
#include "filename.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -68,6 +69,8 @@ PUBLISHED:
|
||||
void set_int64_word(size_t n, int64_t value);
|
||||
void set_double_word(size_t n, double value);
|
||||
|
||||
Filename get_filename_value() const;
|
||||
|
||||
INLINE int get_decl_seq() const;
|
||||
|
||||
void output(std::ostream &out) const;
|
||||
|
||||
@@ -18,6 +18,18 @@
|
||||
*/
|
||||
void ConfigVariableBool::
|
||||
reload_value() const {
|
||||
mark_cache_valid(_local_modified);
|
||||
_cache = get_bool_word(0);
|
||||
// NB. MSVC doesn't guarantee that this mutex is initialized in a
|
||||
// thread-safe manner. But chances are that the first time this is called
|
||||
// is at static init time, when there is no risk of data races.
|
||||
static MutexImpl lock;
|
||||
lock.lock();
|
||||
|
||||
// We check again for cache validity since another thread may have beaten
|
||||
// us to the punch while we were waiting for the lock.
|
||||
if (!is_cache_valid(_local_modified)) {
|
||||
_cache = get_bool_word(0);
|
||||
mark_cache_valid(_local_modified);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@@ -29,17 +29,9 @@ reload_cache() {
|
||||
// us to the punch while we were waiting for the lock.
|
||||
if (!is_cache_valid(_local_modified)) {
|
||||
nassertv(_core != nullptr);
|
||||
|
||||
const ConfigDeclaration *decl = _core->get_declaration(0);
|
||||
const ConfigPage *page = decl->get_page();
|
||||
|
||||
Filename page_filename(page->get_name());
|
||||
Filename page_dirname = page_filename.get_dirname();
|
||||
ExecutionEnvironment::shadow_environment_variable("THIS_PRC_DIR", page_dirname.to_os_specific());
|
||||
|
||||
_cache = Filename::expand_from(decl->get_string_value());
|
||||
ExecutionEnvironment::clear_shadow("THIS_PRC_DIR");
|
||||
|
||||
_cache = decl->get_filename_value();
|
||||
mark_cache_valid(_local_modified);
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
@@ -93,20 +93,24 @@ INLINE ConfigVariableSearchPath::
|
||||
* Returns the variable's value.
|
||||
*/
|
||||
INLINE ConfigVariableSearchPath::
|
||||
operator const DSearchPath & () const {
|
||||
operator DSearchPath () const {
|
||||
return get_value();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE const DSearchPath &ConfigVariableSearchPath::
|
||||
INLINE DSearchPath ConfigVariableSearchPath::
|
||||
get_value() const {
|
||||
TAU_PROFILE("const DSearchPath &ConfigVariableSearchPath::get_value() const", " ", TAU_USER);
|
||||
DSearchPath value;
|
||||
_lock.lock();
|
||||
if (!is_cache_valid(_local_modified)) {
|
||||
((ConfigVariableSearchPath *)this)->reload_search_path();
|
||||
}
|
||||
return _cache;
|
||||
value = _cache;
|
||||
_lock.unlock();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +127,7 @@ get_default_value() const {
|
||||
*/
|
||||
INLINE bool ConfigVariableSearchPath::
|
||||
clear_local_value() {
|
||||
_lock.lock();
|
||||
nassertr(_core != nullptr, false);
|
||||
|
||||
bool any_to_clear = !_prefix.is_empty() || _postfix.is_empty();
|
||||
@@ -134,6 +139,7 @@ clear_local_value() {
|
||||
}
|
||||
|
||||
_local_modified = initial_invalid_cache();
|
||||
_lock.unlock();
|
||||
return any_to_clear;
|
||||
}
|
||||
|
||||
@@ -151,8 +157,10 @@ clear() {
|
||||
*/
|
||||
INLINE void ConfigVariableSearchPath::
|
||||
append_directory(const Filename &directory) {
|
||||
_lock.lock();
|
||||
_postfix.append_directory(directory);
|
||||
_local_modified = initial_invalid_cache();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,8 +168,10 @@ append_directory(const Filename &directory) {
|
||||
*/
|
||||
INLINE void ConfigVariableSearchPath::
|
||||
prepend_directory(const Filename &directory) {
|
||||
_lock.lock();
|
||||
_prefix.prepend_directory(directory);
|
||||
_local_modified = initial_invalid_cache();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,8 +180,10 @@ prepend_directory(const Filename &directory) {
|
||||
*/
|
||||
INLINE void ConfigVariableSearchPath::
|
||||
append_path(const std::string &path, const std::string &separator) {
|
||||
_lock.lock();
|
||||
_postfix.append_path(path, separator);
|
||||
_local_modified = initial_invalid_cache();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,8 +192,10 @@ append_path(const std::string &path, const std::string &separator) {
|
||||
*/
|
||||
INLINE void ConfigVariableSearchPath::
|
||||
append_path(const DSearchPath &path) {
|
||||
_lock.lock();
|
||||
_postfix.append_path(path);
|
||||
_local_modified = initial_invalid_cache();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,8 +204,10 @@ append_path(const DSearchPath &path) {
|
||||
*/
|
||||
INLINE void ConfigVariableSearchPath::
|
||||
prepend_path(const DSearchPath &path) {
|
||||
_lock.lock();
|
||||
_prefix.prepend_path(path);
|
||||
_local_modified = initial_invalid_cache();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,9 +229,13 @@ get_num_directories() const {
|
||||
/**
|
||||
* Returns the nth directory on the search list.
|
||||
*/
|
||||
INLINE const Filename &ConfigVariableSearchPath::
|
||||
INLINE Filename ConfigVariableSearchPath::
|
||||
get_directory(size_t n) const {
|
||||
return get_value().get_directory(n);
|
||||
Filename dir;
|
||||
_lock.lock();
|
||||
dir = _cache.get_directory(n);
|
||||
_lock.unlock();
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,17 +27,10 @@ reload_search_path() {
|
||||
size_t num_unique_references = _core->get_num_unique_references();
|
||||
for (size_t i = 0; i < num_unique_references; i++) {
|
||||
const ConfigDeclaration *decl = _core->get_unique_reference(i);
|
||||
const ConfigPage *page = decl->get_page();
|
||||
|
||||
Filename page_filename(page->get_name());
|
||||
Filename page_dirname = page_filename.get_dirname();
|
||||
ExecutionEnvironment::shadow_environment_variable("THIS_PRC_DIR", page_dirname.to_os_specific());
|
||||
std::string expanded = ExecutionEnvironment::expand_string(decl->get_string_value());
|
||||
ExecutionEnvironment::clear_shadow("THIS_PRC_DIR");
|
||||
if (!expanded.empty()) {
|
||||
Filename dir = Filename::from_os_specific(expanded);
|
||||
dir.make_true_case();
|
||||
_cache.append_directory(dir);
|
||||
Filename fn = decl->get_filename_value();
|
||||
if (!fn.empty()) {
|
||||
_cache.append_directory(std::move(fn));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ PUBLISHED:
|
||||
int flags = 0);
|
||||
INLINE ~ConfigVariableSearchPath();
|
||||
|
||||
INLINE operator const DSearchPath & () const;
|
||||
INLINE const DSearchPath &get_value() const;
|
||||
INLINE operator DSearchPath () const;
|
||||
INLINE DSearchPath get_value() const;
|
||||
INLINE const DSearchPath &get_default_value() const;
|
||||
MAKE_PROPERTY(value, get_value);
|
||||
MAKE_PROPERTY(default_value, get_default_value);
|
||||
@@ -66,7 +66,7 @@ PUBLISHED:
|
||||
|
||||
INLINE bool is_empty() const;
|
||||
INLINE size_t get_num_directories() const;
|
||||
INLINE const Filename &get_directory(size_t n) const;
|
||||
INLINE Filename get_directory(size_t n) const;
|
||||
MAKE_SEQ(get_directories, get_num_directories, get_directory);
|
||||
MAKE_SEQ_PROPERTY(directories, get_num_directories, get_directory);
|
||||
|
||||
@@ -81,6 +81,7 @@ PUBLISHED:
|
||||
private:
|
||||
void reload_search_path();
|
||||
|
||||
mutable MutexImpl _lock;
|
||||
DSearchPath _default_value;
|
||||
DSearchPath _prefix, _postfix;
|
||||
|
||||
|
||||
@@ -248,8 +248,8 @@ inline std::ostream &operator <<(std::ostream &out, const PartBundle &bundle) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream &operator <<(std::ostream &out, PartBundle::BlendType blend_type);
|
||||
std::istream &operator >>(std::istream &in, PartBundle::BlendType &blend_type);
|
||||
EXPCL_PANDA_CHAN std::ostream &operator <<(std::ostream &out, PartBundle::BlendType blend_type);
|
||||
EXPCL_PANDA_CHAN std::istream &operator >>(std::istream &in, PartBundle::BlendType &blend_type);
|
||||
|
||||
#include "partBundle.I"
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
* connectivity, and generates a set of EggTriangleStrips that represent the
|
||||
* same geometry.
|
||||
*/
|
||||
class EggMesher {
|
||||
class EXPCL_PANDA_EGG EggMesher {
|
||||
public:
|
||||
EggMesher();
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class EggMesherStrip;
|
||||
* connected triangles. The edge is actually represented as a pair of vertex
|
||||
* indices into the same vertex pool.
|
||||
*/
|
||||
class EggMesherEdge {
|
||||
class EXPCL_PANDA_EGG EggMesherEdge {
|
||||
public:
|
||||
INLINE EggMesherEdge(int vi_a, int vi_b);
|
||||
INLINE EggMesherEdge(const EggMesherEdge ©);
|
||||
|
||||
@@ -31,7 +31,7 @@ class EggMesher;
|
||||
* This class is used by EggMesher::find_fans() to attempt to make an
|
||||
* EggTriangleFan out of the polygons connected to the indicated vertex.
|
||||
*/
|
||||
class EggMesherFanMaker {
|
||||
class EXPCL_PANDA_EGG EggMesherFanMaker {
|
||||
public:
|
||||
typedef plist<const EggMesherEdge *> Edges;
|
||||
typedef plist<EggMesherStrip *> Strips;
|
||||
|
||||
@@ -27,7 +27,7 @@ class EggMesherEdge;
|
||||
* mesher. It might also represent a single polygon such as a triangle or
|
||||
* quad, since that's how strips generally start out.
|
||||
*/
|
||||
class EggMesherStrip {
|
||||
class EXPCL_PANDA_EGG EggMesherStrip {
|
||||
public:
|
||||
enum PrimType {
|
||||
PT_poly,
|
||||
|
||||
@@ -27,7 +27,7 @@ class EggLoader;
|
||||
* It is used to collect similar polygons together for a Geom, as well as to
|
||||
* group related LOD children together under a single LOD node.
|
||||
*/
|
||||
class EggBinner : public EggBinMaker {
|
||||
class EXPCL_PANDA_EGG2PG EggBinner : public EggBinMaker {
|
||||
public:
|
||||
// The BinNumber serves to identify why a particular EggBin was created.
|
||||
enum BinNumber {
|
||||
|
||||
@@ -64,7 +64,7 @@ class CharacterMaker;
|
||||
*
|
||||
* This class isn't exported from this package.
|
||||
*/
|
||||
class EggLoader {
|
||||
class EXPCL_PANDA_EGG2PG EggLoader {
|
||||
public:
|
||||
EggLoader();
|
||||
EggLoader(const EggData *data);
|
||||
|
||||
@@ -36,7 +36,7 @@ class EggMaterial;
|
||||
* should be assigned to each primitive. It is assigned to EggPrimitive
|
||||
* objects via the EggBinner.
|
||||
*/
|
||||
class EggRenderState : public EggUserData {
|
||||
class EXPCL_PANDA_EGG2PG EggRenderState : public EggUserData {
|
||||
public:
|
||||
INLINE EggRenderState(EggLoader &loader);
|
||||
INLINE void add_attrib(const RenderAttrib *attrib);
|
||||
|
||||
@@ -50,7 +50,7 @@ class EggVertex;
|
||||
* complete (some Panda or egg constructs are not fully supported by this
|
||||
* class).
|
||||
*/
|
||||
class EggSaver {
|
||||
class EXPCL_PANDA_EGG2PG EggSaver {
|
||||
PUBLISHED:
|
||||
EggSaver(EggData *data = nullptr);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* @param filename Heightfield texture
|
||||
*/
|
||||
INLINE void ShaderTerrainMesh::set_heightfield(Texture* heightfield) {
|
||||
MutexHolder holder(_lock);
|
||||
_heightfield_tex = heightfield;
|
||||
}
|
||||
|
||||
@@ -33,6 +34,7 @@ INLINE void ShaderTerrainMesh::set_heightfield(Texture* heightfield) {
|
||||
* @return Path to the heightfield
|
||||
*/
|
||||
INLINE Texture* ShaderTerrainMesh::get_heightfield() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _heightfield_tex;
|
||||
}
|
||||
|
||||
@@ -54,6 +56,7 @@ INLINE Texture* ShaderTerrainMesh::get_heightfield() const {
|
||||
* @param chunk_size Size of the chunks, has to be a power of two
|
||||
*/
|
||||
INLINE void ShaderTerrainMesh::set_chunk_size(size_t chunk_size) {
|
||||
MutexHolder holder(_lock);
|
||||
_chunk_size = chunk_size;
|
||||
}
|
||||
|
||||
@@ -63,6 +66,7 @@ INLINE void ShaderTerrainMesh::set_chunk_size(size_t chunk_size) {
|
||||
* @return Chunk size
|
||||
*/
|
||||
INLINE size_t ShaderTerrainMesh::get_chunk_size() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _chunk_size;
|
||||
}
|
||||
|
||||
@@ -81,6 +85,7 @@ INLINE size_t ShaderTerrainMesh::get_chunk_size() const {
|
||||
* @param generate_patches [description]
|
||||
*/
|
||||
INLINE void ShaderTerrainMesh::set_generate_patches(bool generate_patches) {
|
||||
MutexHolder holder(_lock);
|
||||
_generate_patches = generate_patches;
|
||||
}
|
||||
|
||||
@@ -92,6 +97,7 @@ INLINE void ShaderTerrainMesh::set_generate_patches(bool generate_patches) {
|
||||
* @return Whether to generate patches
|
||||
*/
|
||||
INLINE bool ShaderTerrainMesh::get_generate_patches() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _generate_patches;
|
||||
}
|
||||
|
||||
@@ -107,6 +113,7 @@ INLINE bool ShaderTerrainMesh::get_generate_patches() const {
|
||||
* @param target_triangle_width Desired triangle width in pixels
|
||||
*/
|
||||
INLINE void ShaderTerrainMesh::set_target_triangle_width(PN_stdfloat target_triangle_width) {
|
||||
MutexHolder holder(_lock);
|
||||
_target_triangle_width = target_triangle_width;
|
||||
}
|
||||
|
||||
@@ -118,6 +125,7 @@ INLINE void ShaderTerrainMesh::set_target_triangle_width(PN_stdfloat target_tria
|
||||
* @return Target triangle width
|
||||
*/
|
||||
INLINE PN_stdfloat ShaderTerrainMesh::get_target_triangle_width() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _target_triangle_width;
|
||||
}
|
||||
|
||||
@@ -131,6 +139,7 @@ INLINE PN_stdfloat ShaderTerrainMesh::get_target_triangle_width() const {
|
||||
* @param update_enabled Whether to update the terrain
|
||||
*/
|
||||
INLINE void ShaderTerrainMesh::set_update_enabled(bool update_enabled) {
|
||||
MutexHolder holder(_lock);
|
||||
_update_enabled = update_enabled;
|
||||
}
|
||||
|
||||
@@ -142,6 +151,7 @@ INLINE void ShaderTerrainMesh::set_update_enabled(bool update_enabled) {
|
||||
* @return Whether to update the terrain
|
||||
*/
|
||||
INLINE bool ShaderTerrainMesh::get_update_enabled() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _update_enabled;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ ShaderTerrainMesh::ShaderTerrainMesh() :
|
||||
* @return true if the terrain was initialized, false if an error occured
|
||||
*/
|
||||
bool ShaderTerrainMesh::generate() {
|
||||
MutexHolder holder(_lock);
|
||||
if (!do_check_heightfield())
|
||||
return false;
|
||||
|
||||
@@ -461,6 +462,7 @@ bool ShaderTerrainMesh::safe_to_combine() const {
|
||||
* @copydoc PandaNode::add_for_draw()
|
||||
*/
|
||||
void ShaderTerrainMesh::add_for_draw(CullTraverser *trav, CullTraverserData &data) {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
// Make sure the terrain was properly initialized, and the geom was created
|
||||
// successfully
|
||||
@@ -711,6 +713,7 @@ void ShaderTerrainMesh::do_emit_chunk(Chunk* chunk, TraversalData* data) {
|
||||
* @return World-Space point
|
||||
*/
|
||||
LPoint3 ShaderTerrainMesh::uv_to_world(const LTexCoord& coord) const {
|
||||
MutexHolder holder(_lock);
|
||||
nassertr(_heightfield_tex != nullptr, LPoint3(0)); // Heightfield not set yet
|
||||
nassertr(_heightfield_tex->has_ram_image(), LPoint3(0)); // Heightfield not in memory
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "configVariableInt.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "filename.h"
|
||||
#include "pmutex.h"
|
||||
#include "mutexHolder.h"
|
||||
#include <stdint.h>
|
||||
|
||||
extern ConfigVariableBool stm_use_hexagonal_layout;
|
||||
@@ -160,6 +162,7 @@ private:
|
||||
void do_emit_chunk(Chunk* chunk, TraversalData* data);
|
||||
bool do_check_lod_matches(Chunk* chunk, TraversalData* data);
|
||||
|
||||
Mutex _lock;
|
||||
Chunk _base_chunk;
|
||||
size_t _size;
|
||||
size_t _chunk_size;
|
||||
|
||||
@@ -29,6 +29,8 @@ PT(MovieAudio) MovieTypeRegistry::
|
||||
make_audio(const Filename &name) {
|
||||
string ext = downcase(name.get_extension());
|
||||
|
||||
_audio_lock.lock();
|
||||
|
||||
// Make sure that the list of audio types has been read in.
|
||||
load_audio_types();
|
||||
|
||||
@@ -41,6 +43,7 @@ make_audio(const Filename &name) {
|
||||
// Explicit extension is preferred over catch-all.
|
||||
if (_audio_type_registry.count(ext)) {
|
||||
MakeAudioFunc func = _audio_type_registry[ext];
|
||||
_audio_lock.unlock();
|
||||
return (*func)(name);
|
||||
}
|
||||
|
||||
@@ -53,12 +56,14 @@ make_audio(const Filename &name) {
|
||||
|
||||
if (_audio_type_registry.count("*")) {
|
||||
MakeAudioFunc func = _audio_type_registry["*"];
|
||||
_audio_lock.unlock();
|
||||
return (*func)(name);
|
||||
}
|
||||
|
||||
movies_cat.error()
|
||||
<< "Support for audio files with extension ." << ext << " was not enabled.\n";
|
||||
|
||||
_audio_lock.unlock();
|
||||
return new MovieAudio("Load-Failure Stub");
|
||||
}
|
||||
|
||||
@@ -68,6 +73,7 @@ make_audio(const Filename &name) {
|
||||
*/
|
||||
void MovieTypeRegistry::
|
||||
register_audio_type(MakeAudioFunc func, const string &extensions) {
|
||||
ReMutexHolder holder(_audio_lock);
|
||||
vector_string words;
|
||||
extract_words(downcase(extensions), words);
|
||||
|
||||
@@ -89,6 +95,7 @@ register_audio_type(MakeAudioFunc func, const string &extensions) {
|
||||
*/
|
||||
void MovieTypeRegistry::
|
||||
load_audio_types() {
|
||||
ReMutexHolder holder(_audio_lock);
|
||||
static bool audio_types_loaded = false;
|
||||
|
||||
if (!audio_types_loaded) {
|
||||
@@ -145,6 +152,8 @@ PT(MovieVideo) MovieTypeRegistry::
|
||||
make_video(const Filename &name) {
|
||||
string ext = downcase(name.get_extension());
|
||||
|
||||
_video_lock.lock();
|
||||
|
||||
// Make sure that the list of video types has been read in.
|
||||
load_video_types();
|
||||
|
||||
@@ -157,6 +166,7 @@ make_video(const Filename &name) {
|
||||
// Explicit extension is preferred over catch-all.
|
||||
if (_video_type_registry.count(ext)) {
|
||||
MakeVideoFunc func = _video_type_registry[ext];
|
||||
_video_lock.unlock();
|
||||
return (*func)(name);
|
||||
}
|
||||
|
||||
@@ -169,12 +179,14 @@ make_video(const Filename &name) {
|
||||
|
||||
if (_video_type_registry.count("*")) {
|
||||
MakeVideoFunc func = _video_type_registry["*"];
|
||||
_video_lock.unlock();
|
||||
return (*func)(name);
|
||||
}
|
||||
|
||||
movies_cat.error()
|
||||
<< "Support for video files with extension ." << ext << " was not enabled.\n";
|
||||
|
||||
_video_lock.unlock();
|
||||
return new MovieVideo("Load-Failure Stub");
|
||||
}
|
||||
|
||||
@@ -184,6 +196,7 @@ make_video(const Filename &name) {
|
||||
*/
|
||||
void MovieTypeRegistry::
|
||||
register_video_type(MakeVideoFunc func, const string &extensions) {
|
||||
ReMutexHolder holder(_video_lock);
|
||||
vector_string words;
|
||||
extract_words(downcase(extensions), words);
|
||||
|
||||
@@ -205,6 +218,7 @@ register_video_type(MakeVideoFunc func, const string &extensions) {
|
||||
*/
|
||||
void MovieTypeRegistry::
|
||||
load_video_types() {
|
||||
ReMutexHolder holder(_video_lock);
|
||||
static bool video_types_loaded = false;
|
||||
|
||||
if (!video_types_loaded) {
|
||||
@@ -259,6 +273,7 @@ load_video_types() {
|
||||
*/
|
||||
void MovieTypeRegistry::
|
||||
load_movie_library(const string &name) {
|
||||
ReMutexHolder holder(_video_lock);
|
||||
Filename dlname = Filename::dso_filename("lib" + name + ".so");
|
||||
movies_cat.info()
|
||||
<< "loading video type module: " << name << endl;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "movieVideo.h"
|
||||
#include "filename.h"
|
||||
#include "pmap.h"
|
||||
#include "reMutex.h"
|
||||
|
||||
/**
|
||||
* This class records the different types of MovieAudio and MovieVideo that
|
||||
@@ -43,9 +44,11 @@ public:
|
||||
private:
|
||||
static MovieTypeRegistry *_global_ptr;
|
||||
|
||||
ReMutex _audio_lock;
|
||||
pmap<std::string, MakeAudioFunc> _audio_type_registry;
|
||||
pmap<std::string, std::string> _deferred_audio_types;
|
||||
|
||||
ReMutex _video_lock;
|
||||
pmap<std::string, MakeVideoFunc> _video_type_registry;
|
||||
pmap<std::string, std::string> _deferred_video_types;
|
||||
};
|
||||
|
||||
@@ -133,17 +133,17 @@ get_hash_impl() const {
|
||||
}
|
||||
|
||||
/**
|
||||
* Quantizes the color color to the nearest multiple of 1000, just to prevent
|
||||
* Quantizes the flat color to the nearest multiple of 1024, just to prevent
|
||||
* runaway accumulation of only slightly-different ColorAttribs.
|
||||
*/
|
||||
void ColorAttrib::
|
||||
quantize_color() {
|
||||
switch (_type) {
|
||||
case T_flat:
|
||||
_color[0] = cfloor(_color[0] * 1000.0f + 0.5f) * 0.001f;
|
||||
_color[1] = cfloor(_color[1] * 1000.0f + 0.5f) * 0.001f;
|
||||
_color[2] = cfloor(_color[2] * 1000.0f + 0.5f) * 0.001f;
|
||||
_color[3] = cfloor(_color[3] * 1000.0f + 0.5f) * 0.001f;
|
||||
_color[0] = cfloor(_color[0] * 1024.0f + 0.5f) / 1024.0f;
|
||||
_color[1] = cfloor(_color[1] * 1024.0f + 0.5f) / 1024.0f;
|
||||
_color[2] = cfloor(_color[2] * 1024.0f + 0.5f) / 1024.0f;
|
||||
_color[3] = cfloor(_color[3] * 1024.0f + 0.5f) / 1024.0f;
|
||||
break;
|
||||
|
||||
case T_off:
|
||||
|
||||
@@ -230,15 +230,15 @@ invert_compose_impl(const RenderAttrib *other) const {
|
||||
}
|
||||
|
||||
/**
|
||||
* Quantizes the color scale to the nearest multiple of 1000, just to prevent
|
||||
* Quantizes the color scale to the nearest multiple of 1024, just to prevent
|
||||
* runaway accumulation of only slightly-different ColorScaleAttribs.
|
||||
*/
|
||||
void ColorScaleAttrib::
|
||||
quantize_scale() {
|
||||
_scale[0] = cfloor(_scale[0] * 1000.0f + 0.5f) * 0.001f;
|
||||
_scale[1] = cfloor(_scale[1] * 1000.0f + 0.5f) * 0.001f;
|
||||
_scale[2] = cfloor(_scale[2] * 1000.0f + 0.5f) * 0.001f;
|
||||
_scale[3] = cfloor(_scale[3] * 1000.0f + 0.5f) * 0.001f;
|
||||
_scale[0] = cfloor(_scale[0] * 1024.0f + 0.5f) / 1024.0f;
|
||||
_scale[1] = cfloor(_scale[1] * 1024.0f + 0.5f) / 1024.0f;
|
||||
_scale[2] = cfloor(_scale[2] * 1024.0f + 0.5f) / 1024.0f;
|
||||
_scale[3] = cfloor(_scale[3] * 1024.0f + 0.5f) / 1024.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -207,7 +207,7 @@ load_file(const Filename &filename, const LoaderOptions &options) const {
|
||||
|
||||
if (search) {
|
||||
// Look for the file along the model path.
|
||||
const ConfigVariableSearchPath &model_path = get_model_path();
|
||||
DSearchPath model_path(get_model_path());
|
||||
int num_dirs = model_path.get_num_directories();
|
||||
for (int i = 0; i < num_dirs; ++i) {
|
||||
Filename pathname(model_path.get_directory(i), this_filename);
|
||||
|
||||
@@ -53,14 +53,22 @@ TypeHandle ShaderGenerator::_type_handle;
|
||||
|
||||
#ifdef HAVE_CG
|
||||
|
||||
#define PACK_COMBINE(src0, op0, src1, op1, src2, op2) ( \
|
||||
((uint16_t)src0) | ((((uint16_t)op0 - 1u) & 3u) << 3u) | \
|
||||
((uint16_t)src1 << 5u) | ((((uint16_t)op1 - 1u) & 3u) << 8u) | \
|
||||
((uint16_t)src2 << 10u) | ((((uint16_t)op2 - 1u) & 3u) << 13u))
|
||||
|
||||
#define UNPACK_COMBINE_SRC(from, n) (TextureStage::CombineSource)((from >> ((uint16_t)n * 5u)) & 7u)
|
||||
#define UNPACK_COMBINE_OP(from, n) (TextureStage::CombineOperand)(((from >> (((uint16_t)n * 5u) + 3u)) & 3u) + 1u)
|
||||
|
||||
static inline uint16_t
|
||||
pack_combine(TextureStage::CombineSource src0, TextureStage::CombineOperand op0,
|
||||
TextureStage::CombineSource src1, TextureStage::CombineOperand op1,
|
||||
TextureStage::CombineSource src2, TextureStage::CombineOperand op2) {
|
||||
if (op0 == TextureStage::CO_undefined) op0 = TextureStage::CO_src_alpha;
|
||||
if (op1 == TextureStage::CO_undefined) op1 = TextureStage::CO_src_alpha;
|
||||
if (op2 == TextureStage::CO_undefined) op2 = TextureStage::CO_src_alpha;
|
||||
|
||||
return ((uint16_t)src0) | ((((uint16_t)op0 - 1u) & 3u) << 3u) |
|
||||
((uint16_t)src1 << 5u) | ((((uint16_t)op1 - 1u) & 3u) << 8u) |
|
||||
((uint16_t)src2 << 10u) | ((((uint16_t)op2 - 1u) & 3u) << 13u);
|
||||
}
|
||||
|
||||
static PStatCollector lookup_collector("*:Munge:ShaderGen:Lookup");
|
||||
static PStatCollector synthesize_collector("*:Munge:ShaderGen:Synthesize");
|
||||
|
||||
@@ -399,11 +407,12 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) {
|
||||
if (stage->get_alpha_scale() == 4) {
|
||||
info._flags |= ShaderKey::TF_alpha_scale_4;
|
||||
}
|
||||
info._combine_rgb = PACK_COMBINE(
|
||||
|
||||
info._combine_rgb = pack_combine(
|
||||
stage->get_combine_rgb_source0(), stage->get_combine_rgb_operand0(),
|
||||
stage->get_combine_rgb_source1(), stage->get_combine_rgb_operand1(),
|
||||
stage->get_combine_rgb_source2(), stage->get_combine_rgb_operand2());
|
||||
info._combine_alpha = PACK_COMBINE(
|
||||
info._combine_alpha = pack_combine(
|
||||
stage->get_combine_alpha_source0(), stage->get_combine_alpha_operand0(),
|
||||
stage->get_combine_alpha_source1(), stage->get_combine_alpha_operand1(),
|
||||
stage->get_combine_alpha_source2(), stage->get_combine_alpha_operand2());
|
||||
|
||||
@@ -58,4 +58,6 @@ wait(double timeout) {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
#undef PAUSE
|
||||
|
||||
#endif // MUTEX_SPINLOCK
|
||||
|
||||
@@ -54,4 +54,6 @@ try_lock() {
|
||||
}
|
||||
}
|
||||
|
||||
#undef PAUSE
|
||||
|
||||
#endif // MUTEX_SPINLOCK
|
||||
|
||||
+140
-30
@@ -33,6 +33,7 @@ get_line_height() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_max_rows(int max_rows) {
|
||||
MutexHolder holder(_lock);
|
||||
_max_rows = max_rows;
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -43,6 +44,7 @@ set_max_rows(int max_rows) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_max_rows() {
|
||||
MutexHolder holder(_lock);
|
||||
_max_rows = 0;
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -53,6 +55,7 @@ clear_max_rows() {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
has_max_rows() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _max_rows > 0;
|
||||
}
|
||||
|
||||
@@ -62,6 +65,7 @@ has_max_rows() const {
|
||||
*/
|
||||
INLINE int TextNode::
|
||||
get_max_rows() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _max_rows;
|
||||
}
|
||||
|
||||
@@ -71,6 +75,7 @@ get_max_rows() const {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
has_overflow() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return (_flags & F_has_overflow) != 0;
|
||||
}
|
||||
@@ -88,6 +93,7 @@ set_frame_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_frame_color(const LColor &frame_color) {
|
||||
MutexHolder holder(_lock);
|
||||
if (_frame_color != frame_color) {
|
||||
_frame_color = frame_color;
|
||||
invalidate_no_measure();
|
||||
@@ -99,6 +105,7 @@ set_frame_color(const LColor &frame_color) {
|
||||
*/
|
||||
INLINE LColor TextNode::
|
||||
get_frame_color() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _frame_color;
|
||||
}
|
||||
|
||||
@@ -107,7 +114,8 @@ get_frame_color() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_card_border(PN_stdfloat size, PN_stdfloat uv_portion) {
|
||||
if (!has_card_border() || _card_border_size != size || _card_border_uv_portion != uv_portion) {
|
||||
MutexHolder holder(_lock);
|
||||
if ((_flags & F_has_card_border) == 0 || _card_border_size != size || _card_border_uv_portion != uv_portion) {
|
||||
_flags |= F_has_card_border;
|
||||
_card_border_size = size;
|
||||
_card_border_uv_portion = uv_portion;
|
||||
@@ -120,7 +128,8 @@ set_card_border(PN_stdfloat size, PN_stdfloat uv_portion) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_card_border() {
|
||||
if (has_card_border()) {
|
||||
MutexHolder holder(_lock);
|
||||
if (_flags & F_has_card_border) {
|
||||
_flags &= ~F_has_card_border;
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -131,6 +140,7 @@ clear_card_border() {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_card_border_size() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _card_border_size;
|
||||
}
|
||||
|
||||
@@ -139,6 +149,7 @@ get_card_border_size() const {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_card_border_uv_portion() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _card_border_uv_portion;
|
||||
}
|
||||
|
||||
@@ -147,6 +158,7 @@ get_card_border_uv_portion() const {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
has_card_border() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_flags & F_has_card_border) != 0;
|
||||
}
|
||||
|
||||
@@ -163,6 +175,7 @@ set_card_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_card_color(const LColor &card_color) {
|
||||
MutexHolder holder(_lock);
|
||||
if (_card_color != card_color) {
|
||||
_card_color = card_color;
|
||||
invalidate_no_measure();
|
||||
@@ -174,6 +187,7 @@ set_card_color(const LColor &card_color) {
|
||||
*/
|
||||
INLINE LColor TextNode::
|
||||
get_card_color() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _card_color;
|
||||
}
|
||||
|
||||
@@ -185,7 +199,8 @@ set_card_texture(Texture *card_texture) {
|
||||
if (card_texture == nullptr) {
|
||||
clear_card_texture();
|
||||
} else {
|
||||
if (!has_card_texture() || _card_texture != card_texture) {
|
||||
MutexHolder holder(_lock);
|
||||
if ((_flags & F_has_card_texture) == 0 || _card_texture != card_texture) {
|
||||
_flags |= F_has_card_texture;
|
||||
_card_texture = card_texture;
|
||||
invalidate_no_measure();
|
||||
@@ -198,7 +213,8 @@ set_card_texture(Texture *card_texture) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_card_texture() {
|
||||
if (has_card_texture()) {
|
||||
MutexHolder holder(_lock);
|
||||
if (_flags & F_has_card_texture) {
|
||||
_flags &= ~F_has_card_texture;
|
||||
_card_texture = nullptr;
|
||||
invalidate_no_measure();
|
||||
@@ -210,6 +226,7 @@ clear_card_texture() {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
has_card_texture() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_flags & F_has_card_texture) != 0;
|
||||
}
|
||||
|
||||
@@ -218,6 +235,7 @@ has_card_texture() const {
|
||||
*/
|
||||
INLINE Texture *TextNode::
|
||||
get_card_texture() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _card_texture;
|
||||
}
|
||||
|
||||
@@ -229,6 +247,7 @@ get_card_texture() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_frame_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
|
||||
MutexHolder holder(_lock);
|
||||
_flags |= (F_has_frame | F_frame_as_margin);
|
||||
_frame_ul.set(left, top);
|
||||
_frame_lr.set(right, bottom);
|
||||
@@ -243,6 +262,7 @@ set_frame_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_frame_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
|
||||
MutexHolder holder(_lock);
|
||||
_flags |= F_has_frame;
|
||||
_flags &= ~F_frame_as_margin;
|
||||
_frame_ul.set(left, top);
|
||||
@@ -255,6 +275,7 @@ set_frame_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_std
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_frame() {
|
||||
MutexHolder holder(_lock);
|
||||
_flags &= ~F_has_frame;
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -264,6 +285,7 @@ clear_frame() {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
has_frame() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_flags & F_has_frame) != 0;
|
||||
}
|
||||
|
||||
@@ -276,7 +298,8 @@ has_frame() const {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
is_frame_as_margin() const {
|
||||
nassertr(has_frame(), false);
|
||||
MutexHolder holder(_lock);
|
||||
nassertr((_flags & F_has_frame) != 0, false);
|
||||
return (_flags & F_frame_as_margin) != 0;
|
||||
}
|
||||
|
||||
@@ -288,7 +311,8 @@ is_frame_as_margin() const {
|
||||
*/
|
||||
INLINE LVecBase4 TextNode::
|
||||
get_frame_as_set() const {
|
||||
nassertr(has_frame(), LVecBase4(0.0, 0.0, 0.0, 0.0));
|
||||
MutexHolder holder(_lock);
|
||||
nassertr((_flags & F_has_frame) != 0, LVecBase4(0.0, 0.0, 0.0, 0.0));
|
||||
return LVecBase4(_frame_ul[0], _frame_lr[0], _frame_lr[1], _frame_ul[1]);
|
||||
}
|
||||
|
||||
@@ -303,18 +327,20 @@ get_frame_as_set() const {
|
||||
*/
|
||||
INLINE LVecBase4 TextNode::
|
||||
get_frame_actual() const {
|
||||
if (!has_frame()) {
|
||||
MutexHolder holder(_lock);
|
||||
if (_flags & F_has_frame) {
|
||||
if (_flags & F_frame_as_margin) {
|
||||
check_measure();
|
||||
return LVecBase4(_text_ul[0] - _frame_ul[0],
|
||||
_text_lr[0] + _frame_lr[0],
|
||||
_text_lr[1] - _frame_lr[1],
|
||||
_text_ul[1] + _frame_ul[1]);
|
||||
} else {
|
||||
return LVecBase4(_frame_ul[0], _frame_lr[0], _frame_lr[1], _frame_ul[1]);
|
||||
}
|
||||
} else {
|
||||
check_measure();
|
||||
return LVecBase4(_text_ul[0], _text_lr[0], _text_lr[1], _text_ul[1]);
|
||||
|
||||
} else if (is_frame_as_margin()) {
|
||||
check_measure();
|
||||
return LVecBase4(_text_ul[0] - _frame_ul[0],
|
||||
_text_lr[0] + _frame_lr[0],
|
||||
_text_lr[1] - _frame_lr[1],
|
||||
_text_ul[1] + _frame_ul[1]);
|
||||
} else {
|
||||
return get_frame_as_set();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,6 +349,7 @@ get_frame_actual() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_frame_line_width(PN_stdfloat frame_width) {
|
||||
MutexHolder holder(_lock);
|
||||
_frame_width = frame_width;
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -332,6 +359,7 @@ set_frame_line_width(PN_stdfloat frame_width) {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_frame_line_width() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _frame_width;
|
||||
}
|
||||
|
||||
@@ -342,6 +370,7 @@ get_frame_line_width() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_frame_corners(bool corners) {
|
||||
MutexHolder holder(_lock);
|
||||
if (corners) {
|
||||
_flags |= F_frame_corners;
|
||||
} else {
|
||||
@@ -355,6 +384,7 @@ set_frame_corners(bool corners) {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
get_frame_corners() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_flags & F_frame_corners) != 0;
|
||||
}
|
||||
|
||||
@@ -366,6 +396,7 @@ get_frame_corners() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_card_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
|
||||
MutexHolder holder(_lock);
|
||||
_flags |= (F_has_card | F_card_as_margin);
|
||||
_card_ul.set(left, top);
|
||||
_card_lr.set(right, bottom);
|
||||
@@ -380,6 +411,7 @@ set_card_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_s
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_card_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
|
||||
MutexHolder holder(_lock);
|
||||
_flags |= F_has_card;
|
||||
_flags &= ~F_card_as_margin;
|
||||
_card_ul.set(left, top);
|
||||
@@ -394,6 +426,7 @@ set_card_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdf
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_card_decal(bool card_decal) {
|
||||
MutexHolder holder(_lock);
|
||||
if (card_decal) {
|
||||
_flags |= F_card_decal;
|
||||
} else {
|
||||
@@ -407,6 +440,7 @@ set_card_decal(bool card_decal) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_card() {
|
||||
MutexHolder holder(_lock);
|
||||
_flags &= ~F_has_card;
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -416,6 +450,7 @@ clear_card() {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
has_card() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_flags & F_has_card) != 0;
|
||||
}
|
||||
|
||||
@@ -424,6 +459,7 @@ has_card() const {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
get_card_decal() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_flags & F_card_decal) != 0;
|
||||
}
|
||||
|
||||
@@ -436,7 +472,8 @@ get_card_decal() const {
|
||||
*/
|
||||
INLINE bool TextNode::
|
||||
is_card_as_margin() const {
|
||||
nassertr(has_card(), false);
|
||||
MutexHolder holder(_lock);
|
||||
nassertr((_flags & F_has_card) != 0, false);
|
||||
return (_flags & F_card_as_margin) != 0;
|
||||
}
|
||||
|
||||
@@ -448,7 +485,8 @@ is_card_as_margin() const {
|
||||
*/
|
||||
INLINE LVecBase4 TextNode::
|
||||
get_card_as_set() const {
|
||||
nassertr(has_card(), LVecBase4(0.0, 0.0, 0.0, 0.0));
|
||||
MutexHolder holder(_lock);
|
||||
nassertr((_flags & F_has_card) != 0, LVecBase4(0.0, 0.0, 0.0, 0.0));
|
||||
return LVecBase4(_card_ul[0], _card_lr[0], _card_lr[1], _card_ul[1]);
|
||||
}
|
||||
|
||||
@@ -463,18 +501,20 @@ get_card_as_set() const {
|
||||
*/
|
||||
INLINE LVecBase4 TextNode::
|
||||
get_card_actual() const {
|
||||
if (!has_card()) {
|
||||
MutexHolder holder(_lock);
|
||||
if (_flags & F_has_card) {
|
||||
if (_flags & F_card_as_margin) {
|
||||
check_measure();
|
||||
return LVecBase4(_text_ul[0] - _card_ul[0],
|
||||
_text_lr[0] + _card_lr[0],
|
||||
_text_lr[1] - _card_lr[1],
|
||||
_text_ul[1] + _card_ul[1]);
|
||||
} else {
|
||||
return LVecBase4(_card_ul[0], _card_lr[0], _card_lr[1], _card_ul[1]);
|
||||
}
|
||||
} else {
|
||||
check_measure();
|
||||
return LVecBase4(_text_ul[0], _text_lr[0], _text_lr[1], _text_ul[1]);
|
||||
|
||||
} else if (is_card_as_margin()) {
|
||||
check_measure();
|
||||
return LVecBase4(_text_ul[0] - _card_ul[0],
|
||||
_text_lr[0] + _card_lr[0],
|
||||
_text_lr[1] - _card_lr[1],
|
||||
_text_ul[1] + _card_ul[1]);
|
||||
} else {
|
||||
return get_card_as_set();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,6 +527,8 @@ get_card_actual() const {
|
||||
INLINE LVecBase4 TextNode::
|
||||
get_card_transformed() const {
|
||||
LVecBase4 card = get_card_actual();
|
||||
|
||||
MutexHolder holder(_lock);
|
||||
LPoint3 ul = LPoint3(card[0], 0.0, card[3]) * _transform;
|
||||
LPoint3 lr = LPoint3(card[1], 0.0, card[2]) * _transform;
|
||||
|
||||
@@ -498,6 +540,7 @@ get_card_transformed() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_transform(const LMatrix4 &transform) {
|
||||
MutexHolder holder(_lock);
|
||||
_transform = transform;
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -507,6 +550,7 @@ set_transform(const LMatrix4 &transform) {
|
||||
*/
|
||||
INLINE LMatrix4 TextNode::
|
||||
get_transform() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _transform;
|
||||
}
|
||||
|
||||
@@ -515,6 +559,7 @@ get_transform() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_coordinate_system(CoordinateSystem coordinate_system) {
|
||||
MutexHolder holder(_lock);
|
||||
_coordinate_system = coordinate_system;
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -524,6 +569,7 @@ set_coordinate_system(CoordinateSystem coordinate_system) {
|
||||
*/
|
||||
INLINE CoordinateSystem TextNode::
|
||||
get_coordinate_system() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _coordinate_system;
|
||||
}
|
||||
|
||||
@@ -535,6 +581,7 @@ get_coordinate_system() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_usage_hint(Geom::UsageHint usage_hint) {
|
||||
MutexHolder holder(_lock);
|
||||
_usage_hint = usage_hint;
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -545,6 +592,7 @@ set_usage_hint(Geom::UsageHint usage_hint) {
|
||||
*/
|
||||
INLINE Geom::UsageHint TextNode::
|
||||
get_usage_hint() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _usage_hint;
|
||||
}
|
||||
|
||||
@@ -585,6 +633,7 @@ get_usage_hint() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_flatten_flags(int flatten_flags) {
|
||||
MutexHolder holder(_lock);
|
||||
_flatten_flags = flatten_flags;
|
||||
}
|
||||
|
||||
@@ -593,6 +642,7 @@ set_flatten_flags(int flatten_flags) {
|
||||
*/
|
||||
INLINE int TextNode::
|
||||
get_flatten_flags() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _flatten_flags;
|
||||
}
|
||||
|
||||
@@ -602,6 +652,7 @@ get_flatten_flags() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_font(TextFont *font) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_font(font);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -611,6 +662,7 @@ set_font(TextFont *font) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_font() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_font();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -631,6 +683,7 @@ clear_font() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_small_caps(bool small_caps) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_small_caps(small_caps);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -640,6 +693,7 @@ set_small_caps(bool small_caps) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_small_caps() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_small_caps();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -651,6 +705,7 @@ clear_small_caps() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_small_caps_scale(PN_stdfloat small_caps_scale) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_small_caps_scale(small_caps_scale);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -660,6 +715,7 @@ set_small_caps_scale(PN_stdfloat small_caps_scale) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_small_caps_scale() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_small_caps_scale();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -669,6 +725,7 @@ clear_small_caps_scale() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_slant(PN_stdfloat slant) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_slant(slant);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -678,6 +735,7 @@ set_slant(PN_stdfloat slant) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_slant() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_slant();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -687,6 +745,7 @@ clear_slant() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_align(TextNode::Alignment align_type) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_align(align_type);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -696,6 +755,7 @@ set_align(TextNode::Alignment align_type) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_align() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_align();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -706,6 +766,7 @@ clear_align() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_indent(PN_stdfloat indent) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_indent(indent);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -715,6 +776,7 @@ set_indent(PN_stdfloat indent) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_indent() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_indent();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -725,6 +787,7 @@ clear_indent() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_wordwrap(PN_stdfloat wordwrap) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_wordwrap(wordwrap);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -735,6 +798,7 @@ set_wordwrap(PN_stdfloat wordwrap) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_wordwrap() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_wordwrap();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -744,6 +808,7 @@ clear_wordwrap() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_text_color(const LColor &text_color) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_text_color(text_color);
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -762,6 +827,7 @@ set_text_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_text_color() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_text_color();
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -779,6 +845,7 @@ set_shadow_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_shadow_color(const LColor &shadow_color) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_shadow_color(shadow_color);
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -788,6 +855,7 @@ set_shadow_color(const LColor &shadow_color) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_shadow_color() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_shadow_color();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -807,6 +875,7 @@ set_shadow(PN_stdfloat xoffset, PN_stdfloat yoffset) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_shadow(const LVecBase2 &shadow_offset) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_shadow(shadow_offset);
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -816,6 +885,7 @@ set_shadow(const LVecBase2 &shadow_offset) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_shadow() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_shadow();
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -831,6 +901,7 @@ clear_shadow() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_bin(const std::string &bin) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_bin(bin);
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -841,6 +912,7 @@ set_bin(const std::string &bin) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_bin() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_bin();
|
||||
invalidate_no_measure();
|
||||
}
|
||||
@@ -858,6 +930,7 @@ clear_bin() {
|
||||
*/
|
||||
INLINE int TextNode::
|
||||
set_draw_order(int draw_order) {
|
||||
MutexHolder holder(_lock);
|
||||
invalidate_no_measure();
|
||||
return TextProperties::set_draw_order(draw_order);
|
||||
}
|
||||
@@ -867,6 +940,7 @@ set_draw_order(int draw_order) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_draw_order() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_draw_order();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -877,6 +951,7 @@ clear_draw_order() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_tab_width(PN_stdfloat tab_width) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_tab_width(tab_width);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -886,6 +961,7 @@ set_tab_width(PN_stdfloat tab_width) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_tab_width() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_tab_width();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -897,6 +973,7 @@ clear_tab_width() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_glyph_scale(PN_stdfloat glyph_scale) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_glyph_scale(glyph_scale);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -906,6 +983,7 @@ set_glyph_scale(PN_stdfloat glyph_scale) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_glyph_scale() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_glyph_scale();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -917,6 +995,7 @@ clear_glyph_scale() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_glyph_shift(PN_stdfloat glyph_shift) {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::set_glyph_shift(glyph_shift);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -926,6 +1005,7 @@ set_glyph_shift(PN_stdfloat glyph_shift) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_glyph_shift() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_glyph_shift();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -936,6 +1016,7 @@ clear_glyph_shift() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_text(const std::string &text) {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::set_text(text);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -948,6 +1029,7 @@ set_text(const std::string &text) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_text(const std::string &text, TextNode::Encoding encoding) {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::set_text(text, encoding);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -957,6 +1039,7 @@ set_text(const std::string &text, TextNode::Encoding encoding) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_text() {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::clear_text();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -966,6 +1049,7 @@ clear_text() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
append_text(const std::string &text) {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::append_text(text);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -976,6 +1060,7 @@ append_text(const std::string &text) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
append_unicode_char(wchar_t character) {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::append_unicode_char(character);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -1008,6 +1093,7 @@ calc_width(const std::string &line) const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_wtext(const std::wstring &wtext) {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::set_wtext(wtext);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -1017,6 +1103,7 @@ set_wtext(const std::wstring &wtext) {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
append_wtext(const std::wstring &wtext) {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::append_wtext(wtext);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
@@ -1030,6 +1117,7 @@ append_wtext(const std::wstring &wtext) {
|
||||
*/
|
||||
INLINE std::wstring TextNode::
|
||||
get_wordwrapped_wtext() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _wordwrapped_wtext;
|
||||
}
|
||||
@@ -1040,6 +1128,7 @@ get_wordwrapped_wtext() const {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_left() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_ul[0];
|
||||
}
|
||||
@@ -1050,6 +1139,7 @@ get_left() const {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_right() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_lr[0];
|
||||
}
|
||||
@@ -1060,6 +1150,7 @@ get_right() const {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_bottom() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_lr[1];
|
||||
}
|
||||
@@ -1070,6 +1161,7 @@ get_bottom() const {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_top() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_ul[1];
|
||||
}
|
||||
@@ -1079,6 +1171,7 @@ get_top() const {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_height() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_ul[1] - _text_lr[1];
|
||||
}
|
||||
@@ -1088,6 +1181,7 @@ get_height() const {
|
||||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_width() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_lr[0] - _text_ul[0];
|
||||
}
|
||||
@@ -1098,6 +1192,7 @@ get_width() const {
|
||||
*/
|
||||
INLINE LPoint3 TextNode::
|
||||
get_upper_left_3d() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _ul3d;
|
||||
}
|
||||
@@ -1108,6 +1203,7 @@ get_upper_left_3d() const {
|
||||
*/
|
||||
INLINE LPoint3 TextNode::
|
||||
get_lower_right_3d() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _lr3d;
|
||||
}
|
||||
@@ -1118,10 +1214,22 @@ get_lower_right_3d() const {
|
||||
*/
|
||||
INLINE int TextNode::
|
||||
get_num_rows() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _num_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the text, according to the parameters indicated within the
|
||||
* TextNode, and returns a Node that may be parented within the tree to
|
||||
* represent it.
|
||||
*/
|
||||
PT(PandaNode) TextNode::
|
||||
generate() {
|
||||
MutexHolder holder(_lock);
|
||||
return do_generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be called after the TextNode has been fully configured, to force the
|
||||
* node to recompute its text immediately, rather than waiting for it to be
|
||||
@@ -1129,6 +1237,7 @@ get_num_rows() const {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
update() {
|
||||
MutexHolder holder(_lock);
|
||||
check_rebuild();
|
||||
}
|
||||
|
||||
@@ -1140,8 +1249,9 @@ update() {
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
force_update() {
|
||||
invalidate_with_measure();
|
||||
check_rebuild();
|
||||
MutexHolder holder(_lock);
|
||||
mark_internal_bounds_stale();
|
||||
do_rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+373
-331
@@ -74,7 +74,7 @@ TextNode(const string &name) : PandaNode(name) {
|
||||
}
|
||||
|
||||
if (text_small_caps) {
|
||||
set_small_caps(true);
|
||||
TextProperties::set_small_caps(true);
|
||||
}
|
||||
|
||||
_frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
@@ -255,11 +255,16 @@ is_whitespace(wchar_t character) const {
|
||||
*/
|
||||
PN_stdfloat TextNode::
|
||||
calc_width(const std::wstring &line) const {
|
||||
TextFont *font = get_font();
|
||||
if (font == nullptr) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
PN_stdfloat width = 0.0f;
|
||||
|
||||
std::wstring::const_iterator si;
|
||||
for (si = line.begin(); si != line.end(); ++si) {
|
||||
width += calc_width(*si);
|
||||
width += TextAssembler::calc_width(*si, *this);
|
||||
}
|
||||
|
||||
return width;
|
||||
@@ -272,10 +277,10 @@ void TextNode::
|
||||
output(std::ostream &out) const {
|
||||
PandaNode::output(out);
|
||||
|
||||
check_rebuild();
|
||||
PT(PandaNode) internal_geom = do_get_internal_geom();
|
||||
int geom_count = 0;
|
||||
if (_internal_geom != nullptr) {
|
||||
geom_count = count_geoms(_internal_geom);
|
||||
if (internal_geom != nullptr) {
|
||||
geom_count = count_geoms(internal_geom);
|
||||
}
|
||||
|
||||
out << " (" << geom_count << " geoms)";
|
||||
@@ -286,6 +291,7 @@ output(std::ostream &out) const {
|
||||
*/
|
||||
void TextNode::
|
||||
write(std::ostream &out, int indent_level) const {
|
||||
MutexHolder holder(_lock);
|
||||
PandaNode::write(out, indent_level);
|
||||
TextProperties::write(out, indent_level + 2);
|
||||
indent(out, indent_level + 2)
|
||||
@@ -296,13 +302,263 @@ write(std::ostream &out, int indent_level) const {
|
||||
<< "text is " << get_text() << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual node that is used internally to render the text, if the
|
||||
* TextNode is parented within the scene graph.
|
||||
*
|
||||
* In general, you should not call this method. Call generate() instead if
|
||||
* you want to get a handle to geometry that represents the text. This method
|
||||
* is provided as a debugging aid only.
|
||||
*/
|
||||
PT(PandaNode) TextNode::
|
||||
get_internal_geom() const {
|
||||
// Output a nuisance warning to discourage the naive from calling this
|
||||
// method accidentally.
|
||||
text_cat.info()
|
||||
<< "TextNode::get_internal_geom() called.\n";
|
||||
return do_get_internal_geom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the union of all attributes from SceneGraphReducer::AttribTypes
|
||||
* that may not safely be applied to the vertices of this node. If this is
|
||||
* nonzero, these attributes must be dropped at this node as a state change.
|
||||
*
|
||||
* This is a generalization of safe_to_transform().
|
||||
*/
|
||||
int TextNode::
|
||||
get_unsafe_to_apply_attribs() const {
|
||||
// We have no way to apply these kinds of attributes to our TextNode, so
|
||||
// insist they get dropped into the PandaNode's basic state.
|
||||
return
|
||||
SceneGraphReducer::TT_tex_matrix |
|
||||
SceneGraphReducer::TT_other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies whatever attributes are specified in the AccumulatedAttribs object
|
||||
* (and by the attrib_types bitmask) to the vertices on this node, if
|
||||
* appropriate. If this node uses geom arrays like a GeomNode, the supplied
|
||||
* GeomTransformer may be used to unify shared arrays across multiple
|
||||
* different nodes.
|
||||
*
|
||||
* This is a generalization of xform().
|
||||
*/
|
||||
void TextNode::
|
||||
apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
|
||||
GeomTransformer &transformer) {
|
||||
MutexHolder holder(_lock);
|
||||
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
|
||||
const LMatrix4 &mat = attribs._transform->get_mat();
|
||||
_transform *= mat;
|
||||
|
||||
if ((_flags & F_needs_measure) == 0) {
|
||||
// If we already have a measure, transform it too. We don't need to
|
||||
// invalidate the 2-d parts, since that's not affected by the transform
|
||||
// anyway.
|
||||
_ul3d = _ul3d * mat;
|
||||
_lr3d = _lr3d * mat;
|
||||
}
|
||||
}
|
||||
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
|
||||
if (attribs._color != nullptr) {
|
||||
const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color);
|
||||
if (ca->get_color_type() == ColorAttrib::T_flat) {
|
||||
const LColor &c = ca->get_color();
|
||||
TextProperties::set_text_color(c);
|
||||
TextProperties::set_shadow_color(c);
|
||||
_frame_color = c;
|
||||
_card_color = c;
|
||||
invalidate_no_measure();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
|
||||
if (attribs._color_scale != nullptr) {
|
||||
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale);
|
||||
const LVecBase4 &s = csa->get_scale();
|
||||
if (s != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)) {
|
||||
LVecBase4 tc = get_text_color();
|
||||
tc.componentwise_mult(s);
|
||||
TextProperties::set_text_color(tc);
|
||||
|
||||
LVecBase4 sc = get_shadow_color();
|
||||
sc.componentwise_mult(s);
|
||||
TextProperties::set_shadow_color(sc);
|
||||
|
||||
_frame_color.componentwise_mult(s);
|
||||
_card_color.componentwise_mult(s);
|
||||
|
||||
invalidate_no_measure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now propagate the attributes down to our already-generated geometry, if
|
||||
// we have any.
|
||||
if ((_flags & F_needs_rebuild) == 0 &&
|
||||
_internal_geom != nullptr) {
|
||||
SceneGraphReducer gr;
|
||||
gr.apply_attribs(_internal_geom, attribs, attrib_types, transformer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to support NodePath::calc_tight_bounds(). It is not intended
|
||||
* to be called directly, and it has nothing to do with the normal Panda
|
||||
* bounding-volume computation.
|
||||
*
|
||||
* If the node contains any geometry, this updates min_point and max_point to
|
||||
* enclose its bounding box. found_any is to be set true if the node has any
|
||||
* geometry at all, or left alone if it has none. This method may be called
|
||||
* over several nodes, so it may enter with min_point, max_point, and
|
||||
* found_any already set.
|
||||
*/
|
||||
CPT(TransformState) TextNode::
|
||||
calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any,
|
||||
const TransformState *transform, Thread *current_thread) const {
|
||||
CPT(TransformState) next_transform =
|
||||
PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform,
|
||||
current_thread);
|
||||
|
||||
PT(PandaNode) geom = do_get_internal_geom();
|
||||
if (geom != nullptr) {
|
||||
geom->calc_tight_bounds(min_point, max_point,
|
||||
found_any, next_transform, current_thread);
|
||||
}
|
||||
|
||||
return next_transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will be called during the cull traversal to perform any
|
||||
* additional operations that should be performed at cull time. This may
|
||||
* include additional manipulation of render state or additional
|
||||
* visible/invisible decisions, or any other arbitrary operation.
|
||||
*
|
||||
* Note that this function will *not* be called unless set_cull_callback() is
|
||||
* called in the constructor of the derived class. It is necessary to call
|
||||
* set_cull_callback() to indicated that we require cull_callback() to be
|
||||
* called.
|
||||
*
|
||||
* By the time this function is called, the node has already passed the
|
||||
* bounding-volume test for the viewing frustum, and the node's transform and
|
||||
* state have already been applied to the indicated CullTraverserData object.
|
||||
*
|
||||
* The return value is true if this node should be visible, or false if it
|
||||
* should be culled.
|
||||
*/
|
||||
bool TextNode::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
|
||||
PT(PandaNode) internal_geom = do_get_internal_geom();
|
||||
if (internal_geom != nullptr) {
|
||||
// Render the text with this node.
|
||||
CullTraverserData next_data(data, internal_geom);
|
||||
trav->traverse(next_data);
|
||||
}
|
||||
|
||||
// Now continue to render everything else below this node.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is some value to visiting this particular node during
|
||||
* the cull traversal for any camera, false otherwise. This will be used to
|
||||
* optimize the result of get_net_draw_show_mask(), so that any subtrees that
|
||||
* contain only nodes for which is_renderable() is false need not be visited.
|
||||
*/
|
||||
bool TextNode::
|
||||
is_renderable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when needed to recompute the node's _internal_bound object. Nodes
|
||||
* that contain anything of substance should redefine this to do the right
|
||||
* thing.
|
||||
*/
|
||||
void TextNode::
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
PT(BoundingVolume) bound = new BoundingSphere;
|
||||
|
||||
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
|
||||
|
||||
// Now enclose the bounding box around the text. We can do this without
|
||||
// actually generating the text, if we have at least measured it.
|
||||
LPoint3 vertices[8];
|
||||
{
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
|
||||
vertices[0].set(_ul3d[0], _ul3d[1], _ul3d[2]);
|
||||
vertices[1].set(_ul3d[0], _ul3d[1], _lr3d[2]);
|
||||
vertices[2].set(_ul3d[0], _lr3d[1], _ul3d[2]);
|
||||
vertices[3].set(_ul3d[0], _lr3d[1], _lr3d[2]);
|
||||
vertices[4].set(_lr3d[0], _ul3d[1], _ul3d[2]);
|
||||
vertices[5].set(_lr3d[0], _ul3d[1], _lr3d[2]);
|
||||
vertices[6].set(_lr3d[0], _lr3d[1], _ul3d[2]);
|
||||
vertices[7].set(_lr3d[0], _lr3d[1], _lr3d[2]);
|
||||
}
|
||||
|
||||
gbv->around(vertices, vertices + 8);
|
||||
|
||||
internal_bounds = bound;
|
||||
internal_vertices = 0; // TODO: estimate this better.
|
||||
}
|
||||
|
||||
/**
|
||||
* The recursive implementation of prepare_scene(). Don't call this directly;
|
||||
* call PandaNode::prepare_scene() or NodePath::prepare_scene() instead.
|
||||
*/
|
||||
void TextNode::
|
||||
r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state,
|
||||
GeomTransformer &transformer, Thread *current_thread) {
|
||||
|
||||
PT(PandaNode) child = do_get_internal_geom();
|
||||
if (child != nullptr) {
|
||||
CPT(RenderState) child_state = node_state->compose(child->get_state());
|
||||
child->r_prepare_scene(gsg, child_state, transformer, current_thread);
|
||||
}
|
||||
|
||||
PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any existing children of the TextNode, and adds the newly generated
|
||||
* text instead.
|
||||
*/
|
||||
void TextNode::
|
||||
do_rebuild() {
|
||||
nassertv(_lock.debug_is_locked());
|
||||
_flags &= ~(F_needs_rebuild | F_needs_measure);
|
||||
_internal_geom = do_generate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Can be called in lieu of do_rebuild() to measure the text and set up the
|
||||
* bounding boxes properly without actually assembling it.
|
||||
*/
|
||||
void TextNode::
|
||||
do_measure() {
|
||||
// We no longer make this a special case.
|
||||
do_rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the text, according to the parameters indicated within the
|
||||
* TextNode, and returns a Node that may be parented within the tree to
|
||||
* represent it.
|
||||
*/
|
||||
PT(PandaNode) TextNode::
|
||||
generate() {
|
||||
do_generate() {
|
||||
nassertr(_lock.debug_is_locked(), nullptr);
|
||||
|
||||
PStatTimer timer(_text_generate_pcollector);
|
||||
if (text_cat.is_debug()) {
|
||||
text_cat.debug()
|
||||
@@ -403,20 +659,20 @@ generate() {
|
||||
|
||||
// Now deal with the decorations.
|
||||
|
||||
if (has_card()) {
|
||||
if (_flags & F_has_card) {
|
||||
PT(PandaNode) card_root;
|
||||
if (has_card_border()) {
|
||||
if (_flags & F_has_card_border) {
|
||||
card_root = make_card_with_border();
|
||||
} else {
|
||||
card_root = make_card();
|
||||
}
|
||||
card_root->set_transform(transform);
|
||||
card_root->set_attrib(ColorAttrib::make_flat(get_card_color()));
|
||||
if (get_card_color()[3] != 1.0f) {
|
||||
card_root->set_attrib(ColorAttrib::make_flat(_card_color));
|
||||
if (_card_color[3] != 1.0f) {
|
||||
card_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
}
|
||||
if (has_card_texture()) {
|
||||
card_root->set_attrib(TextureAttrib::make(get_card_texture()));
|
||||
if (_flags & F_has_card_texture) {
|
||||
card_root->set_attrib(TextureAttrib::make(_card_texture));
|
||||
}
|
||||
|
||||
if (has_bin()) {
|
||||
@@ -432,17 +688,17 @@ generate() {
|
||||
card_root->add_child(root);
|
||||
root = card_root;
|
||||
|
||||
if (get_card_decal()) {
|
||||
if (_flags & F_card_decal) {
|
||||
card_root->set_effect(DecalEffect::make());
|
||||
}
|
||||
}
|
||||
|
||||
if (has_frame()) {
|
||||
if (_flags & F_has_frame) {
|
||||
PT(PandaNode) frame_root = make_frame();
|
||||
frame_root->set_transform(transform);
|
||||
root->add_child(frame_root, get_draw_order() + 1);
|
||||
frame_root->set_attrib(ColorAttrib::make_flat(get_frame_color()));
|
||||
if (get_frame_color()[3] != 1.0f) {
|
||||
frame_root->set_attrib(ColorAttrib::make_flat(_frame_color));
|
||||
if (_frame_color[3] != 1.0f) {
|
||||
frame_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
}
|
||||
|
||||
@@ -460,285 +716,50 @@ generate() {
|
||||
/**
|
||||
* Returns the actual node that is used internally to render the text, if the
|
||||
* TextNode is parented within the scene graph.
|
||||
*
|
||||
* In general, you should not call this method. Call generate() instead if
|
||||
* you want to get a handle to geometry that represents the text. This method
|
||||
* is provided as a debugging aid only.
|
||||
*/
|
||||
PandaNode *TextNode::
|
||||
get_internal_geom() const {
|
||||
// Output a nuisance warning to discourage the naive from calling this
|
||||
// method accidentally.
|
||||
text_cat.info()
|
||||
<< "TextNode::get_internal_geom() called.\n";
|
||||
PT(PandaNode) TextNode::
|
||||
do_get_internal_geom() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_rebuild();
|
||||
return _internal_geom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the union of all attributes from SceneGraphReducer::AttribTypes
|
||||
* that may not safely be applied to the vertices of this node. If this is
|
||||
* nonzero, these attributes must be dropped at this node as a state change.
|
||||
*
|
||||
* This is a generalization of safe_to_transform().
|
||||
*/
|
||||
int TextNode::
|
||||
get_unsafe_to_apply_attribs() const {
|
||||
// We have no way to apply these kinds of attributes to our TextNode, so
|
||||
// insist they get dropped into the PandaNode's basic state.
|
||||
return
|
||||
SceneGraphReducer::TT_tex_matrix |
|
||||
SceneGraphReducer::TT_other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies whatever attributes are specified in the AccumulatedAttribs object
|
||||
* (and by the attrib_types bitmask) to the vertices on this node, if
|
||||
* appropriate. If this node uses geom arrays like a GeomNode, the supplied
|
||||
* GeomTransformer may be used to unify shared arrays across multiple
|
||||
* different nodes.
|
||||
*
|
||||
* This is a generalization of xform().
|
||||
*/
|
||||
void TextNode::
|
||||
apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
|
||||
GeomTransformer &transformer) {
|
||||
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
|
||||
const LMatrix4 &mat = attribs._transform->get_mat();
|
||||
_transform *= mat;
|
||||
|
||||
if ((_flags & F_needs_measure) == 0) {
|
||||
// If we already have a measure, transform it too. We don't need to
|
||||
// invalidate the 2-d parts, since that's not affected by the transform
|
||||
// anyway.
|
||||
_ul3d = _ul3d * mat;
|
||||
_lr3d = _lr3d * mat;
|
||||
}
|
||||
}
|
||||
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
|
||||
if (attribs._color != nullptr) {
|
||||
const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color);
|
||||
if (ca->get_color_type() == ColorAttrib::T_flat) {
|
||||
const LColor &c = ca->get_color();
|
||||
set_text_color(c);
|
||||
set_frame_color(c);
|
||||
set_card_color(c);
|
||||
set_shadow_color(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
|
||||
if (attribs._color_scale != nullptr) {
|
||||
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale);
|
||||
const LVecBase4 &s = csa->get_scale();
|
||||
if (s != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)) {
|
||||
LVecBase4 tc = get_text_color();
|
||||
tc[0] *= s[0];
|
||||
tc[1] *= s[1];
|
||||
tc[2] *= s[2];
|
||||
tc[3] *= s[3];
|
||||
set_text_color(tc);
|
||||
LVecBase4 sc = get_shadow_color();
|
||||
sc[0] *= s[0];
|
||||
sc[1] *= s[1];
|
||||
sc[2] *= s[2];
|
||||
sc[3] *= s[3];
|
||||
set_shadow_color(sc);
|
||||
LVecBase4 fc = get_frame_color();
|
||||
fc[0] *= s[0];
|
||||
fc[1] *= s[1];
|
||||
fc[2] *= s[2];
|
||||
fc[3] *= s[3];
|
||||
set_frame_color(fc);
|
||||
LVecBase4 cc = get_card_color();
|
||||
cc[0] *= s[0];
|
||||
cc[1] *= s[1];
|
||||
cc[2] *= s[2];
|
||||
cc[3] *= s[3];
|
||||
set_card_color(cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now propagate the attributes down to our already-generated geometry, if
|
||||
// we have any.
|
||||
if ((_flags & F_needs_rebuild) == 0 &&
|
||||
_internal_geom != nullptr) {
|
||||
SceneGraphReducer gr;
|
||||
gr.apply_attribs(_internal_geom, attribs, attrib_types, transformer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to support NodePath::calc_tight_bounds(). It is not intended
|
||||
* to be called directly, and it has nothing to do with the normal Panda
|
||||
* bounding-volume computation.
|
||||
*
|
||||
* If the node contains any geometry, this updates min_point and max_point to
|
||||
* enclose its bounding box. found_any is to be set true if the node has any
|
||||
* geometry at all, or left alone if it has none. This method may be called
|
||||
* over several nodes, so it may enter with min_point, max_point, and
|
||||
* found_any already set.
|
||||
*/
|
||||
CPT(TransformState) TextNode::
|
||||
calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any,
|
||||
const TransformState *transform, Thread *current_thread) const {
|
||||
CPT(TransformState) next_transform =
|
||||
PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform,
|
||||
current_thread);
|
||||
|
||||
check_rebuild();
|
||||
|
||||
if (_internal_geom != nullptr) {
|
||||
_internal_geom->calc_tight_bounds(min_point, max_point,
|
||||
found_any, next_transform, current_thread);
|
||||
}
|
||||
|
||||
return next_transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will be called during the cull traversal to perform any
|
||||
* additional operations that should be performed at cull time. This may
|
||||
* include additional manipulation of render state or additional
|
||||
* visible/invisible decisions, or any other arbitrary operation.
|
||||
*
|
||||
* Note that this function will *not* be called unless set_cull_callback() is
|
||||
* called in the constructor of the derived class. It is necessary to call
|
||||
* set_cull_callback() to indicated that we require cull_callback() to be
|
||||
* called.
|
||||
*
|
||||
* By the time this function is called, the node has already passed the
|
||||
* bounding-volume test for the viewing frustum, and the node's transform and
|
||||
* state have already been applied to the indicated CullTraverserData object.
|
||||
*
|
||||
* The return value is true if this node should be visible, or false if it
|
||||
* should be culled.
|
||||
*/
|
||||
bool TextNode::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
check_rebuild();
|
||||
if (_internal_geom != nullptr) {
|
||||
// Render the text with this node.
|
||||
CullTraverserData next_data(data, _internal_geom);
|
||||
trav->traverse(next_data);
|
||||
}
|
||||
|
||||
// Now continue to render everything else below this node.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is some value to visiting this particular node during
|
||||
* the cull traversal for any camera, false otherwise. This will be used to
|
||||
* optimize the result of get_net_draw_show_mask(), so that any subtrees that
|
||||
* contain only nodes for which is_renderable() is false need not be visited.
|
||||
*/
|
||||
bool TextNode::
|
||||
is_renderable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when needed to recompute the node's _internal_bound object. Nodes
|
||||
* that contain anything of substance should redefine this to do the right
|
||||
* thing.
|
||||
*/
|
||||
void TextNode::
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
PT(BoundingVolume) bound = new BoundingSphere;
|
||||
|
||||
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
|
||||
|
||||
// Now enclose the bounding box around the text. We can do this without
|
||||
// actually generating the text, if we have at least measured it.
|
||||
check_measure();
|
||||
|
||||
LPoint3 vertices[8];
|
||||
vertices[0].set(_ul3d[0], _ul3d[1], _ul3d[2]);
|
||||
vertices[1].set(_ul3d[0], _ul3d[1], _lr3d[2]);
|
||||
vertices[2].set(_ul3d[0], _lr3d[1], _ul3d[2]);
|
||||
vertices[3].set(_ul3d[0], _lr3d[1], _lr3d[2]);
|
||||
vertices[4].set(_lr3d[0], _ul3d[1], _ul3d[2]);
|
||||
vertices[5].set(_lr3d[0], _ul3d[1], _lr3d[2]);
|
||||
vertices[6].set(_lr3d[0], _lr3d[1], _ul3d[2]);
|
||||
vertices[7].set(_lr3d[0], _lr3d[1], _lr3d[2]);
|
||||
|
||||
gbv->around(vertices, vertices + 8);
|
||||
|
||||
internal_bounds = bound;
|
||||
internal_vertices = 0; // TODO: estimate this better.
|
||||
}
|
||||
|
||||
/**
|
||||
* The recursive implementation of prepare_scene(). Don't call this directly;
|
||||
* call PandaNode::prepare_scene() or NodePath::prepare_scene() instead.
|
||||
*/
|
||||
void TextNode::
|
||||
r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state,
|
||||
GeomTransformer &transformer, Thread *current_thread) {
|
||||
check_rebuild();
|
||||
|
||||
PandaNode *child = _internal_geom;
|
||||
if (child != nullptr) {
|
||||
CPT(RenderState) child_state = node_state->compose(child->get_state());
|
||||
child->r_prepare_scene(gsg, child_state, transformer, current_thread);
|
||||
}
|
||||
|
||||
PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any existing children of the TextNode, and adds the newly generated
|
||||
* text instead.
|
||||
*/
|
||||
void TextNode::
|
||||
do_rebuild() {
|
||||
_flags &= ~(F_needs_rebuild | F_needs_measure);
|
||||
_internal_geom = generate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Can be called in lieu of do_rebuild() to measure the text and set up the
|
||||
* bounding boxes properly without actually assembling it.
|
||||
*/
|
||||
void TextNode::
|
||||
do_measure() {
|
||||
// We no longer make this a special case.
|
||||
do_rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a frame around the text.
|
||||
*/
|
||||
PT(PandaNode) TextNode::
|
||||
make_frame() {
|
||||
nassertr(_lock.debug_is_locked(), nullptr);
|
||||
nassertr((_flags & F_needs_measure) == 0, nullptr);
|
||||
|
||||
PT(GeomNode) frame_node = new GeomNode("frame");
|
||||
|
||||
LVector4 dimensions = get_frame_actual();
|
||||
PN_stdfloat left = dimensions[0];
|
||||
PN_stdfloat right = dimensions[1];
|
||||
PN_stdfloat bottom = dimensions[2];
|
||||
PN_stdfloat top = dimensions[3];
|
||||
PN_stdfloat left = _frame_ul[0];
|
||||
PN_stdfloat right = _frame_lr[0];
|
||||
PN_stdfloat bottom = _frame_lr[1];
|
||||
PN_stdfloat top = _frame_ul[1];
|
||||
|
||||
if (_flags & F_frame_as_margin) {
|
||||
left = _text_ul[0] - left;
|
||||
right = _text_lr[0] + right;
|
||||
bottom = _text_lr[1] - bottom;
|
||||
top = _text_ul[1] + top;
|
||||
}
|
||||
|
||||
CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _frame_width);
|
||||
CPT(RenderState) state = RenderState::make(thick);
|
||||
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
("text", GeomVertexFormat::get_v3(), get_usage_hint());
|
||||
("text", GeomVertexFormat::get_v3(), _usage_hint);
|
||||
vdata->unclean_set_num_rows(4);
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
|
||||
vertex.add_data3(left, 0.0f, top);
|
||||
vertex.add_data3(left, 0.0f, bottom);
|
||||
vertex.add_data3(right, 0.0f, bottom);
|
||||
vertex.add_data3(right, 0.0f, top);
|
||||
vertex.set_data3(left, 0.0f, top);
|
||||
vertex.set_data3(left, 0.0f, bottom);
|
||||
vertex.set_data3(right, 0.0f, bottom);
|
||||
vertex.set_data3(right, 0.0f, top);
|
||||
|
||||
PT(GeomLinestrips) frame = new GeomLinestrips(get_usage_hint());
|
||||
PT(GeomLinestrips) frame = new GeomLinestrips(_usage_hint);
|
||||
frame->add_consecutive_vertices(0, 4);
|
||||
frame->add_vertex(0);
|
||||
frame->close_primitive();
|
||||
@@ -747,8 +768,8 @@ make_frame() {
|
||||
geom->add_primitive(frame);
|
||||
frame_node->add_geom(geom, state);
|
||||
|
||||
if (get_frame_corners()) {
|
||||
PT(GeomPoints) corners = new GeomPoints(get_usage_hint());
|
||||
if (_flags & F_frame_corners) {
|
||||
PT(GeomPoints) corners = new GeomPoints(_usage_hint);
|
||||
corners->add_consecutive_vertices(0, 4);
|
||||
PT(Geom) geom2 = new Geom(vdata);
|
||||
geom2->add_primitive(corners);
|
||||
@@ -763,30 +784,40 @@ make_frame() {
|
||||
*/
|
||||
PT(PandaNode) TextNode::
|
||||
make_card() {
|
||||
nassertr(_lock.debug_is_locked(), nullptr);
|
||||
nassertr((_flags & F_needs_measure) == 0, nullptr);
|
||||
|
||||
PT(GeomNode) card_node = new GeomNode("card");
|
||||
|
||||
LVector4 dimensions = get_card_actual();
|
||||
PN_stdfloat left = dimensions[0];
|
||||
PN_stdfloat right = dimensions[1];
|
||||
PN_stdfloat bottom = dimensions[2];
|
||||
PN_stdfloat top = dimensions[3];
|
||||
PN_stdfloat left = _card_ul[0];
|
||||
PN_stdfloat right = _card_lr[0];
|
||||
PN_stdfloat bottom = _card_lr[1];
|
||||
PN_stdfloat top = _card_ul[1];
|
||||
|
||||
if (_flags & F_card_as_margin) {
|
||||
left = _text_ul[0] - left;
|
||||
right = _text_lr[0] + right;
|
||||
bottom = _text_lr[1] - bottom;
|
||||
top = _text_ul[1] + top;
|
||||
}
|
||||
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
("text", GeomVertexFormat::get_v3t2(), get_usage_hint());
|
||||
("text", GeomVertexFormat::get_v3t2(), _usage_hint);
|
||||
vdata->unclean_set_num_rows(4);
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
|
||||
vertex.add_data3(left, 0.0f, top);
|
||||
vertex.add_data3(left, 0.0f, bottom);
|
||||
vertex.add_data3(right, 0.0f, top);
|
||||
vertex.add_data3(right, 0.0f, bottom);
|
||||
vertex.set_data3(left, 0.0f, top);
|
||||
vertex.set_data3(left, 0.0f, bottom);
|
||||
vertex.set_data3(right, 0.0f, top);
|
||||
vertex.set_data3(right, 0.0f, bottom);
|
||||
|
||||
texcoord.add_data2(0.0f, 1.0f);
|
||||
texcoord.add_data2(0.0f, 0.0f);
|
||||
texcoord.add_data2(1.0f, 1.0f);
|
||||
texcoord.add_data2(1.0f, 0.0f);
|
||||
texcoord.set_data2(0.0f, 1.0f);
|
||||
texcoord.set_data2(0.0f, 0.0f);
|
||||
texcoord.set_data2(1.0f, 1.0f);
|
||||
texcoord.set_data2(1.0f, 0.0f);
|
||||
|
||||
PT(GeomTristrips) card = new GeomTristrips(get_usage_hint());
|
||||
PT(GeomTristrips) card = new GeomTristrips(_usage_hint);
|
||||
card->add_consecutive_vertices(0, 4);
|
||||
card->close_primitive();
|
||||
|
||||
@@ -805,13 +836,22 @@ make_card() {
|
||||
*/
|
||||
PT(PandaNode) TextNode::
|
||||
make_card_with_border() {
|
||||
nassertr(_lock.debug_is_locked(), nullptr);
|
||||
nassertr((_flags & F_needs_measure) == 0, nullptr);
|
||||
|
||||
PT(GeomNode) card_node = new GeomNode("card");
|
||||
|
||||
LVector4 dimensions = get_card_actual();
|
||||
PN_stdfloat left = dimensions[0];
|
||||
PN_stdfloat right = dimensions[1];
|
||||
PN_stdfloat bottom = dimensions[2];
|
||||
PN_stdfloat top = dimensions[3];
|
||||
PN_stdfloat left = _card_ul[0];
|
||||
PN_stdfloat right = _card_lr[0];
|
||||
PN_stdfloat bottom = _card_lr[1];
|
||||
PN_stdfloat top = _card_ul[1];
|
||||
|
||||
if (_flags & F_card_as_margin) {
|
||||
left = _text_ul[0] - left;
|
||||
right = _text_lr[0] + right;
|
||||
bottom = _text_lr[1] - bottom;
|
||||
top = _text_ul[1] + top;
|
||||
}
|
||||
|
||||
/*
|
||||
* we now create three tri-strips instead of one with vertices arranged as
|
||||
@@ -820,57 +860,59 @@ make_card_with_border() {
|
||||
*/
|
||||
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
("text", GeomVertexFormat::get_v3t2(), get_usage_hint());
|
||||
("text", GeomVertexFormat::get_v3t2(), _usage_hint);
|
||||
vdata->unclean_set_num_rows(16);
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
|
||||
// verts 1,2,3,4
|
||||
vertex.add_data3(left, 0.02, top);
|
||||
vertex.add_data3(left, 0.02, top - _card_border_size);
|
||||
vertex.add_data3(left + _card_border_size, 0.02, top);
|
||||
vertex.add_data3(left + _card_border_size, 0.02,
|
||||
vertex.set_data3(left, 0.02, top);
|
||||
vertex.set_data3(left, 0.02, top - _card_border_size);
|
||||
vertex.set_data3(left + _card_border_size, 0.02, top);
|
||||
vertex.set_data3(left + _card_border_size, 0.02,
|
||||
top - _card_border_size);
|
||||
// verts 5,6,7,8
|
||||
vertex.add_data3(right - _card_border_size, 0.02, top);
|
||||
vertex.add_data3(right - _card_border_size, 0.02,
|
||||
vertex.set_data3(right - _card_border_size, 0.02, top);
|
||||
vertex.set_data3(right - _card_border_size, 0.02,
|
||||
top - _card_border_size);
|
||||
vertex.add_data3(right, 0.02, top);
|
||||
vertex.add_data3(right, 0.02, top - _card_border_size);
|
||||
vertex.set_data3(right, 0.02, top);
|
||||
vertex.set_data3(right, 0.02, top - _card_border_size);
|
||||
// verts 9,10,11,12
|
||||
vertex.add_data3(left, 0.02, bottom + _card_border_size);
|
||||
vertex.add_data3(left, 0.02, bottom);
|
||||
vertex.add_data3(left + _card_border_size, 0.02,
|
||||
vertex.set_data3(left, 0.02, bottom + _card_border_size);
|
||||
vertex.set_data3(left, 0.02, bottom);
|
||||
vertex.set_data3(left + _card_border_size, 0.02,
|
||||
bottom + _card_border_size);
|
||||
vertex.add_data3(left + _card_border_size, 0.02, bottom);
|
||||
vertex.set_data3(left + _card_border_size, 0.02, bottom);
|
||||
// verts 13,14,15,16
|
||||
vertex.add_data3(right - _card_border_size, 0.02,
|
||||
vertex.set_data3(right - _card_border_size, 0.02,
|
||||
bottom + _card_border_size);
|
||||
vertex.add_data3(right - _card_border_size, 0.02, bottom);
|
||||
vertex.add_data3(right, 0.02, bottom + _card_border_size);
|
||||
vertex.add_data3(right, 0.02, bottom);
|
||||
vertex.set_data3(right - _card_border_size, 0.02, bottom);
|
||||
vertex.set_data3(right, 0.02, bottom + _card_border_size);
|
||||
vertex.set_data3(right, 0.02, bottom);
|
||||
|
||||
texcoord.add_data2(0.0f, 1.0f); //1
|
||||
texcoord.add_data2(0.0f, 1.0f - _card_border_uv_portion); //2
|
||||
texcoord.add_data2(0.0f + _card_border_uv_portion, 1.0f); //3
|
||||
texcoord.add_data2(0.0f + _card_border_uv_portion,
|
||||
texcoord.set_data2(0.0f, 1.0f); //1
|
||||
texcoord.set_data2(0.0f, 1.0f - _card_border_uv_portion); //2
|
||||
texcoord.set_data2(0.0f + _card_border_uv_portion, 1.0f); //3
|
||||
texcoord.set_data2(0.0f + _card_border_uv_portion,
|
||||
1.0f - _card_border_uv_portion); //4
|
||||
texcoord.add_data2(1.0f -_card_border_uv_portion, 1.0f); //5
|
||||
texcoord.add_data2(1.0f -_card_border_uv_portion,
|
||||
texcoord.set_data2(1.0f -_card_border_uv_portion, 1.0f); //5
|
||||
texcoord.set_data2(1.0f -_card_border_uv_portion,
|
||||
1.0f - _card_border_uv_portion); //6
|
||||
texcoord.add_data2(1.0f, 1.0f); //7
|
||||
texcoord.add_data2(1.0f, 1.0f - _card_border_uv_portion); //8
|
||||
texcoord.set_data2(1.0f, 1.0f); //7
|
||||
texcoord.set_data2(1.0f, 1.0f - _card_border_uv_portion); //8
|
||||
|
||||
texcoord.add_data2(0.0f, _card_border_uv_portion); //9
|
||||
texcoord.add_data2(0.0f, 0.0f); //10
|
||||
texcoord.add_data2(_card_border_uv_portion, _card_border_uv_portion); //11
|
||||
texcoord.add_data2(_card_border_uv_portion, 0.0f); //12
|
||||
texcoord.set_data2(0.0f, _card_border_uv_portion); //9
|
||||
texcoord.set_data2(0.0f, 0.0f); //10
|
||||
texcoord.set_data2(_card_border_uv_portion, _card_border_uv_portion); //11
|
||||
texcoord.set_data2(_card_border_uv_portion, 0.0f); //12
|
||||
|
||||
texcoord.add_data2(1.0f - _card_border_uv_portion, _card_border_uv_portion);//13
|
||||
texcoord.add_data2(1.0f - _card_border_uv_portion, 0.0f);//14
|
||||
texcoord.add_data2(1.0f, _card_border_uv_portion);//15
|
||||
texcoord.add_data2(1.0f, 0.0f);//16
|
||||
texcoord.set_data2(1.0f - _card_border_uv_portion, _card_border_uv_portion);//13
|
||||
texcoord.set_data2(1.0f - _card_border_uv_portion, 0.0f);//14
|
||||
texcoord.set_data2(1.0f, _card_border_uv_portion);//15
|
||||
texcoord.set_data2(1.0f, 0.0f);//16
|
||||
|
||||
PT(GeomTristrips) card = new GeomTristrips(get_usage_hint());
|
||||
PT(GeomTristrips) card = new GeomTristrips(_usage_hint);
|
||||
card->reserve_num_vertices(24);
|
||||
|
||||
// tristrip #1
|
||||
card->add_consecutive_vertices(0, 8);
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "pandaNode.h"
|
||||
#include "luse.h"
|
||||
#include "geom.h"
|
||||
#include "pmutex.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
/**
|
||||
* The primary interface to this module. This class does basic text assembly;
|
||||
@@ -225,11 +227,11 @@ PUBLISHED:
|
||||
|
||||
INLINE int get_num_rows() const;
|
||||
|
||||
PT(PandaNode) generate();
|
||||
INLINE PT(PandaNode) generate();
|
||||
INLINE void update();
|
||||
INLINE void force_update();
|
||||
|
||||
PandaNode *get_internal_geom() const;
|
||||
PT(PandaNode) get_internal_geom() const;
|
||||
|
||||
PUBLISHED:
|
||||
MAKE_PROPERTY(max_rows, get_max_rows, set_max_rows);
|
||||
@@ -312,12 +314,16 @@ private:
|
||||
void do_rebuild();
|
||||
void do_measure();
|
||||
|
||||
PT(PandaNode) do_generate();
|
||||
PT(PandaNode) do_get_internal_geom() const;
|
||||
|
||||
PT(PandaNode) make_frame();
|
||||
PT(PandaNode) make_card();
|
||||
PT(PandaNode) make_card_with_border();
|
||||
|
||||
static int count_geoms(PandaNode *node);
|
||||
|
||||
Mutex _lock;
|
||||
PT(PandaNode) _internal_geom;
|
||||
|
||||
PT(Texture) _card_texture;
|
||||
|
||||
@@ -34,7 +34,10 @@ class ShaderTerrainDemo(ShowBase):
|
||||
|
||||
# Set a heightfield, the heightfield should be a 16-bit png and
|
||||
# have a quadratic size of a power of two.
|
||||
self.terrain_node.heightfield = self.loader.loadTexture("heightfield.png")
|
||||
heightfield = self.loader.loadTexture("heightfield.png")
|
||||
heightfield.wrap_u = SamplerState.WM_clamp
|
||||
heightfield.wrap_v = SamplerState.WM_clamp
|
||||
self.terrain_node.heightfield = heightfield
|
||||
|
||||
# Set the target triangle width. For a value of 10.0 for example,
|
||||
# the terrain will attempt to make every triangle 10 pixels wide on screen.
|
||||
|
||||
@@ -2,7 +2,11 @@ import sys
|
||||
import pytest
|
||||
from panda3d import core
|
||||
from contextlib import contextmanager
|
||||
import collections
|
||||
|
||||
if sys.version_info >= (3, 3):
|
||||
import collections.abc as collections_abc
|
||||
else:
|
||||
import _abcoll as collections_abc
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -52,7 +56,6 @@ def test_property2():
|
||||
|
||||
|
||||
# The next tests are for MAKE_SEQ_PROPERTY.
|
||||
@pytest.fixture
|
||||
def seq_property(*items):
|
||||
""" Returns a sequence property initialized with the given items. """
|
||||
|
||||
@@ -73,11 +76,11 @@ item_c = core.CollisionSphere((0, 0, 0), 3)
|
||||
|
||||
def test_seq_property_abc():
|
||||
prop = seq_property()
|
||||
assert isinstance(prop, collections.Container)
|
||||
assert isinstance(prop, collections.Sized)
|
||||
assert isinstance(prop, collections.Iterable)
|
||||
assert isinstance(prop, collections.MutableSequence)
|
||||
assert isinstance(prop, collections.Sequence)
|
||||
assert isinstance(prop, collections_abc.Container)
|
||||
assert isinstance(prop, collections_abc.Sized)
|
||||
assert isinstance(prop, collections_abc.Iterable)
|
||||
assert isinstance(prop, collections_abc.MutableSequence)
|
||||
assert isinstance(prop, collections_abc.Sequence)
|
||||
|
||||
|
||||
def test_seq_property_empty():
|
||||
@@ -411,7 +414,6 @@ def test_seq_property_extend():
|
||||
|
||||
|
||||
# The next tests are for MAKE_MAP_PROPERTY.
|
||||
@pytest.fixture
|
||||
def map_property(**items):
|
||||
""" Returns a mapping property initialized with the given values. """
|
||||
|
||||
@@ -425,11 +427,11 @@ def map_property(**items):
|
||||
|
||||
def test_map_property_abc():
|
||||
prop = map_property()
|
||||
assert isinstance(prop, collections.Container)
|
||||
assert isinstance(prop, collections.Sized)
|
||||
assert isinstance(prop, collections.Iterable)
|
||||
assert isinstance(prop, collections.MutableMapping)
|
||||
assert isinstance(prop, collections.Mapping)
|
||||
assert isinstance(prop, collections_abc.Container)
|
||||
assert isinstance(prop, collections_abc.Sized)
|
||||
assert isinstance(prop, collections_abc.Iterable)
|
||||
assert isinstance(prop, collections_abc.MutableMapping)
|
||||
assert isinstance(prop, collections_abc.Mapping)
|
||||
|
||||
|
||||
def test_map_property_empty():
|
||||
@@ -607,19 +609,19 @@ def test_map_property_update():
|
||||
def test_map_property_keys():
|
||||
prop = map_property(key='value', key2='value2')
|
||||
|
||||
assert isinstance(prop.keys(), collections.MappingView)
|
||||
assert isinstance(prop.keys(), collections_abc.MappingView)
|
||||
assert frozenset(prop.keys()) == frozenset(('key', 'key2'))
|
||||
|
||||
|
||||
def test_map_property_values():
|
||||
prop = map_property(key='value', key2='value2')
|
||||
|
||||
assert isinstance(prop.values(), collections.ValuesView)
|
||||
assert isinstance(prop.values(), collections_abc.ValuesView)
|
||||
assert frozenset(prop.values()) == frozenset(('value', 'value2'))
|
||||
|
||||
|
||||
def test_map_property_items():
|
||||
prop = map_property(key='value', key2='value2')
|
||||
|
||||
assert isinstance(prop.items(), collections.MappingView)
|
||||
assert isinstance(prop.items(), collections_abc.MappingView)
|
||||
assert frozenset(prop.items()) == frozenset((('key', 'value'), ('key2', 'value2')))
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
from panda3d import core
|
||||
|
||||
|
||||
def test_textnode_card_as_margin():
|
||||
text = core.TextNode("test")
|
||||
text.text = "Test"
|
||||
|
||||
l, r, b, t = 0.1, 0.2, 0.3, 0.4
|
||||
text.set_card_as_margin(l, r, b, t)
|
||||
|
||||
assert text.has_card()
|
||||
assert text.is_card_as_margin()
|
||||
assert text.get_card_as_set() == (l, r, b, t)
|
||||
|
||||
card_actual = text.get_card_actual()
|
||||
card_expect = core.LVecBase4(
|
||||
text.get_left() - l,
|
||||
text.get_right() + r,
|
||||
text.get_bottom() - b,
|
||||
text.get_top() + t)
|
||||
assert card_actual == card_expect
|
||||
|
||||
|
||||
def test_textnode_card_actual():
|
||||
text = core.TextNode("test")
|
||||
text.text = "Test"
|
||||
|
||||
l, r, b, t = 0.1, 0.2, 0.3, 0.4
|
||||
text.set_card_actual(l, r, b, t)
|
||||
|
||||
assert text.has_card()
|
||||
assert not text.is_card_as_margin()
|
||||
assert text.get_card_as_set() == (l, r, b, t)
|
||||
|
||||
card_actual = text.get_card_actual()
|
||||
card_expect = core.LVecBase4(l, r, b, t)
|
||||
assert card_actual == card_expect
|
||||
|
||||
|
||||
def test_textnode_frame_as_margin():
|
||||
text = core.TextNode("test")
|
||||
text.text = "Test"
|
||||
|
||||
l, r, b, t = 0.1, 0.2, 0.3, 0.4
|
||||
text.set_frame_as_margin(l, r, b, t)
|
||||
|
||||
assert text.has_frame()
|
||||
assert text.is_frame_as_margin()
|
||||
assert text.get_frame_as_set() == (l, r, b, t)
|
||||
|
||||
frame_actual = text.get_frame_actual()
|
||||
frame_expect = core.LVecBase4(
|
||||
text.get_left() - l,
|
||||
text.get_right() + r,
|
||||
text.get_bottom() - b,
|
||||
text.get_top() + t)
|
||||
assert frame_actual == frame_expect
|
||||
|
||||
|
||||
def test_textnode_frame_actual():
|
||||
text = core.TextNode("test")
|
||||
text.text = "Test"
|
||||
|
||||
l, r, b, t = 0.1, 0.2, 0.3, 0.4
|
||||
text.set_frame_actual(l, r, b, t)
|
||||
|
||||
assert text.has_frame()
|
||||
assert not text.is_frame_as_margin()
|
||||
assert text.get_frame_as_set() == (l, r, b, t)
|
||||
|
||||
frame_actual = text.get_frame_actual()
|
||||
frame_expect = core.LVecBase4(l, r, b, t)
|
||||
assert frame_actual == frame_expect
|
||||
|
||||
|
||||
def test_textnode_flatten_color():
|
||||
text = core.TextNode("test")
|
||||
text.text_color = (0, 0, 0, 1)
|
||||
path = core.NodePath(text)
|
||||
|
||||
color = core.LColor(1, 0, 0, 1)
|
||||
path.set_color(color)
|
||||
path.flatten_strong()
|
||||
|
||||
assert text.text_color.almost_equal(color)
|
||||
assert text.shadow_color.almost_equal(color)
|
||||
assert text.frame_color.almost_equal(color)
|
||||
assert text.card_color.almost_equal(color)
|
||||
|
||||
|
||||
def test_textnode_flatten_colorscale():
|
||||
text = core.TextNode("test")
|
||||
text.text_color = (1, 0, 0, 0)
|
||||
text.shadow_color = (0, 1, 0, 0)
|
||||
text.frame_color = (0, 0, 1, 0)
|
||||
text.card_color = (0, 0, 0, 1)
|
||||
path = core.NodePath(text)
|
||||
|
||||
color = core.LColor(.5, .5, .5, .5)
|
||||
path.set_color_scale(color)
|
||||
path.flatten_strong()
|
||||
|
||||
assert text.text_color.almost_equal((.5, 0, 0, 0))
|
||||
assert text.shadow_color.almost_equal((0, .5, 0, 0))
|
||||
assert text.frame_color.almost_equal((0, 0, .5, 0))
|
||||
assert text.card_color.almost_equal((0, 0, 0, .5))
|
||||
Reference in New Issue
Block a user