Merge branch 'master' into deploy-ng
This commit is contained in:
commit
c28045990c
44
README.md
44
README.md
|
|
@ -43,8 +43,9 @@ Building Panda3D
|
|||
Windows
|
||||
-------
|
||||
|
||||
We currently build using the Microsoft Visual C++ 2015 compiler. You will
|
||||
also need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk),
|
||||
You can build Panda3D with the Microsoft Visual C++ 2015 or 2017 compiler,
|
||||
which can be downloaded for free from the [Visual Studio site](https://visualstudio.microsoft.com/downloads/).
|
||||
You will also need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk),
|
||||
and if you intend to target Windows XP, you will also need the
|
||||
[Windows 7.1 SDK](https://www.microsoft.com/en-us/download/details.aspx?id=8279).
|
||||
|
||||
|
|
@ -58,11 +59,12 @@ http://rdb.name/thirdparty-vc14-x64.7z
|
|||
http://rdb.name/thirdparty-vc14.7z
|
||||
|
||||
After acquiring these dependencies, you may simply build Panda3D from the
|
||||
command prompt using the following command. (Add the `--windows-sdk=10`
|
||||
option if you don't need to support Windows XP.)
|
||||
command prompt using the following command. (Change `14.1` to `14` if you are
|
||||
using Visual C++ 2015 instead of 2017. Add the `--windows-sdk=10` option if
|
||||
you don't need to support Windows XP and did not install the Windows 7.1 SDK.)
|
||||
|
||||
```bash
|
||||
makepanda\makepanda.bat --everything --installer --no-eigen --threads=2
|
||||
makepanda\makepanda.bat --everything --installer --msvc-version=14.1 --no-eigen --threads=2
|
||||
```
|
||||
|
||||
When the build succeeds, it will produce an .exe file that you can use to
|
||||
|
|
@ -101,7 +103,7 @@ If you are on Ubuntu, this command should cover the most frequently
|
|||
used third-party packages:
|
||||
|
||||
```bash
|
||||
sudo apt-get install build-essential pkg-config python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev
|
||||
sudo apt-get install build-essential pkg-config python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev libassimp-dev libopenexr-dev
|
||||
```
|
||||
|
||||
Once Panda3D has built, you can either install the .deb or .rpm package that
|
||||
|
|
@ -163,6 +165,36 @@ python3.6 makepanda/makepanda.py --everything --installer --no-egl --no-gles --n
|
|||
If successful, this will produce a .pkg file in the root of the source
|
||||
directory which you can install using `pkg install`.
|
||||
|
||||
Android
|
||||
-------
|
||||
|
||||
Note: building on Android is very experimental and not guaranteed to work.
|
||||
|
||||
You can experimentally build the Android Python runner via the [termux](https://termux.com/)
|
||||
shell. You will need to install [Termux](https://play.google.com/store/apps/details?id=com.termux)
|
||||
and [Termux API](https://play.google.com/store/apps/details?id=com.termux.api)
|
||||
from the Play Store. Many of the dependencies can be installed by running the
|
||||
following command in the Termux shell:
|
||||
|
||||
```bash
|
||||
pkg install python-dev termux-tools ndk-stl ndk-sysroot clang libvorbis-dev libopus-dev opusfile-dev openal-soft-dev freetype-dev harfbuzz-dev libpng-dev ecj4.6 dx patchelf aapt apksigner libcrypt-dev
|
||||
```
|
||||
|
||||
Then, you can build and install the .apk right away using these commands:
|
||||
|
||||
```bash
|
||||
python makepanda/makepanda.py --everything --target android-21 --installer
|
||||
xdg-open panda3d.apk
|
||||
```
|
||||
|
||||
To launch a Python program from Termux, you can use the `run_python.sh` script
|
||||
inside the `panda/src/android` directory. It will launch Python in a separate
|
||||
activity, load it with the Python script you passed as argument, and use a
|
||||
socket for returning the command-line output to the Termux shell. Do note
|
||||
that this requires the Python application to reside on the SD card and that
|
||||
Termux needs to be set up with access to the SD card (using the
|
||||
`termux-setup-storage` command).
|
||||
|
||||
Running Tests
|
||||
=============
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
#include "filename_ext.cxx"
|
||||
#include "globPattern_ext.cxx"
|
||||
#include "textEncoder_ext.cxx"
|
||||
|
|
|
|||
|
|
@ -53,5 +53,5 @@ StringUtf8Decoder(const std::string &input) : StringDecoder(input) {
|
|||
*
|
||||
*/
|
||||
INLINE StringUnicodeDecoder::
|
||||
StringUnicodeDecoder(const std::string &input) : StringDecoder(input) {
|
||||
StringUtf16Decoder(const std::string &input) : StringDecoder(input) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ StringDecoder::
|
|||
/**
|
||||
* Returns the next character in sequence.
|
||||
*/
|
||||
int StringDecoder::
|
||||
char32_t StringDecoder::
|
||||
get_next_character() {
|
||||
if (test_eof()) {
|
||||
return -1;
|
||||
|
|
@ -57,19 +57,20 @@ get_notify_ptr() {
|
|||
|
||||
/*
|
||||
In UTF-8, each 16-bit Unicode character is encoded as a sequence of
|
||||
one, two, or three 8-bit bytes, depending on the value of the
|
||||
one, two, three or four 8-bit bytes, depending on the value of the
|
||||
character. The following table shows the format of such UTF-8 byte
|
||||
sequences (where the "free bits" shown by x's in the table are
|
||||
combined in the order shown, and interpreted from most significant to
|
||||
least significant):
|
||||
|
||||
Binary format of bytes in sequence:
|
||||
Number of Maximum expressible
|
||||
1st byte 2nd byte 3rd byte free bits: Unicode value:
|
||||
Number of Maximum expressible
|
||||
1st byte 2nd byte 3rd byte 4th byte free bits: Unicode value:
|
||||
|
||||
0xxxxxxx 7 007F hex (127)
|
||||
110xxxxx 10xxxxxx (5+6)=11 07FF hex (2047)
|
||||
1110xxxx 10xxxxxx 10xxxxxx (4+6+6)=16 FFFF hex (65535)
|
||||
0xxxxxxx 7 007F hex (127)
|
||||
110xxxxx 10xxxxxx (5+6)=11 07FF hex (2047)
|
||||
1110xxxx 10xxxxxx 10xxxxxx (4+6+6)=16 FFFF hex (65535)
|
||||
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (4+6*3)=21 10FFFF hex (1114111)
|
||||
|
||||
The value of each individual byte indicates its UTF-8 function, as follows:
|
||||
|
||||
|
|
@ -77,12 +78,13 @@ The value of each individual byte indicates its UTF-8 function, as follows:
|
|||
80 to BF hex (128 to 191): continuing byte in a multi-byte sequence.
|
||||
C2 to DF hex (194 to 223): first byte of a two-byte sequence.
|
||||
E0 to EF hex (224 to 239): first byte of a three-byte sequence.
|
||||
F0 to F7 hex (240 to 247): first byte of a four-byte sequence.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the next character in sequence.
|
||||
*/
|
||||
int StringUtf8Decoder::
|
||||
char32_t StringUtf8Decoder::
|
||||
get_next_character() {
|
||||
unsigned int result;
|
||||
while (!test_eof()) {
|
||||
|
|
@ -125,6 +127,35 @@ get_next_character() {
|
|||
unsigned int three = (unsigned char)_input[_p++];
|
||||
result = ((result & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f);
|
||||
return result;
|
||||
|
||||
} else if ((result & 0xf8) == 0xf0) {
|
||||
// First byte of four.
|
||||
if (test_eof()) {
|
||||
if (_notify_ptr != nullptr) {
|
||||
(*_notify_ptr)
|
||||
<< "utf-8 encoded string '" << _input << "' ends abruptly.\n";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
unsigned int two = (unsigned char)_input[_p++];
|
||||
if (test_eof()) {
|
||||
if (_notify_ptr != nullptr) {
|
||||
(*_notify_ptr)
|
||||
<< "utf-8 encoded string '" << _input << "' ends abruptly.\n";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
unsigned int three = (unsigned char)_input[_p++];
|
||||
if (test_eof()) {
|
||||
if (_notify_ptr != nullptr) {
|
||||
(*_notify_ptr)
|
||||
<< "utf-8 encoded string '" << _input << "' ends abruptly.\n";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
unsigned int four = (unsigned char)_input[_p++];
|
||||
result = ((result & 0x07) << 18) | ((two & 0x3f) << 12) | ((three & 0x3f) << 6) | (four & 0x3f);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Otherwise--the high bit is set but it is not one of the introductory
|
||||
|
|
@ -144,7 +175,7 @@ get_next_character() {
|
|||
/**
|
||||
* Returns the next character in sequence.
|
||||
*/
|
||||
int StringUnicodeDecoder::
|
||||
char32_t StringUtf16Decoder::
|
||||
get_next_character() {
|
||||
if (test_eof()) {
|
||||
return -1;
|
||||
|
|
@ -159,5 +190,33 @@ get_next_character() {
|
|||
return -1;
|
||||
}
|
||||
unsigned int low = (unsigned char)_input[_p++];
|
||||
return ((high << 8) | low);
|
||||
int ch = ((high << 8) | low);
|
||||
|
||||
/*
|
||||
using std::swap;
|
||||
|
||||
if (ch == 0xfffe) {
|
||||
// This is a byte-swapped byte-order-marker. That means we need to swap
|
||||
// the endianness of the rest of the stream.
|
||||
char *data = (char *)_input.data();
|
||||
for (size_t p = _p; p < _input.size() - 1; p += 2) {
|
||||
std::swap(data[p], data[p + 1]);
|
||||
}
|
||||
ch = 0xfeff;
|
||||
}
|
||||
*/
|
||||
|
||||
if (ch >= 0xd800 && ch < 0xdc00 && (_p + 1) < _input.size()) {
|
||||
// This is a high surrogate. Look for a subsequent low surrogate.
|
||||
unsigned int high = (unsigned char)_input[_p];
|
||||
unsigned int low = (unsigned char)_input[_p + 1];
|
||||
int ch2 = ((high << 8) | low);
|
||||
if (ch2 >= 0xdc00 && ch2 < 0xe000) {
|
||||
// Yes, this is a low surrogate.
|
||||
_p += 2;
|
||||
return 0x10000 + ((ch - 0xd800) << 10) + (ch2 - 0xdc00);
|
||||
}
|
||||
}
|
||||
// No, this is just a regular character, or an unpaired surrogate.
|
||||
return ch;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public:
|
|||
INLINE StringDecoder(const std::string &input);
|
||||
virtual ~StringDecoder();
|
||||
|
||||
virtual int get_next_character();
|
||||
virtual char32_t get_next_character();
|
||||
INLINE bool is_eof();
|
||||
|
||||
static void set_notify_ptr(std::ostream *ptr);
|
||||
|
|
@ -48,20 +48,23 @@ class StringUtf8Decoder : public StringDecoder {
|
|||
public:
|
||||
INLINE StringUtf8Decoder(const std::string &input);
|
||||
|
||||
virtual int get_next_character();
|
||||
virtual char32_t get_next_character();
|
||||
};
|
||||
|
||||
/**
|
||||
* This decoder extracts characters two at a time to get a plain wide
|
||||
* character sequence.
|
||||
* character sequence. It supports surrogate pairs.
|
||||
*/
|
||||
class StringUnicodeDecoder : public StringDecoder {
|
||||
class StringUtf16Decoder : public StringDecoder {
|
||||
public:
|
||||
INLINE StringUnicodeDecoder(const std::string &input);
|
||||
INLINE StringUtf16Decoder(const std::string &input);
|
||||
|
||||
virtual int get_next_character();
|
||||
virtual char32_t get_next_character();
|
||||
};
|
||||
|
||||
// Deprecated alias of StringUtf16Encoder.
|
||||
typedef StringUtf16Decoder StringUnicodeDecoder;
|
||||
|
||||
#include "stringDecoder.I"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ set_text(const std::string &text) {
|
|||
if (!has_text() || _text != text) {
|
||||
_text = text;
|
||||
_flags = (_flags | F_got_text) & ~F_got_wtext;
|
||||
text_changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +102,11 @@ set_text(const std::string &text) {
|
|||
*/
|
||||
INLINE void TextEncoder::
|
||||
set_text(const std::string &text, TextEncoder::Encoding encoding) {
|
||||
set_wtext(decode_text(text, encoding));
|
||||
if (encoding == _encoding) {
|
||||
set_text(text);
|
||||
} else {
|
||||
set_wtext(decode_text(text, encoding));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -112,6 +117,7 @@ clear_text() {
|
|||
_text = std::string();
|
||||
_wtext = std::wstring();
|
||||
_flags |= (F_got_text | F_got_wtext);
|
||||
text_changed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,8 +157,11 @@ get_text(TextEncoder::Encoding encoding) const {
|
|||
*/
|
||||
INLINE void TextEncoder::
|
||||
append_text(const std::string &text) {
|
||||
_text = get_text() + text;
|
||||
_flags = (_flags | F_got_text) & ~F_got_wtext;
|
||||
if (!text.empty()) {
|
||||
_text = get_text() + text;
|
||||
_flags = (_flags | F_got_text) & ~F_got_wtext;
|
||||
text_changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -160,9 +169,25 @@ append_text(const std::string &text) {
|
|||
* wide character, up to 16 bits in Unicode.
|
||||
*/
|
||||
INLINE void TextEncoder::
|
||||
append_unicode_char(int character) {
|
||||
append_unicode_char(char32_t character) {
|
||||
#if WCHAR_MAX >= 0x10FFFF
|
||||
// wchar_t might be UTF-32.
|
||||
_wtext = get_wtext() + std::wstring(1, (wchar_t)character);
|
||||
#else
|
||||
if ((character & ~0xffff) == 0) {
|
||||
_wtext = get_wtext() + std::wstring(1, (wchar_t)character);
|
||||
} else {
|
||||
// Encode as a surrogate pair.
|
||||
uint32_t v = (uint32_t)character - 0x10000u;
|
||||
wchar_t wstr[2] = {
|
||||
(wchar_t)((v >> 10u) | 0xd800u),
|
||||
(wchar_t)((v & 0x3ffu) | 0xdc00u),
|
||||
};
|
||||
_wtext = get_wtext() + std::wstring(wstr, 2);
|
||||
}
|
||||
#endif
|
||||
_flags = (_flags | F_got_wtext) & ~F_got_text;
|
||||
text_changed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -200,6 +225,7 @@ set_unicode_char(size_t index, int character) {
|
|||
if (index < _wtext.length()) {
|
||||
_wtext[index] = character;
|
||||
_flags &= ~F_got_text;
|
||||
text_changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,6 +444,7 @@ set_wtext(const std::wstring &wtext) {
|
|||
if (!has_text() || _wtext != wtext) {
|
||||
_wtext = wtext;
|
||||
_flags = (_flags | F_got_wtext) & ~F_got_text;
|
||||
text_changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,8 +466,11 @@ get_wtext() const {
|
|||
*/
|
||||
INLINE void TextEncoder::
|
||||
append_wtext(const std::wstring &wtext) {
|
||||
_wtext = get_wtext() + wtext;
|
||||
_flags = (_flags | F_got_wtext) & ~F_got_text;
|
||||
if (!wtext.empty()) {
|
||||
_wtext = get_wtext() + wtext;
|
||||
_flags = (_flags | F_got_wtext) & ~F_got_text;
|
||||
text_changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ using std::ostream;
|
|||
using std::string;
|
||||
using std::wstring;
|
||||
|
||||
TextEncoder::Encoding TextEncoder::_default_encoding = TextEncoder::E_iso8859;
|
||||
TextEncoder::Encoding TextEncoder::_default_encoding = TextEncoder::E_utf8;
|
||||
|
||||
/**
|
||||
* Adjusts the text stored within the encoder to all uppercase letters
|
||||
|
|
@ -35,6 +35,7 @@ make_upper() {
|
|||
(*si) = unicode_toupper(*si);
|
||||
}
|
||||
_flags &= ~F_got_text;
|
||||
text_changed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -49,6 +50,7 @@ make_lower() {
|
|||
(*si) = unicode_tolower(*si);
|
||||
}
|
||||
_flags &= ~F_got_text;
|
||||
text_changed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -107,11 +109,11 @@ is_wtext() const {
|
|||
}
|
||||
|
||||
/**
|
||||
* Encodes a single wide char into a one-, two-, or three-byte string,
|
||||
* according to the given encoding system.
|
||||
* Encodes a single Unicode character into a one-, two-, three-, or four-byte
|
||||
* string, according to the given encoding system.
|
||||
*/
|
||||
string TextEncoder::
|
||||
encode_wchar(wchar_t ch, TextEncoder::Encoding encoding) {
|
||||
encode_wchar(char32_t ch, TextEncoder::Encoding encoding) {
|
||||
switch (encoding) {
|
||||
case E_iso8859:
|
||||
if ((ch & ~0xff) == 0) {
|
||||
|
|
@ -143,17 +145,38 @@ encode_wchar(wchar_t ch, TextEncoder::Encoding encoding) {
|
|||
return
|
||||
string(1, (char)((ch >> 6) | 0xc0)) +
|
||||
string(1, (char)((ch & 0x3f) | 0x80));
|
||||
} else {
|
||||
} else if ((ch & ~0xffff) == 0) {
|
||||
return
|
||||
string(1, (char)((ch >> 12) | 0xe0)) +
|
||||
string(1, (char)(((ch >> 6) & 0x3f) | 0x80)) +
|
||||
string(1, (char)((ch & 0x3f) | 0x80));
|
||||
} else {
|
||||
return
|
||||
string(1, (char)((ch >> 18) | 0xf0)) +
|
||||
string(1, (char)(((ch >> 12) & 0x3f) | 0x80)) +
|
||||
string(1, (char)(((ch >> 6) & 0x3f) | 0x80)) +
|
||||
string(1, (char)((ch & 0x3f) | 0x80));
|
||||
}
|
||||
|
||||
case E_unicode:
|
||||
return
|
||||
string(1, (char)(ch >> 8)) +
|
||||
string(1, (char)(ch & 0xff));
|
||||
case E_utf16be:
|
||||
if ((ch & ~0xffff) == 0) {
|
||||
// Note that this passes through surrogates and BOMs unharmed.
|
||||
return
|
||||
string(1, (char)(ch >> 8)) +
|
||||
string(1, (char)(ch & 0xff));
|
||||
} else {
|
||||
// Use a surrogate pair.
|
||||
uint32_t v = (uint32_t)ch - 0x10000u;
|
||||
uint16_t hi = (v >> 10u) | 0xd800u;
|
||||
uint16_t lo = (v & 0x3ffu) | 0xdc00u;
|
||||
char encoded[4] = {
|
||||
(char)(hi >> 8),
|
||||
(char)(hi & 0xff),
|
||||
(char)(lo >> 8),
|
||||
(char)(lo & 0xff),
|
||||
};
|
||||
return string(encoded, 4);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
|
|
@ -167,8 +190,25 @@ string TextEncoder::
|
|||
encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) {
|
||||
string result;
|
||||
|
||||
for (wstring::const_iterator pi = wtext.begin(); pi != wtext.end(); ++pi) {
|
||||
result += encode_wchar(*pi, encoding);
|
||||
for (size_t i = 0; i < wtext.size(); ++i) {
|
||||
wchar_t ch = wtext[i];
|
||||
|
||||
// On some systems, wstring may be UTF-16, and contain surrogate pairs.
|
||||
#if WCHAR_MAX < 0x10FFFF
|
||||
if (ch >= 0xd800 && ch < 0xdc00 && (i + 1) < wtext.size()) {
|
||||
// This is a high surrogate. Look for a subsequent low surrogate.
|
||||
wchar_t ch2 = wtext[i + 1];
|
||||
if (ch2 >= 0xdc00 && ch2 < 0xe000) {
|
||||
// Yes, this is a low surrogate.
|
||||
char32_t code_point = 0x10000 + ((ch - 0xd800) << 10) + (ch2 - 0xdc00);
|
||||
result += encode_wchar(code_point, encoding);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
result += encode_wchar(ch, encoding);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -187,9 +227,9 @@ decode_text(const string &text, TextEncoder::Encoding encoding) {
|
|||
return decode_text_impl(decoder);
|
||||
}
|
||||
|
||||
case E_unicode:
|
||||
case E_utf16be:
|
||||
{
|
||||
StringUnicodeDecoder decoder(text);
|
||||
StringUtf16Decoder decoder(text);
|
||||
return decode_text_impl(decoder);
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +251,7 @@ decode_text_impl(StringDecoder &decoder) {
|
|||
wstring result;
|
||||
// bool expand_amp = get_expand_amp();
|
||||
|
||||
wchar_t character = decoder.get_next_character();
|
||||
char32_t character = decoder.get_next_character();
|
||||
while (!decoder.is_eof()) {
|
||||
/*
|
||||
if (character == '&' && expand_amp) {
|
||||
|
|
@ -219,7 +259,14 @@ decode_text_impl(StringDecoder &decoder) {
|
|||
character = expand_amp_sequence(decoder);
|
||||
}
|
||||
*/
|
||||
result += character;
|
||||
if (character <= WCHAR_MAX) {
|
||||
result += character;
|
||||
} else {
|
||||
// We need to encode this as a surrogate pair.
|
||||
uint32_t v = (uint32_t)character - 0x10000u;
|
||||
result += (wchar_t)((v >> 10u) | 0xd800u);
|
||||
result += (wchar_t)((v & 0x3ffu) | 0xdc00u);
|
||||
}
|
||||
character = decoder.get_next_character();
|
||||
}
|
||||
|
||||
|
|
@ -314,6 +361,12 @@ expand_amp_sequence(StringDecoder &decoder) const {
|
|||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Called whenever the text has been changed.
|
||||
*/
|
||||
void TextEncoder::
|
||||
text_changed() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -327,8 +380,8 @@ operator << (ostream &out, TextEncoder::Encoding encoding) {
|
|||
case TextEncoder::E_utf8:
|
||||
return out << "utf8";
|
||||
|
||||
case TextEncoder::E_unicode:
|
||||
return out << "unicode";
|
||||
case TextEncoder::E_utf16be:
|
||||
return out << "utf16be";
|
||||
};
|
||||
|
||||
return out << "**invalid TextEncoder::Encoding(" << (int)encoding << ")**";
|
||||
|
|
@ -346,8 +399,9 @@ operator >> (istream &in, TextEncoder::Encoding &encoding) {
|
|||
encoding = TextEncoder::E_iso8859;
|
||||
} else if (word == "utf8" || word == "utf-8") {
|
||||
encoding = TextEncoder::E_utf8;
|
||||
} else if (word == "unicode") {
|
||||
encoding = TextEncoder::E_unicode;
|
||||
} else if (word == "unicode" || word == "utf16be" || word == "utf-16be" ||
|
||||
word == "utf16-be" || word == "utf-16-be") {
|
||||
encoding = TextEncoder::E_utf16be;
|
||||
} else {
|
||||
ostream *notify_ptr = StringDecoder::get_notify_ptr();
|
||||
if (notify_ptr != nullptr) {
|
||||
|
|
|
|||
|
|
@ -35,12 +35,17 @@ PUBLISHED:
|
|||
enum Encoding {
|
||||
E_iso8859,
|
||||
E_utf8,
|
||||
E_unicode
|
||||
E_utf16be,
|
||||
|
||||
// Deprecated alias for E_utf16be
|
||||
E_unicode = E_utf16be,
|
||||
};
|
||||
|
||||
INLINE TextEncoder();
|
||||
INLINE TextEncoder(const TextEncoder ©);
|
||||
|
||||
virtual ~TextEncoder() = default;
|
||||
|
||||
INLINE void set_encoding(Encoding encoding);
|
||||
INLINE Encoding get_encoding() const;
|
||||
|
||||
|
|
@ -48,18 +53,29 @@ PUBLISHED:
|
|||
INLINE static Encoding get_default_encoding();
|
||||
MAKE_PROPERTY(default_encoding, get_default_encoding, set_default_encoding);
|
||||
|
||||
#ifdef CPPPARSER
|
||||
EXTEND void set_text(PyObject *text);
|
||||
EXTEND void set_text(PyObject *text, Encoding encoding);
|
||||
#else
|
||||
INLINE void set_text(const std::string &text);
|
||||
INLINE void set_text(const std::string &text, Encoding encoding);
|
||||
#endif
|
||||
INLINE void clear_text();
|
||||
INLINE bool has_text() const;
|
||||
|
||||
void make_upper();
|
||||
void make_lower();
|
||||
|
||||
#ifdef CPPPARSER
|
||||
EXTEND PyObject *get_text() const;
|
||||
EXTEND PyObject *get_text(Encoding encoding) const;
|
||||
EXTEND void append_text(PyObject *text);
|
||||
#else
|
||||
INLINE std::string get_text() const;
|
||||
INLINE std::string get_text(Encoding encoding) const;
|
||||
INLINE void append_text(const std::string &text);
|
||||
INLINE void append_unicode_char(int character);
|
||||
#endif
|
||||
INLINE void append_unicode_char(char32_t character);
|
||||
INLINE size_t get_num_chars() const;
|
||||
INLINE int get_unicode_char(size_t index) const;
|
||||
INLINE void set_unicode_char(size_t index, int character);
|
||||
|
|
@ -91,11 +107,24 @@ PUBLISHED:
|
|||
std::wstring get_wtext_as_ascii() const;
|
||||
bool is_wtext() const;
|
||||
|
||||
static std::string encode_wchar(wchar_t ch, Encoding encoding);
|
||||
#ifdef CPPPARSER
|
||||
EXTEND static PyObject *encode_wchar(char32_t ch, Encoding encoding);
|
||||
EXTEND INLINE PyObject *encode_wtext(const std::wstring &wtext) const;
|
||||
EXTEND static PyObject *encode_wtext(const std::wstring &wtext, Encoding encoding);
|
||||
EXTEND INLINE PyObject *decode_text(PyObject *text) const;
|
||||
EXTEND static PyObject *decode_text(PyObject *text, Encoding encoding);
|
||||
#else
|
||||
static std::string encode_wchar(char32_t ch, Encoding encoding);
|
||||
INLINE std::string encode_wtext(const std::wstring &wtext) const;
|
||||
static std::string encode_wtext(const std::wstring &wtext, Encoding encoding);
|
||||
INLINE std::wstring decode_text(const std::string &text) const;
|
||||
static std::wstring decode_text(const std::string &text, Encoding encoding);
|
||||
#endif
|
||||
|
||||
MAKE_PROPERTY(text, get_text, set_text);
|
||||
|
||||
protected:
|
||||
virtual void text_changed();
|
||||
|
||||
private:
|
||||
enum Flags {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file textEncoder_ext.I
|
||||
* @author rdb
|
||||
* @date 2018-10-08
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encodes a wide-text string into a single-char string, according to the
|
||||
* current encoding.
|
||||
*/
|
||||
INLINE PyObject *Extension<TextEncoder>::
|
||||
encode_wtext(const std::wstring &wtext) const {
|
||||
return encode_wtext(wtext, _this->get_encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given wstring decoded to a single-byte string, via the current
|
||||
* encoding system.
|
||||
*/
|
||||
INLINE PyObject *Extension<TextEncoder>::
|
||||
decode_text(PyObject *text) const {
|
||||
return decode_text(text, _this->get_encoding());
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file textEncoder_ext.cxx
|
||||
* @author rdb
|
||||
* @date 2018-09-29
|
||||
*/
|
||||
|
||||
#include "textEncoder_ext.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
/**
|
||||
* Sets the text as a Unicode string. In Python 2, if a regular str is given,
|
||||
* it is assumed to be in the TextEncoder's specified encoding.
|
||||
*/
|
||||
void Extension<TextEncoder>::
|
||||
set_text(PyObject *text) {
|
||||
if (PyUnicode_Check(text)) {
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
Py_ssize_t len;
|
||||
const char *str = PyUnicode_AsUTF8AndSize(text, &len);
|
||||
_this->set_text(std::string(str, len), TextEncoder::E_utf8);
|
||||
#else
|
||||
Py_ssize_t len = PyUnicode_GET_SIZE(text);
|
||||
wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1));
|
||||
PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len);
|
||||
_this->set_wtext(std::wstring(str, len));
|
||||
#endif
|
||||
} else {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
Dtool_Raise_TypeError("expected string");
|
||||
#else
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) {
|
||||
_this->set_text(std::string(str, len));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text as an encoded byte string of the given encoding.
|
||||
*/
|
||||
void Extension<TextEncoder>::
|
||||
set_text(PyObject *text, TextEncoder::Encoding encoding) {
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) {
|
||||
_this->set_text(std::string(str, len), encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text as a string. In Python 2, the returned string is in the
|
||||
* TextEncoder's specified encoding. In Python 3, it is returned as unicode.
|
||||
*/
|
||||
PyObject *Extension<TextEncoder>::
|
||||
get_text() const {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
std::wstring text = _this->get_wtext();
|
||||
return PyUnicode_FromWideChar(text.data(), (Py_ssize_t)text.size());
|
||||
#else
|
||||
std::string text = _this->get_text();
|
||||
return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text as a bytes object in the given encoding.
|
||||
*/
|
||||
PyObject *Extension<TextEncoder>::
|
||||
get_text(TextEncoder::Encoding encoding) const {
|
||||
std::string text = _this->get_text(encoding);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size());
|
||||
#else
|
||||
return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text as a string (or Unicode object in Python 2).
|
||||
*/
|
||||
void Extension<TextEncoder>::
|
||||
append_text(PyObject *text) {
|
||||
if (PyUnicode_Check(text)) {
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
Py_ssize_t len;
|
||||
const char *str = PyUnicode_AsUTF8AndSize(text, &len);
|
||||
std::string text_str(str, len);
|
||||
if (_this->get_encoding() == TextEncoder::E_utf8) {
|
||||
_this->append_text(text_str);
|
||||
} else {
|
||||
_this->append_wtext(TextEncoder::decode_text(text_str, TextEncoder::E_utf8));
|
||||
}
|
||||
#else
|
||||
Py_ssize_t len = PyUnicode_GET_SIZE(text);
|
||||
wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1));
|
||||
PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len);
|
||||
_this->append_wtext(std::wstring(str, len));
|
||||
#endif
|
||||
} else {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
Dtool_Raise_TypeError("expected string");
|
||||
#else
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) {
|
||||
_this->append_text(std::string(str, len));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given wide character as byte string in the given encoding.
|
||||
*/
|
||||
PyObject *Extension<TextEncoder>::
|
||||
encode_wchar(char32_t ch, TextEncoder::Encoding encoding) {
|
||||
std::string value = TextEncoder::encode_wchar(ch, encoding);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
||||
#else
|
||||
return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a wide-text string into a single-char string, according to the
|
||||
* given encoding.
|
||||
*/
|
||||
PyObject *Extension<TextEncoder>::
|
||||
encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) {
|
||||
std::string value = TextEncoder::encode_wtext(wtext, encoding);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
||||
#else
|
||||
return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given wstring decoded to a single-byte string, via the given
|
||||
* encoding system.
|
||||
*/
|
||||
PyObject *Extension<TextEncoder>::
|
||||
decode_text(PyObject *text, TextEncoder::Encoding encoding) {
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) {
|
||||
return Dtool_WrapValue(TextEncoder::decode_text(std::string(str, len), encoding));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file textEncoder_ext.h
|
||||
* @author rdb
|
||||
* @date 2018-09-29
|
||||
*/
|
||||
|
||||
#ifndef TEXTENCODER_EXT_H
|
||||
#define TEXTENCODER_EXT_H
|
||||
|
||||
#include "dtoolbase.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "extension.h"
|
||||
#include "textEncoder.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
/**
|
||||
* This class defines the extension methods for TextEncoder, which are called
|
||||
* instead of any C++ methods with the same prototype.
|
||||
*/
|
||||
template<>
|
||||
class Extension<TextEncoder> : public ExtensionBase<TextEncoder> {
|
||||
public:
|
||||
void set_text(PyObject *text);
|
||||
void set_text(PyObject *text, TextEncoder::Encoding encoding);
|
||||
|
||||
PyObject *get_text() const;
|
||||
PyObject *get_text(TextEncoder::Encoding encoding) const;
|
||||
void append_text(PyObject *text);
|
||||
|
||||
static PyObject *encode_wchar(char32_t ch, TextEncoder::Encoding encoding);
|
||||
INLINE PyObject *encode_wtext(const std::wstring &wtext) const;
|
||||
static PyObject *encode_wtext(const std::wstring &wtext, TextEncoder::Encoding encoding);
|
||||
INLINE PyObject *decode_text(PyObject *text) const;
|
||||
static PyObject *decode_text(PyObject *text, TextEncoder::Encoding encoding);
|
||||
};
|
||||
|
||||
#include "textEncoder_ext.I"
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif // TEXTENCODER_EXT_H
|
||||
|
|
@ -2943,7 +2943,7 @@ define_method(CPPInstance *function, InterrogateType &itype,
|
|||
// specifically flag get_class_type() as published.
|
||||
bool force_publish = false;
|
||||
if (function->get_simple_name() == "get_class_type" &&
|
||||
(function->_storage_class && CPPInstance::SC_static) != 0 &&
|
||||
(function->_storage_class & CPPInstance::SC_static) != 0 &&
|
||||
function->_vis <= V_public) {
|
||||
force_publish = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,8 +235,8 @@ PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute) {
|
|||
"'%.100s' object has no attribute '%.200s'",
|
||||
Py_TYPE(obj)->tp_name, attribute);
|
||||
|
||||
Py_INCREF(PyExc_TypeError);
|
||||
PyErr_Restore(PyExc_TypeError, message, nullptr);
|
||||
Py_INCREF(PyExc_AttributeError);
|
||||
PyErr_Restore(PyExc_AttributeError, message, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@
|
|||
|
||||
load-file-type egg pandaegg
|
||||
|
||||
# If we built with Assimp support, we can enable the Assimp loader,
|
||||
# which allows us to load many model formats natively.
|
||||
|
||||
load-file-type p3assimp
|
||||
|
||||
# These entries work very similar to load-file-type, except they are
|
||||
# used by the MovieVideo and MovieAudio code to determine which module
|
||||
# should be loaded in order to decode files of the given extension.
|
||||
|
|
|
|||
|
|
@ -1010,8 +1010,6 @@ if (COMPILER=="GCC"):
|
|||
|
||||
if GetTarget() == 'darwin':
|
||||
LibName("ALWAYS", "-framework AppKit")
|
||||
if (PkgSkip("OPENCV")==0):
|
||||
LibName("OPENCV", "-framework QuickTime")
|
||||
LibName("AGL", "-framework AGL")
|
||||
LibName("CARBON", "-framework Carbon")
|
||||
LibName("COCOA", "-framework Cocoa")
|
||||
|
|
@ -1398,9 +1396,10 @@ def CompileCxx(obj,src,opts):
|
|||
# Work around Apple compiler bug.
|
||||
cmd += " -U__EXCEPTIONS"
|
||||
|
||||
if 'RTTI' not in opts:
|
||||
target = GetTarget()
|
||||
if 'RTTI' not in opts and target != "darwin":
|
||||
# We always disable RTTI on Android for memory usage reasons.
|
||||
if optlevel >= 4 or GetTarget() == "android":
|
||||
if optlevel >= 4 or target == "android":
|
||||
cmd += " -fno-rtti"
|
||||
|
||||
if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm") and arch != 'aarch64':
|
||||
|
|
@ -2979,6 +2978,9 @@ else:
|
|||
# otherwise, disable it.
|
||||
confautoprc = confautoprc.replace('#st#', '#')
|
||||
|
||||
if PkgSkip("ASSIMP"):
|
||||
confautoprc = confautoprc.replace("load-file-type p3assimp", "#load-file-type p3assimp")
|
||||
|
||||
if (os.path.isfile("makepanda/myconfig.in")):
|
||||
configprc = ReadFile("makepanda/myconfig.in")
|
||||
else:
|
||||
|
|
@ -3645,6 +3647,7 @@ IGATEFILES += [
|
|||
"dSearchPath.h",
|
||||
"executionEnvironment.h",
|
||||
"textEncoder.h",
|
||||
"textEncoder_ext.h",
|
||||
"filename.h",
|
||||
"filename_ext.h",
|
||||
"globPattern.h",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#import "cocoaPandaApp.h"
|
||||
#include "config_cocoadisplay.h"
|
||||
|
||||
@implementation CocoaPandaApp
|
||||
- (void) sendEvent: (NSEvent *) event {
|
||||
|
|
|
|||
|
|
@ -593,8 +593,7 @@ remove_all_windows() {
|
|||
Windows old_windows;
|
||||
old_windows.swap(_windows);
|
||||
Windows::iterator wi;
|
||||
for (wi = old_windows.begin(); wi != old_windows.end(); ++wi) {
|
||||
GraphicsOutput *win = (*wi);
|
||||
for (GraphicsOutput *win : old_windows) {
|
||||
nassertv(win != nullptr);
|
||||
do_remove_window(win, current_thread);
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
|
|
@ -605,6 +604,14 @@ remove_all_windows() {
|
|||
|
||||
{
|
||||
MutexHolder new_windows_holder(_new_windows_lock, current_thread);
|
||||
for (GraphicsOutput *win : _new_windows) {
|
||||
nassertv(win != nullptr);
|
||||
do_remove_window(win, current_thread);
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
if (gsg != nullptr) {
|
||||
gsg->release_all();
|
||||
}
|
||||
}
|
||||
_new_windows.clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2722,7 +2722,7 @@ do_issue_color_scale() {
|
|||
}
|
||||
|
||||
if (_alpha_scale_via_texture && !_has_scene_graph_color &&
|
||||
target_color_scale->has_alpha_scale()) {
|
||||
_vertex_colors_enabled && target_color_scale->has_alpha_scale()) {
|
||||
// This color scale will set a special texture--so again, clear the
|
||||
// texture.
|
||||
_state_mask.clear_bit(TextureAttrib::get_class_slot());
|
||||
|
|
@ -3168,6 +3168,17 @@ determine_light_color_scale() {
|
|||
_scene_graph_color[3] * _current_color_scale[3]);
|
||||
}
|
||||
|
||||
} else if (!_vertex_colors_enabled) {
|
||||
// We don't have a scene graph color, but we don't want to enable vertex
|
||||
// colors either, so we still need to force a white material color in
|
||||
// absence of any other color.
|
||||
_has_material_force_color = true;
|
||||
_material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
_light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
if (!_color_blend_involves_color_scale && _color_scale_enabled) {
|
||||
_material_force_color.componentwise_mult(_current_color_scale);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Otherise, leave the materials alone, but we might still scale the
|
||||
// lights.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class GraphicsWindow;
|
|||
class EXPCL_PANDA_DISPLAY GraphicsWindowProc {
|
||||
public:
|
||||
GraphicsWindowProc();
|
||||
virtual ~GraphicsWindowProc() = default;
|
||||
#if defined(__WIN32__) || defined(_WIN32)
|
||||
virtual LONG wnd_proc(GraphicsWindow* graphicsWindow, HWND hwnd,
|
||||
UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
|
|
|
|||
|
|
@ -12,10 +12,14 @@
|
|||
*/
|
||||
|
||||
#include "standardMunger.h"
|
||||
#include "renderState.h"
|
||||
#include "graphicsStateGuardian.h"
|
||||
|
||||
#include "config_gobj.h"
|
||||
|
||||
#include "displayRegion.h"
|
||||
#include "graphicsStateGuardian.h"
|
||||
#include "lightAttrib.h"
|
||||
#include "materialAttrib.h"
|
||||
#include "renderState.h"
|
||||
|
||||
TypeHandle StandardMunger::_type_handle;
|
||||
|
||||
|
|
@ -36,7 +40,8 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
|
|||
_munge_color(false),
|
||||
_munge_color_scale(false),
|
||||
_auto_shader(false),
|
||||
_shader_skinning(false)
|
||||
_shader_skinning(false),
|
||||
_remove_material(false)
|
||||
{
|
||||
const ShaderAttrib *shader_attrib;
|
||||
state->get_attrib_def(shader_attrib);
|
||||
|
|
@ -54,24 +59,10 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
|
|||
const ColorScaleAttrib *color_scale_attrib;
|
||||
|
||||
if (state->get_attrib(color_attrib) &&
|
||||
color_attrib->get_color_type() == ColorAttrib::T_flat) {
|
||||
color_attrib->get_color_type() != ColorAttrib::T_vertex) {
|
||||
|
||||
if (!get_gsg()->get_color_scale_via_lighting()) {
|
||||
// We only need to munge the color directly if the GSG says it can't
|
||||
// cheat the color via lighting (presumably, in this case, by applying
|
||||
// a material).
|
||||
_color = color_attrib->get_color();
|
||||
if (state->get_attrib(color_scale_attrib) &&
|
||||
color_scale_attrib->has_scale()) {
|
||||
const LVecBase4 &cs = color_scale_attrib->get_scale();
|
||||
_color.set(_color[0] * cs[0],
|
||||
_color[1] * cs[1],
|
||||
_color[2] * cs[2],
|
||||
_color[3] * cs[3]);
|
||||
}
|
||||
_munge_color = true;
|
||||
_should_munge_state = true;
|
||||
}
|
||||
// In this case, we don't need to munge anything as we can apply the
|
||||
// color and color scale via glColor4f.
|
||||
|
||||
} else if (state->get_attrib(color_scale_attrib) &&
|
||||
color_scale_attrib->has_scale()) {
|
||||
|
|
@ -94,6 +85,19 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
|
|||
// effort to detect this contrived situation and handle it correctly.
|
||||
}
|
||||
}
|
||||
|
||||
// If we have no lights but do have a material, we will need to remove it so
|
||||
// that it won't appear when we enable color scale via lighting.
|
||||
const LightAttrib *light_attrib;
|
||||
const MaterialAttrib *material_attrib;
|
||||
if (get_gsg()->get_color_scale_via_lighting() &&
|
||||
(!state->get_attrib(light_attrib) || !light_attrib->has_any_on_light()) &&
|
||||
state->get_attrib(material_attrib) &&
|
||||
material_attrib->get_material() != nullptr &&
|
||||
shader_attrib->get_shader() == nullptr) {
|
||||
_remove_material = true;
|
||||
_should_munge_state = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -291,6 +295,9 @@ compare_to_impl(const GeomMunger *other) const {
|
|||
if (_auto_shader != om->_auto_shader) {
|
||||
return (int)_auto_shader - (int)om->_auto_shader;
|
||||
}
|
||||
if (_remove_material != om->_remove_material) {
|
||||
return (int)_remove_material - (int)om->_remove_material;
|
||||
}
|
||||
|
||||
return StateMunger::compare_to_impl(other);
|
||||
}
|
||||
|
|
@ -344,5 +351,9 @@ munge_state_impl(const RenderState *state) {
|
|||
munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
|
||||
}
|
||||
|
||||
if (_remove_material) {
|
||||
munged_state = munged_state->remove_attrib(MaterialAttrib::get_class_slot());
|
||||
}
|
||||
|
||||
return munged_state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,11 +51,13 @@ private:
|
|||
NumericType _numeric_type;
|
||||
Contents _contents;
|
||||
|
||||
bool _munge_color;
|
||||
bool _munge_color_scale;
|
||||
bool _auto_shader;
|
||||
bool _shader_skinning;
|
||||
bool _remove_material;
|
||||
|
||||
protected:
|
||||
bool _munge_color;
|
||||
bool _munge_color_scale;
|
||||
LColor _color;
|
||||
LVecBase4 _color_scale;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
#include "graphicsEngine.h"
|
||||
#include "config_display.h"
|
||||
#include "nativeWindowHandle.h"
|
||||
#include "mouseButton.h"
|
||||
#include "throw_event.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,34 +10,3 @@
|
|||
* @author drose
|
||||
* @date 2005-03-11
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE DXGeomMunger9::
|
||||
DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) :
|
||||
StandardMunger(gsg, state, 1, NT_packed_dabc, C_color),
|
||||
_texture(nullptr),
|
||||
_tex_gen(nullptr)
|
||||
{
|
||||
const TextureAttrib *texture = nullptr;
|
||||
const TexGenAttrib *tex_gen = nullptr;
|
||||
state->get_attrib(texture);
|
||||
state->get_attrib(tex_gen);
|
||||
_texture = texture;
|
||||
_tex_gen = tex_gen;
|
||||
|
||||
_filtered_texture = nullptr;
|
||||
_reffed_filtered_texture = false;
|
||||
if (texture != nullptr) {
|
||||
_filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages());
|
||||
if (_filtered_texture != texture) {
|
||||
_filtered_texture->ref();
|
||||
_reffed_filtered_texture = true;
|
||||
}
|
||||
}
|
||||
// Set a callback to unregister ourselves when either the Texture or the
|
||||
// TexGen object gets deleted.
|
||||
_texture.add_callback(this);
|
||||
_tex_gen.add_callback(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,66 @@
|
|||
GeomMunger *DXGeomMunger9::_deleted_chain = nullptr;
|
||||
TypeHandle DXGeomMunger9::_type_handle;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DXGeomMunger9::
|
||||
DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) :
|
||||
StandardMunger(gsg, state, 1, NT_packed_dabc, C_color),
|
||||
_texture(nullptr),
|
||||
_tex_gen(nullptr)
|
||||
{
|
||||
const TextureAttrib *texture = nullptr;
|
||||
const TexGenAttrib *tex_gen = nullptr;
|
||||
state->get_attrib(texture);
|
||||
state->get_attrib(tex_gen);
|
||||
_texture = texture;
|
||||
_tex_gen = tex_gen;
|
||||
|
||||
if (!gsg->get_color_scale_via_lighting()) {
|
||||
// We might need to munge the colors, if we are overriding the vertex
|
||||
// colors and the GSG can't cheat the color via lighting.
|
||||
|
||||
const ColorAttrib *color_attrib;
|
||||
const ShaderAttrib *shader_attrib;
|
||||
state->get_attrib_def(shader_attrib);
|
||||
|
||||
if (!shader_attrib->auto_shader() &&
|
||||
shader_attrib->get_shader() == nullptr &&
|
||||
state->get_attrib(color_attrib) &&
|
||||
color_attrib->get_color_type() != ColorAttrib::T_vertex) {
|
||||
|
||||
if (color_attrib->get_color_type() == ColorAttrib::T_off) {
|
||||
_color.set(1, 1, 1, 1);
|
||||
} else {
|
||||
_color = color_attrib->get_color();
|
||||
}
|
||||
|
||||
const ColorScaleAttrib *color_scale_attrib;
|
||||
if (state->get_attrib(color_scale_attrib) &&
|
||||
color_scale_attrib->has_scale()) {
|
||||
_color.componentwise_mult(color_scale_attrib->get_scale());
|
||||
}
|
||||
_munge_color = true;
|
||||
_should_munge_state = true;
|
||||
}
|
||||
}
|
||||
|
||||
_filtered_texture = nullptr;
|
||||
_reffed_filtered_texture = false;
|
||||
if (texture != nullptr) {
|
||||
_filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages());
|
||||
if (_filtered_texture != texture) {
|
||||
_filtered_texture->ref();
|
||||
_reffed_filtered_texture = true;
|
||||
}
|
||||
}
|
||||
// Set a callback to unregister ourselves when either the Texture or the
|
||||
// TexGen object gets deleted.
|
||||
_texture.add_callback(this);
|
||||
_tex_gen.add_callback(this);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
*/
|
||||
class EXPCL_PANDADX DXGeomMunger9 : public StandardMunger, public WeakPointerCallback {
|
||||
public:
|
||||
INLINE DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state);
|
||||
DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state);
|
||||
virtual ~DXGeomMunger9();
|
||||
ALLOC_DELETED_CHAIN(DXGeomMunger9);
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ DXGraphicsStateGuardian9(GraphicsEngine *engine, GraphicsPipe *pipe) :
|
|||
|
||||
_last_fvf = 0;
|
||||
_num_bound_streams = 0;
|
||||
_white_vbuffer = nullptr;
|
||||
|
||||
_vertex_shader_version_major = 0;
|
||||
_vertex_shader_version_minor = 0;
|
||||
|
|
@ -798,9 +799,9 @@ clear(DrawableRegion *clearable) {
|
|||
main_flags |= D3DCLEAR_TARGET;
|
||||
}
|
||||
|
||||
if (clearable->get_clear_depth_active()) {
|
||||
if (clearable->get_clear_depth_active() &&
|
||||
_screen->_presentation_params.EnableAutoDepthStencil) {
|
||||
aux_flags |= D3DCLEAR_ZBUFFER;
|
||||
nassertv(_screen->_presentation_params.EnableAutoDepthStencil);
|
||||
}
|
||||
|
||||
if (clearable->get_clear_stencil_active()) {
|
||||
|
|
@ -4545,6 +4546,11 @@ reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params,
|
|||
release_all_vertex_buffers();
|
||||
release_all_index_buffers();
|
||||
|
||||
if (_white_vbuffer != nullptr) {
|
||||
_white_vbuffer->Release();
|
||||
_white_vbuffer = nullptr;
|
||||
}
|
||||
|
||||
// must be called before reset
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
_prepared_objects->begin_frame(this, current_thread);
|
||||
|
|
@ -5404,6 +5410,40 @@ set_cg_device(LPDIRECT3DDEVICE9 cg_device) {
|
|||
#endif // HAVE_CG
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a vertex buffer containing only a full-white color.
|
||||
*/
|
||||
LPDIRECT3DVERTEXBUFFER9 DXGraphicsStateGuardian9::
|
||||
get_white_vbuffer() {
|
||||
if (_white_vbuffer != nullptr) {
|
||||
return _white_vbuffer;
|
||||
}
|
||||
|
||||
LPDIRECT3DVERTEXBUFFER9 vbuffer;
|
||||
HRESULT hr;
|
||||
hr = _screen->_d3d_device->CreateVertexBuffer(sizeof(D3DCOLOR), D3DUSAGE_WRITEONLY, D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &vbuffer, nullptr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dxgsg9_cat.error()
|
||||
<< "CreateVertexBuffer failed" << D3DERRORSTRING(hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3DCOLOR *local_pointer;
|
||||
hr = vbuffer->Lock(0, sizeof(D3DCOLOR), (void **) &local_pointer, D3DLOCK_DISCARD);
|
||||
if (FAILED(hr)) {
|
||||
dxgsg9_cat.error()
|
||||
<< "VertexBuffer::Lock failed" << D3DERRORSTRING(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
*local_pointer = D3DCOLOR_ARGB(255, 255, 255, 255);
|
||||
|
||||
vbuffer->Unlock();
|
||||
_white_vbuffer = vbuffer;
|
||||
return vbuffer;
|
||||
}
|
||||
|
||||
typedef std::string KEY;
|
||||
|
||||
typedef struct _KEY_ELEMENT
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ public:
|
|||
static void set_cg_device(LPDIRECT3DDEVICE9 cg_device);
|
||||
virtual bool get_supports_cg_profile(const std::string &name) const;
|
||||
|
||||
LPDIRECT3DVERTEXBUFFER9 get_white_vbuffer();
|
||||
|
||||
protected:
|
||||
void do_issue_transform();
|
||||
|
|
@ -274,12 +275,6 @@ protected:
|
|||
|
||||
RenderBuffer::Type _cur_read_pixel_buffer; // source for copy_pixel_buffer operation
|
||||
|
||||
PN_stdfloat _material_ambient;
|
||||
PN_stdfloat _material_diffuse;
|
||||
PN_stdfloat _material_specular;
|
||||
PN_stdfloat _material_shininess;
|
||||
PN_stdfloat _material_emission;
|
||||
|
||||
enum DxgsgFogType {
|
||||
None,
|
||||
PerVertexFog=D3DRS_FOGVERTEXMODE,
|
||||
|
|
@ -320,6 +315,7 @@ protected:
|
|||
|
||||
DWORD _last_fvf;
|
||||
int _num_bound_streams;
|
||||
LPDIRECT3DVERTEXBUFFER9 _white_vbuffer;
|
||||
|
||||
// Cache the data necessary to bind each particular light each frame, so if
|
||||
// we bind a given light multiple times, we only have to compute its data
|
||||
|
|
|
|||
|
|
@ -390,6 +390,8 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) {
|
|||
// arrays ("streams"), and we repeatedly iterate the parameters to pull
|
||||
// out only those for a single stream.
|
||||
|
||||
bool apply_white_color = false;
|
||||
|
||||
int number_of_arrays = gsg->_data_reader->get_num_arrays();
|
||||
for (int array_index = 0; array_index < number_of_arrays; ++array_index) {
|
||||
const GeomVertexArrayDataHandle* array_reader =
|
||||
|
|
@ -423,6 +425,11 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) {
|
|||
}
|
||||
}
|
||||
|
||||
if (name == InternalName::get_color() && !gsg->_vertex_colors_enabled) {
|
||||
apply_white_color = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const GeomVertexArrayDataHandle *param_array_reader;
|
||||
Geom::NumericType numeric_type;
|
||||
int num_values, start, stride;
|
||||
|
|
@ -435,6 +442,9 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) {
|
|||
// shader parameter, which can cause Bad Things to happen so I'd
|
||||
// like to at least get a hint as to what's gone wrong.
|
||||
dxgsg9_cat.info() << "Geometry contains no data for shader parameter " << *name << "\n";
|
||||
if (name == InternalName::get_color()) {
|
||||
apply_white_color = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -564,6 +574,19 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) {
|
|||
|
||||
_num_bound_streams = number_of_arrays;
|
||||
|
||||
if (apply_white_color) {
|
||||
// The shader needs a vertex color, but vertex colors are disabled.
|
||||
// Bind a vertex buffer containing only one white colour.
|
||||
int array_index = number_of_arrays;
|
||||
LPDIRECT3DVERTEXBUFFER9 vbuffer = gsg->get_white_vbuffer();
|
||||
hr = device->SetStreamSource(array_index, vbuffer, 0, 0);
|
||||
if (FAILED(hr)) {
|
||||
dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr);
|
||||
}
|
||||
vertex_element_array->add_diffuse_color_vertex_element(array_index, 0);
|
||||
++_num_bound_streams;
|
||||
}
|
||||
|
||||
if (_vertex_element_array != nullptr &&
|
||||
_vertex_element_array->add_end_vertex_element()) {
|
||||
if (dxgsg9_cat.is_debug()) {
|
||||
|
|
|
|||
|
|
@ -1229,7 +1229,10 @@ init_resized_window() {
|
|||
DWORD flags;
|
||||
D3DCOLOR clear_color;
|
||||
|
||||
flags = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER;
|
||||
flags = D3DCLEAR_TARGET;
|
||||
if (_fb_properties.get_depth_bits() > 0) {
|
||||
flags |= D3DCLEAR_ZBUFFER;
|
||||
}
|
||||
clear_color = 0x00000000;
|
||||
hr = _wcontext._d3d_device-> Clear (0, nullptr, flags, clear_color, 0.0f, 0);
|
||||
if (FAILED(hr)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,27 @@ PUBLISHED:
|
|||
|
||||
virtual void output(std::ostream &out) const;
|
||||
|
||||
PUBLISHED:
|
||||
MAKE_PROPERTY(state, get_state);
|
||||
MAKE_PROPERTY(alive, is_alive);
|
||||
MAKE_PROPERTY(manager, get_manager);
|
||||
|
||||
// The name of this task.
|
||||
MAKE_PROPERTY(name, get_name, set_name);
|
||||
|
||||
// This is a number guaranteed to be unique for each different AsyncTask
|
||||
// object in the universe.
|
||||
MAKE_PROPERTY(id, get_task_id);
|
||||
|
||||
MAKE_PROPERTY(task_chain, get_task_chain, set_task_chain);
|
||||
MAKE_PROPERTY(sort, get_sort, set_sort);
|
||||
MAKE_PROPERTY(priority, get_priority, set_priority);
|
||||
MAKE_PROPERTY(done_event, get_done_event, set_done_event);
|
||||
|
||||
MAKE_PROPERTY(dt, get_dt);
|
||||
MAKE_PROPERTY(max_dt, get_max_dt);
|
||||
MAKE_PROPERTY(average_dt, get_average_dt);
|
||||
|
||||
protected:
|
||||
void jump_to_task_chain(AsyncTaskManager *manager);
|
||||
DoneStatus unlock_and_do_task();
|
||||
|
|
|
|||
|
|
@ -61,9 +61,6 @@ PUBLISHED:
|
|||
int __clear__();
|
||||
|
||||
PUBLISHED:
|
||||
// The name of this task.
|
||||
MAKE_PROPERTY(name, get_name, set_name);
|
||||
|
||||
// The amount of seconds that have elapsed since the task was started,
|
||||
// according to the task manager's clock.
|
||||
MAKE_PROPERTY(time, get_elapsed_time);
|
||||
|
|
@ -88,10 +85,6 @@ PUBLISHED:
|
|||
// according to the task manager's clock.
|
||||
MAKE_PROPERTY(frame, get_elapsed_frames);
|
||||
|
||||
// This is a number guaranteed to be unique for each different AsyncTask
|
||||
// object in the universe.
|
||||
MAKE_PROPERTY(id, get_task_id);
|
||||
|
||||
// This is a special variable to hold the instance dictionary in which
|
||||
// custom variables may be stored.
|
||||
PyObject *__dict__;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ INLINE void set_matrix_view(Py_buffer &view, int flags, int length, int size, bo
|
|||
} else if (size == 4 && double_prec) {
|
||||
mat_size = sizeof(UnalignedLMatrix4d);
|
||||
} else {
|
||||
assert(false);
|
||||
nassertv_always(false);
|
||||
return; // Make sure compiler knows control flow doesn't proceed.
|
||||
}
|
||||
|
||||
view.len = length * mat_size;
|
||||
|
|
|
|||
|
|
@ -97,11 +97,11 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
|||
|
||||
#ifdef _MSC_VER
|
||||
// Ugh... MSVC needs this because they still don't have a decent linker.
|
||||
#include "PTA_uchar.h"
|
||||
#include "PTA_ushort.h"
|
||||
#include "PTA_float.h"
|
||||
#include "PTA_double.h"
|
||||
#include "PTA_int.h"
|
||||
#include "pta_uchar.h"
|
||||
#include "pta_ushort.h"
|
||||
#include "pta_float.h"
|
||||
#include "pta_double.h"
|
||||
#include "pta_int.h"
|
||||
|
||||
template class EXPORT_THIS Extension<PTA_uchar>;
|
||||
template class EXPORT_THIS Extension<PTA_ushort>;
|
||||
|
|
|
|||
|
|
@ -226,12 +226,14 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
|
|||
if (!resource) {
|
||||
resource = "unknown";
|
||||
}
|
||||
GLCAT.error()
|
||||
<< "Could not find Cg varying " << cgGetParameterName(p);
|
||||
if (attribname) {
|
||||
GLCAT.error(false) << " : " << attribname;
|
||||
if (GLCAT.is_debug()) {
|
||||
GLCAT.debug()
|
||||
<< "Could not find Cg varying " << cgGetParameterName(p);
|
||||
if (attribname) {
|
||||
GLCAT.debug(false) << " : " << attribname;
|
||||
}
|
||||
GLCAT.debug(false) << " (" << resource << ") in the compiled GLSL program.\n";
|
||||
}
|
||||
GLCAT.error(false) << " (" << resource << ") in the compiled GLSL program.\n";
|
||||
|
||||
} else if (loc != 0 && bind._id._name == "vtx_position") {
|
||||
// We really have to bind the vertex position to attribute 0, since
|
||||
|
|
@ -312,10 +314,10 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
|
|||
GLCAT.debug(false)
|
||||
<< " is bound to a conventional attribute (" << resource << ")\n";
|
||||
}
|
||||
}
|
||||
if (loc == CA_unknown) {
|
||||
// Suggest fix to developer.
|
||||
GLCAT.error() << "Try using a different semantic.\n";
|
||||
if (loc == CA_unknown) {
|
||||
// Suggest fix to developer.
|
||||
GLCAT.debug() << "Try using a different semantic.\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -283,6 +283,13 @@ begin_frame(FrameMode mode, Thread *current_thread) {
|
|||
rebuild_bitplanes();
|
||||
}
|
||||
|
||||
// The host window may not have had sRGB enabled, so we need to do this.
|
||||
#ifndef OPENGLES
|
||||
if (get_fb_properties().get_srgb_color()) {
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
#endif
|
||||
|
||||
_gsg->set_current_properties(&get_fb_properties());
|
||||
report_my_gl_errors();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -4392,7 +4392,8 @@ update_standard_vertex_arrays(bool force) {
|
|||
GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
} else
|
||||
#endif // NDEBUG
|
||||
if (_data_reader->get_color_info(array_reader, num_values, numeric_type,
|
||||
if (_vertex_colors_enabled &&
|
||||
_data_reader->get_color_info(array_reader, num_values, numeric_type,
|
||||
start, stride)) {
|
||||
if (!setup_array_data(client_pointer, array_reader, force)) {
|
||||
return false;
|
||||
|
|
@ -4409,7 +4410,13 @@ update_standard_vertex_arrays(bool force) {
|
|||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// Since we don't have per-vertex color, the implicit color is white.
|
||||
GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
if (_color_scale_via_lighting) {
|
||||
GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
} else {
|
||||
LColor color = _scene_graph_color;
|
||||
color.componentwise_mult(_current_color_scale);
|
||||
GLPf(Color4)(color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now set up each of the active texture coordinate stages--or at least
|
||||
|
|
|
|||
|
|
@ -2440,9 +2440,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
|
|||
if (p == _color_attrib_index) {
|
||||
// Vertex colors are disabled or not present. Apply flat color.
|
||||
#ifdef STDFLOAT_DOUBLE
|
||||
_glgsg->_glVertexAttrib4dv(p, color_attrib->get_color().get_data());
|
||||
_glgsg->_glVertexAttrib4dv(p, _glgsg->_scene_graph_color.get_data());
|
||||
#else
|
||||
_glgsg->_glVertexAttrib4fv(p, color_attrib->get_color().get_data());
|
||||
_glgsg->_glVertexAttrib4fv(p, _glgsg->_scene_graph_color.get_data());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ operator = (const TextureStage &other) {
|
|||
_combine_rgb_operand2 = other._combine_rgb_operand2;
|
||||
_combine_alpha_mode = other._combine_alpha_mode;
|
||||
_combine_alpha_source0 = other._combine_alpha_source0;
|
||||
_combine_alpha_operand0 = _combine_alpha_operand0;
|
||||
_combine_alpha_operand0 = other._combine_alpha_operand0;
|
||||
_combine_alpha_source1 = other._combine_alpha_source1;
|
||||
_combine_alpha_operand1 = other._combine_alpha_operand1;
|
||||
_combine_alpha_source2 = other._combine_alpha_source2;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -69,14 +69,12 @@ PUBLISHED:
|
|||
};
|
||||
|
||||
private:
|
||||
enum {
|
||||
// Period parameters
|
||||
N = 624,
|
||||
M = 397,
|
||||
MATRIX_A = 0x9908b0dfUL, // constant vector a
|
||||
UPPER_MASK = 0x80000000UL, // most significant w-r bits
|
||||
LOWER_MASK = 0x7fffffffUL, // least significant r bits
|
||||
};
|
||||
// Period parameters
|
||||
static const unsigned long N = 624;
|
||||
static const unsigned long M = 397;
|
||||
static const unsigned long MATRIX_A = 0x9908b0dfUL; // constant vector a
|
||||
static const unsigned long UPPER_MASK = 0x80000000UL; // most significant w-r bits
|
||||
static const unsigned long LOWER_MASK = 0x7fffffffUL; // least significant r bits
|
||||
|
||||
unsigned long mt[N]; // the array for the state vector
|
||||
unsigned int mti; // mti==N+1 means mt[N] is not initialized
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@
|
|||
*/
|
||||
|
||||
#include "movieTypeRegistry.h"
|
||||
|
||||
#include "string_utils.h"
|
||||
#include "config_movies.h"
|
||||
#include "config_putil.h"
|
||||
#include "load_dso.h"
|
||||
#include "reMutexHolder.h"
|
||||
|
||||
using std::endl;
|
||||
using std::string;
|
||||
|
|
@ -29,6 +31,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 +45,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 +58,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 +75,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 +97,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 +154,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 +168,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 +181,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 +198,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 +220,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 +275,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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ private:
|
|||
CGGammaValue _gOriginalRedTable[ 256 ];
|
||||
CGGammaValue _gOriginalGreenTable[ 256 ];
|
||||
CGGammaValue _gOriginalBlueTable[ 256 ];
|
||||
CGTableCount _sampleCount;
|
||||
uint32_t _sampleCount;
|
||||
CGDisplayErr _cgErr;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ write(std::ostream &out, int indent) const {
|
|||
out.width(indent+2); out<<""; out<<"_lifespan "<<_lifespan<<"\n";
|
||||
out.width(indent+2); out<<""; out<<"_alive "<<_alive<<"\n";
|
||||
out.width(indent+2); out<<""; out<<"_index "<<_index<<"\n";
|
||||
out.width(indent+2); out<<""; out<<"_last_position "<<_last_position<<"\n";
|
||||
PhysicsObject::write(out, indent+2);
|
||||
#endif //] NDEBUG
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ private:
|
|||
PN_stdfloat _lifespan;
|
||||
bool _alive;
|
||||
int _index;
|
||||
|
||||
LPoint3 _last_position;
|
||||
};
|
||||
|
||||
#include "baseParticle.I"
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ make_off() {
|
|||
*/
|
||||
CPT(RenderAttrib) ColorAttrib::
|
||||
make_default() {
|
||||
return make_off();
|
||||
return make_vertex();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public:
|
|||
register_type(_type_handle, "ColorAttrib",
|
||||
RenderAttrib::get_class_type());
|
||||
_attrib_slot = register_slot(_type_handle, 100,
|
||||
new ColorAttrib(T_off, LColor(1, 1, 1, 1)));
|
||||
new ColorAttrib(T_vertex, LColor::zero()));
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -200,7 +200,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
|
||||
|
|
|
|||
|
|
@ -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,60 +1005,11 @@ set_glyph_shift(PN_stdfloat glyph_shift) {
|
|||
*/
|
||||
INLINE void TextNode::
|
||||
clear_glyph_shift() {
|
||||
MutexHolder holder(_lock);
|
||||
TextProperties::clear_glyph_shift();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the text that is displayed under the TextNode.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_text(const std::string &text) {
|
||||
TextEncoder::set_text(text);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* The two-parameter version of set_text() accepts an explicit encoding; the
|
||||
* text is immediately decoded and stored as a wide-character string.
|
||||
* Subsequent calls to get_text() will return the same text re-encoded using
|
||||
* whichever encoding is specified by set_encoding().
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_text(const std::string &text, TextNode::Encoding encoding) {
|
||||
TextEncoder::set_text(text, encoding);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the text from the TextNode.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_text() {
|
||||
TextEncoder::clear_text();
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the indicates string to the end of the stored text.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
append_text(const std::string &text) {
|
||||
TextEncoder::append_text(text);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a single character to the end of the stored text. This may be a
|
||||
* wide character, up to 16 bits in Unicode.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
append_unicode_char(wchar_t character) {
|
||||
TextEncoder::append_unicode_char(character);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string that represents the contents of the text, as it has been
|
||||
* formatted by wordwrap rules.
|
||||
|
|
@ -1001,26 +1031,6 @@ calc_width(const std::string &line) const {
|
|||
return calc_width(decode_text(line));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the text that is displayed under the TextNode, with a wide text.
|
||||
* This automatically sets the string reported by get_text() to the 8-bit
|
||||
* encoded version of the same string.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_wtext(const std::wstring &wtext) {
|
||||
TextEncoder::set_wtext(wtext);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the indicates string to the end of the stored wide-character text.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
append_wtext(const std::wstring &wtext) {
|
||||
TextEncoder::append_wtext(wtext);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a wstring that represents the contents of the text, as it has been
|
||||
* formatted by wordwrap rules.
|
||||
|
|
@ -1030,6 +1040,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 +1051,7 @@ get_wordwrapped_wtext() const {
|
|||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_left() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_ul[0];
|
||||
}
|
||||
|
|
@ -1050,6 +1062,7 @@ get_left() const {
|
|||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_right() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_lr[0];
|
||||
}
|
||||
|
|
@ -1060,6 +1073,7 @@ get_right() const {
|
|||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_bottom() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_lr[1];
|
||||
}
|
||||
|
|
@ -1070,6 +1084,7 @@ get_bottom() const {
|
|||
*/
|
||||
INLINE PN_stdfloat TextNode::
|
||||
get_top() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _text_ul[1];
|
||||
}
|
||||
|
|
@ -1079,6 +1094,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 +1104,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 +1115,7 @@ get_width() const {
|
|||
*/
|
||||
INLINE LPoint3 TextNode::
|
||||
get_upper_left_3d() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _ul3d;
|
||||
}
|
||||
|
|
@ -1108,6 +1126,7 @@ get_upper_left_3d() const {
|
|||
*/
|
||||
INLINE LPoint3 TextNode::
|
||||
get_lower_right_3d() const {
|
||||
MutexHolder holder(_lock);
|
||||
check_measure();
|
||||
return _lr3d;
|
||||
}
|
||||
|
|
@ -1118,10 +1137,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 +1160,7 @@ get_num_rows() const {
|
|||
*/
|
||||
INLINE void TextNode::
|
||||
update() {
|
||||
MutexHolder holder(_lock);
|
||||
check_rebuild();
|
||||
}
|
||||
|
||||
|
|
@ -1140,8 +1172,9 @@ update() {
|
|||
*/
|
||||
INLINE void TextNode::
|
||||
force_update() {
|
||||
invalidate_with_measure();
|
||||
check_rebuild();
|
||||
MutexHolder holder(_lock);
|
||||
mark_internal_bounds_stale();
|
||||
do_rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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,272 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever the text has been changed.
|
||||
*/
|
||||
void TextNode::
|
||||
text_changed() {
|
||||
MutexHolder holder(_lock);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +668,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 +697,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 +725,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 +777,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 +793,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 +845,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 +869,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;
|
||||
|
|
@ -180,14 +182,6 @@ PUBLISHED:
|
|||
INLINE void set_glyph_shift(PN_stdfloat glyph_shift);
|
||||
INLINE void clear_glyph_shift();
|
||||
|
||||
// These methods are inherited from TextEncoder, but we override here so we
|
||||
// can flag the TextNode as dirty when they have been changed.
|
||||
INLINE void set_text(const std::string &text);
|
||||
INLINE void set_text(const std::string &text, Encoding encoding);
|
||||
INLINE void clear_text();
|
||||
INLINE void append_text(const std::string &text);
|
||||
INLINE void append_unicode_char(wchar_t character);
|
||||
|
||||
// After the text has been set, you can query this to determine how it will
|
||||
// be wordwrapped.
|
||||
INLINE std::string get_wordwrapped_text() const;
|
||||
|
|
@ -201,10 +195,6 @@ PUBLISHED:
|
|||
bool has_character(wchar_t character) const;
|
||||
bool is_whitespace(wchar_t character) const;
|
||||
|
||||
// Direct support for wide-character strings.
|
||||
INLINE void set_wtext(const std::wstring &wtext);
|
||||
INLINE void append_wtext(const std::wstring &text);
|
||||
|
||||
INLINE std::wstring get_wordwrapped_wtext() const;
|
||||
PN_stdfloat calc_width(const std::wstring &line) const;
|
||||
|
||||
|
|
@ -225,11 +215,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);
|
||||
|
|
@ -243,8 +233,6 @@ PUBLISHED:
|
|||
MAKE_PROPERTY(usage_hint, get_usage_hint, set_usage_hint);
|
||||
MAKE_PROPERTY(flatten_flags, get_flatten_flags, set_flatten_flags);
|
||||
|
||||
MAKE_PROPERTY(text, get_text, set_text);
|
||||
|
||||
MAKE_PROPERTY2(font, has_font, get_font, set_font, clear_font);
|
||||
MAKE_PROPERTY2(small_caps, has_small_caps, get_small_caps,
|
||||
set_small_caps, clear_small_caps);
|
||||
|
|
@ -279,6 +267,9 @@ PUBLISHED:
|
|||
set_text_scale, clear_text_scale);
|
||||
|
||||
public:
|
||||
// From parent class TextEncoder;
|
||||
virtual void text_changed() final;
|
||||
|
||||
// From parent class PandaNode
|
||||
virtual int get_unsafe_to_apply_attribs() const;
|
||||
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs,
|
||||
|
|
@ -312,12 +303,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;
|
||||
|
|
|
|||
|
|
@ -283,6 +283,25 @@ set_properties_now(WindowProperties &properties) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (properties.has_undecorated() ||
|
||||
properties.has_fixed_size()) {
|
||||
if (properties.has_undecorated()) {
|
||||
_properties.set_undecorated(properties.get_undecorated());
|
||||
properties.clear_undecorated();
|
||||
}
|
||||
if (properties.has_fixed_size()) {
|
||||
_properties.set_fixed_size(properties.get_fixed_size());
|
||||
properties.clear_fixed_size();
|
||||
}
|
||||
DWORD window_style = make_style(_properties);
|
||||
SetWindowLong(_hWnd, GWL_STYLE, window_style);
|
||||
|
||||
// We need to call this to ensure that the style change takes effect.
|
||||
SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE |
|
||||
SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
if (properties.has_title()) {
|
||||
std::string title = properties.get_title();
|
||||
_properties.set_title(title);
|
||||
|
|
@ -487,7 +506,7 @@ open_window() {
|
|||
// CreateWindow() and know which window it is sending events to even before
|
||||
// it gives us a handle. Warning: this is not thread safe!
|
||||
_creating_window = this;
|
||||
bool opened = open_graphic_window(is_fullscreen());
|
||||
bool opened = open_graphic_window();
|
||||
_creating_window = nullptr;
|
||||
|
||||
if (!opened) {
|
||||
|
|
@ -865,7 +884,9 @@ do_fullscreen_switch() {
|
|||
return false;
|
||||
}
|
||||
|
||||
DWORD window_style = make_style(true);
|
||||
WindowProperties props(_properties);
|
||||
props.set_fullscreen(true);
|
||||
DWORD window_style = make_style(props);
|
||||
SetWindowLong(_hWnd, GWL_STYLE, window_style);
|
||||
|
||||
WINDOW_METRICS metrics;
|
||||
|
|
@ -885,7 +906,10 @@ do_fullscreen_switch() {
|
|||
bool WinGraphicsWindow::
|
||||
do_windowed_switch() {
|
||||
do_fullscreen_disable();
|
||||
DWORD window_style = make_style(false);
|
||||
|
||||
WindowProperties props(_properties);
|
||||
props.set_fullscreen(false);
|
||||
DWORD window_style = make_style(props);
|
||||
SetWindowLong(_hWnd, GWL_STYLE, window_style);
|
||||
|
||||
WINDOW_METRICS metrics;
|
||||
|
|
@ -928,7 +952,7 @@ support_overlay_window(bool) {
|
|||
* Constructs a dwStyle for the specified mode, be it windowed or fullscreen.
|
||||
*/
|
||||
DWORD WinGraphicsWindow::
|
||||
make_style(bool fullscreen) {
|
||||
make_style(const WindowProperties &properties) {
|
||||
// from MSDN: An OpenGL window has its own pixel format. Because of this,
|
||||
// only device contexts retrieved for the client area of an OpenGL window
|
||||
// are allowed to draw into the window. As a result, an OpenGL window
|
||||
|
|
@ -938,7 +962,7 @@ make_style(bool fullscreen) {
|
|||
|
||||
DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||||
|
||||
if (fullscreen){
|
||||
if (_properties.get_fullscreen()) {
|
||||
window_style |= WS_SYSMENU;
|
||||
} else if (!_properties.get_undecorated()) {
|
||||
window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
|
||||
|
|
@ -1015,8 +1039,8 @@ calculate_metrics(bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics,
|
|||
* Creates a regular or fullscreen window.
|
||||
*/
|
||||
bool WinGraphicsWindow::
|
||||
open_graphic_window(bool fullscreen) {
|
||||
DWORD window_style = make_style(fullscreen);
|
||||
open_graphic_window() {
|
||||
DWORD window_style = make_style(_properties);
|
||||
|
||||
wstring title;
|
||||
if (_properties.has_title()) {
|
||||
|
|
@ -2186,12 +2210,12 @@ update_cursor_window(WinGraphicsWindow *to_window) {
|
|||
// We are leaving a graphics window; we should restore the Win2000
|
||||
// effects.
|
||||
if (_got_saved_params) {
|
||||
SystemParametersInfo(SPI_SETMOUSETRAILS, 0,
|
||||
(PVOID)_saved_mouse_trails, 0);
|
||||
SystemParametersInfo(SPI_SETMOUSETRAILS, _saved_mouse_trails,
|
||||
0, 0);
|
||||
SystemParametersInfo(SPI_SETCURSORSHADOW, 0,
|
||||
(PVOID)_saved_cursor_shadow, 0);
|
||||
_saved_cursor_shadow ? (PVOID)1 : nullptr, 0);
|
||||
SystemParametersInfo(SPI_SETMOUSEVANISH, 0,
|
||||
(PVOID)_saved_mouse_vanish, 0);
|
||||
_saved_mouse_vanish ? (PVOID)1 : nullptr, 0);
|
||||
_got_saved_params = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ protected:
|
|||
virtual bool calculate_metrics(bool fullscreen, DWORD style,
|
||||
WINDOW_METRICS &metrics, bool &has_origin);
|
||||
|
||||
virtual DWORD make_style(bool fullscreen);
|
||||
DWORD make_style(const WindowProperties &properties);
|
||||
|
||||
virtual void reconsider_fullscreen_size(DWORD &x_size, DWORD &y_size,
|
||||
DWORD &bitdepth);
|
||||
|
|
@ -127,7 +127,7 @@ protected:
|
|||
virtual void support_overlay_window(bool flag);
|
||||
|
||||
private:
|
||||
bool open_graphic_window(bool fullscreen);
|
||||
bool open_graphic_window();
|
||||
void adjust_z_order();
|
||||
void adjust_z_order(WindowProperties::ZOrder last_z_order,
|
||||
WindowProperties::ZOrder this_z_order);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,293 @@
|
|||
from panda3d import core
|
||||
import pytest
|
||||
|
||||
TEST_COLOR = core.LColor(1, 127/255.0, 0, 127/255.0)
|
||||
TEST_COLOR_SCALE = core.LVecBase4(0.5, 0.5, 0.5, 0.5)
|
||||
TEST_SCALED_COLOR = core.LColor(TEST_COLOR)
|
||||
TEST_SCALED_COLOR.componentwise_mult(TEST_COLOR_SCALE)
|
||||
FUZZ = 0.02
|
||||
|
||||
|
||||
@pytest.fixture(scope='session', params=[False, True], ids=["shader:off", "shader:auto"])
|
||||
def shader_attrib(request):
|
||||
"""Returns two ShaderAttribs: one with auto shader, one without."""
|
||||
if request.param:
|
||||
return core.ShaderAttrib.make_default().set_shader_auto(True)
|
||||
else:
|
||||
return core.ShaderAttrib.make_off()
|
||||
|
||||
|
||||
@pytest.fixture(scope='session', params=["mat:off", "mat:empty", "mat:amb", "mat:diff", "mat:both"])
|
||||
def material_attrib(request):
|
||||
"""Returns two MaterialAttribs: one with material, one without. It
|
||||
shouldn't really matter what we set them to, since the tests in here do
|
||||
not use lighting, and therefore the material should be ignored."""
|
||||
|
||||
if request.param == "mat:off":
|
||||
return core.MaterialAttrib.make_off()
|
||||
|
||||
elif request.param == "mat:empty":
|
||||
return core.MaterialAttrib.make(core.Material())
|
||||
|
||||
elif request.param == "mat:amb":
|
||||
mat = core.Material()
|
||||
mat.ambient = (0.1, 1, 0.5, 1)
|
||||
return core.MaterialAttrib.make(mat)
|
||||
|
||||
elif request.param == "mat:diff":
|
||||
mat = core.Material()
|
||||
mat.diffuse = (0.1, 1, 0.5, 1)
|
||||
return core.MaterialAttrib.make(mat)
|
||||
|
||||
elif request.param == "mat:both":
|
||||
mat = core.Material()
|
||||
mat.diffuse = (0.1, 1, 0.5, 1)
|
||||
mat.ambient = (0.1, 1, 0.5, 1)
|
||||
return core.MaterialAttrib.make(mat)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', params=[False, True], ids=["srgb:off", "srgb:on"])
|
||||
def color_region(request, graphics_pipe):
|
||||
"""Creates and returns a DisplayRegion with a depth buffer."""
|
||||
|
||||
engine = core.GraphicsEngine()
|
||||
engine.set_threading_model("")
|
||||
|
||||
host_fbprops = core.FrameBufferProperties()
|
||||
host_fbprops.force_hardware = True
|
||||
|
||||
host = engine.make_output(
|
||||
graphics_pipe,
|
||||
'host',
|
||||
0,
|
||||
host_fbprops,
|
||||
core.WindowProperties.size(32, 32),
|
||||
core.GraphicsPipe.BF_refuse_window,
|
||||
)
|
||||
engine.open_windows()
|
||||
|
||||
if host is None:
|
||||
pytest.skip("GraphicsPipe cannot make offscreen buffers")
|
||||
|
||||
fbprops = core.FrameBufferProperties()
|
||||
fbprops.force_hardware = True
|
||||
fbprops.set_rgba_bits(8, 8, 8, 8)
|
||||
fbprops.srgb_color = request.param
|
||||
|
||||
buffer = engine.make_output(
|
||||
graphics_pipe,
|
||||
'buffer',
|
||||
0,
|
||||
fbprops,
|
||||
core.WindowProperties.size(32, 32),
|
||||
core.GraphicsPipe.BF_refuse_window,
|
||||
host.gsg,
|
||||
host
|
||||
)
|
||||
engine.open_windows()
|
||||
|
||||
if buffer is None:
|
||||
pytest.skip("Cannot make color buffer")
|
||||
|
||||
if fbprops.srgb_color != buffer.get_fb_properties().srgb_color:
|
||||
pytest.skip("Cannot make buffer with required srgb_color setting")
|
||||
|
||||
buffer.set_clear_color_active(True)
|
||||
buffer.set_clear_color((0, 0, 0, 1))
|
||||
|
||||
yield buffer.make_display_region()
|
||||
|
||||
if buffer is not None:
|
||||
engine.remove_window(buffer)
|
||||
|
||||
|
||||
def render_color_pixel(region, state, vertex_color=None):
|
||||
"""Renders a fragment using the specified render settings, and returns the
|
||||
resulting color value."""
|
||||
|
||||
# Set up the scene with a blank card rendering at specified distance.
|
||||
scene = core.NodePath("root")
|
||||
scene.set_attrib(core.DepthTestAttrib.make(core.RenderAttrib.M_always))
|
||||
|
||||
camera = scene.attach_new_node(core.Camera("camera"))
|
||||
camera.node().get_lens(0).set_near_far(1, 3)
|
||||
camera.node().set_cull_bounds(core.OmniBoundingVolume())
|
||||
|
||||
if vertex_color is not None:
|
||||
format = core.GeomVertexFormat.get_v3cp()
|
||||
else:
|
||||
format = core.GeomVertexFormat.get_v3()
|
||||
|
||||
vdata = core.GeomVertexData("card", format, core.Geom.UH_static)
|
||||
vdata.unclean_set_num_rows(4)
|
||||
|
||||
vertex = core.GeomVertexWriter(vdata, "vertex")
|
||||
vertex.set_data3(core.Vec3.rfu(-1, 0, 1))
|
||||
vertex.set_data3(core.Vec3.rfu(-1, 0, -1))
|
||||
vertex.set_data3(core.Vec3.rfu(1, 0, 1))
|
||||
vertex.set_data3(core.Vec3.rfu(1, 0, -1))
|
||||
|
||||
if vertex_color is not None:
|
||||
color = core.GeomVertexWriter(vdata, "color")
|
||||
color.set_data4(vertex_color)
|
||||
color.set_data4(vertex_color)
|
||||
color.set_data4(vertex_color)
|
||||
color.set_data4(vertex_color)
|
||||
|
||||
strip = core.GeomTristrips(core.Geom.UH_static)
|
||||
strip.set_shade_model(core.Geom.SM_uniform)
|
||||
strip.add_next_vertices(4)
|
||||
strip.close_primitive()
|
||||
|
||||
geom = core.Geom(vdata)
|
||||
geom.add_primitive(strip)
|
||||
|
||||
gnode = core.GeomNode("card")
|
||||
gnode.add_geom(geom, state)
|
||||
card = scene.attach_new_node(gnode)
|
||||
card.set_pos(0, 2, 0)
|
||||
card.set_scale(60)
|
||||
|
||||
region.active = True
|
||||
region.camera = camera
|
||||
|
||||
color_texture = core.Texture("color")
|
||||
region.window.add_render_texture(color_texture,
|
||||
core.GraphicsOutput.RTM_copy_ram,
|
||||
core.GraphicsOutput.RTP_color)
|
||||
|
||||
region.window.engine.render_frame()
|
||||
region.window.clear_render_textures()
|
||||
|
||||
col = core.LColor()
|
||||
color_texture.peek().lookup(col, 0.5, 0.5)
|
||||
return col
|
||||
|
||||
|
||||
def test_color_write_mask(color_region):
|
||||
state = core.RenderState.make(
|
||||
core.ColorWriteAttrib.make(core.ColorWriteAttrib.C_green),
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result == (0, 1, 0, 1)
|
||||
|
||||
|
||||
def test_color_empty(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result == (1, 1, 1, 1)
|
||||
|
||||
|
||||
def test_color_off(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_off(),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result == (1, 1, 1, 1)
|
||||
|
||||
|
||||
def test_color_flat(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_flat(TEST_COLOR),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result.almost_equal(TEST_COLOR, FUZZ)
|
||||
|
||||
|
||||
def test_color_vertex(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_vertex(),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||
assert result.almost_equal(TEST_COLOR, FUZZ)
|
||||
|
||||
|
||||
def test_color_empty_vertex(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||
assert result.almost_equal(TEST_COLOR, FUZZ)
|
||||
|
||||
|
||||
def test_color_off_vertex(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_off(),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||
assert result == (1, 1, 1, 1)
|
||||
|
||||
|
||||
def test_scaled_color_empty(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result == (1, 1, 1, 1)
|
||||
|
||||
|
||||
def test_scaled_color_off(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_off(),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result == (1, 1, 1, 1)
|
||||
|
||||
|
||||
def test_scaled_color_flat(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_flat(TEST_COLOR),
|
||||
core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
|
||||
|
||||
|
||||
def test_scaled_color_vertex(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_vertex(),
|
||||
core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||
assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
|
||||
|
||||
|
||||
def test_scaled_color_empty_vertex(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||
assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
|
||||
|
||||
|
||||
def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib):
|
||||
state = core.RenderState.make(
|
||||
core.ColorAttrib.make_off(),
|
||||
core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||
assert result.almost_equal(TEST_COLOR_SCALE, FUZZ)
|
||||
|
||||
|
|
@ -91,8 +91,6 @@ def render_depth_pixel(region, distance, near, far, clear=None, write=True):
|
|||
region.window.engine.render_frame()
|
||||
region.window.clear_render_textures()
|
||||
|
||||
depth_texture.write("test2.png")
|
||||
|
||||
col = core.LColor()
|
||||
depth_texture.peek().lookup(col, 0.5, 0.5)
|
||||
return col[0]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import sys
|
||||
import pytest
|
||||
from panda3d.core import TextEncoder
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
unichr = chr
|
||||
xrange = range
|
||||
|
||||
|
||||
def valid_characters():
|
||||
"""Generator yielding all valid Unicode code points."""
|
||||
|
||||
for i in xrange(0xd800):
|
||||
yield unichr(i)
|
||||
|
||||
for i in xrange(0xe000, sys.maxunicode + 1):
|
||||
if i != 0xfeff and i & 0xfffe != 0xfffe:
|
||||
yield unichr(i)
|
||||
|
||||
|
||||
def test_text_decode_iso8859():
|
||||
encoder = TextEncoder()
|
||||
encoder.set_encoding(TextEncoder.E_iso8859)
|
||||
|
||||
for i in xrange(255):
|
||||
enc = unichr(i).encode('latin-1')
|
||||
assert len(enc) == 1
|
||||
|
||||
dec = encoder.decode_text(enc)
|
||||
assert len(dec) == 1
|
||||
assert ord(dec) == i
|
||||
|
||||
|
||||
def test_text_decode_utf8():
|
||||
encoder = TextEncoder()
|
||||
encoder.set_encoding(TextEncoder.E_utf8)
|
||||
|
||||
for c in valid_characters():
|
||||
enc = c.encode('utf-8')
|
||||
assert len(enc) <= 4
|
||||
|
||||
dec = encoder.decode_text(enc)
|
||||
assert len(dec) == 1
|
||||
assert dec == c
|
||||
|
||||
|
||||
def test_text_decode_utf16be():
|
||||
encoder = TextEncoder()
|
||||
encoder.set_encoding(TextEncoder.E_utf16be)
|
||||
|
||||
for c in valid_characters():
|
||||
enc = c.encode('utf-16be')
|
||||
|
||||
dec = encoder.decode_text(enc)
|
||||
assert len(c) == len(dec)
|
||||
assert c == dec
|
||||
|
||||
|
||||
def test_text_encode_iso8859():
|
||||
encoder = TextEncoder()
|
||||
encoder.set_encoding(TextEncoder.E_iso8859)
|
||||
|
||||
for i in xrange(255):
|
||||
c = unichr(i)
|
||||
enc = encoder.encode_wtext(c)
|
||||
assert enc == c.encode('latin-1')
|
||||
|
||||
|
||||
def test_text_encode_utf8():
|
||||
encoder = TextEncoder()
|
||||
encoder.set_encoding(TextEncoder.E_utf8)
|
||||
|
||||
for c in valid_characters():
|
||||
enc = encoder.encode_wtext(c)
|
||||
assert enc == c.encode('utf-8')
|
||||
|
||||
|
||||
def test_text_encode_utf16be():
|
||||
encoder = TextEncoder()
|
||||
encoder.set_encoding(TextEncoder.E_utf16be)
|
||||
|
||||
for c in valid_characters():
|
||||
enc = encoder.encode_wtext(c)
|
||||
assert enc == c.encode('utf-16-be')
|
||||
|
||||
|
||||
def test_text_append_unicode_char():
|
||||
encoder = TextEncoder()
|
||||
encoder.set_encoding(TextEncoder.E_iso8859)
|
||||
|
||||
code_points = []
|
||||
for code_point in [0, 1, 127, 128, 255, 256, 0xfffd, 0x10000, 0x10ffff]:
|
||||
if code_point <= sys.maxunicode:
|
||||
code_points.append(code_point)
|
||||
encoder.append_unicode_char(code_point)
|
||||
|
||||
encoded = encoder.get_wtext()
|
||||
assert len(encoded) == len(code_points)
|
||||
|
||||
for a, b in zip(code_points, encoded):
|
||||
assert a == ord(b)
|
||||
|
|
@ -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))
|
||||
Loading…
Reference in New Issue