Merge branch 'master' into cmake
This commit is contained in:
commit
ea1b50a522
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
|
||||
=============
|
||||
|
||||
|
|
|
|||
|
|
@ -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,159 @@
|
|||
/**
|
||||
* 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);
|
||||
_this->append_text(std::string(str, len));
|
||||
#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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -2882,6 +2882,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:
|
||||
|
|
@ -3548,6 +3551,7 @@ IGATEFILES += [
|
|||
"dSearchPath.h",
|
||||
"executionEnvironment.h",
|
||||
"textEncoder.h",
|
||||
"textEncoder_ext.h",
|
||||
"filename.h",
|
||||
"filename_ext.h",
|
||||
"globPattern.h",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -1010,61 +1010,6 @@ clear_glyph_shift() {
|
|||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the text that is displayed under the TextNode.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
set_text(const std::string &text) {
|
||||
MutexHolder holder(_lock);
|
||||
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) {
|
||||
MutexHolder holder(_lock);
|
||||
TextEncoder::set_text(text, encoding);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the text from the TextNode.
|
||||
*/
|
||||
INLINE void TextNode::
|
||||
clear_text() {
|
||||
MutexHolder holder(_lock);
|
||||
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) {
|
||||
MutexHolder holder(_lock);
|
||||
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) {
|
||||
MutexHolder holder(_lock);
|
||||
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.
|
||||
|
|
@ -1086,28 +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) {
|
||||
MutexHolder holder(_lock);
|
||||
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) {
|
||||
MutexHolder holder(_lock);
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -319,6 +319,15 @@ get_internal_geom() const {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -182,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;
|
||||
|
|
@ -203,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;
|
||||
|
||||
|
|
@ -245,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);
|
||||
|
|
@ -281,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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
Loading…
Reference in New Issue